1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Make Symbol#to_proc calls handle keyword arguments

Make rb_sym_proc_call take a flag for whether a keyword argument
is used, and use the new rb_funcall_with_block_kw function to
pass that information.
This commit is contained in:
Jeremy Evans 2019-09-03 14:54:37 -07:00
parent 38dae1d510
commit 6f9b86616a
4 changed files with 77 additions and 5 deletions

View file

@ -2140,7 +2140,7 @@ VALUE rb_str_initialize(VALUE str, const char *ptr, long len, rb_encoding *enc);
#define is_ascii_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)
#define is_broken_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN)
size_t rb_str_memsize(VALUE);
VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, VALUE passed_proc);
VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc);
VALUE rb_sym_to_proc(VALUE sym);
char *rb_str_to_cstr(VALUE str);
VALUE rb_str_eql(VALUE str1, VALUE str2);

View file

@ -10887,7 +10887,7 @@ sym_to_sym(VALUE sym)
}
MJIT_FUNC_EXPORTED VALUE
rb_sym_proc_call(ID mid, int argc, const VALUE *argv, VALUE passed_proc)
rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc)
{
VALUE obj;
@ -10895,7 +10895,7 @@ rb_sym_proc_call(ID mid, int argc, const VALUE *argv, VALUE passed_proc)
rb_raise(rb_eArgError, "no receiver given");
}
obj = argv[0];
return rb_funcall_with_block(obj, mid, argc - 1, argv + 1, passed_proc);
return rb_funcall_with_block_kw(obj, mid, argc - 1, argv + 1, passed_proc, kw_splat);
}
#if 0

View file

@ -447,6 +447,79 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal([1, h3], c.send(:m, **h3))
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([h2], :m.to_proc.call(c, **h2))
assert_equal([h3], :m.to_proc.call(c, **h3))
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, **h2) }
assert_raise(ArgumentError) { :m.to_proc.call(c, **h3) }
c.singleton_class.remove_method(:m)
def c.m(args)
args
end
assert_raise(ArgumentError) { :m.to_proc.call(c, **{}) }
assert_raise(ArgumentError) { :m.to_proc.call(c, **kw) }
assert_equal(h, :m.to_proc.call(c, **h))
assert_equal(h2, :m.to_proc.call(c, **h2))
assert_equal(h3, :m.to_proc.call(c, **h3))
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(h2, :m.to_proc.call(c, **h2))
assert_equal(h3, :m.to_proc.call(c, **h3))
c.singleton_class.remove_method(:m)
def c.m(arg, **args)
[arg, args]
end
assert_raise(ArgumentError) { :m.to_proc.call(c, **{}) }
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([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
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, h2], :m.to_proc.call(c, **h2))
assert_equal([1, h3], :m.to_proc.call(c, **h3))
end
def test_method_missing_kwsplat
kw = {}
h = {'a'=>1}

View file

@ -2884,8 +2884,7 @@ vm_yield_with_cfunc(rb_execution_context_t *ec,
static VALUE
vm_yield_with_symbol(rb_execution_context_t *ec, VALUE symbol, int argc, const VALUE *argv, int kw_splat, VALUE block_handler)
{
/* XXX: need to pass kw_splat? */
return rb_sym_proc_call(SYM2ID(symbol), argc, argv, rb_vm_bh_to_procval(ec, block_handler));
return rb_sym_proc_call(SYM2ID(symbol), argc, argv, kw_splat, rb_vm_bh_to_procval(ec, block_handler));
}
static inline int