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

ruby-changes:59728

From: Yusuke <ko1@a...>
Date: Fri, 17 Jan 2020 17:20:54 +0900 (JST)
Subject: [ruby-changes:59728] 7cfe93c028 (master): hash.c: Add a feature to manipulate ruby2_keywords flag

https://git.ruby-lang.org/ruby.git/commit/?id=7cfe93c028

From 7cfe93c028fbf7aa0022ca8a4ac6a66d0103337a Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@r...>
Date: Mon, 6 Jan 2020 18:22:43 +0900
Subject: hash.c: Add a feature to manipulate ruby2_keywords flag

It was found that a feature to check and add ruby2_keywords flag to an
existing Hash is needed when arguments are serialized and deserialized.
It is possible to do the same without explicit APIs, but it would be
good to provide them as a core feature.

https://github.com/rails/rails/pull/38105#discussion_r361863767

Hash.ruby2_keywords_hash?(hash) checks if hash is flagged or not.
Hash.ruby2_keywords_hash(hash) returns a duplicated hash that has a
ruby2_keywords flag,

[Bug #16486]

diff --git a/hash.c b/hash.c
index 644f85d..a1b57ce 100644
--- a/hash.c
+++ b/hash.c
@@ -1874,6 +1874,52 @@ rb_hash_s_try_convert(VALUE dummy, VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1874
     return rb_check_hash_type(hash);
 }
 
+/*
+ *  call-seq:
+ *     Hash.ruby2_keywords_hash?(hash) -> true or false
+ *
+ *  Checks if a given hash is flagged by Module#ruby2_keywords (or
+ *  Proc#ruby2_keywords).
+ *  This method is not for casual use; debugging, researching, and
+ *  some truly necessary cases like serialization of arguments.
+ *
+ *     ruby2_keywords def foo(*args)
+ *       Hash.ruby2_keywords_hash?(args.last)
+ *     end
+ *     foo(k: 1)   #=> true
+ *     foo({k: 1}) #=> false
+ */
+static VALUE
+rb_hash_s_ruby2_keywords_hash_p(VALUE dummy, VALUE hash)
+{
+    Check_Type(hash, T_HASH);
+    return (RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS) ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     Hash.ruby2_keywords_hash(hash) -> hash
+ *
+ *  Duplicates a given hash and adds a ruby2_keywords flag.
+ *  This method is not for casual use; debugging, researching, and
+ *  some truly necessary cases like deserialization of arguments.
+ *
+ *     h = {k: 1}
+ *     h = Hash.ruby2_keywords_hash(h)
+ *     def foo(k: 42)
+ *       k
+ *     end
+ *     foo(*[h]) #=> 1 with neither a warning or an error
+ */
+static VALUE
+rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
+{
+    Check_Type(hash, T_HASH);
+    hash = rb_hash_dup(hash);
+    RHASH(hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
+    return hash;
+}
+
 struct rehash_arg {
     VALUE hash;
     st_table *tbl;
@@ -6415,6 +6461,9 @@ Init_Hash(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L6461
 
     rb_define_method(rb_cHash, "deconstruct_keys", rb_hash_deconstruct_keys, 1);
 
+    rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash?", rb_hash_s_ruby2_keywords_hash_p, 1);
+    rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1);
+
     /* Document-class: ENV
      *
      * ENV is a hash-like accessor for environment variables.
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index ef32cff..2c44973 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1756,4 +1756,28 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1756
       super
     end
   end
+
+  ruby2_keywords def get_flagged_hash(*args)
+    args.last
+  end
+
+  def check_flagged_hash(k: :NG)
+    k
+  end
+
+  def test_ruby2_keywords_hash?
+    flagged_hash = get_flagged_hash(k: 1)
+    assert_equal(true, Hash.ruby2_keywords_hash?(flagged_hash))
+    assert_equal(false, Hash.ruby2_keywords_hash?({}))
+    assert_raise(TypeError) { Hash.ruby2_keywords_hash?(1) }
+  end
+
+  def test_ruby2_keywords_hash!
+    hash = {k: 1}
+    assert_equal(false, Hash.ruby2_keywords_hash?(hash))
+    hash = Hash.ruby2_keywords_hash(hash)
+    assert_equal(true, Hash.ruby2_keywords_hash?(hash))
+    assert_equal(1, check_flagged_hash(*[hash]))
+    assert_raise(TypeError) { Hash.ruby2_keywords_hash(1) }
+  end
 end
-- 
cgit v0.10.2


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

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