diff options
author | Benoit Daloze <eregontp@gmail.com> | 2020-01-28 20:47:48 +0100 |
---|---|---|
committer | Benoit Daloze <eregontp@gmail.com> | 2020-01-28 20:47:48 +0100 |
commit | 809f0b8a1357f14f9645210d4812f4400c8d397e (patch) | |
tree | 7ce6192f94b1dc4b004798aa5d0c4d6bac02577f /spec/ruby/language | |
parent | ed377cc9aaf1ccbede19ddc6c464f5fbf3cabc34 (diff) |
Update to ruby/spec@f8a2d54
Diffstat (limited to 'spec/ruby/language')
-rw-r--r-- | spec/ruby/language/alias_spec.rb | 5 | ||||
-rw-r--r-- | spec/ruby/language/comment_spec.rb | 15 | ||||
-rw-r--r-- | spec/ruby/language/numbered_parameters_spec.rb | 87 | ||||
-rw-r--r-- | spec/ruby/language/numbers_spec.rb | 4 | ||||
-rw-r--r-- | spec/ruby/language/pattern_matching_spec.rb | 966 | ||||
-rw-r--r-- | spec/ruby/language/predefined_spec.rb | 31 | ||||
-rw-r--r-- | spec/ruby/language/range_spec.rb | 7 | ||||
-rw-r--r-- | spec/ruby/language/rescue_spec.rb | 10 |
8 files changed, 1125 insertions, 0 deletions
diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb index 79348f70c3..13f5c49513 100644 --- a/spec/ruby/language/alias_spec.rb +++ b/spec/ruby/language/alias_spec.rb @@ -255,4 +255,9 @@ describe "The alias keyword" do code = '$a = 1; $b = 2; alias $b $a; p [$a, $b]; $b = 3; p [$a, $b]' ruby_exe(code).should == "[1, 1]\n[3, 3]\n" end + + it "supports aliasing twice the same global variables" do + code = '$a = 1; alias $b $a; alias $b $a; p [$a, $b]' + ruby_exe(code).should == "[1, 1]\n" + end end diff --git a/spec/ruby/language/comment_spec.rb b/spec/ruby/language/comment_spec.rb new file mode 100644 index 0000000000..690e844dc0 --- /dev/null +++ b/spec/ruby/language/comment_spec.rb @@ -0,0 +1,15 @@ +require_relative '../spec_helper' + +describe "The comment" do + ruby_version_is "2.7" do + it "can be placed between fluent dot now" do + code = <<~CODE + 10 + # some comment + .to_s + CODE + + eval(code).should == '10' + end + end +end diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb new file mode 100644 index 0000000000..e7b2204d4a --- /dev/null +++ b/spec/ruby/language/numbered_parameters_spec.rb @@ -0,0 +1,87 @@ +require_relative '../spec_helper' + +ruby_version_is "2.7" do + describe "Numbered parameters" do + it "provides default parameters _1, _2, ... in a block" do + -> { _1 }.call("a").should == "a" + proc { _1 }.call("a").should == "a" + lambda { _1 }.call("a").should == "a" + ["a"].map { _1 }.should == ["a"] + end + + it "assigns nil to not passed parameters" do + proc { [_1, _2] }.call("a").should == ["a", nil] + proc { [_1, _2] }.call("a", "b").should == ["a", "b"] + end + + it "supports variables _1-_9 only for the first 9 passed parameters" do + block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] } + result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9) + result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9] + end + + it "does not support more than 9 parameters" do + -> { + proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + }.should raise_error(NameError, /undefined local variable or method `_10'/) + end + + it "can not be used in both outer and nested blocks at the same time" do + -> { + eval("-> { _1; -> { _2 } }") + }.should raise_error(SyntaxError, /numbered parameter is already used in.+ outer block here/m) + end + + it "can be overwritten with local variable" do + suppress_warning do + eval <<~CODE + _1 = 0 + proc { _1 }.call("a").should == 0 + CODE + end + end + + it "warns when numbered parameter is overriten with local variable" do + -> { + eval("_1 = 0") + }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/) + end + + it "raises SyntaxError when block parameters are specified explicitly" do + -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + end + + it "affects block arity" do + -> { _1 }.arity.should == 1 + -> { _2 }.arity.should == 2 + -> { _3 }.arity.should == 3 + -> { _4 }.arity.should == 4 + -> { _5 }.arity.should == 5 + -> { _6 }.arity.should == 6 + -> { _7 }.arity.should == 7 + -> { _8 }.arity.should == 8 + -> { _9 }.arity.should == 9 + + -> { _9 }.arity.should == 9 + proc { _9 }.arity.should == 9 + lambda { _9 }.arity.should == 9 + end + + it "does not work in methods" do + obj = Object.new + def obj.foo; _1 end + + -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/) + end + end +end diff --git a/spec/ruby/language/numbers_spec.rb b/spec/ruby/language/numbers_spec.rb index c82a630632..418bc60fa6 100644 --- a/spec/ruby/language/numbers_spec.rb +++ b/spec/ruby/language/numbers_spec.rb @@ -45,6 +45,10 @@ describe "A number literal" do eval('-3r').should == Rational(-3, 1) end + it "can be a float literal with trailing 'r' to represent a Rational" do + eval('0.0174532925199432957r').should == Rational(174532925199432957, 10000000000000000000) + end + it "can be an bignum literal with trailing 'r' to represent a Rational" do eval('1111111111111111111111111111111111111111111111r').should == Rational(1111111111111111111111111111111111111111111111, 1) eval('-1111111111111111111111111111111111111111111111r').should == Rational(-1111111111111111111111111111111111111111111111, 1) diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb new file mode 100644 index 0000000000..6a6de506ff --- /dev/null +++ b/spec/ruby/language/pattern_matching_spec.rb @@ -0,0 +1,966 @@ +require_relative '../spec_helper' + +ruby_version_is "2.7" do + describe "Pattern matching" do + # TODO: Remove excessive eval calls when support of previous version + # Ruby 2.6 will be dropped + + before do + ScratchPad.record [] + end + + it "can be standalone in operator that deconstructs value" do + eval(<<-RUBY).should == [0, 1] + [0, 1] in [a, b] + [a, b] + RUBY + end + + it "extends case expression with case/in construction" do + eval(<<~RUBY).should == :bar + case [0, 1] + in [0] + :foo + in [0, 1] + :bar + end + RUBY + end + + it "allows using then operator" do + eval(<<~RUBY).should == :bar + case [0, 1] + in [0] then :foo + in [0, 1] then :bar + end + RUBY + end + + it "warns about pattern matching is experimental feature" do + -> { + eval <<~RUBY + case 0 + in 0 + end + RUBY + }.should complain(/warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!/) + end + + it "binds variables" do + eval(<<~RUBY).should == 1 + case [0, 1] + in [0, a] + a + end + RUBY + end + + it "cannot mix in and when operators" do + -> { + eval <<~RUBY + case [] + when 1 == 1 + in [] + end + RUBY + }.should raise_error(SyntaxError, /syntax error, unexpected `in'/) + + -> { + eval <<~RUBY + case [] + in [] + when 1 == 1 + end + RUBY + }.should raise_error(SyntaxError, /syntax error, unexpected `when'/) + end + + it "checks patterns until the first matching" do + eval(<<~RUBY).should == :bar + case [0, 1] + in [0] + :foo + in [0, 1] + :bar + in [0, 1] + :baz + end + RUBY + end + + it "executes else clause if no pattern matches" do + eval(<<~RUBY).should == false + case [0, 1] + in [0] + true + else + false + end + RUBY + end + + it "raises NoMatchingPatternError if no pattern matches and no else clause" do + -> { + eval <<~RUBY + case [0, 1] + in [0] + end + RUBY + }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) + end + + it "does not allow calculation or method calls in a pattern" do + -> { + eval <<~RUBY + case 0 + in 1 + 1 + true + end + RUBY + }.should raise_error(SyntaxError, /unexpected/) + end + + describe "guards" do + it "supports if guard" do + eval(<<~RUBY).should == false + case 0 + in 0 if false + true + else + false + end + RUBY + + eval(<<~RUBY).should == true + case 0 + in 0 if true + true + else + false + end + RUBY + end + + it "supports unless guard" do + eval(<<~RUBY).should == false + case 0 + in 0 unless true + true + else + false + end + RUBY + + eval(<<~RUBY).should == true + case 0 + in 0 unless false + true + else + false + end + RUBY + end + + it "makes bound variables visible in guard" do + eval(<<~RUBY).should == true + case [0, 1] + in [a, 1] if a >= 0 + true + end + RUBY + end + + it "does not evaluate guard if pattern does not match" do + eval <<~RUBY + case 0 + in 1 if (ScratchPad << :foo) || true + else + end + RUBY + + ScratchPad.recorded.should == [] + end + + it "takes guards into account when there are several matching patterns" do + eval(<<~RUBY).should == :bar + case 0 + in 0 if false + :foo + in 0 if true + :bar + end + RUBY + end + + it "executes else clause if no guarded pattern matches" do + eval(<<~RUBY).should == false + case 0 + in 0 if false + true + else + false + end + RUBY + end + + it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do + -> { + eval <<~RUBY + case [0, 1] + in [0, 1] if false + end + RUBY + }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) + end + end + + describe "value pattern" do + it "matches an object such that pattern === object" do + eval(<<~RUBY).should == true + case 0 + in 0 + true + end + RUBY + + eval(<<~RUBY).should == true + case 0 + in (-1..1) + true + end + RUBY + + eval(<<~RUBY).should == true + case 0 + in Integer + true + end + RUBY + + eval(<<~RUBY).should == true + case "0" + in /0/ + true + end + RUBY + + eval(<<~RUBY).should == true + case "0" + in ->(s) { s == "0" } + true + end + RUBY + end + + it "allows string literal with interpolation" do + x = "x" + + eval(<<~RUBY).should == true + case "x" + in "#{x + ""}" + true + end + RUBY + end + end + + describe "variable pattern" do + it "matches a value and binds variable name to this value" do + eval(<<~RUBY).should == 0 + case 0 + in a + a + end + RUBY + end + + it "makes bounded variable visible outside a case statement scope" do + eval(<<~RUBY).should == 0 + case 0 + in a + end + + a + RUBY + end + + it "create local variables even if a pattern doesn't match" do + eval(<<~RUBY).should == [0, nil, nil] + case 0 + in a + in b + in c + end + + [a, b, c] + RUBY + end + + it "allow using _ name to drop values" do + eval(<<~RUBY).should == 0 + case [0, 1] + in [a, _] + a + end + RUBY + end + + it "supports using _ in a pattern several times" do + eval(<<~RUBY).should == 2 + case [0, 1, 2] + in [0, _, _] + _ + end + RUBY + end + + it "supports using any name with _ at the beginning in a pattern several times" do + eval(<<~RUBY).should == 2 + case [0, 1, 2] + in [0, _x, _x] + _x + end + RUBY + + eval(<<~RUBY).should == 2 + case {a: 0, b: 1, c: 2} + in {a: 0, b: _x, c: _x} + _x + end + RUBY + end + + it "does not support using variable name (except _) several times" do + -> { + eval <<~RUBY + case [0] + in [a, a] + end + RUBY + }.should raise_error(SyntaxError, /duplicated variable name/) + end + + it "supports existing variables in a pattern specified with ^ operator" do + a = 0 + + eval(<<~RUBY).should == true + case 0 + in ^a + true + end + RUBY + end + + it "allows applying ^ operator to bound variables" do + eval(<<~RUBY).should == 1 + case [1, 1] + in [n, ^n] + n + end + RUBY + + eval(<<~RUBY).should == false + case [1, 2] + in [n, ^n] + true + else + false + end + RUBY + end + + it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do + -> { + eval <<~RUBY + case [1, 2] + in [^n, n] + true + else + false + end + RUBY + }.should raise_error(SyntaxError, /n: no such local variable/) + end + end + + describe "alternative pattern" do + it "matches if any of patterns matches" do + eval(<<~RUBY).should == true + case 0 + in 0 | 1 | 2 + true + end + RUBY + end + + it "does not support variable binding" do + -> { + eval <<~RUBY + case [0, 1] + in [0, 0] | [0, a] + end + RUBY + }.should raise_error(SyntaxError, /illegal variable in alternative pattern/) + end + end + + describe "AS pattern" do + it "binds a variable to a value if pattern matches" do + eval(<<~RUBY).should == 0 + case 0 + in Integer => n + n + end + RUBY + end + + it "can be used as a nested pattern" do + eval(<<~RUBY).should == [2, 3] + case [1, [2, 3]] + in [1, Array => ary] + ary + end + RUBY + end + end + + describe "Array pattern" do + it "supports form Constant(pat, pat, ...)" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in Array(0, 1, 2) + true + end + RUBY + end + + it "supports form Constant[pat, pat, ...]" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in Array[0, 1, 2] + true + end + RUBY + end + + it "supports form [pat, pat, ...]" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in [0, 1, 2] + true + end + RUBY + end + + it "supports form pat, pat, ..." do + eval(<<~RUBY).should == true + case [0, 1, 2] + in 0, 1, 2 + true + end + RUBY + + eval(<<~RUBY).should == 1 + case [0, 1, 2] + in 0, a, 2 + a + end + RUBY + + eval(<<~RUBY).should == [1, 2] + case [0, 1, 2] + in 0, *rest + rest + end + RUBY + end + + it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do + obj = Object.new + def obj.deconstruct; [0, 1] end + + eval(<<~RUBY).should == true + case obj + in [Integer, Integer] + true + end + RUBY + end + + it "does not match object if Constant === object returns false" do + eval(<<~RUBY).should == false + case [0, 1, 2] + in String[0, 1, 2] + true + else + false + end + RUBY + end + + it "does not match object without #deconstruct method" do + obj = Object.new + + eval(<<~RUBY).should == false + case obj + in Object[] + true + else + false + end + RUBY + end + + it "raises TypeError if #deconstruct method does not return array" do + obj = Object.new + def obj.deconstruct; "" end + + -> { + eval <<~RUBY + case obj + in Object[] + else + end + RUBY + }.should raise_error(TypeError, /deconstruct must return Array/) + end + + it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do + obj = Object.new + def obj.deconstruct; [1] end + + eval(<<~RUBY).should == false + case obj + in Object[0] + true + else + false + end + RUBY + end + + it "binds variables" do + eval(<<~RUBY).should == [0, 1, 2] + case [0, 1, 2] + in [a, b, c] + [a, b, c] + end + RUBY + end + + it "binds variable even if patter matches only partially" do + a = nil + + eval(<<~RUBY).should == 0 + case [0, 1, 2] + in [a, 1, 3] + else + end + + a + RUBY + end + + it "supports splat operator *rest" do + eval(<<~RUBY).should == [1, 2] + case [0, 1, 2] + in [0, *rest] + rest + end + RUBY + end + + it "does not match partially by default" do + eval(<<~RUBY).should == false + case [0, 1, 2, 3] + in [1, 2] + true + else + false + end + RUBY + end + + it "does match partially from the array beginning if list + , syntax used" do + eval(<<~RUBY).should == true + case [0, 1, 2, 3] + in [0, 1,] + true + end + RUBY + + eval(<<~RUBY).should == true + case [0, 1, 2, 3] + in 0, 1,; + true + end + RUBY + end + + it "matches [] with []" do + eval(<<~RUBY).should == true + case [] + in [] + true + end + RUBY + end + + it "matches anything with *" do + eval(<<~RUBY).should == true + case [0, 1] + in *; + true + end + RUBY + end + end + + describe "Hash pattern" do + it "supports form Constant(id: pat, id: pat, ...)" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in Hash(a: 0, b: 1) + true + end + RUBY + end + + it "supports form Constant[id: pat, id: pat, ...]" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in Hash[a: 0, b: 1] + true + end + RUBY + end + + it "supports form {id: pat, id: pat, ...}" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in {a: 0, b: 1} + true + end + RUBY + end + + it "supports form id: pat, id: pat, ..." do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in a: 0, b: 1 + true + end + RUBY + + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in a: a, b: b + [a, b] + end + RUBY + + eval(<<~RUBY).should == { b: 1, c: 2 } + case {a: 0, b: 1, c: 2} + in a: 0, **rest + rest + end + RUBY + end + + it "supports a: which means a: a" do + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash(a:, b:) + [a, b] + end + RUBY + + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash[a:, b:] + [a, b] + end + RUBY + + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in {a:, b:} + [a, b] + end + RUBY + + a = nil + eval(<<~RUBY).should == [0, {b: 1, c: 2}] + case {a: 0, b: 1, c: 2} + in {a:, **rest} + [a, rest] + end + RUBY + + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in a:, b: + [a, b] + end + RUBY + end + + it "can mix key (a:) and key-value (a: b) declarations" do + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash(a:, b: x) + [a, x] + end + RUBY + end + + it "supports 'string': key literal" do + eval(<<~RUBY).should == true + case {a: 0} + in {"a": 0} + true + end + RUBY + end + + it "does not support non-symbol keys" do + -> { + eval <<~RUBY + case {a: 1} + in {"a" => 1} + end + RUBY + }.should raise_error(SyntaxError, /unexpected/) + end + + it "does not support string interpolation in keys" do + x = "a" + + -> { + eval <<~'RUBY' + case {a: 1} + in {"#{x}": 1} + end + RUBY + }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/) + end + + it "raise SyntaxError when keys duplicate in pattern" do + -> { + eval <<~RUBY + case {a: 1} + in {a: 1, b: 2, a: 3} + end + RUBY + }.should raise_error(SyntaxError, /duplicated key name/) + end + + it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do + obj = Object.new + def obj.deconstruct_keys(*); {a: 1} end + + eval(<<~RUBY).should == true + case obj + in {a: 1} + true + end + RUBY + end + + it "does not match object if Constant === object returns false" do + eval(<<~RUBY).should == false + case {a: 1} + in String[a: 1] + true + else + false + end + RUBY + end + + it "does not match object without #deconstruct_keys method" do + obj = Object.new + + eval(<<~RUBY).should == false + case obj + in Object[a: 1] + true + else + false + end + RUBY + end + + it "does not match object if #deconstruct_keys method does not return Hash" do + obj = Object.new + def obj.deconstruct_keys(*); "" end + + -> { + eval <<~RUBY + case obj + in Object[a: 1] + end + RUBY + }.should raise_error(TypeError, /deconstruct_keys must return Hash/) + end + + it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do + obj = Object.new + def obj.deconstruct_keys(*); {"a" => 1} end + + eval(<<~RUBY).should == false + case obj + in Object[a: 1] + true + else + false + end + RUBY + end + + it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do + obj = Object.new + def obj.deconstruct_keys(*); {a: 1} end + + eval(<<~RUBY).should == false + case obj + in Object[a: 2] + true + else + false + end + RUBY + end + + it "passes keys specified in pattern as arguments to #deconstruct_keys method" do + obj = Object.new + + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2, c: 3} + end + + eval <<~RUBY + case obj + in Object[a: 1, b: 2, c: 3] + end + RUBY + + ScratchPad.recorded.should == [[[:a, :b, :c]]] + end + + it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do + obj = Object.new + + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2, c: 3} + end + + eval <<~RUBY + case obj + in Object[a: 1, b: 2, **] + end + RUBY + + ScratchPad.recorded.should == [[[:a, :b]]] + end + + it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do + obj = Object.new + + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2} + end + + eval <<~RUBY + case obj + in Object[a: 1, **rest] + end + RUBY + + ScratchPad.recorded.should == [[nil]] + end + + it "binds variables" do + eval(<<~RUBY).should == [0, 1, 2] + case {a: 0, b: 1, c: 2} + in {a: x, b: y, c: z} + [x, y, z] + end + RUBY + end + + it "binds variable even if pattern matches only partially" do + x = nil + + eval(<<~RUBY).should == 0 + case {a: 0, b: 1} + in {a: x, b: 2} + else + end + + x + RUBY + end + + it "supports double splat operator **rest" do + eval(<<~RUBY).should == {b: 1, c: 2} + case {a: 0, b: 1, c: 2} + in {a: 0, **rest} + rest + end + RUBY + end + + it "treats **nil like there should not be any other keys in a matched Hash" do + eval(<<~RUBY).should == true + case {a: 1, b: 2} + in {a: 1, b: 2, **nil} + true + end + RUBY + + eval(<<~RUBY).should == false + case {a: 1, b: 2} + in {a: 1, **nil} + true + else + false + end + RUBY + end + + it "can match partially" do + eval(<<~RUBY).should == true + case {a: 1, b: 2} + in {a: 1} + true + end + RUBY + end + + it "matches {} with {}" do + eval(<<~RUBY).should == true + case {} + in {} + true + end + RUBY + end + + it "matches anything with **" do + eval(<<~RUBY).should == true + case {a: 1} + in **; + true + end + RUBY + end + end + end +end diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index cec6bc852c..6f902eb822 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -398,6 +398,19 @@ describe "Predefined global $!" do $!.should == nil end + it "should be cleared when an exception is rescued even when a non-local return from block" do + [ 1 ].each do + begin + raise StandardError.new('err') + rescue => e + $!.should == e + return + end + end + + $!.should == nil + end + it "should not be cleared when an exception is not rescued" do e = StandardError.new begin @@ -633,6 +646,12 @@ describe "Predefined global $," do it "raises TypeError if assigned a non-String" do -> { $, = Object.new }.should raise_error(TypeError) end + + ruby_version_is "2.7" do + it "warns if assigned non-nil" do + -> { $, = "_" }.should complain(/warning: `\$,' is deprecated/) + end + end end describe "Predefined global $." do @@ -662,6 +681,18 @@ describe "Predefined global $." do end end +describe "Predefined global $;" do + after :each do + $; = nil + end + + ruby_version_is "2.7" do + it "warns if assigned non-nil" do + -> { $; = "_" }.should complain(/warning: `\$;' is deprecated/) + end + end +end + describe "Predefined global $_" do it "is set to the last line read by e.g. StringIO#gets" do stdin = StringIO.new("foo\nbar\n", "r") diff --git a/spec/ruby/language/range_spec.rb b/spec/ruby/language/range_spec.rb index c720c5b98e..c0f90f84d6 100644 --- a/spec/ruby/language/range_spec.rb +++ b/spec/ruby/language/range_spec.rb @@ -16,4 +16,11 @@ describe "Literal Ranges" do eval("(1...)").should == Range.new(1, nil, true) end end + + ruby_version_is "2.7" do + it "creates beginless ranges" do + eval("(..1)").should == Range.new(nil, 1) + eval("(...1)").should == Range.new(nil, 1, true) + end + end end diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb index a912e17431..aae16bbefb 100644 --- a/spec/ruby/language/rescue_spec.rb +++ b/spec/ruby/language/rescue_spec.rb @@ -481,5 +481,15 @@ describe "The rescue keyword" do a = raise(Exception) rescue 1 }.should raise_error(Exception) end + + ruby_version_is "2.7" do + it "rescues with multiple assignment" do + + a, b = raise rescue [1, 2] + + a.should == 1 + b.should == 2 + end + end end end |