1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2018-04-28 19:50:06 +00:00
parent b864bd05bf
commit 4fbb9aa3cb
145 changed files with 2847 additions and 2596 deletions

View file

@ -62,14 +62,12 @@ describe "A block yielded a single" do
result.should == [{"a" => 1}, b: 2]
end
ruby_version_is "2.2.1" do # SEGV on MRI 2.2.0
it "calls #to_hash on the argument but does not use the result when no keywords are present" do
obj = mock("coerce block keyword arguments")
obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})
it "calls #to_hash on the argument but does not use the result when no keywords are present" do
obj = mock("coerce block keyword arguments")
obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})
result = m([obj]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 1, "b" => 2}, {}]
end
result = m([obj]) { |a=nil, **b| [a, b] }
result.should == [{"a" => 1, "b" => 2}, {}]
end
it "assigns non-symbol keys to non-keyword arguments" do

View file

@ -13,11 +13,9 @@ describe "The class keyword" do
ClassSpecsKeywordWithSemicolon.should be_an_instance_of(Class)
end
ruby_version_is "2.3" do
it "does not raise a SyntaxError when opening a class without a semicolon" do
eval "class ClassSpecsKeywordWithoutSemicolon end"
ClassSpecsKeywordWithoutSemicolon.should be_an_instance_of(Class)
end
it "does not raise a SyntaxError when opening a class without a semicolon" do
eval "class ClassSpecsKeywordWithoutSemicolon end"
ClassSpecsKeywordWithoutSemicolon.should be_an_instance_of(Class)
end
end

View file

@ -404,24 +404,22 @@ describe "Constant resolution within a singleton class (class << obj)" do
ConstantSpecs::CS_SINGLETON1.foo.should == 1
end
ruby_version_is "2.3" do
it "uses its own namespace for each object" do
a = ConstantSpecs::CS_SINGLETON2[0].foo
b = ConstantSpecs::CS_SINGLETON2[1].foo
[a, b].should == [1, 2]
end
it "uses its own namespace for each object" do
a = ConstantSpecs::CS_SINGLETON2[0].foo
b = ConstantSpecs::CS_SINGLETON2[1].foo
[a, b].should == [1, 2]
end
it "uses its own namespace for nested modules" do
a = ConstantSpecs::CS_SINGLETON3[0].x
b = ConstantSpecs::CS_SINGLETON3[1].x
a.should_not equal(b)
end
it "uses its own namespace for nested modules" do
a = ConstantSpecs::CS_SINGLETON3[0].x
b = ConstantSpecs::CS_SINGLETON3[1].x
a.should_not equal(b)
end
it "allows nested modules to have proper resolution" do
a = ConstantSpecs::CS_SINGLETON4_CLASSES[0].new
b = ConstantSpecs::CS_SINGLETON4_CLASSES[1].new
[a.foo, b.foo].should == [1, 2]
end
it "allows nested modules to have proper resolution" do
a = ConstantSpecs::CS_SINGLETON4_CLASSES[0].new
b = ConstantSpecs::CS_SINGLETON4_CLASSES[1].new
[a.foo, b.foo].should == [1, 2]
end
end

View file

@ -66,6 +66,18 @@ describe "An ensure block inside a begin block" do
:ensure
end.should == :begin
end
it "sets exception cause if raises exception in block and in ensure" do
-> {
begin
raise "from block"
ensure
raise "from ensure"
end
}.should raise_error(RuntimeError, "from ensure") do |e|
e.cause.message.should == "from block"
end
end
end
describe "The value of an ensure expression," do
@ -117,6 +129,34 @@ describe "An ensure block inside a method" do
it "has an impact on the method's explicit return value" do
@obj.explicit_return_in_method_with_ensure.should == :ensure
end
it "has an impact on the method's explicit return value from rescue if returns explicitly" do
@obj.explicit_return_in_rescue_and_explicit_return_in_ensure.should == "returned in ensure"
end
it "has no impact on the method's explicit return value from rescue if returns implicitly" do
@obj.explicit_return_in_rescue_and_implicit_return_in_ensure.should == "returned in rescue"
end
it "suppresses exception raised in method if returns value explicitly" do
@obj.raise_and_explicit_return_in_ensure.should == "returned in ensure"
end
it "suppresses exception raised in rescue if returns value explicitly" do
@obj.raise_in_rescue_and_explicit_return_in_ensure.should == "returned in ensure"
end
it "overrides exception raised in rescue if raises exception itself" do
-> {
@obj.raise_in_rescue_and_raise_in_ensure
}.should raise_error(RuntimeError, "raised in ensure")
end
it "suppresses exception raised in method if raises exception itself" do
-> {
@obj.raise_in_method_and_raise_in_ensure
}.should raise_error(RuntimeError, "raised in ensure")
end
end
describe "An ensure block inside a class" do

View file

@ -40,6 +40,50 @@ module EnsureSpec
ensure
return :ensure
end
def explicit_return_in_rescue_and_explicit_return_in_ensure
raise
rescue
return 2
ensure
return "returned in ensure"
end
def explicit_return_in_rescue_and_implicit_return_in_ensure
raise
rescue
return "returned in rescue"
ensure
3
end
def raise_and_explicit_return_in_ensure
raise
ensure
return "returned in ensure"
end
def raise_in_rescue_and_explicit_return_in_ensure
raise
rescue
raise
ensure
return "returned in ensure"
end
def raise_in_rescue_and_raise_in_ensure
raise
rescue
raise "raised in rescue"
ensure
raise "raised in ensure"
end
def raise_in_method_and_raise_in_ensure
raise
ensure
raise "raised in ensure"
end
end
end

View file

@ -455,6 +455,38 @@ module Super
end
end
module ZSuperWithRestReassigned
class A
def a(*args)
args
end
end
class B < A
def a(*args)
args = ["foo"]
super
end
end
end
module ZSuperWithRestReassignedWithScalar
class A
def a(*args)
args
end
end
class B < A
def a(*args)
args = "foo"
super
end
end
end
module ZSuperWithUnderscores
class A
def m(*args)

View file

@ -53,35 +53,33 @@ HERE
s.should == ' foo bar#{@ip}' + "\n"
end
ruby_version_is "2.3" do
it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.message.should == "character density, n.:\n The number of very weird people in the office.\n"
end
it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.message.should == "character density, n.:\n The number of very weird people in the office.\n"
end
it "trims trailing newline character for blank HEREDOC with <<~'identifier'" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.blank.should == ""
end
it "trims trailing newline character for blank HEREDOC with <<~'identifier'" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.blank.should == ""
end
it 'allows HEREDOC with <<~identifier, interpolated' do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.unquoted.should == "unquoted interpolated\n"
end
it 'allows HEREDOC with <<~identifier, interpolated' do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.unquoted.should == "unquoted interpolated\n"
end
it 'allows HEREDOC with <<~"identifier", interpolated' do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.doublequoted.should == "doublequoted interpolated\n"
end
it 'allows HEREDOC with <<~"identifier", interpolated' do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.doublequoted.should == "doublequoted interpolated\n"
end
it "allows HEREDOC with <<~'identifier', no interpolation" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.singlequoted.should == "singlequoted \#{\"interpolated\"}\n"
end
it "allows HEREDOC with <<~'identifier', no interpolation" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.singlequoted.should == "singlequoted \#{\"interpolated\"}\n"
end
it "selects the least-indented line and removes its indentation from all the lines" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.least_indented_on_the_last_line.should == " a\n b\nc\n"
end
it "selects the least-indented line and removes its indentation from all the lines" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.least_indented_on_the_last_line.should == " a\n b\nc\n"
end
end

View file

@ -181,6 +181,52 @@ describe 'Optional variable assignments' do
@a.b.should == 20
end
end
describe 'using a #[]' do
before do
@a = {}
end
it 'leaves new variable unassigned' do
@a[:k] &&= 10
@a.key?(:k).should == false
end
it 'leaves false' do
@a[:k] = false
@a[:k] &&= 10
@a[:k].should == false
end
it 'leaves nil' do
@a[:k] = nil
@a[:k] &&= 10
@a[:k].should == nil
end
it 'does not evaluate the right side when not needed' do
@a[:k] = nil
@a[:k] &&= raise('should not be executed')
@a[:k].should == nil
end
it 'does re-assign a variable with a truthy value' do
@a[:k] = 10
@a[:k] &&= 20
@a[:k].should == 20
end
it 'does re-assign a variable with a truthy value when using an inline rescue' do
@a[:k] = 10
@a[:k] &&= 20 rescue 30
@a[:k].should == 20
end
end
end
describe 'using compunded constants' do

View file

@ -0,0 +1,4 @@
p TOPLEVEL_BINDING.local_variables.sort
TOPLEVEL_BINDING.local_variable_set(:dynamic_set_main, 2)
p TOPLEVEL_BINDING.local_variables.sort
main_script = 3

View file

@ -0,0 +1,2 @@
TOPLEVEL_BINDING.local_variable_set(:dynamic_set_required, 1)
p TOPLEVEL_BINDING.local_variables

View file

@ -0,0 +1,4 @@
a = TOPLEVEL_BINDING.object_id
require_relative 'toplevel_binding_id_required'
c = eval('TOPLEVEL_BINDING.object_id')
p [a, $b, c].uniq.size

View file

@ -0,0 +1 @@
$b = TOPLEVEL_BINDING.object_id

View file

@ -0,0 +1,2 @@
required = true
p [:required_before, TOPLEVEL_BINDING.local_variables]

View file

@ -0,0 +1,9 @@
p TOPLEVEL_BINDING.local_variable_get(:a)
p TOPLEVEL_BINDING.local_variable_get(:b)
a = 1
p TOPLEVEL_BINDING.local_variable_get(:a)
p TOPLEVEL_BINDING.local_variable_get(:b)
b = 2
a = 3
p TOPLEVEL_BINDING.local_variable_get(:a)
p TOPLEVEL_BINDING.local_variable_get(:b)

View file

@ -0,0 +1,4 @@
main_script = 1
require_relative 'toplevel_binding_variables_required'
eval('eval_var = 3')
p TOPLEVEL_BINDING.local_variables

View file

@ -0,0 +1,2 @@
required = 2
p [:required_after, TOPLEVEL_BINDING.local_variables]

View file

@ -0,0 +1,34 @@
require_relative '../../spec_helper'
describe "The TOPLEVEL_BINDING constant" do
it "only includes local variables defined in the main script, not in required files or eval" do
binding_toplevel_variables = ruby_exe(fixture(__FILE__, "toplevel_binding_variables.rb"))
binding_toplevel_variables.should == "[:required_after, [:main_script]]\n[:main_script]\n"
end
it "has no local variables in files required before the main script" do
required = fixture(__FILE__, 'toplevel_binding_required_before.rb')
out = ruby_exe("a=1; p TOPLEVEL_BINDING.local_variables.sort; b=2", options: "-r#{required}")
out.should == "[:required_before, []]\n[:a, :b]\n"
end
it "merges local variables of the main script with dynamically-defined Binding variables" do
required = fixture(__FILE__, 'toplevel_binding_dynamic_required.rb')
out = ruby_exe(fixture(__FILE__, 'toplevel_binding_dynamic.rb'), options: "-r#{required}")
out.should == <<EOS
[:dynamic_set_required]
[:dynamic_set_required, :main_script]
[:dynamic_set_main, :dynamic_set_required, :main_script]
EOS
end
it "gets updated variables values as they are defined and set" do
out = ruby_exe(fixture(__FILE__, "toplevel_binding_values.rb"))
out.should == "nil\nnil\n1\nnil\n3\n2\n"
end
it "is always the same object for all top levels" do
binding_toplevel_id = ruby_exe(fixture(__FILE__, "toplevel_binding_id.rb"))
binding_toplevel_id.should == "1\n"
end
end

View file

@ -371,11 +371,23 @@ describe "The rescue keyword" do
end
it "evaluates rescue expressions only when needed" do
invalid_rescuer = Object.new
begin
:foo
rescue invalid_rescuer
end.should == :foo
ScratchPad << :foo
rescue -> { ScratchPad << :bar; StandardError }.call
end
ScratchPad.recorded.should == [:foo]
end
it "suppresses exception from block when raises one from rescue expression" do
-> {
begin
raise "from block"
rescue (raise "from rescue expression")
end
}.should raise_error(RuntimeError, "from rescue expression") do |e|
e.cause.message.should == "from block"
end
end
it "should splat the handling Error classes" do

View file

@ -1,101 +1,99 @@
require_relative '../spec_helper'
ruby_version_is "2.3" do
describe "Safe navigator" do
it "requires a method name to be provided" do
lambda { eval("obj&. {}") }.should raise_error(SyntaxError)
describe "Safe navigator" do
it "requires a method name to be provided" do
lambda { eval("obj&. {}") }.should raise_error(SyntaxError)
end
context "when context is nil" do
it "always returns nil" do
eval("nil&.unknown").should == nil
eval("[][10]&.unknown").should == nil
end
context "when context is nil" do
it "always returns nil" do
eval("nil&.unknown").should == nil
eval("[][10]&.unknown").should == nil
end
it "can be chained" do
eval("nil&.one&.two&.three").should == nil
end
it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
eval("nil&.unknown(obj.m) { obj.m }")
end
it "can be chained" do
eval("nil&.one&.two&.three").should == nil
end
context "when context is false" do
it "calls the method" do
eval("false&.to_s").should == "false"
lambda { eval("false&.unknown") }.should raise_error(NoMethodError)
end
end
context "when context is truthy" do
it "calls the method" do
eval("1&.to_s").should == "1"
lambda { eval("1&.unknown") }.should raise_error(NoMethodError)
end
end
it "takes a list of arguments" do
eval("[1,2,3]&.first(2)").should == [1,2]
end
it "takes a block" do
eval("[1,2]&.map { |i| i * 2 }").should == [2, 4]
end
it "allows assignment methods" do
klass = Class.new do
attr_reader :foo
def foo=(val)
@foo = val
42
end
end
obj = klass.new
eval("obj&.foo = 3").should == 3
obj.foo.should == 3
obj = nil
eval("obj&.foo = 3").should == nil
end
it "allows assignment operators" do
klass = Class.new do
attr_accessor :m
def initialize
@m = 0
end
end
obj = klass.new
eval("obj&.m += 3")
obj.m.should == 3
obj = nil
eval("obj&.m += 3").should == nil
end
it "does not call the operator method lazily with an assignment operator" do
klass = Class.new do
attr_writer :foo
def foo
nil
end
end
obj = klass.new
lambda {
eval("obj&.foo += 3")
}.should raise_error(NoMethodError) { |e|
e.name.should == :+
}
it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
eval("nil&.unknown(obj.m) { obj.m }")
end
end
context "when context is false" do
it "calls the method" do
eval("false&.to_s").should == "false"
lambda { eval("false&.unknown") }.should raise_error(NoMethodError)
end
end
context "when context is truthy" do
it "calls the method" do
eval("1&.to_s").should == "1"
lambda { eval("1&.unknown") }.should raise_error(NoMethodError)
end
end
it "takes a list of arguments" do
eval("[1,2,3]&.first(2)").should == [1,2]
end
it "takes a block" do
eval("[1,2]&.map { |i| i * 2 }").should == [2, 4]
end
it "allows assignment methods" do
klass = Class.new do
attr_reader :foo
def foo=(val)
@foo = val
42
end
end
obj = klass.new
eval("obj&.foo = 3").should == 3
obj.foo.should == 3
obj = nil
eval("obj&.foo = 3").should == nil
end
it "allows assignment operators" do
klass = Class.new do
attr_accessor :m
def initialize
@m = 0
end
end
obj = klass.new
eval("obj&.m += 3")
obj.m.should == 3
obj = nil
eval("obj&.m += 3").should == nil
end
it "does not call the operator method lazily with an assignment operator" do
klass = Class.new do
attr_writer :foo
def foo
nil
end
end
obj = klass.new
lambda {
eval("obj&.foo += 3")
}.should raise_error(NoMethodError) { |e|
e.name.should == :+
}
end
end

View file

@ -233,27 +233,25 @@ describe "Ruby String literals" do
long_string_literals.should == "Beautiful is better than ugly.Explicit is better than implicit."
end
ruby_version_is "2.3" do
describe "with a magic frozen comment" do
it "produce the same object each time" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_one_literal.rb")).chomp.should == "true"
end
describe "with a magic frozen comment" do
it "produce the same object each time" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_one_literal.rb")).chomp.should == "true"
end
it "produce the same object for literals with the same content" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_two_literals.rb")).chomp.should == "true"
end
it "produce the same object for literals with the same content" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_two_literals.rb")).chomp.should == "true"
end
it "produce the same object for literals with the same content in different files" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files.rb")).chomp.should == "true"
end
it "produce the same object for literals with the same content in different files" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if they have different encodings" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_diff_enc.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if they have different encodings" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_diff_enc.rb")).chomp.should == "true"
end
end

View file

@ -191,6 +191,20 @@ describe "The super keyword" do
Super::RestArgsWithSuper::B.new.a.should == ["foo"]
end
# https://bugs.ruby-lang.org/issues/14279
it "passes along reassigned rest args" do
Super::ZSuperWithRestReassigned::B.new.a("bar").should == ["foo"]
end
# Don't run this spec on Appveyor because it uses old Ruby versions
# The specs ends with segfault on old versions so let's just disable it
platform_is_not :windows do
# https://bugs.ruby-lang.org/issues/14279
it "wraps into array and passes along reassigned rest args with non-array scalar value" do
Super::ZSuperWithRestReassignedWithScalar::B.new.a("bar").should == ["foo"]
end
end
it "invokes methods from a chain of anonymous modules" do
Super::AnonymousModuleIncludedTwice.new.a([]).should == ["anon", "anon", "non-anon"]
end

View file

@ -69,7 +69,7 @@ describe "The yield call" do
}.should raise_error(ArgumentError)
end
ruby_bug "#12705", "2.2"..."2.5" do
ruby_bug "#12705", ""..."2.5" do
it "should not destructure an Array into multiple arguments" do
lambda {
@y.s([1, 2], &lambda { |a,b| [a,b] })