mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Do not autosplat when calling procs that accept rest and keywords
When providing a single array to a block that takes a splat, pass the array as one argument of the splat instead of as the splat itself, even if the block also accepts keyword arguments. Previously, this behavior was only used for blocks that did not accept keywords. Implements [Feature#16166]
This commit is contained in:
parent
040cfc89b9
commit
f4394bbca3
Notes:
git
2020-03-09 12:49:36 +09:00
4 changed files with 61 additions and 20 deletions
|
@ -76,18 +76,18 @@ describe "A block yielded a single" do
|
|||
result.should == [1, 2, [3], {x: 9}, 2, {}]
|
||||
end
|
||||
|
||||
it "does not treat final Hash as keyword arguments" do
|
||||
it "does not treat final Hash as keyword arguments and does not autosplat" do
|
||||
result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
|
||||
result.should == [{"a" => 1, a: 10}, {}]
|
||||
result.should == [[{"a" => 1, a: 10}], {}]
|
||||
end
|
||||
|
||||
it "does not call #to_hash on final argument to get keyword arguments" do
|
||||
it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do
|
||||
suppress_keyword_warning do
|
||||
obj = mock("coerce block keyword arguments")
|
||||
obj.should_not_receive(:to_hash)
|
||||
|
||||
result = m([obj]) { |a=nil, **b| [a, b] }
|
||||
result.should == [obj, {}]
|
||||
result.should == [[obj], {}]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -113,12 +113,12 @@ describe "A block yielded a single" do
|
|||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
it "does not call #to_hash on the argument when optional argument and keyword argument accepted" do
|
||||
it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do
|
||||
obj = mock("coerce block keyword arguments")
|
||||
obj.should_not_receive(:to_hash)
|
||||
|
||||
result = m([obj]) { |a=nil, **b| [a, b] }
|
||||
result.should == [obj, {}]
|
||||
result.should == [[obj], {}]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -132,18 +132,27 @@ describe "A block yielded a single" do
|
|||
end
|
||||
end
|
||||
ruby_version_is "2.8" do
|
||||
it "does not separates non-symbol keys and symbol keys" do
|
||||
it "does not separate non-symbol keys and symbol keys and does not autosplat" do
|
||||
suppress_keyword_warning do
|
||||
result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
|
||||
result.should == [{"a" => 10, b: 2}, {}]
|
||||
result.should == [[{"a" => 10, b: 2}], {}]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "does not treat hashes with string keys as keyword arguments" do
|
||||
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
|
||||
result.should == [{"a" => 10}, {}]
|
||||
ruby_version_is ""..."2.8" do
|
||||
it "does not treat hashes with string keys as keyword arguments" do
|
||||
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
|
||||
result.should == [{"a" => 10}, {}]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
it "does not treat hashes with string keys as keyword arguments and does not autosplat" do
|
||||
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
|
||||
result.should == [[{"a" => 10}], {}]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ''...'2.8' do
|
||||
|
|
|
@ -3284,15 +3284,20 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||
bug7665 = '[ruby-core:51278]'
|
||||
bug8463 = '[ruby-core:55203] [Bug #8463]'
|
||||
a = [*%w[foo bar], {zzz: 42}]
|
||||
expect = a + [{}]
|
||||
assert_equal(expect, rest_keyrest(*a), bug7665)
|
||||
splat_expect = a + [{}]
|
||||
nonsplat_expect = [a, {}]
|
||||
assert_equal(splat_expect, rest_keyrest(*a), bug7665)
|
||||
assert_equal(nonsplat_expect, rest_keyrest(a), bug7665)
|
||||
|
||||
pr = proc {|*args, **opt| next *args, opt}
|
||||
assert_equal(expect, pr.call(*a), bug7665)
|
||||
assert_equal(expect, pr.call(a), bug8463)
|
||||
assert_equal(splat_expect, pr.call(*a), bug7665)
|
||||
assert_equal(nonsplat_expect, pr.call(a), bug8463)
|
||||
|
||||
pr = proc {|a, *b, **opt| next a, *b, opt}
|
||||
assert_equal(expect, pr.call(a), bug8463)
|
||||
assert_equal(splat_expect, pr.call(a), bug8463)
|
||||
|
||||
pr = proc {|a, **opt| next a, opt}
|
||||
assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463)
|
||||
assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463)
|
||||
end
|
||||
|
||||
def req_plus_keyword(x, **h)
|
||||
|
@ -3662,7 +3667,7 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||
|
||||
def test_nonsymbol_key
|
||||
result = m(["a" => 10]) { |a = nil, **b| [a, b] }
|
||||
assert_equal([{"a" => 10}, {}], result)
|
||||
assert_equal([[{"a" => 10}], {}], result)
|
||||
end
|
||||
|
||||
def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw
|
||||
|
|
|
@ -784,6 +784,33 @@ class TestProc < Test::Unit::TestCase
|
|||
assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x})
|
||||
end
|
||||
|
||||
def test_proc_args_only_rest
|
||||
pr = proc {|*c| c }
|
||||
assert_equal [], pr.call()
|
||||
assert_equal [1], pr.call(1)
|
||||
assert_equal [[1]], pr.call([1])
|
||||
assert_equal [1, 2], pr.call(1,2)
|
||||
assert_equal [[1, 2]], pr.call([1,2])
|
||||
end
|
||||
|
||||
def test_proc_args_rest_kw
|
||||
pr = proc {|*c, a: 1| [c, a] }
|
||||
assert_equal [[], 1], pr.call()
|
||||
assert_equal [[1], 1], pr.call(1)
|
||||
assert_equal [[[1]], 1], pr.call([1])
|
||||
assert_equal [[1, 2], 1], pr.call(1,2)
|
||||
assert_equal [[[1, 2]], 1], pr.call([1,2])
|
||||
end
|
||||
|
||||
def test_proc_args_rest_kwsplat
|
||||
pr = proc {|*c, **kw| [c, kw] }
|
||||
assert_equal [[], {}], pr.call()
|
||||
assert_equal [[1], {}], pr.call(1)
|
||||
assert_equal [[[1]], {}], pr.call([1])
|
||||
assert_equal [[1, 2], {}], pr.call(1,2)
|
||||
assert_equal [[[1, 2]], {}], pr.call([1,2])
|
||||
end
|
||||
|
||||
def test_proc_args_pos_rest_post_block
|
||||
pr = proc {|a,b,*c,d,e,&f|
|
||||
[a, b, c, d, e, f.class, f&&f.call(:x)]
|
||||
|
|
|
@ -568,14 +568,14 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
rb_raise(rb_eArgError, "no keywords accepted");
|
||||
}
|
||||
|
||||
|
||||
switch (arg_setup_type) {
|
||||
case arg_setup_method:
|
||||
break; /* do nothing special */
|
||||
case arg_setup_block:
|
||||
if (given_argc == (keyword_hash == Qnil ? 1 : 2) &&
|
||||
allow_autosplat &&
|
||||
(min_argc > 0 || iseq->body->param.opt_num > 1 ||
|
||||
iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) &&
|
||||
(min_argc > 0 || iseq->body->param.opt_num > 1) &&
|
||||
!iseq->body->param.flags.ambiguous_param0 &&
|
||||
args_check_block_arg0(args)) {
|
||||
given_argc = RARRAY_LENINT(args->rest);
|
||||
|
|
Loading…
Add table
Reference in a new issue