diff options
Diffstat (limited to 'spec/ruby/core/kernel/eval_spec.rb')
| -rw-r--r-- | spec/ruby/core/kernel/eval_spec.rb | 153 |
1 files changed, 110 insertions, 43 deletions
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 5f4cd27da0..f9ca47866e 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -5,7 +5,7 @@ EvalSpecs::A.new.c describe "Kernel#eval" do it "is a private method" do - Kernel.should have_private_instance_method(:eval) + Kernel.private_instance_methods(false).should.include?(:eval) end it "is a module function" do @@ -76,12 +76,12 @@ describe "Kernel#eval" do x = 1 bind = proc {} - -> { eval("x", bind) }.should raise_error(TypeError) + -> { eval("x", bind) }.should.raise(TypeError) end it "does not make Proc locals visible to evaluated code" do bind = proc { inner = 4 } - -> { eval("inner", bind.binding) }.should raise_error(NameError) + -> { eval("inner", bind.binding) }.should.raise(NameError) end # REWRITE ME: This obscures the real behavior of where locals are stored @@ -119,7 +119,7 @@ describe "Kernel#eval" do outer_binding = binding eval("if false; a = 1; end", outer_binding) - eval("a", outer_binding).should be_nil + eval("a", outer_binding).should == nil end it "allows creating a new class in a binding" do @@ -136,7 +136,7 @@ describe "Kernel#eval" do expected = 'speccing.rb' -> { eval('if true', TOPLEVEL_BINDING, expected) - }.should raise_error(SyntaxError) { |e| + }.should.raise(SyntaxError) { |e| e.message.should =~ /#{expected}:1:.+/ } end @@ -145,7 +145,7 @@ describe "Kernel#eval" do expected_file = 'speccing.rb' -> { eval('if true', TOPLEVEL_BINDING, expected_file, -100) - }.should raise_error(SyntaxError) { |e| + }.should.raise(SyntaxError) { |e| e.message.should =~ /#{expected_file}:-100:.+/ } end @@ -159,36 +159,87 @@ describe "Kernel#eval" do end end - ruby_version_is ""..."3.3" do - it "uses (eval) filename if none is provided" do - eval("__FILE__").should == "(eval)" - eval("__FILE__", binding).should == "(eval)" - eval("__FILE__", binding, "success").should == "success" - eval("eval '__FILE__', binding").should == "(eval)" - eval("eval '__FILE__', binding", binding).should == "(eval)" - eval("eval '__FILE__', binding", binding, 'success').should == '(eval)' - eval("eval '__FILE__', binding, 'success'", binding).should == 'success' + context "parameter forwarding" do + it "allows anonymous rest parameter forwarding" do + object = Object.new + def object.foo(a, b, c) + [a, b, c] + end + def object.bar(*) + eval "foo(*)" + end + + object.bar(1, 2, 3).should == [1, 2, 3] end - it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do - eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1] + it "allows anonymous keyword parameters forwarding" do + object = Object.new + def object.foo(a:, b:, c:) + [a, b, c] + end + def object.bar(**) + eval "foo(**)" + end + + object.bar(a: 1, b: 2, c: 3).should == [1, 2, 3] end - end - ruby_version_is "3.3" do - it "uses (eval at __FILE__:__LINE__) if none is provided" do - eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding, "success").should == "success" - eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)" - eval("eval '__FILE__', binding, 'success'", binding).should == 'success' + it "allows anonymous block parameter forwarding" do + object = Object.new + def object.foo(&block) + block.call + end + def object.bar(&) + eval "foo(&)" + end + + object.bar { :foobar }.should == :foobar end - it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do - eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1] + it "allows ... forwarding" do + object = Object.new + def object.foo(a, b:, &block) + [a, b, block.call] + end + def object.bar(...) + eval "foo(...)" + end + + object.bar(1, b: 2) { 3 }.should == [1, 2, 3] end + + it "allows parameter forwarding to super" do + m = Module.new do + def foo(a, b:, &block) + [a, b, block.call] + end + end + + c = Class.new do + include m + + def foo(a, b:, &block) + eval "super" + end + end + + object = c.new + object.foo(1, b: 2) { 3 }.should == [1, 2, 3] + end + end + + it "uses (eval at __FILE__:__LINE__) if none is provided" do + eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" + eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})" + eval("__FILE__", binding, "success").should == "success" + eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" + eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" + eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)" + eval("eval '__FILE__', binding, 'success'", binding).should == 'success' + end + + it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do + eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1] end # Found via Rubinius bug github:#149 it "does not alter the value of __FILE__ in the binding" do @@ -212,14 +263,14 @@ describe "Kernel#eval" do # See http://jira.codehaus.org/browse/JRUBY-5163 it "uses the receiver as self inside the eval" do - eval("self").should equal(self) - Kernel.eval("self").should equal(Kernel) + eval("self").should.equal?(self) + Kernel.eval("self").should.equal?(Kernel) end it "does not pass the block to the method being eval'ed" do -> { eval('KernelSpecs::EvalTest.call_yield') { "content" } - }.should raise_error(LocalJumpError) + }.should.raise(LocalJumpError) end it "returns from the scope calling #eval when evaluating 'return'" do @@ -257,7 +308,7 @@ describe "Kernel#eval" do it "has the correct default definee when called through Method#call" do class EvalSpecs method(:eval).call("def eval_spec_method_call; end") - EvalSpecs.should have_instance_method(:eval_spec_method_call) + EvalSpecs.should.method_defined?(:eval_spec_method_call, false) end end @@ -311,8 +362,10 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπ") + EvalSpecs.constants(false).should.include?(:"Vπ") EvalSpecs::Vπ.should == 3.14 + ensure + EvalSpecs.send(:remove_const, :Vπ) end it "allows an emacs-style magic comment encoding" do @@ -324,8 +377,10 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπemacs") + EvalSpecs.constants(false).should.include?(:"Vπemacs") EvalSpecs::Vπemacs.should == 3.14 + ensure + EvalSpecs.send(:remove_const, :Vπemacs) end it "allows spaces before the magic encoding comment" do @@ -337,8 +392,10 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπspaces") + EvalSpecs.constants(false).should.include?(:"Vπspaces") EvalSpecs::Vπspaces.should == 3.14 + ensure + EvalSpecs.send(:remove_const, :Vπspaces) end it "allows a shebang line before the magic encoding comment" do @@ -351,8 +408,10 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπshebang") + EvalSpecs.constants(false).should.include?(:"Vπshebang") EvalSpecs::Vπshebang.should == 3.14 + ensure + EvalSpecs.send(:remove_const, :Vπshebang) end it "allows a shebang line and some spaces before the magic encoding comment" do @@ -365,8 +424,10 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπshebang_spaces") + EvalSpecs.constants(false).should.include?(:"Vπshebang_spaces") EvalSpecs::Vπshebang_spaces.should == 3.14 + ensure + EvalSpecs.send(:remove_const, :Vπshebang_spaces) end it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do @@ -381,10 +442,12 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπstring") + EvalSpecs.constants(false).should.include?(:"Vπstring") EvalSpecs::Vπstring.should == "frozen" EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8 EvalSpecs::Vπstring.frozen?.should == !frozen_string_default + ensure + EvalSpecs.send(:remove_const, :Vπstring) end it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do @@ -396,10 +459,12 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should include(:"Vπsame_line") + EvalSpecs.constants(false).should.include?(:"Vπsame_line") EvalSpecs::Vπsame_line.should == "frozen" EvalSpecs::Vπsame_line.encoding.should == Encoding::UTF_8 - EvalSpecs::Vπsame_line.frozen?.should be_true + EvalSpecs::Vπsame_line.frozen?.should == true + ensure + EvalSpecs.send(:remove_const, :Vπsame_line) end it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do @@ -413,13 +478,15 @@ end CODE code.encoding.should == Encoding::BINARY eval(code) - EvalSpecs.constants(false).should_not include(:"Vπfrozen_first") + EvalSpecs.constants(false).should_not.include?(:"Vπfrozen_first") binary_constant = "Vπfrozen_first".b.to_sym - EvalSpecs.constants(false).should include(binary_constant) + EvalSpecs.constants(false).should.include?(binary_constant) value = EvalSpecs.const_get(binary_constant) value.should == "frozen" value.encoding.should == Encoding::BINARY value.frozen?.should == !frozen_string_default + ensure + EvalSpecs.send(:remove_const, binary_constant) end it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do |
