зеркало из https://github.com/github/ruby.git
Fix more keyword separation issues
This fixes instance_exec and similar methods. It also fixes Enumerator::Yielder#yield, rb_yield_block, and a couple of cases with Proc#{<<,>>}. This support requires the addition of rb_yield_values_kw, similar to rb_yield_values2, for passing the keyword flag. Unlike earlier attempts at this, this does not modify the rb_block_call_func type or add a separate function type. The functions of type rb_block_call_func are called by Ruby with a separate VM frame, and we can get the keyword flag information from the VM frame flags, so it doesn't need to be passed as a function argument. These changes require the following VM functions accept a keyword flag: * vm_yield_with_cref * vm_yield * vm_yield_with_block
This commit is contained in:
Родитель
0c6f36668a
Коммит
660c7e050f
|
@ -1320,7 +1320,7 @@ yielder_yield(VALUE obj, VALUE args)
|
||||||
{
|
{
|
||||||
struct yielder *ptr = yielder_ptr(obj);
|
struct yielder *ptr = yielder_ptr(obj);
|
||||||
|
|
||||||
return rb_proc_call(ptr->proc, args);
|
return rb_proc_call_kw(ptr->proc, args, RB_PASS_CALLED_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :nodoc: */
|
/* :nodoc: */
|
||||||
|
@ -1357,7 +1357,7 @@ yielder_to_proc(VALUE obj)
|
||||||
static VALUE
|
static VALUE
|
||||||
yielder_yield_i(RB_BLOCK_CALL_FUNC_ARGLIST(obj, memo))
|
yielder_yield_i(RB_BLOCK_CALL_FUNC_ARGLIST(obj, memo))
|
||||||
{
|
{
|
||||||
return rb_yield_values2(argc, argv);
|
return rb_yield_values_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
|
|
@ -4,7 +4,7 @@ static VALUE
|
||||||
yield_block(int argc, VALUE *argv, VALUE self)
|
yield_block(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
||||||
return rb_block_call(self, rb_to_id(argv[0]), argc-1, argv+1, rb_yield_block, 0);
|
return rb_block_call_kw(self, rb_to_id(argv[0]), argc-1, argv+1, rb_yield_block, 0, RB_PASS_CALLED_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
2
hash.c
2
hash.c
|
@ -4471,7 +4471,7 @@ rb_hash_gt(VALUE hash, VALUE other)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
hash_proc_call(VALUE key, VALUE hash, int argc, const VALUE *argv, VALUE passed_proc)
|
hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash))
|
||||||
{
|
{
|
||||||
rb_check_arity(argc, 1, 1);
|
rb_check_arity(argc, 1, 1);
|
||||||
return rb_hash_aref(hash, *argv);
|
return rb_hash_aref(hash, *argv);
|
||||||
|
|
|
@ -1970,8 +1970,9 @@ VALUE rb_each(VALUE);
|
||||||
VALUE rb_yield(VALUE);
|
VALUE rb_yield(VALUE);
|
||||||
VALUE rb_yield_values(int n, ...);
|
VALUE rb_yield_values(int n, ...);
|
||||||
VALUE rb_yield_values2(int n, const VALUE *argv);
|
VALUE rb_yield_values2(int n, const VALUE *argv);
|
||||||
|
VALUE rb_yield_values_kw(int n, const VALUE *argv, int kw_splat);
|
||||||
VALUE rb_yield_splat(VALUE);
|
VALUE rb_yield_splat(VALUE);
|
||||||
VALUE rb_yield_block(VALUE, VALUE, int, const VALUE *, VALUE); /* rb_block_call_func */
|
VALUE rb_yield_block(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)); /* rb_block_call_func */
|
||||||
#define RB_NO_KEYWORDS 0
|
#define RB_NO_KEYWORDS 0
|
||||||
#define RB_PASS_KEYWORDS 1
|
#define RB_PASS_KEYWORDS 1
|
||||||
#define RB_PASS_EMPTY_KEYWORDS 2
|
#define RB_PASS_EMPTY_KEYWORDS 2
|
||||||
|
|
2
proc.c
2
proc.c
|
@ -2895,7 +2895,7 @@ mlambda(VALUE method)
|
||||||
static VALUE
|
static VALUE
|
||||||
bmcall(RB_BLOCK_CALL_FUNC_ARGLIST(args, method))
|
bmcall(RB_BLOCK_CALL_FUNC_ARGLIST(args, method))
|
||||||
{
|
{
|
||||||
return rb_method_call_with_block(argc, argv, method, blockarg);
|
return rb_method_call_with_block_kw(argc, argv, method, blockarg, RB_PASS_CALLED_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
require '-test-/rb_call_super_kw'
|
require '-test-/rb_call_super_kw'
|
||||||
|
require '-test-/iter'
|
||||||
|
|
||||||
class TestKeywordArguments < Test::Unit::TestCase
|
class TestKeywordArguments < Test::Unit::TestCase
|
||||||
def f1(str: "foo", num: 424242)
|
def f1(str: "foo", num: 424242)
|
||||||
|
@ -918,6 +919,83 @@ class TestKeywordArguments < Test::Unit::TestCase
|
||||||
assert_equal([1, h3], g.new(&f).each(a: 1, **h2))
|
assert_equal([1, h3], g.new(&f).each(a: 1, **h2))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_Enumerator_Yielder_yield_kwsplat
|
||||||
|
kw = {}
|
||||||
|
h = {:a=>1}
|
||||||
|
h2 = {'a'=>1}
|
||||||
|
h3 = {'a'=>1, :a=>1}
|
||||||
|
|
||||||
|
g = Enumerator::Generator
|
||||||
|
f = -> { true }
|
||||||
|
assert_equal(true, g.new{|y| y.yield(**{})}.each(&f))
|
||||||
|
assert_equal(true, g.new{|y| y.yield(**kw)}.each(&f))
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(**h)}.each(&f) }
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(a: 1)}.each(&f) }
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(**h2)}.each(&f) }
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(**h3)}.each(&f) }
|
||||||
|
|
||||||
|
f = ->(a) { a }
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
|
||||||
|
assert_equal(kw, g.new{|y| y.yield(**{})}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
|
||||||
|
assert_equal(kw, g.new{|y| y.yield(**kw)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_equal(h, g.new{|y| y.yield(**h)}.each(&f))
|
||||||
|
assert_equal(h, g.new{|y| y.yield(a: 1)}.each(&f))
|
||||||
|
assert_equal(h2, g.new{|y| y.yield(**h2)}.each(&f))
|
||||||
|
assert_equal(h3, g.new{|y| y.yield(**h3)}.each(&f))
|
||||||
|
assert_equal(h3, g.new{|y| y.yield(a: 1, **h2)}.each(&f))
|
||||||
|
|
||||||
|
f = ->(**x) { x }
|
||||||
|
assert_equal(kw, g.new{|y| y.yield(**{})}.each(&f))
|
||||||
|
assert_equal(kw, g.new{|y| y.yield(**kw)}.each(&f))
|
||||||
|
assert_equal(h, g.new{|y| y.yield(**h)}.each(&f))
|
||||||
|
assert_equal(h, g.new{|y| y.yield(a: 1)}.each(&f))
|
||||||
|
assert_equal(h2, g.new{|y| y.yield(**h2)}.each(&f))
|
||||||
|
assert_equal(h3, g.new{|y| y.yield(**h3)}.each(&f))
|
||||||
|
assert_equal(h3, g.new{|y| y.yield(a: 1, **h2)}.each(&f))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
||||||
|
assert_equal(h, g.new{|y| y.yield(h)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(h2)}.each(&f) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters.*for method/m) do
|
||||||
|
assert_raise(ArgumentError) { g.new{|y| y.yield(h3)}.each(&f) }
|
||||||
|
end
|
||||||
|
|
||||||
|
f = ->(a, **x) { [a,x] }
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([{}, {}], g.new{|y| y.yield(**{})}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([{}, {}], g.new{|y| y.yield(**kw)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, {}], g.new{|y| y.yield(**h)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, {}], g.new{|y| y.yield(a: 1)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h2, {}], g.new{|y| y.yield(**h2)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, {}], g.new{|y| y.yield(**h3)}.each(&f))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, {}], g.new{|y| y.yield(a: 1, **h2)}.each(&f))
|
||||||
|
end
|
||||||
|
|
||||||
|
f = ->(a=1, **x) { [a, x] }
|
||||||
|
assert_equal([1, kw], g.new{|y| y.yield(**{})}.each(&f))
|
||||||
|
assert_equal([1, kw], g.new{|y| y.yield(**kw)}.each(&f))
|
||||||
|
assert_equal([1, h], g.new{|y| y.yield(**h)}.each(&f))
|
||||||
|
assert_equal([1, h], g.new{|y| y.yield(a: 1)}.each(&f))
|
||||||
|
assert_equal([1, h2], g.new{|y| y.yield(**h2)}.each(&f))
|
||||||
|
assert_equal([1, h3], g.new{|y| y.yield(**h3)}.each(&f))
|
||||||
|
assert_equal([1, h3], g.new{|y| y.yield(a: 1, **h2)}.each(&f))
|
||||||
|
end
|
||||||
|
|
||||||
def test_Class_new_kwsplat_call
|
def test_Class_new_kwsplat_call
|
||||||
kw = {}
|
kw = {}
|
||||||
h = {:a=>1}
|
h = {:a=>1}
|
||||||
|
@ -3131,6 +3209,576 @@ class TestKeywordArguments < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_instance_exec_kwsplat
|
||||||
|
kw = {}
|
||||||
|
h = {:a=>1}
|
||||||
|
h2 = {'a'=>1}
|
||||||
|
h3 = {'a'=>1, :a=>1}
|
||||||
|
|
||||||
|
c = Object.new
|
||||||
|
m = ->(*args) { args }
|
||||||
|
assert_equal([], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
m = ->() { nil }
|
||||||
|
assert_nil(c.instance_exec(**{}, &m))
|
||||||
|
assert_nil(c.instance_exec(**kw, &m))
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h2, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h3, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, **h2, &m) }
|
||||||
|
|
||||||
|
m = ->(args) { args }
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.instance_exec(kw, **kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
m = ->(**args) { args }
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/) do
|
||||||
|
assert_equal(h, c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h2, &m) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h3, &m) }
|
||||||
|
end
|
||||||
|
|
||||||
|
m = ->(arg, **args) { [arg, args] }
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**{}, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**kw, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(**h, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(a: 1, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h2, kw], c.instance_exec(**h2, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(**h3, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h, kw], c.instance_exec(h, &m))
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_equal([h3, kw], c.instance_exec(h3, &m))
|
||||||
|
|
||||||
|
m = ->(arg=1, **args) { [arg, args] }
|
||||||
|
assert_equal([1, kw], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([1, kw], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([1, h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/m) do
|
||||||
|
assert_equal([1, h], c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/m) do
|
||||||
|
assert_equal([h2, h], c.instance_exec(h3, &m))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instance_exec_method_kwsplat
|
||||||
|
kw = {}
|
||||||
|
h = {:a=>1}
|
||||||
|
h2 = {'a'=>1}
|
||||||
|
h3 = {'a'=>1, :a=>1}
|
||||||
|
|
||||||
|
c = Object.new
|
||||||
|
def c.m(*args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal([], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_nil(c.instance_exec(**{}, &m))
|
||||||
|
assert_nil(c.instance_exec(**kw, &m))
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h2, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h3, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, **h2, &m) }
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.instance_exec(kw, **kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(**args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/) do
|
||||||
|
assert_equal(h, c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h2, &m) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h3, &m) }
|
||||||
|
end
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**{}, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**kw, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(**h, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(a: 1, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h2, kw], c.instance_exec(**h2, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(**h3, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h, kw], c.instance_exec(h, &m))
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_equal([h3, kw], c.instance_exec(h3, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(arg=1, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal([1, kw], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([1, kw], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([1, h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/m) do
|
||||||
|
assert_equal([1, h], c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_equal([h2, h], c.instance_exec(h3, &m))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instance_exec_define_method_kwsplat
|
||||||
|
kw = {}
|
||||||
|
h = {:a=>1}
|
||||||
|
h2 = {'a'=>1}
|
||||||
|
h3 = {'a'=>1, :a=>1}
|
||||||
|
|
||||||
|
c = Object.new
|
||||||
|
c.define_singleton_method(:m) do |*args|
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal([], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
c.define_singleton_method(:m) do
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_nil(c.instance_exec(**{}, &m))
|
||||||
|
assert_nil(c.instance_exec(**kw, &m))
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h2, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(**h3, &m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(a: 1, **h2, &m) }
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
c.define_singleton_method(:m) do |args|
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.instance_exec(kw, **kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
c.define_singleton_method(:m) do |**args|
|
||||||
|
args
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal(kw, c.instance_exec(**{}, &m))
|
||||||
|
assert_equal(kw, c.instance_exec(**kw, &m))
|
||||||
|
assert_equal(h, c.instance_exec(**h, &m))
|
||||||
|
assert_equal(h, c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal(h2, c.instance_exec(**h2, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(**h3, &m))
|
||||||
|
assert_equal(h3, c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/) do
|
||||||
|
assert_equal(h, c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h2, &m) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(h3, &m) }
|
||||||
|
end
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
c.define_singleton_method(:m) do |arg, **args|
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**{}, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(**kw, &m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(**h, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(a: 1, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h2, kw], c.instance_exec(**h2, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(**h3, &m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h, kw], c.instance_exec(h, &m))
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_equal([h3, kw], c.instance_exec(h3, &m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
c.define_singleton_method(:m) do |arg=1, **args|
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
m = c.method(:m)
|
||||||
|
assert_equal([1, kw], c.instance_exec(**{}, &m))
|
||||||
|
assert_equal([1, kw], c.instance_exec(**kw, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(**h, &m))
|
||||||
|
assert_equal([1, h], c.instance_exec(a: 1, &m))
|
||||||
|
assert_equal([1, h2], c.instance_exec(**h2, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(**h3, &m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/m) do
|
||||||
|
assert_equal([1, h], c.instance_exec(h, &m))
|
||||||
|
end
|
||||||
|
assert_equal([h2, kw], c.instance_exec(h2, &m))
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_equal([h2, h], c.instance_exec(h3, &m))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instance_exec_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([], c.instance_exec(c, **{}, &:m))
|
||||||
|
assert_equal([], c.instance_exec(c, **kw, &:m))
|
||||||
|
assert_equal([h], c.instance_exec(c, **h, &:m))
|
||||||
|
assert_equal([h], c.instance_exec(c, a: 1, &:m))
|
||||||
|
assert_equal([h2], c.instance_exec(c, **h2, &:m))
|
||||||
|
assert_equal([h3], c.instance_exec(c, **h3, &:m))
|
||||||
|
assert_equal([h3], c.instance_exec(c, a: 1, **h2, &:m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m
|
||||||
|
end
|
||||||
|
assert_nil(c.instance_exec(c, **{}, &:m))
|
||||||
|
assert_nil(c.instance_exec(c, **kw, &:m))
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, **h, &:m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, a: 1, &:m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, **h2, &:m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, **h3, &:m) }
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, a: 1, **h2, &:m) }
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(c, **{}, &:m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal(kw, c.instance_exec(c, **kw, &:m))
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.instance_exec(c, kw, **kw, &:m))
|
||||||
|
assert_equal(h, c.instance_exec(c, **h, &:m))
|
||||||
|
assert_equal(h, c.instance_exec(c, a: 1, &:m))
|
||||||
|
assert_equal(h2, c.instance_exec(c, **h2, &:m))
|
||||||
|
assert_equal(h3, c.instance_exec(c, **h3, &:m))
|
||||||
|
assert_equal(h3, c.instance_exec(c, a: 1, **h2, &:m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(**args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.instance_exec(c, **{}, &:m))
|
||||||
|
assert_equal(kw, c.instance_exec(c, **kw, &:m))
|
||||||
|
assert_equal(h, c.instance_exec(c, **h, &:m))
|
||||||
|
assert_equal(h, c.instance_exec(c, a: 1, &:m))
|
||||||
|
assert_equal(h2, c.instance_exec(c, **h2, &:m))
|
||||||
|
assert_equal(h3, c.instance_exec(c, **h3, &:m))
|
||||||
|
assert_equal(h3, c.instance_exec(c, a: 1, **h2, &:m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/) do
|
||||||
|
assert_equal(h, c.instance_exec(c, h, &:m))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, h2, &:m) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_raise(ArgumentError) { c.instance_exec(c, h3, &:m) }
|
||||||
|
end
|
||||||
|
|
||||||
|
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/) do
|
||||||
|
c.instance_exec(c, **{}, &:m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
c.instance_exec(c, **kw, &:m)
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(c, **h, &:m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h, kw], c.instance_exec(c, a: 1, &:m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h2, kw], c.instance_exec(c, **h2, &:m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(c, **h3, &:m))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter/) do
|
||||||
|
assert_equal([h3, kw], c.instance_exec(c, a: 1, **h2, &:m))
|
||||||
|
end
|
||||||
|
assert_equal([h, kw], c.instance_exec(c, h, &:m))
|
||||||
|
assert_equal([h2, kw], c.instance_exec(c, h2, &:m))
|
||||||
|
assert_equal([h3, kw], c.instance_exec(c, h3, &:m))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:m)
|
||||||
|
def c.m(arg=1, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
assert_equal([1, kw], c.instance_exec(c, **{}, &:m))
|
||||||
|
assert_equal([1, kw], c.instance_exec(c, **kw, &:m))
|
||||||
|
assert_equal([1, h], c.instance_exec(c, **h, &:m))
|
||||||
|
assert_equal([1, h], c.instance_exec(c, a: 1, &:m))
|
||||||
|
assert_equal([1, h2], c.instance_exec(c, **h2, &:m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(c, **h3, &:m))
|
||||||
|
assert_equal([1, h3], c.instance_exec(c, a: 1, **h2, &:m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter/m) do
|
||||||
|
assert_equal([1, h], c.instance_exec(c, h, &:m))
|
||||||
|
end
|
||||||
|
assert_equal([h2, kw], c.instance_exec(c, h2, &:m))
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters/) do
|
||||||
|
assert_equal([h2, h], c.instance_exec(c, h3, &:m))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rb_yield_block_kwsplat
|
||||||
|
kw = {}
|
||||||
|
h = {:a=>1}
|
||||||
|
h2 = {'a'=>1}
|
||||||
|
h3 = {'a'=>1, :a=>1}
|
||||||
|
|
||||||
|
c = Object.new
|
||||||
|
c.extend Bug::Iter::Yield
|
||||||
|
class << c
|
||||||
|
alias m yield_block
|
||||||
|
end
|
||||||
|
def c.c(*args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
assert_equal([], c.m(:c, **{}))
|
||||||
|
assert_equal([], c.m(:c, **kw))
|
||||||
|
assert_equal([h], c.m(:c, **h))
|
||||||
|
assert_equal([h], c.m(:c, a: 1))
|
||||||
|
assert_equal([h2], c.m(:c, **h2))
|
||||||
|
assert_equal([h3], c.m(:c, **h3))
|
||||||
|
assert_equal([h3], c.m(:c, a: 1, **h2))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:c)
|
||||||
|
def c.c; end
|
||||||
|
assert_nil(c.m(:c, **{}))
|
||||||
|
assert_nil(c.m(:c, **kw))
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, **h) }
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, a: 1) }
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, **h2) }
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, **h3) }
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, a: 1, **h2) }
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:c)
|
||||||
|
def c.c(args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal(kw, c.m(:c, **{}))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal(kw, c.m(:c, **kw))
|
||||||
|
end
|
||||||
|
assert_equal(kw, c.m(:c, kw, **kw))
|
||||||
|
assert_equal(h, c.m(:c, **h))
|
||||||
|
assert_equal(h, c.m(:c, a: 1))
|
||||||
|
assert_equal(h2, c.m(:c, **h2))
|
||||||
|
assert_equal(h3, c.m(:c, **h3))
|
||||||
|
assert_equal(h3, c.m(:c, a: 1, **h2))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:c)
|
||||||
|
def c.c(**args)
|
||||||
|
[args, yield(**args)]
|
||||||
|
end
|
||||||
|
m = ->(**args){ args }
|
||||||
|
assert_equal([kw, kw], c.m(:c, **{}, &m))
|
||||||
|
assert_equal([kw, kw], c.m(:c, **kw, &m))
|
||||||
|
assert_equal([h, h], c.m(:c, **h, &m))
|
||||||
|
assert_equal([h, h], c.m(:c, a: 1, &m))
|
||||||
|
assert_equal([h2, h2], c.m(:c, **h2, &m))
|
||||||
|
assert_equal([h3, h3], c.m(:c, **h3, &m))
|
||||||
|
assert_equal([h3, h3], c.m(:c, a: 1, **h2, &m))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter.*for `c'/m) do
|
||||||
|
assert_equal([h, h], c.m(:c, h, &m))
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, h2, &m) }
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters.*for `c'/m) do
|
||||||
|
assert_raise(ArgumentError) { c.m(:c, h3, &m) }
|
||||||
|
end
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:c)
|
||||||
|
def c.c(arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([kw, kw], c.m(:c, **{}))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([kw, kw], c.m(:c, **kw))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([h, kw], c.m(:c, **h))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([h, kw], c.m(:c, a: 1))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([h2, kw], c.m(:c, **h2))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([h3, kw], c.m(:c, **h3))
|
||||||
|
end
|
||||||
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `c'/m) do
|
||||||
|
assert_equal([h3, kw], c.m(:c, a: 1, **h2))
|
||||||
|
end
|
||||||
|
assert_equal([h, kw], c.m(:c, h))
|
||||||
|
assert_equal([h2, kw], c.m(:c, h2))
|
||||||
|
assert_equal([h3, kw], c.m(:c, h3))
|
||||||
|
|
||||||
|
c.singleton_class.remove_method(:c)
|
||||||
|
def c.c(arg=1, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
assert_equal([1, kw], c.m(:c, **{}))
|
||||||
|
assert_equal([1, kw], c.m(:c, **kw))
|
||||||
|
assert_equal([1, h], c.m(:c, **h))
|
||||||
|
assert_equal([1, h], c.m(:c, a: 1))
|
||||||
|
assert_equal([1, h2], c.m(:c, **h2))
|
||||||
|
assert_equal([1, h3], c.m(:c, **h3))
|
||||||
|
assert_equal([1, h3], c.m(:c, a: 1, **h2))
|
||||||
|
assert_warn(/The last argument is used as the keyword parameter.*for `c'/m) do
|
||||||
|
assert_equal([1, h], c.m(:c, h))
|
||||||
|
end
|
||||||
|
assert_equal([h2, kw], c.m(:c, h2))
|
||||||
|
assert_warn(/The last argument is split into positional and keyword parameters.*for `c'/m) do
|
||||||
|
assert_equal([h2, h], c.m(:c, h3))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def p1
|
def p1
|
||||||
Proc.new do |str: "foo", num: 424242|
|
Proc.new do |str: "foo", num: 424242|
|
||||||
[str, num]
|
[str, num]
|
||||||
|
|
|
@ -1552,9 +1552,7 @@ class TestProcKeywords < Test::Unit::TestCase
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
||||||
assert_equal(1, (f << g).call(a: 3)[:a])
|
assert_equal(1, (f << g).call(a: 3)[:a])
|
||||||
end
|
end
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
assert_equal(2, (f >> g).call(a: 3)[:a])
|
||||||
assert_equal(2, (f >> g).call(a: 3)[:a])
|
|
||||||
end
|
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
||||||
assert_equal(1, (f << g).call({a: 3})[:a])
|
assert_equal(1, (f << g).call({a: 3})[:a])
|
||||||
end
|
end
|
||||||
|
@ -1574,9 +1572,7 @@ class TestProcKeywords < Test::Unit::TestCase
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.*The last argument is used as the keyword parameter.*for method/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.*The last argument is used as the keyword parameter.*for method/m) do
|
||||||
assert_equal(1, (f << g).call(**{})[:a])
|
assert_equal(1, (f << g).call(**{})[:a])
|
||||||
end
|
end
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
|
assert_equal(2, (f >> g).call(**{})[:a])
|
||||||
assert_equal(2, (f >> g).call(**{})[:a])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_keywords_non_proc
|
def test_compose_keywords_non_proc
|
||||||
|
@ -1632,9 +1628,7 @@ class TestProcKeywords < Test::Unit::TestCase
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for `call'/m) do
|
assert_warn(/The last argument is used as the keyword parameter.*for `call'/m) do
|
||||||
assert_equal(2, (g << f).call(a: 3)[:a])
|
assert_equal(2, (g << f).call(a: 3)[:a])
|
||||||
end
|
end
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for `call'/m) do
|
assert_equal(1, (g >> f).call(a: 3)[:a])
|
||||||
assert_equal(1, (g >> f).call(a: 3)[:a])
|
|
||||||
end
|
|
||||||
assert_warn(/The last argument is used as the keyword parameter.*for `call'/m) do
|
assert_warn(/The last argument is used as the keyword parameter.*for `call'/m) do
|
||||||
assert_equal(2, (g << f).call({a: 3})[:a])
|
assert_equal(2, (g << f).call({a: 3})[:a])
|
||||||
end
|
end
|
||||||
|
|
16
vm.c
16
vm.c
|
@ -1164,26 +1164,26 @@ check_block_handler(rb_execution_context_t *ec)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda)
|
vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat, const rb_cref_t *cref, int is_lambda)
|
||||||
{
|
{
|
||||||
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
||||||
argc, argv, VM_NO_KEYWORDS, VM_BLOCK_HANDLER_NONE,
|
argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE,
|
||||||
cref, is_lambda, FALSE);
|
cref, is_lambda, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv)
|
vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat)
|
||||||
{
|
{
|
||||||
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
||||||
argc, argv, VM_NO_KEYWORDS, VM_BLOCK_HANDLER_NONE,
|
argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE,
|
||||||
NULL, FALSE, FALSE);
|
NULL, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler)
|
vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler, int kw_splat)
|
||||||
{
|
{
|
||||||
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
return invoke_block_from_c_bh(ec, check_block_handler(ec),
|
||||||
argc, argv, VM_NO_KEYWORDS, block_handler,
|
argc, argv, kw_splat, block_handler,
|
||||||
NULL, FALSE, FALSE);
|
NULL, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,6 +1213,10 @@ invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
||||||
case block_type_iseq:
|
case block_type_iseq:
|
||||||
return invoke_iseq_block_from_c(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, NULL, is_lambda, me);
|
return invoke_iseq_block_from_c(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, NULL, is_lambda, me);
|
||||||
case block_type_ifunc:
|
case block_type_ifunc:
|
||||||
|
if (kw_splat == 1 && RHASH_EMPTY_P(argv[argc-1])) {
|
||||||
|
argc--;
|
||||||
|
kw_splat = 2;
|
||||||
|
}
|
||||||
return vm_yield_with_cfunc(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, me);
|
return vm_yield_with_cfunc(ec, &block->as.captured, self, argc, argv, kw_splat, passed_block_handler, me);
|
||||||
case block_type_symbol:
|
case block_type_symbol:
|
||||||
return vm_yield_with_symbol(ec, block->as.symbol, argc, argv, kw_splat, passed_block_handler);
|
return vm_yield_with_symbol(ec, block->as.symbol, argc, argv, kw_splat, passed_block_handler);
|
||||||
|
|
50
vm_eval.c
50
vm_eval.c
|
@ -16,9 +16,9 @@ struct local_var_list {
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status, int kw_splat);
|
static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status, int kw_splat);
|
||||||
static inline VALUE vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda);
|
static inline VALUE vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat, const rb_cref_t *cref, int is_lambda);
|
||||||
static inline VALUE vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv);
|
static inline VALUE vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat);
|
||||||
static inline VALUE vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler);
|
static inline VALUE vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler, int kw_splat);
|
||||||
static inline VALUE vm_yield_force_blockarg(rb_execution_context_t *ec, VALUE args);
|
static inline VALUE vm_yield_force_blockarg(rb_execution_context_t *ec, VALUE args);
|
||||||
VALUE vm_exec(rb_execution_context_t *ec, int mjit_enable_p);
|
VALUE vm_exec(rb_execution_context_t *ec, int mjit_enable_p);
|
||||||
static void vm_set_eval_stack(rb_execution_context_t * th, const rb_iseq_t *iseq, const rb_cref_t *cref, const struct rb_block *base_block);
|
static void vm_set_eval_stack(rb_execution_context_t * th, const rb_iseq_t *iseq, const rb_cref_t *cref, const struct rb_block *base_block);
|
||||||
|
@ -1198,10 +1198,19 @@ rb_f_public_send(int argc, VALUE *argv, VALUE recv)
|
||||||
|
|
||||||
/* yield */
|
/* yield */
|
||||||
|
|
||||||
|
static inline VALUE
|
||||||
|
rb_yield_0_kw(int argc, const VALUE * argv, int kw_splat)
|
||||||
|
{
|
||||||
|
VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat);
|
||||||
|
VALUE ret = vm_yield(GET_EC(), argc, argv, kw_splat);
|
||||||
|
rb_free_tmp_buffer(&v);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
rb_yield_0(int argc, const VALUE * argv)
|
rb_yield_0(int argc, const VALUE * argv)
|
||||||
{
|
{
|
||||||
return vm_yield(GET_EC(), argc, argv);
|
return vm_yield(GET_EC(), argc, argv, RB_NO_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
|
@ -1250,6 +1259,12 @@ rb_yield_values2(int argc, const VALUE *argv)
|
||||||
return rb_yield_0(argc, argv);
|
return rb_yield_0(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_yield_values_kw(int argc, const VALUE *argv, int kw_splat)
|
||||||
|
{
|
||||||
|
return rb_yield_0_kw(argc, argv, kw_splat);
|
||||||
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_yield_splat(VALUE values)
|
rb_yield_splat(VALUE values)
|
||||||
{
|
{
|
||||||
|
@ -1270,10 +1285,15 @@ rb_yield_force_blockarg(VALUE values)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_yield_block(VALUE val, VALUE arg, int argc, const VALUE *argv, VALUE blockarg)
|
rb_yield_block(RB_BLOCK_CALL_FUNC_ARGLIST(val, arg))
|
||||||
{
|
{
|
||||||
return vm_yield_with_block(GET_EC(), argc, argv,
|
int kw_splat = RB_PASS_CALLED_KEYWORDS;
|
||||||
NIL_P(blockarg) ? VM_BLOCK_HANDLER_NONE : blockarg);
|
VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat);
|
||||||
|
VALUE ret = vm_yield_with_block(GET_EC(), argc, argv,
|
||||||
|
NIL_P(blockarg) ? VM_BLOCK_HANDLER_NONE : blockarg,
|
||||||
|
kw_splat);
|
||||||
|
rb_free_tmp_buffer(&v);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -1772,6 +1792,10 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv)
|
||||||
const VALUE *ep = NULL;
|
const VALUE *ep = NULL;
|
||||||
rb_cref_t *cref;
|
rb_cref_t *cref;
|
||||||
int is_lambda = FALSE;
|
int is_lambda = FALSE;
|
||||||
|
VALUE v = 0, ret;
|
||||||
|
int kw_splat = RB_PASS_CALLED_KEYWORDS;
|
||||||
|
|
||||||
|
v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat);
|
||||||
|
|
||||||
if (block_handler != VM_BLOCK_HANDLER_NONE) {
|
if (block_handler != VM_BLOCK_HANDLER_NONE) {
|
||||||
again:
|
again:
|
||||||
|
@ -1791,8 +1815,10 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv)
|
||||||
block_handler = vm_proc_to_block_handler(VM_BH_TO_PROC(block_handler));
|
block_handler = vm_proc_to_block_handler(VM_BH_TO_PROC(block_handler));
|
||||||
goto again;
|
goto again;
|
||||||
case block_handler_type_symbol:
|
case block_handler_type_symbol:
|
||||||
return rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)),
|
ret = rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)),
|
||||||
argc, argv, VM_NO_KEYWORDS, VM_BLOCK_HANDLER_NONE);
|
argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE);
|
||||||
|
rb_free_tmp_buffer(&v);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_captured.self = self;
|
new_captured.self = self;
|
||||||
|
@ -1802,7 +1828,9 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
cref = vm_cref_push(ec, under, ep, TRUE);
|
cref = vm_cref_push(ec, under, ep, TRUE);
|
||||||
return vm_yield_with_cref(ec, argc, argv, cref, is_lambda);
|
ret = vm_yield_with_cref(ec, argc, argv, kw_splat, cref, is_lambda);
|
||||||
|
rb_free_tmp_buffer(&v);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
|
@ -1823,7 +1851,7 @@ rb_yield_refine_block(VALUE refinement, VALUE refinements)
|
||||||
CREF_REFINEMENTS_SET(cref, refinements);
|
CREF_REFINEMENTS_SET(cref, refinements);
|
||||||
VM_FORCE_WRITE_SPECIAL_CONST(&VM_CF_LEP(ec->cfp)[VM_ENV_DATA_INDEX_SPECVAL], new_block_handler);
|
VM_FORCE_WRITE_SPECIAL_CONST(&VM_CF_LEP(ec->cfp)[VM_ENV_DATA_INDEX_SPECVAL], new_block_handler);
|
||||||
new_captured.self = refinement;
|
new_captured.self = refinement;
|
||||||
return vm_yield_with_cref(ec, 0, NULL, cref, FALSE);
|
return vm_yield_with_cref(ec, 0, NULL, RB_NO_KEYWORDS, cref, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче