[前][次][番号順一覧][スレッド一覧]

ruby-changes:57594

From: Jeremy <ko1@a...>
Date: Fri, 6 Sep 2019 12:55:10 +0900 (JST)
Subject: [ruby-changes:57594] 6f9b86616a (master): Make Symbol#to_proc calls handle keyword arguments

https://git.ruby-lang.org/ruby.git/commit/?id=6f9b86616a

From 6f9b86616a8ad60cfed2979e2a0f8398a12e7c85 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Tue, 3 Sep 2019 14:54:37 -0700
Subject: 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.

diff --git a/internal.h b/internal.h
index 14f7830..21491c3 100644
--- a/internal.h
+++ b/internal.h
@@ -2140,7 +2140,7 @@ VALUE rb_str_initialize(VALUE str, const char *ptr, long len, rb_encoding *enc); https://github.com/ruby/ruby/blob/trunk/internal.h#L2140
 #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);
diff --git a/string.c b/string.c
index d6ea7d6..05ce0ed 100644
--- a/string.c
+++ b/string.c
@@ -10887,7 +10887,7 @@ sym_to_sym(VALUE sym) https://github.com/ruby/ruby/blob/trunk/string.c#L10887
 }
 
 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) https://github.com/ruby/ruby/blob/trunk/string.c#L10895
 	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
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index b8d8736..91e53e1 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -447,6 +447,79 @@ class TestKeywordArguments < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_keyword.rb#L447
     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}
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 7895c8a..5730007 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2884,8 +2884,7 @@ vm_yield_with_cfunc(rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2884
 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
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]