diff options
author | Benoit Daloze <eregontp@gmail.com> | 2021-10-20 21:41:46 +0200 |
---|---|---|
committer | Benoit Daloze <eregontp@gmail.com> | 2021-10-20 21:41:46 +0200 |
commit | a6c6eef04aaa075f4bbd0eef740d011737afec91 (patch) | |
tree | e8779ca2ddc044899caabca88c16abc9a9054fff /spec/ruby/language | |
parent | 207a5a5bc13018344dc2ab7913fdcaeaeca01292 (diff) | |
download | ruby-a6c6eef04aaa075f4bbd0eef740d011737afec91.tar.gz |
Update to ruby/spec@d6921ef
Diffstat (limited to 'spec/ruby/language')
-rw-r--r-- | spec/ruby/language/hash_spec.rb | 39 | ||||
-rw-r--r-- | spec/ruby/language/method_spec.rb | 157 | ||||
-rw-r--r-- | spec/ruby/language/pattern_matching_spec.rb | 173 | ||||
-rw-r--r-- | spec/ruby/language/proc_spec.rb | 26 | ||||
-rw-r--r-- | spec/ruby/language/range_spec.rb | 6 | ||||
-rw-r--r-- | spec/ruby/language/singleton_class_spec.rb | 17 | ||||
-rw-r--r-- | spec/ruby/language/yield_spec.rb | 28 |
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 |