Skip to content

Commit a62129f

Browse files
committed
Move Module to rely less on shared examples
1 parent 1b95566 commit a62129f

6 files changed

Lines changed: 209 additions & 217 deletions

File tree

core/module/class_eval_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require_relative '../../spec_helper'
2-
require_relative 'fixtures/classes'
3-
require_relative 'shared/class_eval'
42

53
describe "Module#class_eval" do
6-
it_behaves_like :module_class_eval, :class_eval
4+
it "is an alias of Module#module_eval" do
5+
Module.instance_method(:class_eval).should == Module.instance_method(:module_eval)
6+
end
77
end

core/module/class_exec_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require_relative '../../spec_helper'
2-
require_relative 'fixtures/classes'
3-
require_relative 'shared/class_exec'
42

53
describe "Module#class_exec" do
6-
it_behaves_like :module_class_exec, :class_exec
4+
it "is an alias of Module#module_exec" do
5+
Module.instance_method(:class_exec).should == Module.instance_method(:module_exec)
6+
end
77
end

core/module/module_eval_spec.rb

Lines changed: 170 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,175 @@
11
require_relative '../../spec_helper'
22
require_relative 'fixtures/classes'
3-
require_relative 'shared/class_eval'
43

54
describe "Module#module_eval" do
6-
it_behaves_like :module_class_eval, :module_eval
5+
# TODO: This should probably be replaced with a "should behave like" that uses
6+
# the many scoping/binding specs from kernel/eval_spec, since most of those
7+
# behaviors are the same for instance_eval. See also module_eval/class_eval.
8+
9+
it "evaluates a given string in the context of self" do
10+
ModuleSpecs.module_eval("self").should == ModuleSpecs
11+
ModuleSpecs.module_eval("1 + 1").should == 2
12+
end
13+
14+
it "does not add defined methods to other classes" do
15+
FalseClass.module_eval do
16+
def foo
17+
'foo'
18+
end
19+
end
20+
-> {42.foo}.should.raise(NoMethodError)
21+
end
22+
23+
it "resolves constants in the caller scope" do
24+
ModuleSpecs::ClassEvalTest.get_constant_from_scope.should == ModuleSpecs::Lookup
25+
end
26+
27+
it "resolves constants in the caller scope ignoring send" do
28+
ModuleSpecs::ClassEvalTest.get_constant_from_scope_with_send(:module_eval).should == ModuleSpecs::Lookup
29+
end
30+
31+
it "resolves constants in the receiver's scope" do
32+
ModuleSpecs.module_eval("Lookup").should == ModuleSpecs::Lookup
33+
ModuleSpecs.module_eval("Lookup::LOOKIE").should == ModuleSpecs::Lookup::LOOKIE
34+
end
35+
36+
it "defines constants in the receiver's scope" do
37+
ModuleSpecs.module_eval("module NewEvaluatedModule;end")
38+
ModuleSpecs.const_defined?(:NewEvaluatedModule, false).should == true
39+
end
40+
41+
it "evaluates a given block in the context of self" do
42+
ModuleSpecs.module_eval { self }.should == ModuleSpecs
43+
ModuleSpecs.module_eval { 1 + 1 }.should == 2
44+
end
45+
46+
it "passes the module as the first argument of the block" do
47+
given = nil
48+
ModuleSpecs.module_eval do |block_parameter|
49+
given = block_parameter
50+
end
51+
given.should.equal? ModuleSpecs
52+
end
53+
54+
it "uses the optional filename and lineno parameters for error messages" do
55+
ModuleSpecs.module_eval("[__FILE__, __LINE__]", "test", 102).should == ["test", 102]
56+
end
57+
58+
it "uses the caller location as default filename" do
59+
ModuleSpecs.module_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
60+
end
61+
62+
it "converts a non-string filename to a string using to_str" do
63+
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
64+
ModuleSpecs.module_eval("1+1", file)
65+
66+
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
67+
ModuleSpecs.module_eval("1+1", file, 15)
68+
end
69+
70+
it "raises a TypeError when the given filename can't be converted to string using to_str" do
71+
(file = mock('123')).should_receive(:to_str).and_return(123)
72+
-> { ModuleSpecs.module_eval("1+1", file) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
73+
end
74+
75+
it "converts non string eval-string to string using to_str" do
76+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
77+
ModuleSpecs.module_eval(o).should == 2
78+
79+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
80+
ModuleSpecs.module_eval(o, "file.rb").should == 2
81+
82+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
83+
ModuleSpecs.module_eval(o, "file.rb", 15).should == 2
84+
end
85+
86+
it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
87+
o = mock('x')
88+
-> { ModuleSpecs.module_eval(o) }.should.raise(TypeError, "no implicit conversion of MockObject into String")
89+
90+
(o = mock('123')).should_receive(:to_str).and_return(123)
91+
-> { ModuleSpecs.module_eval(o) }.should raise_consistent_error(TypeError, /can't convert MockObject into String/)
92+
end
93+
94+
it "raises an ArgumentError when no arguments and no block are given" do
95+
-> { ModuleSpecs.module_eval }.should.raise(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
96+
end
97+
98+
it "raises an ArgumentError when more than 3 arguments are given" do
99+
-> {
100+
ModuleSpecs.module_eval("1 + 1", "some file", 0, "bogus")
101+
}.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
102+
end
103+
104+
it "raises an ArgumentError when a block and normal arguments are given" do
105+
-> {
106+
ModuleSpecs.module_eval("1 + 1") { 1 + 1 }
107+
}.should.raise(ArgumentError, "wrong number of arguments (given 1, expected 0)")
108+
end
109+
110+
# This case was found because Rubinius was caching the compiled
111+
# version of the string and not duping the methods within the
112+
# eval, causing the method addition to change the static scope
113+
# of the shared CompiledCode.
114+
it "adds methods respecting the lexical constant scope" do
115+
code = "def self.attribute; C; end"
116+
117+
a = Class.new do
118+
self::C = "A"
119+
end
120+
121+
b = Class.new do
122+
self::C = "B"
123+
end
124+
125+
a.module_eval(code)
126+
b.module_eval(code)
127+
128+
a.attribute.should == "A"
129+
b.attribute.should == "B"
130+
end
131+
132+
it "activates refinements from the eval scope" do
133+
refinery = Module.new do
134+
refine ModuleSpecs::NamedClass do
135+
def foo
136+
"bar"
137+
end
138+
end
139+
end
140+
141+
mid = :module_eval
142+
result = nil
143+
144+
Class.new do
145+
using refinery
146+
147+
result = send(mid, "ModuleSpecs::NamedClass.new.foo")
148+
end
149+
150+
result.should == "bar"
151+
end
152+
153+
it "activates refinements from the eval scope with block" do
154+
refinery = Module.new do
155+
refine ModuleSpecs::NamedClass do
156+
def foo
157+
"bar"
158+
end
159+
end
160+
end
161+
162+
mid = :module_eval
163+
result = nil
164+
165+
Class.new do
166+
using refinery
167+
168+
result = send(mid) do
169+
ModuleSpecs::NamedClass.new.foo
170+
end
171+
end
172+
173+
result.should == "bar"
174+
end
7175
end

core/module/module_exec_spec.rb

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,38 @@
11
require_relative '../../spec_helper'
22
require_relative 'fixtures/classes'
3-
require_relative 'shared/class_exec'
43

54
describe "Module#module_exec" do
6-
it_behaves_like :module_class_exec, :module_exec
5+
it "does not add defined methods to other classes" do
6+
FalseClass.module_exec do
7+
def foo
8+
'foo'
9+
end
10+
end
11+
-> {42.foo}.should.raise(NoMethodError)
12+
end
13+
14+
it "defines method in the receiver's scope" do
15+
ModuleSpecs::Subclass.module_exec { def foo; end }
16+
ModuleSpecs::Subclass.new.respond_to?(:foo).should == true
17+
end
18+
19+
it "evaluates a given block in the context of self" do
20+
ModuleSpecs::Subclass.module_exec { self }.should == ModuleSpecs::Subclass
21+
ModuleSpecs::Subclass.new.module_exec { 1 + 1 }.should == 2
22+
end
23+
24+
it "raises a LocalJumpError when no block is given" do
25+
-> { ModuleSpecs::Subclass.module_exec }.should.raise(LocalJumpError)
26+
end
27+
28+
it "passes arguments to the block" do
29+
a = ModuleSpecs::Subclass
30+
a.module_exec(1) { |b| b }.should.equal?(1)
31+
end
32+
33+
describe "with optional argument" do
34+
it "does not destructure a single array argument" do
35+
ModuleSpecs::Subclass.module_exec([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
36+
end
37+
end
738
end

0 commit comments

Comments
 (0)