aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/language
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2021-10-20 21:41:46 +0200
committerBenoit Daloze <eregontp@gmail.com>2021-10-20 21:41:46 +0200
commita6c6eef04aaa075f4bbd0eef740d011737afec91 (patch)
treee8779ca2ddc044899caabca88c16abc9a9054fff /spec/ruby/language
parent207a5a5bc13018344dc2ab7913fdcaeaeca01292 (diff)
downloadruby-a6c6eef04aaa075f4bbd0eef740d011737afec91.tar.gz
Update to ruby/spec@d6921ef
Diffstat (limited to 'spec/ruby/language')
-rw-r--r--spec/ruby/language/hash_spec.rb39
-rw-r--r--spec/ruby/language/method_spec.rb157
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb173
-rw-r--r--spec/ruby/language/proc_spec.rb26
-rw-r--r--spec/ruby/language/range_spec.rb6
-rw-r--r--spec/ruby/language/singleton_class_spec.rb17
-rw-r--r--spec/ruby/language/yield_spec.rb28
7 files changed, 410 insertions, 36 deletions
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index f99ff8ab3f..2f8b97199a 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -225,4 +225,43 @@ describe "The ** operator" do
h.should == { two: 2 }
end
end
+
+ ruby_version_is "3.1" do
+ describe "hash with omitted value" do
+ it "accepts short notation 'key' for 'key: value' syntax" do
+ a, b, c = 1, 2, 3
+ h = eval('{a:}')
+ {a: 1}.should == h
+ h = eval('{a:, b:, c:}')
+ {a: 1, b: 2, c: 3}.should == h
+ end
+
+ it "ignores hanging comma on short notation" do
+ a, b, c = 1, 2, 3
+ h = eval('{a:, b:, c:,}')
+ {a: 1, b: 2, c: 3}.should == h
+ end
+
+ it "accepts mixed syntax" do
+ a, e = 1, 5
+ h = eval('{a:, b: 2, "c" => 3, :d => 4, e:}')
+ eval('{a: 1, :b => 2, "c" => 3, "d": 4, e: 5}').should == h
+ end
+
+ it "works with methods and local vars" do
+ a = Class.new
+ a.class_eval(<<-RUBY)
+ def bar
+ "baz"
+ end
+
+ def foo(val)
+ {bar:, val:}
+ end
+ RUBY
+
+ a.new.foo(1).should == {bar: "baz", val: 1}
+ end
+ end
+ end
end
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 449d5e6f1b..0a5bb99d0b 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1861,15 +1861,158 @@ describe "An array-dereference method ([])" do
end
end
-ruby_version_is '3.0' do
+ruby_version_is "3.0" do
describe "An endless method definition" do
- evaluate <<-ruby do
- def m(a) = a
- ruby
+ context "without arguments" do
+ evaluate <<-ruby do
+ def m() = 42
+ ruby
+
+ m.should == 42
+ end
+ end
+
+ context "with arguments" do
+ evaluate <<-ruby do
+ def m(a, b) = a + b
+ ruby
+
+ m(1, 4).should == 5
+ end
+ end
+
+ context "with multiline body" do
+ evaluate <<-ruby do
+ def m(n) =
+ if n > 2
+ m(n - 2) + m(n - 1)
+ else
+ 1
+ end
+ ruby
+
+ m(6).should == 8
+ end
+ end
- a = b = m 1
- a.should == 1
- b.should == 1
+ context "with args forwarding" do
+ evaluate <<-ruby do
+ def mm(word, num:)
+ word * num
+ end
+
+ def m(...) = mm(...) + mm(...)
+ ruby
+
+ m("meow", num: 2).should == "meow" * 4
+ end
+ end
+ end
+
+ describe "Keyword arguments are now separated from positional arguments" do
+ context "when the method has only positional parameters" do
+ it "treats incoming keyword arguments as positional for compatibility" do
+ def foo(a, b, c, hsh)
+ hsh[:key]
+ end
+
+ foo(1, 2, 3, key: 42).should == 42
+ end
+ end
+
+ context "when the method takes a ** parameter" do
+ it "captures the passed literal keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
+
+ foo(1, 2, 3, key: 42).should == 42
+ end
+
+ it "captures the passed ** keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
+
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
+ end
+
+ it "does not convert a positional Hash to keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
+
+ -> {
+ foo(1, 2, 3, { key: 42 })
+ }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ end
+ end
+
+ context "when the method takes a key: parameter" do
+ context "when it's called with a positional Hash and no **" do
+ it "raises ArgumentError" do
+ def foo(a, b, c, key: 1)
+ key
+ end
+
+ -> {
+ foo(1, 2, 3, { key: 42 })
+ }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ end
+ end
+
+ context "when it's called with **" do
+ it "captures the passed keyword arguments" do
+ def foo(a, b, c, key: 1)
+ key
+ end
+
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
+ end
+ end
+ end
+ end
+end
+
+ruby_version_is "3.1" do
+ describe "kwarg with omitted value in a method call" do
+ context "accepts short notation 'kwarg' in method call" do
+ evaluate <<-ruby do
+ def call(*args, **kwargs) = [args, kwargs]
+ ruby
+
+ a, b, c = 1, 2, 3
+ arr, h = eval('call a:')
+ h.should == {a: 1}
+ arr.should == []
+
+ arr, h = eval('call(a:, b:, c:)')
+ h.should == {a: 1, b: 2, c: 3}
+ arr.should == []
+
+ arr, h = eval('call(a:, b: 10, c:)')
+ h.should == {a: 1, b: 10, c: 3}
+ arr.should == []
+ end
+ end
+
+ context "with methods and local variables" do
+ evaluate <<-ruby do
+ def call(*args, **kwargs) = [args, kwargs]
+
+ def bar
+ "baz"
+ end
+
+ def foo(val)
+ call bar:, val:
+ end
+ ruby
+
+ foo(1).should == [[], {bar: "baz", val: 1}]
+ end
end
end
end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index c6a3008458..e4abae9412 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -18,6 +18,63 @@ ruby_version_is "2.7" do
RUBY
end
end
+
+ describe "find pattern" do
+ it "captures preceding elements to the pattern" do
+ eval(<<~RUBY).should == [0, 1]
+ case [0, 1, 2, 3]
+ in [*pre, 2, 3]
+ pre
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "captures following elements to the pattern" do
+ eval(<<~RUBY).should == [2, 3]
+ case [0, 1, 2, 3]
+ in [0, 1, *post]
+ post
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "captures both preceding and following elements to the pattern" do
+ eval(<<~RUBY).should == [[0, 1], [3, 4]]
+ case [0, 1, 2, 3, 4]
+ in [*pre, 2, *post]
+ [pre, post]
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "can capture the entirety of the pattern" do
+ eval(<<~RUBY).should == [0, 1, 2, 3, 4]
+ case [0, 1, 2, 3, 4]
+ in [*everything]
+ everything
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "will match an empty Array-like structure" do
+ eval(<<~RUBY).should == []
+ case []
+ in [*everything]
+ everything
+ else
+ false
+ end
+ RUBY
+ end
+ end
end
it "extends case expression with case/in construction" do
@@ -41,25 +98,49 @@ ruby_version_is "2.7" do
end
describe "warning" do
- ruby_version_is ""..."3.1" do
+ before :each do
+ @experimental, Warning[:experimental] = Warning[:experimental], true
+ end
+
+ after :each do
+ Warning[:experimental] = @experimental
+ end
+
+ context 'when regular form' do
before :each do
- ruby_version_is ""..."3.0" do
- @src = 'case [0, 1]; in [a, b]; end'
- end
+ @src = 'case [0, 1]; in [a, b]; end'
+ end
- ruby_version_is "3.0" do
- @src = '[0, 1] => [a, b]'
+ ruby_version_is ""..."3.0" do
+ it "warns about pattern matching is experimental feature" do
+ -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
end
-
- @experimental, Warning[:experimental] = Warning[:experimental], true
end
- after :each do
- Warning[:experimental] = @experimental
+ ruby_version_is "3.0" do
+ it "does not warn about pattern matching is experimental feature" do
+ -> { eval @src }.should_not complain
+ end
end
+ end
+
+ context 'when one-line form' do
+ ruby_version_is '3.0' do
+ before :each do
+ @src = '[0, 1] => [a, b]'
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "warns about pattern matching is experimental feature" do
+ -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
+ end
+ end
- it "warns about pattern matching is experimental feature" do
- -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
+ ruby_version_is "3.1" do
+ it "does not warn about pattern matching is experimental feature" do
+ -> { eval @src }.should_not complain
+ end
+ end
end
end
end
@@ -444,6 +525,28 @@ ruby_version_is "2.7" do
end
RUBY
end
+
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end
+ RUBY
+ end
end
describe "AS pattern" do
@@ -705,6 +808,28 @@ ruby_version_is "2.7" do
end
RUBY
end
+
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end
+ RUBY
+ end
end
describe "Hash pattern" do
@@ -1060,6 +1185,30 @@ ruby_version_is "2.7" do
end
RUBY
end
+
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
+ in {a: {a: 0}}
+ false
+ in {a: {a: 1}, b: {b: 1}}
+ false
+ in {a: {a: 1}, b: {b: 2}}
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
+ in [{a:, c:},]
+ false
+ in [{a: 1, b:}, {a: 1, c: [Integer]}]
+ false
+ in [_, {a: 1, c: [String]}]
+ true
+ end
+ RUBY
+ end
end
describe "refinements" do
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index c44e711d2b..ef4a43bed6 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -217,4 +217,30 @@ describe "A Proc" do
lambda { @l.call(obj) }.should raise_error(TypeError)
end
end
+
+ describe "taking |*a, **kw| arguments" do
+ before :each do
+ @p = proc { |*a, **kw| [a, kw] }
+ end
+
+ ruby_version_is ""..."2.7" do
+ it 'autosplats keyword arguments' do
+ @p.call([1, {a: 1}]).should == [[1], {a: 1}]
+ end
+ end
+
+ ruby_version_is "2.7"..."3.0" do
+ it 'autosplats keyword arguments and warns' do
+ -> {
+ @p.call([1, {a: 1}]).should == [[1], {a: 1}]
+ }.should complain(/warning: Using the last argument as keyword parameters is deprecated; maybe \*\* should be added to the call/)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it 'does not autosplat keyword arguments' do
+ @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}]
+ end
+ end
+ end
end
diff --git a/spec/ruby/language/range_spec.rb b/spec/ruby/language/range_spec.rb
index 79500c6b33..4cde7e9488 100644
--- a/spec/ruby/language/range_spec.rb
+++ b/spec/ruby/language/range_spec.rb
@@ -15,6 +15,12 @@ describe "Literal Ranges" do
(1...).should == Range.new(1, nil, true)
end
+ ruby_version_is "3.0" do
+ it "is frozen" do
+ (42..).should.frozen?
+ end
+ end
+
ruby_version_is "2.7" do
it "creates beginless ranges" do
eval("(..1)").should == Range.new(nil, 1)
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index 7e9370d6f9..c1fb682ea0 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -157,23 +157,6 @@ describe "A constant on a singleton class" do
end
end
-describe "Defining yield in singleton class" do
- ruby_version_is "2.7"..."3.0" do
- it 'emits a deprecation warning' do
- code = <<~RUBY
- def m
- class << Object.new
- yield
- end
- end
- m { :ok }
- RUBY
-
- -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/)
- end
- end
-end
-
describe "Defining instance methods on a singleton class" do
before :each do
@k = ClassSpecs::K.new
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index 5fad7cb176..3db6d353a9 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -183,5 +183,33 @@ describe "The yield call" do
it "uses captured block of a block used in define_method" do
@y.deep(2).should == 4
end
+end
+
+describe "Using yield in a singleton class literal" do
+ ruby_version_is "2.7"..."3.0" do
+ it 'emits a deprecation warning' do
+ code = <<~RUBY
+ def m
+ class << Object.new
+ yield
+ end
+ end
+ m { :ok }
+ RUBY
+
+ -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it 'raises a SyntaxError' do
+ code = <<~RUBY
+ class << Object.new
+ yield
+ end
+ RUBY
+ -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ end
+ end
end