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