assert('__FILE__') do file = __FILE__[-9, 9] assert_equal 'syntax.rb', file end assert('__LINE__') do assert_equal 7, __LINE__ end assert('super', '11.3.4') do assert_raise NoMethodError do super end class SuperFoo def foo true end def bar(*a) a end end class SuperBar < SuperFoo def foo super end def bar(*a) super(*a) end end bar = SuperBar.new assert_true bar.foo assert_equal [1,2,3], bar.bar(1,2,3) end assert('yield', '11.3.5') do # it's syntax error now # assert_raise LocalJumpError do # yield # end assert_raise LocalJumpError do o = Object.new def o.foo yield end o.foo end end assert('break', '11.5.2.4.3') do n = 0 a = [] while true n += 1 a.push(n) if n > 3 break end end assert_equal [1,2,3,4], a n = 0 a = [] 6.times do n += 1 a.push(n) if n > 3 break end end assert_equal [1,2,3,4], a a = [] begin while true a.push 1 break a.push "NG" end ensure a.push 2 end assert_equal [1, 2], a a = [] begin while true a.push 1 break end a.push 2 ensure a.push 3 end assert_equal [1, 2, 3], a a = [] begin while true begin a.push 1 break ensure a.push 2 end a.push "NG" end ensure a.push 3 end assert_equal [1, 2, 3], a a = [] begin while true begin a.push 1 break ensure a.push 2 end a.push "NG" end a.push 3 ensure a.push 4 end assert_equal [1, 2, 3, 4], a end assert('redo', '11.5.2.4.5') do sum = 0 for i in 1..10 sum += i i -= 1 if i > 0 redo end end assert_equal 220, sum n = 0 a = [] 3.times do n += 1 if n == 2 redo end a.push(n) end assert_equal [1,3,4], a a = [] limit = 3 e = RuntimeError.new("!") for i in 0...3 begin limit -= 1 break unless limit > 0 a.push i * 3 + 1 raise e rescue a.push i * 3 + 2 redo ensure a.push i * 3 + 3 end end assert_equal [1, 2, 3, 1, 2, 3, 3], a a = [] limit = 3 e = RuntimeError.new("!") for i in 0...3 a.push i * 4 + 1 begin limit -= 1 break unless limit > 0 a.push i * 4 + 2 raise e rescue a.push i * 4 + 3 redo ensure a.push i * 4 + 4 end end assert_equal [1, 2, 3, 4, 1, 2, 3, 4, 1, 4], a end assert('Abbreviated variable assignment', '11.4.2.3.2') do a ||= 1 b &&= 1 c = 1 c += 2 assert_equal 1, a assert_nil b assert_equal 3, c end assert('case expression', '11.5.2.2.4') do # case-expression-with-expression, one when-clause x = 0 case "a" when "a" x = 1 end assert_equal 1, x # case-expression-with-expression, multiple when-clauses x = 0 case "b" when "a" x = 1 when "b" x = 2 end assert_equal 2, x # no matching when-clause x = 0 case "c" when "a" x = 1 when "b" x = 2 end assert_equal 0, x # case-expression-with-expression, one when-clause and one else-clause a = 0 case "c" when "a" x = 1 else x = 3 end assert_equal 3, x # case-expression-without-expression, one when-clause x = 0 case when true x = 1 end assert_equal 1, x # case-expression-without-expression, multiple when-clauses x = 0 case when 0 == 1 x = 1 when 1 == 1 x = 2 end assert_equal 2, x # case-expression-without-expression, one when-clause and one else-clause x = 0 case when 0 == 1 x = 1 else x = 3 end assert_equal 3, x # multiple when-arguments x = 0 case 4 when 1, 3, 5 x = 1 when 2, 4, 6 x = 2 end assert_equal 2, x # when-argument with splatting argument x = :integer odds = [ 1, 3, 5, 7, 9 ] evens = [ 2, 4, 6, 8 ] case 5 when *odds x = :odd when *evens x = :even end assert_equal :odd, x true end assert('Nested const reference') do module Syntax4Const CONST1 = "hello world" class Const2 def const1 CONST1 end end end assert_equal "hello world", Syntax4Const::CONST1 assert_equal "hello world", Syntax4Const::Const2.new.const1 assert_raise(NameError) { Syntax4Const::Object } end assert('Abbreviated variable assignment as returns') do module Syntax4AbbrVarAsgnAsReturns class A def b @c ||= 1 end end end assert_equal 1, Syntax4AbbrVarAsgnAsReturns::A.new.b end assert('Abbreviated variable assignment of object attribute') do module Syntax4AbbrVarAsgnObjectAttr class A attr_accessor :c def b self.c ||= 1 end end end assert_equal 1, Syntax4AbbrVarAsgnObjectAttr::A.new.b end assert('Splat and multiple assignment') do *a = *[1,2,3] b, *c = *[7,8,9] assert_equal [1,2,3], a assert_equal 7, b assert_equal [8,9], c (a, b), c = [1,2],3 assert_equal [1,2,3], [a,b,c] (a, b), c = 1,2,3 assert_equal [1,nil,2], [a,b,c] end assert('Splat and multiple assignment from variable') do a = [1, 2, 3] b, *c = a assert_equal 1, b assert_equal [2, 3], c end assert('Splat and multiple assignment from variables') do a = [1, 2, 3] b = [4, 5, 6, 7] c, d, *e, f, g = *a, *b assert_equal 1, c assert_equal 2, d assert_equal [3, 4, 5], e assert_equal 6, f assert_equal 7, g end assert('Splat and multiple assignment in for') do a = [1, 2, 3, 4, 5, 6, 7] for b, c, *d, e, f in [a] do end assert_equal 1, b assert_equal 2, c assert_equal [3, 4, 5], d assert_equal 6, e assert_equal 7, f end assert('Splat without assignment') do * = [0] a, * = [1, 2] assert_equal 1, a end assert('multiple assignment (rest)') do *a = 0 assert_equal [0], a end assert('multiple assignment (rest+post)') do *a, b = 0, 1, 2 *c, d = 3 assert_equal [0, 1], a assert_equal 2, b assert_equal [], c assert_equal 3, d end assert('multiple assignment (nosplat array rhs)') do a, *b = [] *c, d = [0] e, *f, g = [1, 2] assert_nil a assert_equal [], b assert_equal [], c assert_equal 0, d assert_equal 1, e assert_equal [], f assert_equal 2, g end assert('multiple assignment (empty array rhs #3236, #3239)') do a,b,*c = []; assert_equal [nil, nil, []], [a, b, c] a,b,*c = [1]; assert_equal [1, nil, []], [a, b, c] a,b,*c = [nil]; assert_equal [nil,nil, []], [a, b, c] a,b,*c = [[]]; assert_equal [[], nil, []], [a, b, c] end assert('Return values of case statements') do a = [] << case 1 when 3 then 2 when 2 then 2 when 1 then 2 end b = [] << case 1 when 2 then 2 else end def fb n = 0 Proc.new do n += 1 case when n % 15 == 0 else n end end end assert_equal [2], a assert_equal [nil], b assert_equal 1, fb.call end assert('Return values of if and case statements') do true_clause_value = if true 1 else case 2 when 3 end 4 end assert_equal 1, true_clause_value end assert('Return values of no expression case statement') do when_value = case when true 1 end assert_equal 1, when_value end assert('splat object in assignment') do o = Object.new def o.to_a nil end assert_equal [o], (a = *o) def o.to_a 1 end assert_raise(TypeError) { a = *o } def o.to_a [2] end assert_equal [2], (a = *o) end assert('one-line pattern match') do 1 => a assert_equal(1, a) end assert('splat object in case statement') do o = Object.new def o.to_a nil end a = case o when *o 1 end assert_equal 1, a end assert('splat in case statement') do values = [3,5,1,7,8] testa = [1,2,7] testb = [5,6] resulta = [] resultb = [] resultc = [] values.each do |value| case value when *testa resulta << value when *testb resultb << value else resultc << value end end assert_equal [1,7], resulta assert_equal [5], resultb assert_equal [3,8], resultc end assert('External command execution.') do module Kernel sym = '`'.to_sym alias_method :old_cmd, sym results = [] define_method(sym) do |str| results.push str str end `test` # NOVAL NODE_XSTR `test dynamic #{sym}` # NOVAL NODE_DXSTR assert_equal ['test', 'test dynamic `'], results t = `test` # VAL NODE_XSTR assert_equal 'test', t assert_equal ['test', 'test dynamic `', 'test'], results t = `test dynamic #{sym}` # VAL NODE_DXSTR assert_equal 'test dynamic `', t assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results results = [] assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test` alias_method sym, :old_cmd end true end assert('parenthesed do-block in cmdarg') do class ParenDoBlockCmdArg def test(block) block.call end end x = ParenDoBlockCmdArg.new result = x.test (Proc.new do :ok; end) assert_equal :ok, result end assert('method definition in cmdarg') do result = class MethodDefinitionInCmdarg def self.bar(arg); arg end bar def foo; self.each do end end end assert_equal(:foo, result) end assert('optional argument in the rhs default expressions') do class OptArgInRHS def foo "method called" end def t(foo = foo) foo end def t2(foo = foo()) foo end end o = OptArgInRHS.new assert_nil(o.t) assert_equal("method called", o.t2) end assert('optional block argument in the rhs default expressions') do assert_nil(Proc.new {|foo = foo| foo}.call) end assert('local variable definition in default value and subsequent arguments') do def m(a = b = 1, c) [a, b, c] end assert_equal([1, 1, :c], m(:c)) assert_equal([:a, nil, :c], m(:a, :c)) def m(a = b = 1, &c) [a, b, c ? true : nil] end assert_equal([1, 1, nil], m) assert_equal([1, 1, true], m{}) assert_equal([:a, nil, nil], m(:a)) assert_equal([:a, nil, true], m(:a){}) end assert('multiline comments work correctly') do =begin this is a comment with nothing after begin and end =end =begin this is a comment this is a comment with extra after =begin =end =begin this is a comment that has =end with spaces after it =end =begin this is a comment this is a comment that has extra after =begin and =end with spaces after it =end line = __LINE__ =begin this is a comment this is a comment that has extra after =begin and =end with tabs after it =end xxxxxxxxxxxxxxxxxxxxxxxxxx assert_equal(line + 4, __LINE__) end assert 'keyword arguments' do def m(a, b:1) [a, b] end assert_equal [1, 1], m(1) assert_equal [1, 2], m(1, b: 2) def m(a, b:) [a, b] end assert_equal [1, 2], m(1, b: 2) assert_raise(ArgumentError) { m b: 1 } assert_raise(ArgumentError) { m 1 } def m(a:) a end assert_equal 1, m(a: 1) assert_raise(ArgumentError) { m } assert_raise(ArgumentError) { m 'a' => 1, a: 1 } h = { a: 1 } assert_equal 1, m(**h) def m(a: 1) a end assert_equal 1, m assert_equal 2, m(a: 2) assert_raise(ArgumentError) { m 1 } def m(**) end assert_nil m assert_nil m a: 1, b: 2 assert_raise(ArgumentError) { m 2 } def m(a, **) a end assert_equal 1, m(1) assert_equal 1, m(1, a: 2, b: 3) assert_raise(ArgumentError) { m('a' => 1, b: 2) } def m(a, **k) [a, k] end assert_equal [1, {}], m(1) assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3) assert_raise(ArgumentError) { m('a' => 1, b: 2) } def m(a=1, **) a end assert_equal 1, m assert_equal 2, m(2, a: 1, b: 0) def m(a=1, **k) [a, k] end assert_equal [1, {}], m assert_equal [1, {a: 1}], m(a: 1) assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2) assert_equal [{a: 1}, {b: 2}], m({a: 1}, b: 2) assert_raise(ArgumentError) { m({a: 1}, {b: 2}) } def m1(a: {}) a end assert_equal({}, m1) assert_equal(:abc, m1(a: :abc)) def m2(a: +1) a end assert_equal(1, m2) assert_nothing_raised do def m3 arg: 123 end end assert_equal(123, m3(arg: 456)) def m(*, a:) a end assert_equal 1, m(a: 1) assert_equal 3, m(1, 2, a: 3) assert_raise(ArgumentError) { m('a' => 1, a: 2) } def m(*a, b:) [a, b] end assert_equal [[], 1], m(b: 1) assert_equal [[1, 2], 3], m(1, 2, b: 3) assert_raise(ArgumentError) { m('a' => 1, b: 2) } def m(*a, b: 1) [a, b] end assert_equal [[], 1], m assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4) assert_raise(ArgumentError) { m('a' => 1, b: 2) } def m(*, **) end assert_nil m() assert_nil m(a: 1, b: 2) assert_nil m(1, 2, 3, a: 4, b: 5) def m(*a, **) a end assert_equal [], m() assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5) assert_equal [1], m(1, **{a: 2}) def m(*, **k) k end assert_equal({}, m()) assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5)) def m(a = nil, b = nil, **k) [a, k] end assert_equal [nil, {}], m() assert_equal([nil, {a: 1}], m(a: 1)) assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1)) assert_equal([{a: 1}, {}], m({a: 1}, {})) assert_equal([{}, {}], m({})) def m(*a, **k) [a, k] end assert_equal([[], {}], m()) assert_equal([[1], {}], m(1)) assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2)) assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2)) assert_equal([[], {a: 1}], m(a: 1)) assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1)) assert_equal([[{a: 1}, {}], {}], m({a: 1}, {})) def m(a:, b:) [a, b] end assert_equal([1, 2], m(a: 1, b: 2)) assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } def m(a:, b: 1) [a, b] end assert_equal([1, 1], m(a: 1)) assert_equal([1, 2], m(a: 1, b: 2)) assert_raise(ArgumentError) { m(b: 1) } assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } def m(a:, **) a end assert_equal(1, m(a: 1)) assert_equal(1, m(a: 1, b: 2)) def m(a:, **k) [a, k] end assert_equal([1, {}], m(a: 1)) assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3)) def m(a:, &b) [a, b] end assert_equal([1, nil], m(a: 1)) result = m(a: 1, &(l = ->{})) assert_equal([1, l], result) def m(a: 1, b:) [a, b] end assert_equal([1, 0], m(b: 0)) assert_equal([3, 2], m(b: 2, a: 3)) assert_raise(ArgumentError) { m a: 1 } def m(a: def m(a: 1) a end, b:) [a, b] end assert_equal([2, 3], m(a: 2, b: 3)) assert_equal([:m, 1], m(b: 1)) # Note the default value of a: in the original method. assert_equal(1, m()) def m(a: 1, b: 2) [a, b] end assert_equal([1, 2], m()) assert_equal([4, 3], m(b: 3, a: 4)) def m(a: 1, **) a end assert_equal(1, m()) assert_equal(2, m(a: 2, b: 1)) def m(a: 1, **k) [a, k] end assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3)) def m(a:, **) yield end assert_raise(ArgumentError) { m { :blk } } assert_equal :blk, m(a: 1){ :blk } def m(a:, **k, &b) [b.call, k] end assert_raise(ArgumentError) { m { :blk } } assert_equal [:blk, {b: 2}], m(a: 1, b: 2){ :blk } def m(**k, &b) [k, b] end assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2)) assert_equal :blk, m{ :blk }[1].call =begin def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l) [a, b, c, d, e, f, g, h, k, l] end result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{})) assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result) def m a, b=1, *c, d, e:, f: 2, g:, **k, &l [a, b, c, d, e, f, g, k, l] end result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{})) assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result) =end def m(a: b = 1, c:) [a, b, c] end assert_equal([1, 1, :c], m(c: :c)) assert_equal([:a, nil, :c], m(a: :a, c: :c)) end assert('numbered parameters') do assert_equal(15, [1,2,3,4,5].reduce {_1+_2}) assert_equal(45, Proc.new do _1 + _2 + _3 + _4 + _5 + _6 + _7 + _8 + _9 end.call(*[1, 2, 3, 4, 5, 6, 7, 8, 9])) assert_equal(5, -> { _1 }.call(5)) end assert('_0 is not numbered parameter') do _0 = :l assert_equal(:l, ->{_0}.call) end assert('numbered parameters in symbol name (https://github.com/mruby/mruby/issues/5295)') do assert_equal([:_1], Array.new(1) {:_1}) end assert('numbered parameters as hash key') do h = {_1: 3} assert_equal(3, h[:_1]) assert_equal(7, -> { _1 }.call(7)) end assert('numbered parameters as singleton') do o = Object.new lambda { def _1.a(b) = "a#{b}" }.call(o) assert_equal('ab', o.a('b')) end assert('argument forwarding') do c = Class.new { def a0(*a,&b) assert_equal([1,2,3], a) assert_not_nil(b) end def a(...) a0(...) end def b(a,...) assert_equal(a,1) a0(1,...) end def c ... a(...) end def d a,... assert_equal(a,1) b(1,...) end } o = c.new o.a(1,2,3){} o.b(1,2,3){} o.c(1,2,3){} o.d(1,2,3){} end assert('endless def') do c = Class.new { def m1 = 42 def m2() = 42 def m3(x) = x+1 def self.s1 = 42 def self.s2() = 42 def self.s3(x) = x + 1 def cm1 = m3 42 def cm2() = m3 42 def cm3(x) = m3 x+1 def self.cs1 = s3 42 def self.cs2() = s3 42 def self.cs3(x) = s3 x + 1 } o = c.new assert_equal(42, o.m1) assert_equal(43, o.m3(o.m2)) assert_equal(42, c.s1) assert_equal(43, c.s3(c.s2)) assert_equal(43, o.cm1) assert_equal(45, o.cm3(o.cm2)) assert_equal(43, c.cs1) assert_equal(45, c.cs3(c.cs2)) end assert('at-least-once loop') do # basic at-least-once loop that executes once count = 0 begin count += 1 end while false assert_equal 1, count # at-least-once loop with true condition count = 0 begin count += 1 end while count < 3 assert_equal 3, count # at-least-once loop with break count = 0 begin count += 1 break if count == 2 end while count < 10 assert_equal 2, count # at-least-once loop with next count = 0 sum = 0 begin count += 1 if count == 2 next end sum += count end while count < 4 assert_equal 4, count assert_equal 8, sum # 1 + 3 + 4 = 8 (skipped 2) # nested at-least-once loops outer_count = 0 total = 0 begin outer_count += 1 inner_count = 0 begin inner_count += 1 total += inner_count end while inner_count < 2 end while outer_count < 2 assert_equal 2, outer_count assert_equal 6, total # (1+2) + (1+2) = 6 # at-least-once loop with exception handling count = 0 begin count += 1 raise "error" if count == 2 rescue count += 10 end while count < 5 assert_equal 12, count # 1, then 2+10=12 end assert('pattern matching - basic case/in') do # literal patterns result = case 1 in 1 then :one in 2 then :two end assert_equal :one, result # variable binding case 42 in x assert_equal 42, x end # else clause result = case 3 in 1 then :one in 2 then :two else :other end assert_equal :other, result end assert('pattern matching - array patterns') do # simple array pattern case [1, 2, 3] in [a, b, c] assert_equal 1, a assert_equal 2, b assert_equal 3, c end # array pattern with rest case [1, 2, 3, 4, 5] in [first, *rest] assert_equal 1, first assert_equal [2, 3, 4, 5], rest end # array pattern with rest in middle case [1, 2, 3, 4, 5] in [first, *middle, last] assert_equal 1, first assert_equal [2, 3, 4], middle assert_equal 5, last end # nested array pattern case [[1, 2], [3, 4]] in [[a, b], [c, d]] assert_equal [1, 2, 3, 4], [a, b, c, d] end # array pattern with literal match result = case [1, 2, 3] in [1, 2, x] x end assert_equal 3, result end assert('pattern matching - find patterns') do # find pattern - element at end case [1, 2, 3] in [*pre, 3, *post] assert_equal [1, 2], pre assert_equal [], post end # find pattern - element at beginning case [1, 2, 3] in [*pre, 1, *post] assert_equal [], pre assert_equal [2, 3], post end # find pattern - element in middle case [1, 2, 3, 4, 5] in [*pre, 3, *post] assert_equal [1, 2], pre assert_equal [4, 5], post end # find pattern - multiple middle elements case [1, 2, 3, 4, 5] in [*pre, 2, 3, *post] assert_equal [1], pre assert_equal [4, 5], post end # find pattern - anonymous rest result = case [1, 2, 3, 4, 5] in [*, 3, *] :found else :not_found end assert_equal :found, result # find pattern - no match result = case [1, 2, 4, 5] in [*pre, 3, *post] :found else :not_found end assert_equal :not_found, result # find pattern with literal values case [1, 2, 3, 4, 5] in [*pre, 2, x, *post] assert_equal [1], pre assert_equal 3, x assert_equal [4, 5], post end end assert('pattern matching - hash patterns') do # simple hash pattern case {a: 1, b: 2} in {a: x, b: y} assert_equal 1, x assert_equal 2, y end # shorthand hash pattern case {a: 1, b: 2} in {a:, b:} assert_equal 1, a assert_equal 2, b end # hash pattern with extra keys (partial match) case {a: 1, b: 2, c: 3} in {a: x} assert_equal 1, x end # hash pattern with rest (captures unmatched keys) case {a: 1, b: 2, c: 3} in {a:, **rest} assert_equal 1, a assert_equal({b: 2, c: 3}, rest) end # hash value extraction h = {user: "Alice"} case h in {user: u} assert_equal "Alice", u end end assert('pattern matching - guard clauses') do # if guard result = case 10 in x if x > 5 :big in x :small end assert_equal :big, result # unless guard result = case 3 in x unless x > 5 :small in x :big end assert_equal :small, result # guard with pattern result = case [1, 2, 3] in [a, b, c] if a + b + c > 5 :sum_big in [a, b, c] :sum_small end assert_equal :sum_big, result end assert('pattern matching - alternative patterns') do # simple alternatives result = case 2 in 1 | 2 | 3 :found else :not_found end assert_equal :found, result # alternatives in array result = case [1, 2] in [1, 2] | [3, 4] :match else :no_match end assert_equal :match, result end assert('pattern matching - pin operator') do x = 1 # pin matches exact value result = case 1 in ^x :matched else :not_matched end assert_equal :matched, result # pin in array pattern expected = 42 case [42, 100] in [^expected, y] assert_equal 100, y end # pin prevents rebinding a = 1 result = case 2 in ^a :same else :different end assert_equal :different, result end assert('pattern matching - as pattern') do # bind entire match case [1, 2, 3] in [x, *rest] => whole assert_equal 1, x assert_equal [2, 3], rest assert_equal [1, 2, 3], whole end # as pattern with hash case {a: 1, b: 2} in {a:} => h assert_equal 1, a assert_equal({a: 1, b: 2}, h) end end assert('pattern matching - one-line in') do # basic true/false assert_true((1 in 1)) assert_false((1 in 2)) # with variable binding assert_true(([1, 2] in [x, y])) # in conditional matched = false if [1, 2, 3] in [a, *rest] matched = true end assert_true matched # with hash assert_true(({a: 1} in {a: 1})) assert_false(({a: 1} in {a: 2})) end assert('pattern matching - one-line =>') do # simple binding 1 => x assert_equal 1, x # array destructuring [1, 2, 3] => [a, b, c] assert_equal [1, 2, 3], [a, b, c] # hash destructuring {name: "Bob", age: 25} => {name:, age:} assert_equal "Bob", name assert_equal 25, age # with rest [1, 2, 3, 4] => [first, *middle, last] assert_equal 1, first assert_equal [2, 3], middle assert_equal 4, last end assert('pattern matching - NoMatchingPatternError') do # => raises on mismatch assert_raise(NoMatchingPatternError) do 1 => 2 end # can be rescued begin [1, 2] => [1, 2, 3] rescue NoMatchingPatternError => e assert_true e.message.is_a?(String) end # case/in without else raises NoMatchingPatternError assert_raise(NoMatchingPatternError) do case 5 in 1 then :one in 2 then :two end end end assert('pattern matching - complex patterns') do # array of hashes records = [{id: 1, value: "a"}, {id: 2, value: "b"}] case records in [first, second] assert_equal({id: 1, value: "a"}, first) assert_equal({id: 2, value: "b"}, second) end # hash with array value data = {items: [1, 2, 3]} case data in {items: [a, *rest]} assert_equal 1, a assert_equal [2, 3], rest end end assert('&nil in formal parameters') do def m(&nil); end m m(&nil) assert_raise(ArgumentError) { m {} } def m2(a, b, &nil); end m2(1, 2) assert_raise(ArgumentError) { m2(1, 2) {} } def m3(a, b=1, *c, &nil); end m3(1) assert_raise(ArgumentError) { m3(1) {} } def m4(a:, &nil); end m4(a: 1) assert_raise(ArgumentError) { m4(a: 1) {} } f = ->(&nil) { :ok } assert_equal :ok, f.call assert_raise(ArgumentError) { f.call {} } end