1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/test_keyword.rb
Jeremy Evans 37a2c660aa Convert keyword argument to required positional hash argument for Class#new, Method#call, UnboundMethod#bind_call
Also add keyword argument separation warnings for Class#new and Method#call.

To allow for keyword argument to required positional hash converstion in
cfuncs, add a vm frame flag indicating the cfunc was called with an empty
keyword hash (which was removed before calling the cfunc).  The cfunc can
check this frame flag and add back an empty hash if it is passing its
arguments to another Ruby method.  Add rb_empty_keyword_given_p function
for checking if called with an empty keyword hash, and
rb_add_empty_keyword for adding back an empty hash to argv.

All of this empty keyword argument support is only for 2.7.  It will be
removed in 3.0 as Ruby 3 will not convert empty keyword arguments to
required positional hash arguments.  Comment all of the relevent code
to make it obvious this is expected to be removed.

Add rb_funcallv_kw as an public C-API function, just like rb_funcallv
but with a keyword flag.  This is used by rb_obj_call_init (internals
of Class#new).  This also required expected call_type enum with
CALL_FCALL_KW, similar to the recent addition of CALL_PUBLIC_KW.

Add rb_vm_call_kw as a internal function, used by call_method_data
(internals of Method#call and UnboundMethod#bind_call). Add tests
for UnboundMethod#bind_call keyword handling.
2019-09-06 19:41:23 -07:00

1742 lines
57 KiB
Ruby

# frozen_string_literal: false
require 'test/unit'
class TestKeywordArguments < Test::Unit::TestCase
def f1(str: "foo", num: 424242)
[str, num]
end
def test_f1
assert_equal(["foo", 424242], f1)
assert_equal(["bar", 424242], f1(str: "bar"))
assert_equal(["foo", 111111], f1(num: 111111))
assert_equal(["bar", 111111], f1(str: "bar", num: 111111))
assert_raise(ArgumentError) { f1(str: "bar", check: true) }
assert_raise(ArgumentError) { f1("string") }
end
def f2(x, str: "foo", num: 424242)
[x, str, num]
end
def test_f2
assert_equal([:xyz, "foo", 424242], f2(:xyz))
assert_warn(/The keyword argument is passed as the last hash parameter.* for `f2'/m) do
assert_equal([{"bar"=>42}, "foo", 424242], f2("bar"=>42))
end
end
def f3(str: "foo", num: 424242, **h)
[str, num, h]
end
def test_f3
assert_equal(["foo", 424242, {}], f3)
assert_equal(["bar", 424242, {}], f3(str: "bar"))
assert_equal(["foo", 111111, {}], f3(num: 111111))
assert_equal(["bar", 111111, {}], f3(str: "bar", num: 111111))
assert_equal(["bar", 424242, {:check=>true}], f3(str: "bar", check: true))
assert_raise(ArgumentError) { f3("string") }
end
define_method(:f4) {|str: "foo", num: 424242| [str, num] }
def test_f4
assert_equal(["foo", 424242], f4)
assert_equal(["bar", 424242], f4(str: "bar"))
assert_equal(["foo", 111111], f4(num: 111111))
assert_equal(["bar", 111111], f4(str: "bar", num: 111111))
assert_raise(ArgumentError) { f4(str: "bar", check: true) }
assert_raise(ArgumentError) { f4("string") }
end
define_method(:f5) {|str: "foo", num: 424242, **h| [str, num, h] }
def test_f5
assert_equal(["foo", 424242, {}], f5)
assert_equal(["bar", 424242, {}], f5(str: "bar"))
assert_equal(["foo", 111111, {}], f5(num: 111111))
assert_equal(["bar", 111111, {}], f5(str: "bar", num: 111111))
assert_equal(["bar", 424242, {:check=>true}], f5(str: "bar", check: true))
assert_raise(ArgumentError) { f5("string") }
end
def f6(str: "foo", num: 424242, **h, &blk)
[str, num, h, blk]
end
def test_f6 # [ruby-core:40518]
assert_equal(["foo", 424242, {}, nil], f6)
assert_equal(["bar", 424242, {}, nil], f6(str: "bar"))
assert_equal(["foo", 111111, {}, nil], f6(num: 111111))
assert_equal(["bar", 111111, {}, nil], f6(str: "bar", num: 111111))
assert_equal(["bar", 424242, {:check=>true}, nil], f6(str: "bar", check: true))
a = f6 {|x| x + 42 }
assert_equal(["foo", 424242, {}], a[0, 3])
assert_equal(43, a.last.call(1))
end
def f7(*r, str: "foo", num: 424242, **h)
[r, str, num, h]
end
def test_f7 # [ruby-core:41772]
assert_equal([[], "foo", 424242, {}], f7)
assert_equal([[], "bar", 424242, {}], f7(str: "bar"))
assert_equal([[], "foo", 111111, {}], f7(num: 111111))
assert_equal([[], "bar", 111111, {}], f7(str: "bar", num: 111111))
assert_equal([[1], "foo", 424242, {}], f7(1))
assert_equal([[1, 2], "foo", 424242, {}], f7(1, 2))
assert_equal([[1, 2, 3], "foo", 424242, {}], f7(1, 2, 3))
assert_equal([[1], "bar", 424242, {}], f7(1, str: "bar"))
assert_equal([[1, 2], "bar", 424242, {}], f7(1, 2, str: "bar"))
assert_equal([[1, 2, 3], "bar", 424242, {}], f7(1, 2, 3, str: "bar"))
end
define_method(:f8) { |opt = :ion, *rest, key: :word|
[opt, rest, key]
}
def test_f8
assert_equal([:ion, [], :word], f8)
assert_equal([1, [], :word], f8(1))
assert_equal([1, [2], :word], f8(1, 2))
end
def f9(r, o=42, *args, p, k: :key, **kw, &b)
[r, o, args, p, k, kw, b]
end
def test_f9
assert_equal([1, 42, [], 2, :key, {}, nil], f9(1, 2))
assert_equal([1, 2, [], 3, :key, {}, nil], f9(1, 2, 3))
assert_equal([1, 2, [3], 4, :key, {}, nil], f9(1, 2, 3, 4))
assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], f9(1, 2, 3, 4, 5, str: "bar"))
end
def f10(a: 1, **)
a
end
def test_f10
assert_equal(42, f10(a: 42))
assert_equal(1, f10(b: 42))
end
def f11(**nil)
local_variables
end
def test_f11
h = {}
assert_equal([], f11)
assert_equal([], f11(**{}))
assert_equal([], f11(**h))
end
def f12(**nil, &b)
[b, local_variables]
end
def test_f12
h = {}
b = proc{}
assert_equal([nil, [:b]], f12)
assert_equal([nil, [:b]], f12(**{}))
assert_equal([nil, [:b]], f12(**h))
assert_equal([b, [:b]], f12(&b))
assert_equal([b, [:b]], f12(**{}, &b))
assert_equal([b, [:b]], f12(**h, &b))
end
def test_method_parameters
assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters);
assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters);
assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f3).parameters);
assert_equal([[:key, :str], [:key, :num]], method(:f4).parameters);
assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f5).parameters);
assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], method(:f6).parameters);
assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], method(:f7).parameters);
assert_equal([[:opt, :opt], [:rest, :rest], [:key, :key]], method(:f8).parameters) # [Bug #7540] [ruby-core:50735]
assert_equal([[:req, :r], [:opt, :o], [:rest, :args], [:req, :p], [:key, :k],
[:keyrest, :kw], [:block, :b]], method(:f9).parameters)
end
def test_lambda
f = ->(str: "foo", num: 424242) { [str, num] }
assert_equal(["foo", 424242], f[])
assert_equal(["bar", 424242], f[str: "bar"])
assert_equal(["foo", 111111], f[num: 111111])
assert_equal(["bar", 111111], f[str: "bar", num: 111111])
end
def test_regular_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.m(*args)
args
end
assert_equal([], c.m(**{}))
assert_equal([], c.m(**kw))
assert_equal([h], c.m(**h))
assert_equal([h], c.m(a: 1))
assert_equal([h2], c.m(**h2))
assert_equal([h3], c.m(**h3))
assert_equal([h3], c.m(a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m; end
assert_nil(c.m(**{}))
assert_nil(c.m(**kw))
assert_raise(ArgumentError) { c.m(**h) }
assert_raise(ArgumentError) { c.m(a: 1) }
assert_raise(ArgumentError) { c.m(**h2) }
assert_raise(ArgumentError) { c.m(**h3) }
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
c.singleton_class.remove_method(:m)
def c.m(args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.m(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.m(**kw))
end
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(**h3))
assert_equal(h3, c.m(a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(**args)
args
end
assert_equal(kw, c.m(**{}))
assert_equal(kw, c.m(**kw))
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
c.m(**{})
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
c.m(**kw)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.m(**h))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.m(a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h2, kw], c.m(**h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.m(**h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.m(a: 1, **h2))
end
c.singleton_class.remove_method(:m)
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], c.m(**{}))
assert_equal([1, kw], c.m(**kw))
assert_equal([1, h], c.m(**h))
assert_equal([1, h], c.m(a: 1))
assert_equal([1, h2], c.m(**h2))
assert_equal([1, h3], c.m(**h3))
assert_equal([1, h3], c.m(a: 1, **h2))
end
def test_lambda_kwsplat_call
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
f = -> { true }
assert_equal(true, f[**{}])
assert_equal(true, f[**kw])
assert_raise(ArgumentError) { f[**h] }
assert_raise(ArgumentError) { f[a: 1] }
assert_raise(ArgumentError) { f[**h2] }
assert_raise(ArgumentError) { f[**h3] }
f = ->(a) { a }
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, f[**{}])
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, f[**kw])
end
assert_equal(h, f[**h])
assert_equal(h, f[a: 1])
assert_equal(h2, f[**h2])
assert_equal(h3, f[**h3])
assert_equal(h3, f[a: 1, **h2])
f = ->(**x) { x }
assert_equal(kw, f[**{}])
assert_equal(kw, f[**kw])
assert_equal(h, f[**h])
assert_equal(h, f[a: 1])
assert_equal(h2, f[**h2])
assert_equal(h3, f[**h3])
assert_equal(h3, f[a: 1, **h2])
f = ->(a, **x) { [a,x] }
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([{}, {}], f[**{}])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([{}, {}], f[**kw])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([h, {}], f[**h])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([h, {}], f[a: 1])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([h2, {}], f[**h2])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([h3, {}], f[**h3])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `\[\]'/m) do
assert_equal([h3, {}], f[a: 1, **h2])
end
f = ->(a=1, **x) { [a, x] }
assert_equal([1, kw], f[**{}])
assert_equal([1, kw], f[**kw])
assert_equal([1, h], f[**h])
assert_equal([1, h], f[a: 1])
assert_equal([1, h2], f[**h2])
assert_equal([1, h3], f[**h3])
assert_equal([1, h3], f[a: 1, **h2])
end
def test_Class_new_kwsplat_call
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
sc = Class.new do
attr_reader :args
class << self
alias [] new
end
end
c = Class.new(sc) do
def initialize(*args)
@args = args
end
end
assert_equal([], c[**{}].args)
assert_equal([], c[**kw].args)
assert_equal([h], c[**h].args)
assert_equal([h], c[a: 1].args)
assert_equal([h2], c[**h2].args)
assert_equal([h3], c[**h3].args)
assert_equal([h3], c[a: 1, **h2].args)
c = Class.new(sc) do
def initialize; end
end
assert_nil(c[**{}].args)
assert_nil(c[**kw].args)
assert_raise(ArgumentError) { c[**h] }
assert_raise(ArgumentError) { c[a: 1] }
assert_raise(ArgumentError) { c[**h2] }
assert_raise(ArgumentError) { c[**h3] }
assert_raise(ArgumentError) { c[a: 1, **h2] }
c = Class.new(sc) do
def initialize(args)
@args = args
end
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal(kw, c[**{}].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal(kw, c[**kw].args)
end
assert_equal(h, c[**h].args)
assert_equal(h, c[a: 1].args)
assert_equal(h2, c[**h2].args)
assert_equal(h3, c[**h3].args)
assert_equal(h3, c[a: 1, **h2].args)
c = Class.new(sc) do
def initialize(**args)
@args = args
end
end
assert_equal(kw, c[**{}].args)
assert_equal(kw, c[**kw].args)
assert_equal(h, c[**h].args)
assert_equal(h, c[a: 1].args)
assert_equal(h2, c[**h2].args)
assert_equal(h3, c[**h3].args)
assert_equal(h3, c[a: 1, **h2].args)
c = Class.new(sc) do
def initialize(arg, **args)
@args = [arg, args]
end
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([kw, kw], c[**{}].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([kw, kw], c[**kw].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([h, kw], c[**h].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([h, kw], c[a: 1].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([h2, kw], c[**h2].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([h3, kw], c[**h3].args)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `initialize'/m) do
assert_equal([h3, kw], c[a: 1, **h2].args)
end
c = Class.new(sc) do
def initialize(arg=1, **args)
@args = [arg=1, args]
end
end
assert_equal([1, kw], c[**{}].args)
assert_equal([1, kw], c[**kw].args)
assert_equal([1, h], c[**h].args)
assert_equal([1, h], c[a: 1].args)
assert_equal([1, h2], c[**h2].args)
assert_equal([1, h3], c[**h3].args)
assert_equal([1, h3], c[a: 1, **h2].args)
end
def test_Method_call_kwsplat_call
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.m(*args)
args
end
assert_equal([], c.method(:m)[**{}])
assert_equal([], c.method(:m)[**kw])
assert_equal([h], c.method(:m)[**h])
assert_equal([h], c.method(:m)[a: 1])
assert_equal([h2], c.method(:m)[**h2])
assert_equal([h3], c.method(:m)[**h3])
assert_equal([h3], c.method(:m)[a: 1, **h2])
c.singleton_class.remove_method(:m)
def c.m; end
assert_nil(c.method(:m)[**{}])
assert_nil(c.method(:m)[**kw])
assert_raise(ArgumentError) { c.method(:m)[**h] }
assert_raise(ArgumentError) { c.method(:m)[a: 1] }
assert_raise(ArgumentError) { c.method(:m)[**h2] }
assert_raise(ArgumentError) { c.method(:m)[**h3] }
assert_raise(ArgumentError) { c.method(:m)[a: 1, **h2] }
c.singleton_class.remove_method(:m)
def c.m(args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.method(:m)[**{}])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.method(:m)[**kw])
end
assert_equal(h, c.method(:m)[**h])
assert_equal(h, c.method(:m)[a: 1])
assert_equal(h2, c.method(:m)[**h2])
assert_equal(h3, c.method(:m)[**h3])
assert_equal(h3, c.method(:m)[a: 1, **h2])
c.singleton_class.remove_method(:m)
def c.m(**args)
args
end
assert_equal(kw, c.method(:m)[**{}])
assert_equal(kw, c.method(:m)[**kw])
assert_equal(h, c.method(:m)[**h])
assert_equal(h, c.method(:m)[a: 1])
assert_equal(h2, c.method(:m)[**h2])
assert_equal(h3, c.method(:m)[**h3])
assert_equal(h3, c.method(:m)[a: 1, **h2])
c.singleton_class.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], c.method(:m)[**{}])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], c.method(:m)[**kw])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.method(:m)[**h])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.method(:m)[a: 1])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h2, kw], c.method(:m)[**h2])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.method(:m)[**h3])
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.method(:m)[a: 1, **h2])
end
c.singleton_class.remove_method(:m)
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], c.method(:m)[**{}])
assert_equal([1, kw], c.method(:m)[**kw])
assert_equal([1, h], c.method(:m)[**h])
assert_equal([1, h], c.method(:m)[a: 1])
assert_equal([1, h2], c.method(:m)[**h2])
assert_equal([1, h3], c.method(:m)[**h3])
assert_equal([1, h3], c.method(:m)[a: 1, **h2])
end
def test_UnboundMethod_bindcall_kwsplat_call
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
sc = c.singleton_class
def c.m(*args)
args
end
assert_equal([], sc.instance_method(:m).bind_call(c, **{}))
assert_equal([], sc.instance_method(:m).bind_call(c, **kw))
assert_equal([h], sc.instance_method(:m).bind_call(c, **h))
assert_equal([h], sc.instance_method(:m).bind_call(c, a: 1))
assert_equal([h2], sc.instance_method(:m).bind_call(c, **h2))
assert_equal([h3], sc.instance_method(:m).bind_call(c, **h3))
assert_equal([h3], sc.instance_method(:m).bind_call(c, a: 1, **h2))
sc.remove_method(:m)
def c.m; end
assert_nil(sc.instance_method(:m).bind_call(c, **{}))
assert_nil(sc.instance_method(:m).bind_call(c, **kw))
assert_raise(ArgumentError) { sc.instance_method(:m).bind_call(c, **h) }
assert_raise(ArgumentError) { sc.instance_method(:m).bind_call(c, a: 1) }
assert_raise(ArgumentError) { sc.instance_method(:m).bind_call(c, **h2) }
assert_raise(ArgumentError) { sc.instance_method(:m).bind_call(c, **h3) }
assert_raise(ArgumentError) { sc.instance_method(:m).bind_call(c, a: 1, **h2) }
sc.remove_method(:m)
def c.m(args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, sc.instance_method(:m).bind_call(c, **{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, sc.instance_method(:m).bind_call(c, **kw))
end
assert_equal(h, sc.instance_method(:m).bind_call(c, **h))
assert_equal(h, sc.instance_method(:m).bind_call(c, a: 1))
assert_equal(h2, sc.instance_method(:m).bind_call(c, **h2))
assert_equal(h3, sc.instance_method(:m).bind_call(c, **h3))
assert_equal(h3, sc.instance_method(:m).bind_call(c, a: 1, **h2))
sc.remove_method(:m)
def c.m(**args)
args
end
assert_equal(kw, sc.instance_method(:m).bind_call(c, **{}))
assert_equal(kw, sc.instance_method(:m).bind_call(c, **kw))
assert_equal(h, sc.instance_method(:m).bind_call(c, **h))
assert_equal(h, sc.instance_method(:m).bind_call(c, a: 1))
assert_equal(h2, sc.instance_method(:m).bind_call(c, **h2))
assert_equal(h3, sc.instance_method(:m).bind_call(c, **h3))
assert_equal(h3, sc.instance_method(:m).bind_call(c, a: 1, **h2))
sc.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], sc.instance_method(:m).bind_call(c, **{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], sc.instance_method(:m).bind_call(c, **kw))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], sc.instance_method(:m).bind_call(c, **h))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], sc.instance_method(:m).bind_call(c, a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h2, kw], sc.instance_method(:m).bind_call(c, **h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], sc.instance_method(:m).bind_call(c, **h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], sc.instance_method(:m).bind_call(c, a: 1, **h2))
end
sc.remove_method(:m)
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], sc.instance_method(:m).bind_call(c, **{}))
assert_equal([1, kw], sc.instance_method(:m).bind_call(c, **kw))
assert_equal([1, h], sc.instance_method(:m).bind_call(c, **h))
assert_equal([1, h], sc.instance_method(:m).bind_call(c, a: 1))
assert_equal([1, h2], sc.instance_method(:m).bind_call(c, **h2))
assert_equal([1, h3], sc.instance_method(:m).bind_call(c, **h3))
assert_equal([1, h3], sc.instance_method(:m).bind_call(c, a: 1, **h2))
end
def test_send_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.m(*args)
args
end
assert_equal([], c.send(:m, **{}))
assert_equal([], c.send(:m, **kw))
assert_equal([h], c.send(:m, **h))
assert_equal([h], c.send(:m, a: 1))
assert_equal([h2], c.send(:m, **h2))
assert_equal([h3], c.send(:m, **h3))
assert_equal([h3], c.send(:m, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m; end
assert_nil(c.send(:m, **{}))
assert_nil(c.send(:m, **kw))
assert_raise(ArgumentError) { c.send(:m, **h) }
assert_raise(ArgumentError) { c.send(:m, a: 1) }
assert_raise(ArgumentError) { c.send(:m, **h2) }
assert_raise(ArgumentError) { c.send(:m, **h3) }
assert_raise(ArgumentError) { c.send(:m, a: 1, **h2) }
c.singleton_class.remove_method(:m)
def c.m(args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.send(:m, **{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, c.send(:m, **kw))
end
assert_equal(h, c.send(:m, **h))
assert_equal(h, c.send(:m, a: 1))
assert_equal(h2, c.send(:m, **h2))
assert_equal(h3, c.send(:m, **h3))
assert_equal(h3, c.send(:m, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(**args)
args
end
assert_equal(kw, c.send(:m, **{}))
assert_equal(kw, c.send(:m, **kw))
assert_equal(h, c.send(:m, **h))
assert_equal(h, c.send(:m, a: 1))
assert_equal(h2, c.send(:m, **h2))
assert_equal(h3, c.send(:m, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
c.send(:m, **{})
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
c.send(:m, **kw)
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.send(:m, **h))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], c.send(:m, a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h2, kw], c.send(:m, **h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.send(:m, **h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], c.send(:m, a: 1, **h2))
end
c.singleton_class.remove_method(:m)
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], c.send(:m, **{}))
assert_equal([1, kw], c.send(:m, **kw))
assert_equal([1, h], c.send(:m, **h))
assert_equal([1, h], c.send(:m, a: 1))
assert_equal([1, h2], c.send(:m, **h2))
assert_equal([1, h3], c.send(:m, **h3))
assert_equal([1, h3], c.send(:m, a: 1, **h2))
end
def test_sym_proc_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.m(*args)
args
end
assert_equal([], :m.to_proc.call(c, **{}))
assert_equal([], :m.to_proc.call(c, **kw))
assert_equal([h], :m.to_proc.call(c, **h))
assert_equal([h], :m.to_proc.call(c, a: 1))
assert_equal([h2], :m.to_proc.call(c, **h2))
assert_equal([h3], :m.to_proc.call(c, **h3))
assert_equal([h3], :m.to_proc.call(c, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m; end
assert_nil(:m.to_proc.call(c, **{}))
assert_nil(:m.to_proc.call(c, **kw))
assert_raise(ArgumentError) { :m.to_proc.call(c, **h) }
assert_raise(ArgumentError) { :m.to_proc.call(c, a: 1) }
assert_raise(ArgumentError) { :m.to_proc.call(c, **h2) }
assert_raise(ArgumentError) { :m.to_proc.call(c, **h3) }
assert_raise(ArgumentError) { :m.to_proc.call(c, a: 1, **h2) }
c.singleton_class.remove_method(:m)
def c.m(args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, :m.to_proc.call(c, **{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal(kw, :m.to_proc.call(c, **kw))
end
assert_equal(h, :m.to_proc.call(c, **h))
assert_equal(h, :m.to_proc.call(c, a: 1))
assert_equal(h2, :m.to_proc.call(c, **h2))
assert_equal(h3, :m.to_proc.call(c, **h3))
assert_equal(h3, :m.to_proc.call(c, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(**args)
args
end
assert_equal(kw, :m.to_proc.call(c, **{}))
assert_equal(kw, :m.to_proc.call(c, **kw))
assert_equal(h, :m.to_proc.call(c, **h))
assert_equal(h, :m.to_proc.call(c, a: 1))
assert_equal(h2, :m.to_proc.call(c, **h2))
assert_equal(h3, :m.to_proc.call(c, **h3))
assert_equal(h3, :m.to_proc.call(c, a: 1, **h2))
c.singleton_class.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], :m.to_proc.call(c, **{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([kw, kw], :m.to_proc.call(c, **kw))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], :m.to_proc.call(c, **h))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h, kw], :m.to_proc.call(c, a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h2, kw], :m.to_proc.call(c, **h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], :m.to_proc.call(c, **h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
assert_equal([h3, kw], :m.to_proc.call(c, a: 1, **h2))
end
c.singleton_class.remove_method(:m)
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], :m.to_proc.call(c, **{}))
assert_equal([1, kw], :m.to_proc.call(c, **kw))
assert_equal([1, h], :m.to_proc.call(c, **h))
assert_equal([1, h], :m.to_proc.call(c, a: 1))
assert_equal([1, h2], :m.to_proc.call(c, **h2))
assert_equal([1, h3], :m.to_proc.call(c, **h3))
assert_equal([1, h3], :m.to_proc.call(c, a: 1, **h2))
end
def test_method_missing_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.method_missing(_, *args)
args
end
assert_equal([], c.m(**{}))
assert_equal([], c.m(**kw))
assert_equal([h], c.m(**h))
assert_equal([h], c.m(a: 1))
assert_equal([h2], c.m(**h2))
assert_equal([h3], c.m(**h3))
assert_equal([h3], c.m(a: 1, **h2))
c.singleton_class.remove_method(:method_missing)
def c.method_missing(_); end
assert_nil(c.m(**{}))
assert_nil(c.m(**kw))
assert_raise(ArgumentError) { c.m(**h) }
assert_raise(ArgumentError) { c.m(a: 1) }
assert_raise(ArgumentError) { c.m(**h2) }
assert_raise(ArgumentError) { c.m(**h3) }
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
c.singleton_class.remove_method(:method_missing)
def c.method_missing(_, args)
args
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal(kw, c.m(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal(kw, c.m(**kw))
end
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(**h3))
assert_equal(h3, c.m(a: 1, **h2))
c.singleton_class.remove_method(:method_missing)
def c.method_missing(_, **args)
args
end
assert_equal(kw, c.m(**{}))
assert_equal(kw, c.m(**kw))
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(a: 1, **h2))
c.singleton_class.remove_method(:method_missing)
def c.method_missing(_, arg, **args)
[arg, args]
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([kw, kw], c.m(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([kw, kw], c.m(**kw))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([h, kw], c.m(**h))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([h, kw], c.m(a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([h2, kw], c.m(**h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([h3, kw], c.m(**h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
assert_equal([h3, kw], c.m(a: 1, **h2))
end
c.singleton_class.remove_method(:method_missing)
def c.method_missing(_, arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], c.m(**{}))
assert_equal([1, kw], c.m(**kw))
assert_equal([1, h], c.m(**h))
assert_equal([1, h], c.m(a: 1))
assert_equal([1, h2], c.m(**h2))
assert_equal([1, h3], c.m(**h3))
assert_equal([1, h3], c.m(a: 1, **h2))
end
def test_define_method_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
class << c
define_method(:m) { }
end
assert_nil(c.m(**{}))
assert_nil(c.m(**kw))
assert_raise(ArgumentError) { c.m(**h) }
assert_raise(ArgumentError) { c.m(a: 1) }
assert_raise(ArgumentError) { c.m(**h2) }
assert_raise(ArgumentError) { c.m(**h3) }
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
c = Object.new
class << c
define_method(:m) {|arg| arg }
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, c.m(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, c.m(**kw))
end
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(**h3))
assert_equal(h3, c.m(a: 1, **h2))
c = Object.new
class << c
define_method(:m) {|*args| args }
end
assert_equal([], c.m(**{}))
assert_equal([], c.m(**kw))
assert_equal([h], c.m(**h))
assert_equal([h], c.m(a: 1))
assert_equal([h2], c.m(**h2))
assert_equal([h3], c.m(**h3))
assert_equal([h3], c.m(a: 1, **h2))
c = Object.new
class << c
define_method(:m) {|**opt| opt}
end
assert_equal(kw, c.m(**{}))
assert_equal(kw, c.m(**kw))
assert_equal(h, c.m(**h))
assert_equal(h, c.m(a: 1))
assert_equal(h2, c.m(**h2))
assert_equal(h3, c.m(**h3))
assert_equal(h3, c.m(a: 1, **h2))
c = Object.new
class << c
define_method(:m) {|arg, **opt| [arg, opt] }
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([kw, kw], c.m(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([kw, kw], c.m(**kw))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([h, kw], c.m(**h))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([h, kw], c.m(a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([h2, kw], c.m(**h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([h3, kw], c.m(**h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal([h3, kw], c.m(a: 1, **h2))
end
c = Object.new
class << c
define_method(:m) {|arg=1, **opt| [arg, opt] }
end
assert_equal([1, kw], c.m(**{}))
assert_equal([1, kw], c.m(**kw))
assert_equal([1, h], c.m(**h))
assert_equal([1, h], c.m(a: 1))
assert_equal([1, h2], c.m(**h2))
assert_equal([1, h3], c.m(**h3))
assert_equal([1, h3], c.m(a: 1, **h2))
end
def test_attr_reader_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
class << c
attr_reader :m
end
assert_nil(c.m(**{}))
assert_nil(c.m(**kw))
assert_raise(ArgumentError) { c.m(**h) }
assert_raise(ArgumentError) { c.m(a: 1) }
assert_raise(ArgumentError) { c.m(**h2) }
assert_raise(ArgumentError) { c.m(**h3) }
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
end
def test_attr_writer_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
class << c
attr_writer :m
end
assert_warn(/The keyword argument for `m=' is passed as the last hash parameter/) do
c.send(:m=, **{})
end
assert_warn(/The keyword argument for `m=' is passed as the last hash parameter/) do
c.send(:m=, **kw)
end
assert_equal(h, c.send(:m=, **h))
assert_equal(h, c.send(:m=, a: 1))
assert_equal(h2, c.send(:m=, **h2))
assert_equal(h3, c.send(:m=, **h3))
assert_equal(h3, c.send(:m=, a: 1, **h2))
assert_equal(42, c.send(:m=, 42, **{}))
assert_equal(42, c.send(:m=, 42, **kw))
assert_raise(ArgumentError) { c.send(:m=, 42, **h) }
assert_raise(ArgumentError) { c.send(:m=, 42, a: 1) }
assert_raise(ArgumentError) { c.send(:m=, 42, **h2) }
assert_raise(ArgumentError) { c.send(:m=, 42, **h3) }
assert_raise(ArgumentError) { c.send(:m=, 42, a: 1, **h2) }
end
def p1
Proc.new do |str: "foo", num: 424242|
[str, num]
end
end
def test_p1
assert_equal(["foo", 424242], p1[])
assert_equal(["bar", 424242], p1[str: "bar"])
assert_equal(["foo", 111111], p1[num: 111111])
assert_equal(["bar", 111111], p1[str: "bar", num: 111111])
assert_raise(ArgumentError) { p1[str: "bar", check: true] }
assert_equal(["foo", 424242], p1["string"] )
end
def p2
Proc.new do |x, str: "foo", num: 424242|
[x, str, num]
end
end
def test_p2
assert_equal([nil, "foo", 424242], p2[])
assert_equal([:xyz, "foo", 424242], p2[:xyz])
end
def p3
Proc.new do |str: "foo", num: 424242, **h|
[str, num, h]
end
end
def test_p3
assert_equal(["foo", 424242, {}], p3[])
assert_equal(["bar", 424242, {}], p3[str: "bar"])
assert_equal(["foo", 111111, {}], p3[num: 111111])
assert_equal(["bar", 111111, {}], p3[str: "bar", num: 111111])
assert_equal(["bar", 424242, {:check=>true}], p3[str: "bar", check: true])
assert_equal(["foo", 424242, {}], p3["string"])
end
def p4
Proc.new do |str: "foo", num: 424242, **h, &blk|
[str, num, h, blk]
end
end
def test_p4
assert_equal(["foo", 424242, {}, nil], p4[])
assert_equal(["bar", 424242, {}, nil], p4[str: "bar"])
assert_equal(["foo", 111111, {}, nil], p4[num: 111111])
assert_equal(["bar", 111111, {}, nil], p4[str: "bar", num: 111111])
assert_equal(["bar", 424242, {:check=>true}, nil], p4[str: "bar", check: true])
a = p4.call {|x| x + 42 }
assert_equal(["foo", 424242, {}], a[0, 3])
assert_equal(43, a.last.call(1))
end
def p5
Proc.new do |*r, str: "foo", num: 424242, **h|
[r, str, num, h]
end
end
def test_p5
assert_equal([[], "foo", 424242, {}], p5[])
assert_equal([[], "bar", 424242, {}], p5[str: "bar"])
assert_equal([[], "foo", 111111, {}], p5[num: 111111])
assert_equal([[], "bar", 111111, {}], p5[str: "bar", num: 111111])
assert_equal([[1], "foo", 424242, {}], p5[1])
assert_equal([[1, 2], "foo", 424242, {}], p5[1, 2])
assert_equal([[1, 2, 3], "foo", 424242, {}], p5[1, 2, 3])
assert_equal([[1], "bar", 424242, {}], p5[1, str: "bar"])
assert_equal([[1, 2], "bar", 424242, {}], p5[1, 2, str: "bar"])
assert_equal([[1, 2, 3], "bar", 424242, {}], p5[1, 2, 3, str: "bar"])
end
def p6
Proc.new do |o1, o2=42, *args, p, k: :key, **kw, &b|
[o1, o2, args, p, k, kw, b]
end
end
def test_p6
assert_equal([nil, 42, [], nil, :key, {}, nil], p6[])
assert_equal([1, 42, [], 2, :key, {}, nil], p6[1, 2])
assert_equal([1, 2, [], 3, :key, {}, nil], p6[1, 2, 3])
assert_equal([1, 2, [3], 4, :key, {}, nil], p6[1, 2, 3, 4])
assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], p6[1, 2, 3, 4, 5, str: "bar"])
end
def test_proc_parameters
assert_equal([[:key, :str], [:key, :num]], p1.parameters);
assert_equal([[:opt, :x], [:key, :str], [:key, :num]], p2.parameters);
assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], p3.parameters);
assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], p4.parameters);
assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], p5.parameters);
assert_equal([[:opt, :o1], [:opt, :o2], [:rest, :args], [:opt, :p], [:key, :k],
[:keyrest, :kw], [:block, :b]], p6.parameters)
end
def m1(*args, **options)
yield(*args, **options)
end
def test_block
blk = Proc.new {|str: "foo", num: 424242| [str, num] }
assert_equal(["foo", 424242], m1(&blk))
assert_equal(["bar", 424242], m1(str: "bar", &blk))
assert_equal(["foo", 111111], m1(num: 111111, &blk))
assert_equal(["bar", 111111], m1(str: "bar", num: 111111, &blk))
end
def rest_keyrest(*args, **opt)
return *args, opt
end
def test_rest_keyrest
bug7665 = '[ruby-core:51278]'
bug8463 = '[ruby-core:55203] [Bug #8463]'
expect = [*%w[foo bar], {zzz: 42}]
assert_warn(/The last argument is used as the keyword parameter.* for `rest_keyrest'/m) do
assert_equal(expect, rest_keyrest(*expect), bug7665)
end
pr = proc {|*args, **opt| next *args, opt}
assert_warn(/The last argument is used as the keyword parameter.* for `call'/m) do
assert_equal(expect, pr.call(*expect), bug7665)
end
assert_warn(/The last argument is used as the keyword parameter.* for `call'/m) do
assert_equal(expect, pr.call(expect), bug8463)
end
pr = proc {|a, *b, **opt| next a, *b, opt}
assert_warn(/The last argument is used as the keyword parameter.* for `call'/m) do
assert_equal(expect, pr.call(expect), bug8463)
end
pr = proc {|a, **opt| next a, opt}
assert_warn(/The last argument is used as the keyword parameter.* for `call'/m) do
assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463)
end
end
def req_plus_keyword(x, **h)
[x, h]
end
def opt_plus_keyword(x=1, **h)
[x, h]
end
def splat_plus_keyword(*a, **h)
[a, h]
end
def test_keyword_split
assert_warn(/The keyword argument is passed as the last hash parameter.* for `req_plus_keyword'/m) do
assert_equal([{:a=>1}, {}], req_plus_keyword(:a=>1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `req_plus_keyword'/m) do
assert_equal([{"a"=>1}, {}], req_plus_keyword("a"=>1))
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `req_plus_keyword'/m) do
assert_equal([{"a"=>1, :a=>1}, {}], req_plus_keyword("a"=>1, :a=>1))
end
assert_equal([{:a=>1}, {}], req_plus_keyword({:a=>1}))
assert_equal([{"a"=>1}, {}], req_plus_keyword({"a"=>1}))
assert_equal([{"a"=>1, :a=>1}, {}], req_plus_keyword({"a"=>1, :a=>1}))
assert_equal([1, {:a=>1}], opt_plus_keyword(:a=>1))
assert_equal([1, {"a"=>1}], opt_plus_keyword("a"=>1))
assert_equal([1, {"a"=>1, :a=>1}], opt_plus_keyword("a"=>1, :a=>1))
assert_warn(/The last argument is used as the keyword parameter.* for `opt_plus_keyword'/m) do
assert_equal([1, {:a=>1}], opt_plus_keyword({:a=>1}))
end
assert_equal([{"a"=>1}, {}], opt_plus_keyword({"a"=>1}))
assert_warn(/The last argument is split into positional and keyword parameters.* for `opt_plus_keyword'/m) do
assert_equal([{"a"=>1}, {:a=>1}], opt_plus_keyword({"a"=>1, :a=>1}))
end
assert_equal([[], {:a=>1}], splat_plus_keyword(:a=>1))
assert_equal([[], {"a"=>1}], splat_plus_keyword("a"=>1))
assert_equal([[], {"a"=>1, :a=>1}], splat_plus_keyword("a"=>1, :a=>1))
assert_warn(/The last argument is used as the keyword parameter.* for `splat_plus_keyword'/m) do
assert_equal([[], {:a=>1}], splat_plus_keyword({:a=>1}))
end
assert_equal([[{"a"=>1}], {}], splat_plus_keyword({"a"=>1}))
assert_warn(/The last argument is split into positional and keyword parameters.* for `splat_plus_keyword'/m) do
assert_equal([[{"a"=>1}], {:a=>1}], splat_plus_keyword({"a"=>1, :a=>1}))
end
end
def test_bare_kwrest
# valid syntax, but its semantics is undefined
assert_valid_syntax("def bug7662(**) end")
assert_valid_syntax("def bug7662(*, **) end")
assert_valid_syntax("def bug7662(a, **) end")
end
def test_without_paren
bug7942 = '[ruby-core:52820] [Bug #7942]'
assert_valid_syntax("def bug7942 a: 1; end")
assert_valid_syntax("def bug7942 a: 1, **; end")
o = Object.new
eval("def o.bug7942 a: 1; a; end", nil, __FILE__, __LINE__)
assert_equal(1, o.bug7942(), bug7942)
assert_equal(42, o.bug7942(a: 42), bug7942)
o = Object.new
eval("def o.bug7942 a: 1, **; a; end", nil, __FILE__, __LINE__)
assert_equal(1, o.bug7942(), bug7942)
assert_equal(42, o.bug7942(a: 42), bug7942)
end
def test_required_keyword
feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
o = Object.new
assert_nothing_raised(SyntaxError, feature7701) do
eval("def o.foo(a:) a; end", nil, "xyzzy")
eval("def o.bar(a:,**b) [a, b]; end")
end
assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {o.foo}
assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {o.foo(a:0, b:1)}
begin
o.foo(a: 0, b: 1)
rescue => e
assert_equal('xyzzy', e.backtrace_locations[0].path)
end
assert_equal(42, o.foo(a: 42), feature7701)
assert_equal([[:keyreq, :a]], o.method(:foo).parameters, feature7701)
bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
assert_equal([42, {}], o.bar(a: 42), feature7701)
assert_equal([42, {c: feature7701}], o.bar(a: 42, c: feature7701), feature7701)
assert_equal([[:keyreq, :a], [:keyrest, :b]], o.method(:bar).parameters, feature7701)
assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar(c: bug8139)}
assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar}
end
def test_required_keyword_with_newline
bug9669 = '[ruby-core:61658] [Bug #9669]'
assert_nothing_raised(SyntaxError, bug9669) do
eval(<<-'end;', nil, __FILE__, __LINE__)
def bug9669.foo a:
return a
end
end;
end
assert_equal(42, bug9669.foo(a: 42))
o = nil
assert_nothing_raised(SyntaxError, bug9669) do
eval(<<-'end;', nil, __FILE__, __LINE__)
o = {
a:
1
}
end;
end
assert_equal({a: 1}, o, bug9669)
end
def test_required_keyword_with_reserved
bug10279 = '[ruby-core:65211] [Bug #10279]'
h = nil
assert_nothing_raised(SyntaxError, bug10279) do
break eval(<<-'end;', nil, __FILE__, __LINE__)
h = {a: if true then 42 end}
end;
end
assert_equal({a: 42}, h, bug10279)
end
def test_block_required_keyword
feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
b = assert_nothing_raised(SyntaxError, feature7701) do
break eval("proc {|a:| a}", nil, 'xyzzy', __LINE__)
end
assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {b.call}
e = assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {b.call(a:0, b:1)}
assert_equal('xyzzy', e.backtrace_locations[0].path)
assert_equal(42, b.call(a: 42), feature7701)
assert_equal([[:keyreq, :a]], b.parameters, feature7701)
bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
b = assert_nothing_raised(SyntaxError, feature7701) do
break eval("proc {|a:, **bl| [a, bl]}", nil, __FILE__, __LINE__)
end
assert_equal([42, {}], b.call(a: 42), feature7701)
assert_equal([42, {c: feature7701}], b.call(a: 42, c: feature7701), feature7701)
assert_equal([[:keyreq, :a], [:keyrest, :bl]], b.parameters, feature7701)
assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call(c: bug8139)}
assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call}
b = assert_nothing_raised(SyntaxError, feature7701) do
break eval("proc {|m, a:| [m, a]}", nil, 'xyzzy', __LINE__)
end
assert_raise_with_message(ArgumentError, /missing keyword/) {b.call}
assert_equal([:ok, 42], b.call(:ok, a: 42))
e = assert_raise_with_message(ArgumentError, /unknown keyword/) {b.call(42, a:0, b:1)}
assert_equal('xyzzy', e.backtrace_locations[0].path)
assert_equal([[:opt, :m], [:keyreq, :a]], b.parameters)
end
def test_super_with_keyword
bug8236 = '[ruby-core:54094] [Bug #8236]'
base = Class.new do
def foo(*args)
args
end
end
a = Class.new(base) do
def foo(arg, bar: 'x')
super
end
end
b = Class.new(base) do
def foo(*args, bar: 'x')
super
end
end
assert_equal([42, {:bar=>"x"}], a.new.foo(42), bug8236)
assert_equal([42, {:bar=>"x"}], b.new.foo(42), bug8236)
end
def test_zsuper_only_named_kwrest
bug8416 = '[ruby-core:55033] [Bug #8416]'
base = Class.new do
def foo(**h)
h
end
end
a = Class.new(base) do
def foo(**h)
super
end
end
assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
end
def test_zsuper_only_anonymous_kwrest
bug8416 = '[ruby-core:55033] [Bug #8416]'
base = Class.new do
def foo(**h)
h
end
end
a = Class.new(base) do
def foo(**)
super
end
end
assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
end
def test_precedence_of_keyword_arguments
bug8040 = '[ruby-core:53199] [Bug #8040]'
a = Class.new do
def foo(x, **h)
[x, h]
end
end
assert_equal([{}, {}], a.new.foo({}))
assert_equal([{}, {:bar=>"x"}], a.new.foo({}, bar: "x"), bug8040)
end
def test_precedence_of_keyword_arguments_with_post_argument
bug8993 = '[ruby-core:57706] [Bug #8993]'
a = Class.new do
def foo(a, b, c=1, *d, e, f:2, **g)
[a, b, c, d, e, f, g]
end
end
assert_warn(/The keyword argument is passed as the last hash parameter.* for `foo'/m) do
assert_equal([1, 2, 1, [], {:f=>5}, 2, {}], a.new.foo(1, 2, f:5), bug8993)
end
end
def test_splat_keyword_nondestructive
bug9776 = '[ruby-core:62161] [Bug #9776]'
h = {a: 1}
assert_equal({a:1, b:2}, {**h, b:2})
assert_equal({a:1}, h, bug9776)
pr = proc {|**opt| next opt}
assert_equal({a: 1}, pr.call(**h))
assert_equal({a: 1, b: 2}, pr.call(**h, b: 2))
assert_equal({a: 1}, h, bug9776)
end
def test_splat_hash_conversion
bug9898 = '[ruby-core:62921] [Bug #9898]'
o = Object.new
def o.to_hash() { a: 1 } end
assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898)
o2 = Object.new
def o2.to_hash() { b: 2 } end
assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898)
end
def test_implicit_hash_conversion
bug10016 = '[ruby-core:63593] [Bug #10016]'
o = Object.new
def o.to_hash() { k: 9 } end
assert_equal([1, 42, [], o, :key, {}, nil], f9(1, o))
assert_warn(/The last argument is used as the keyword parameter.* for `m1'/m) do
assert_equal([1, 9], m1(1, o) {|a, k: 0| break [a, k]}, bug10016)
end
assert_warn(/The last argument is used as the keyword parameter.* for `m1'/m) do
assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016)
end
end
def test_splat_hash
m = Object.new
def m.f() :ok; end
def m.f1(a) a; end
def m.f2(a = nil) a; end
def m.f3(**a) a; end
def m.f4(*a) a; end
o = {a: 1}
assert_raise_with_message(ArgumentError, /unknown keyword: :a/) {
m.f(**o)
}
o = {}
assert_equal(:ok, m.f(**o), '[ruby-core:68124] [Bug #10856]')
a = []
assert_equal(:ok, m.f(*a, **o), '[ruby-core:83638] [Bug #10856]')
assert_equal(:OK, m.f1(*a, :OK, **o), '[ruby-core:91825] [Bug #10856]')
assert_equal({}, m.f1(*a, o), '[ruby-core:91825] [Bug #10856]')
o = {a: 42}
assert_warning('', 'splat to mandatory') do
assert_equal({a: 42}, m.f1(**o))
end
assert_warning('') do
assert_equal({a: 42}, m.f2(**o), '[ruby-core:82280] [Bug #13791]')
end
assert_warning('', 'splat to kwrest') do
assert_equal({a: 42}, m.f3(**o))
end
assert_warning('', 'splat to rest') do
assert_equal([{a: 42}], m.f4(**o))
end
assert_warning('') do
assert_equal({a: 42}, m.f2("a".to_sym => 42), '[ruby-core:82291] [Bug #13793]')
end
o = {}
a = [:ok]
assert_equal(:ok, m.f2(*a, **o), '[ruby-core:83638] [Bug #10856]')
end
def test_gced_object_in_stack
bug8964 = '[ruby-dev:47729] [Bug #8964]'
assert_normal_exit %q{
def m(a: [])
end
GC.stress = true
tap { m }
GC.start
tap { m }
}, bug8964
assert_normal_exit %q{
prc = Proc.new {|a: []|}
GC.stress = true
tap { prc.call }
GC.start
tap { prc.call }
}, bug8964
end
def test_dynamic_symbol_keyword
bug10266 = '[ruby-dev:48564] [Bug #10266]'
assert_separately(['-', bug10266], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
bug = ARGV.shift
"hoge".to_sym
assert_nothing_raised(bug) {eval("def a(hoge:); end")}
end;
end
def test_unknown_keyword_with_block
bug10413 = '[ruby-core:65837] [Bug #10413]'
class << (o = Object.new)
def bar(k2: 'v2')
end
def foo
bar(k1: 1)
end
end
assert_raise_with_message(ArgumentError, /unknown keyword: :k1/, bug10413) {
o.foo {raise "unreachable"}
}
end
def test_unknown_keyword
bug13004 = '[ruby-dev:49893] [Bug #13004]'
assert_raise_with_message(ArgumentError, /unknown keyword: :"invalid-argument"/, bug13004) {
[].sample(random: nil, "invalid-argument": nil)
}
end
def test_super_with_anon_restkeywords
bug10659 = '[ruby-core:67157] [Bug #10659]'
foo = Class.new do
def foo(**h)
h
end
end
class << (obj = foo.new)
def foo(bar: "bar", **)
super
end
end
assert_nothing_raised(TypeError, bug10659) {
assert_equal({:bar => "bar"}, obj.foo, bug10659)
}
end
def m(a) yield a end
def test_nonsymbol_key
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
assert_equal([{"a" => 10}, {}], result)
end
def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw
[k1, k2, rest_kw]
end
def test_to_hash_call_during_setup_complex_parameters
sym = "sym_#{Time.now}".to_sym
h = method_for_test_to_hash_call_during_setup_complex_parameters k1: "foo", k2: "bar", sym => "baz"
assert_equal ["foo", "bar", {sym => "baz"}], h, '[Bug #11027]'
end
class AttrSetTest
attr_accessor :foo
alias set_foo :foo=
end
def test_attr_set_method_cache
obj = AttrSetTest.new
h = {a: 1, b: 2}
2.times{
obj.foo = 1
assert_equal(1, obj.foo)
obj.set_foo 2
assert_equal(2, obj.foo)
obj.set_foo(x: 1, y: 2)
assert_equal({x: 1, y: 2}, obj.foo)
obj.set_foo(x: 1, y: 2, **h)
assert_equal({x: 1, y: 2, **h}, obj.foo)
}
end
def test_kwrest_overwritten
bug13015 = '[ruby-core:78536] [Bug #13015]'
klass = EnvUtil.labeled_class("Parent") do
def initialize(d:)
end
end
klass = EnvUtil.labeled_class("Child", klass) do
def initialize(d:, **h)
h = [2, 3]
super
end
end
assert_raise_with_message(TypeError, /expected Hash/, bug13015) do
klass.new(d: 4)
end
end
def test_non_keyword_hash_subclass
bug12884 = '[ruby-core:77813] [Bug #12884]'
klass = EnvUtil.labeled_class("Child", Hash)
obj = Object.new
def obj.t(params = klass.new, d: nil); params; end
x = klass.new
x["foo"] = "bar"
result = obj.t(x)
assert_equal(x, result)
assert_kind_of(klass, result, bug12884)
end
def test_arity_error_message
obj = Object.new
def obj.t(x:) end
assert_raise_with_message(ArgumentError, /required keyword: x\)/) do
obj.t(42)
end
obj = Object.new
def obj.t(x:, y:, z: nil) end
assert_raise_with_message(ArgumentError, /required keywords: x, y\)/) do
obj.t(42)
end
end
def many_kwargs(a0: '', a1: '', a2: '', a3: '', a4: '', a5: '', a6: '', a7: '',
b0: '', b1: '', b2: '', b3: '', b4: '', b5: '', b6: '', b7: '',
c0: '', c1: '', c2: '', c3: '', c4: '', c5: '', c6: '', c7: '',
d0: '', d1: '', d2: '', d3: '', d4: '', d5: '', d6: '', d7: '',
e0: '')
[a0, a1, a2, a3, a4, a5, a6, a7,
b0, b1, b2, b3, b4, b5, b6, b7,
c0, c1, c2, c3, c4, c5, c6, c7,
d0, d1, d2, d3, d4, d5, d6, d7,
e0]
end
def test_many_kwargs
i = 0
assert_equal(:ok, many_kwargs(a0: :ok)[i], "#{i}: a0"); i+=1
assert_equal(:ok, many_kwargs(a1: :ok)[i], "#{i}: a1"); i+=1
assert_equal(:ok, many_kwargs(a2: :ok)[i], "#{i}: a2"); i+=1
assert_equal(:ok, many_kwargs(a3: :ok)[i], "#{i}: a3"); i+=1
assert_equal(:ok, many_kwargs(a4: :ok)[i], "#{i}: a4"); i+=1
assert_equal(:ok, many_kwargs(a5: :ok)[i], "#{i}: a5"); i+=1
assert_equal(:ok, many_kwargs(a6: :ok)[i], "#{i}: a6"); i+=1
assert_equal(:ok, many_kwargs(a7: :ok)[i], "#{i}: a7"); i+=1
assert_equal(:ok, many_kwargs(b0: :ok)[i], "#{i}: b0"); i+=1
assert_equal(:ok, many_kwargs(b1: :ok)[i], "#{i}: b1"); i+=1
assert_equal(:ok, many_kwargs(b2: :ok)[i], "#{i}: b2"); i+=1
assert_equal(:ok, many_kwargs(b3: :ok)[i], "#{i}: b3"); i+=1
assert_equal(:ok, many_kwargs(b4: :ok)[i], "#{i}: b4"); i+=1
assert_equal(:ok, many_kwargs(b5: :ok)[i], "#{i}: b5"); i+=1
assert_equal(:ok, many_kwargs(b6: :ok)[i], "#{i}: b6"); i+=1
assert_equal(:ok, many_kwargs(b7: :ok)[i], "#{i}: b7"); i+=1
assert_equal(:ok, many_kwargs(c0: :ok)[i], "#{i}: c0"); i+=1
assert_equal(:ok, many_kwargs(c1: :ok)[i], "#{i}: c1"); i+=1
assert_equal(:ok, many_kwargs(c2: :ok)[i], "#{i}: c2"); i+=1
assert_equal(:ok, many_kwargs(c3: :ok)[i], "#{i}: c3"); i+=1
assert_equal(:ok, many_kwargs(c4: :ok)[i], "#{i}: c4"); i+=1
assert_equal(:ok, many_kwargs(c5: :ok)[i], "#{i}: c5"); i+=1
assert_equal(:ok, many_kwargs(c6: :ok)[i], "#{i}: c6"); i+=1
assert_equal(:ok, many_kwargs(c7: :ok)[i], "#{i}: c7"); i+=1
assert_equal(:ok, many_kwargs(d0: :ok)[i], "#{i}: d0"); i+=1
assert_equal(:ok, many_kwargs(d1: :ok)[i], "#{i}: d1"); i+=1
assert_equal(:ok, many_kwargs(d2: :ok)[i], "#{i}: d2"); i+=1
assert_equal(:ok, many_kwargs(d3: :ok)[i], "#{i}: d3"); i+=1
assert_equal(:ok, many_kwargs(d4: :ok)[i], "#{i}: d4"); i+=1
assert_equal(:ok, many_kwargs(d5: :ok)[i], "#{i}: d5"); i+=1
assert_equal(:ok, many_kwargs(d6: :ok)[i], "#{i}: d6"); i+=1
assert_equal(:ok, many_kwargs(d7: :ok)[i], "#{i}: d7"); i+=1
assert_equal(:ok, many_kwargs(e0: :ok)[i], "#{i}: e0"); i+=1
end
def test_splat_empty_hash_with_block_passing
assert_valid_syntax("bug15087(**{}, &nil)")
end
end