summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2020-01-06 18:22:43 +0900
committerYusuke Endoh <mame@ruby-lang.org>2020-01-17 17:20:38 +0900
commit7cfe93c028fbf7aa0022ca8a4ac6a66d0103337a (patch)
tree505d214877b1c84986ab221a701938a5bd1a6c0b /hash.c
parentb23fd59cbb3f097bcd559d0c85a86ff7a1eeeb7e (diff)
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]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2818
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/hash.c b/hash.c
index 644f85d6da..a1b57cee24 100644
--- a/hash.c
+++ b/hash.c
@@ -1874,6 +1874,52 @@ rb_hash_s_try_convert(VALUE dummy, VALUE hash)
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)
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.