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

ruby-changes:52566

From: mame <ko1@a...>
Date: Wed, 19 Sep 2018 10:59:32 +0900 (JST)
Subject: [ruby-changes:52566] mame:r64777 (trunk): * hash.c (rb_hash_merge): Accepts zero or more hashes as arguments

mame	2018-09-19 10:59:26 +0900 (Wed, 19 Sep 2018)

  New Revision: 64777

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64777

  Log:
    * hash.c (rb_hash_merge): Accepts zero or more hashes as arguments
    
    Hash#merge, merge!, and update could merge exactly two hashes.
    Now, they accepts zero or more hashes as arguments so that it can merge
    hashes more than two.
    
    This patch was created by Koki Ryu <liukoki@g...> at Ruby Hack
    Challenge #5.  Thank you!
    [ruby-core:88970] [Feature #15111] [Fix GH-1951]

  Modified files:
    trunk/hash.c
    trunk/test/ruby/test_hash.rb
Index: test/ruby/test_hash.rb
===================================================================
--- test/ruby/test_hash.rb	(revision 64776)
+++ test/ruby/test_hash.rb	(revision 64777)
@@ -1123,11 +1123,35 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1123
     assert_equal({1=>6, 3=>4, 5=>7}, h1)
   end
 
+  def test_update3
+    h1 = @cls[1=>2, 3=>4]
+    h1.update()
+    assert_equal({1=>2, 3=>4}, h1)
+    h2 = {1=>3, 5=>7}
+    h3 = {1=>1, 2=>4}
+    h1.update(h2, h3)
+    assert_equal({1=>1, 2=>4, 3=>4, 5=>7}, h1)
+  end
+
+  def test_update4
+    h1 = @cls[1=>2, 3=>4]
+    h1.update(){|k, v1, v2| k + v1 + v2 }
+    assert_equal({1=>2, 3=>4}, h1)
+    h2 = {1=>3, 5=>7}
+    h3 = {1=>1, 2=>4}
+    h1.update(h2, h3){|k, v1, v2| k + v1 + v2 }
+    assert_equal({1=>8, 2=>4, 3=>4, 5=>7}, h1)
+  end
+
   def test_merge
     h1 = @cls[1=>2, 3=>4]
     h2 = {1=>3, 5=>7}
+    h3 = {1=>1, 2=>4}
+    assert_equal({1=>2, 3=>4}, h1.merge())
     assert_equal({1=>3, 3=>4, 5=>7}, h1.merge(h2))
     assert_equal({1=>6, 3=>4, 5=>7}, h1.merge(h2) {|k, v1, v2| k + v1 + v2 })
+    assert_equal({1=>1, 2=>4, 3=>4, 5=>7}, h1.merge(h2, h3))
+    assert_equal({1=>8, 2=>4, 3=>4, 5=>7}, h1.merge(h2, h3) {|k, v1, v2| k + v1 + v2 })
   end
 
   def test_assoc
Index: hash.c
===================================================================
--- hash.c	(revision 64776)
+++ hash.c	(revision 64777)
@@ -2548,16 +2548,23 @@ rb_hash_update_block_i(VALUE key, VALUE https://github.com/ruby/ruby/blob/trunk/hash.c#L2548
 
 /*
  *  call-seq:
- *     hsh.merge!(other_hash)                                 -> hsh
- *     hsh.update(other_hash)                                 -> hsh
- *     hsh.merge!(other_hash){|key, oldval, newval| block}    -> hsh
- *     hsh.update(other_hash){|key, oldval, newval| block}    -> hsh
- *
- *  Adds the contents of _other_hash_ to _hsh_.  If no block is specified,
- *  entries with duplicate keys are overwritten with the values from
- *  _other_hash_, otherwise the value of each duplicate key is determined by
+ *     hsh.merge!(other_hash1, other_hash2, ...)              -> hsh
+ *     hsh.update(other_hash1, other_hash2, ...)              -> hsh
+ *     hsh.merge!(other_hash1, other_hash2, ...){|key, oldval, newval| block}
+ *                                                            -> hsh
+ *     hsh.update(other_hash1, other_hash2, ...){|key, oldval, newval| block}
+ *                                                            -> hsh
+ *
+ *  Adds the contents of _other_hash_s to _hsh_ repeatedly. If no block is
+ *  specified, entries with duplicate keys are overwritten with the values from
+ *  each _other_hash_, otherwise the value of each duplicate key is determined by
  *  calling the block with the key, its value in _hsh_ and its value in
- *  _other_hash_.
+ *  each _other_hash_. The method also can be called with no argument,
+ *  then nothing will change in the receiver.
+ *
+ *     h1 = { "a" => 100, "b" => 200 }
+ *     h1.merge!()     #=> {"a"=>100, "b"=>200}
+ *     h1              #=> {"a"=>100, "b"=>200}
  *
  *     h1 = { "a" => 100, "b" => 200 }
  *     h2 = { "b" => 254, "c" => 300 }
@@ -2566,23 +2573,36 @@ rb_hash_update_block_i(VALUE key, VALUE https://github.com/ruby/ruby/blob/trunk/hash.c#L2573
  *
  *     h1 = { "a" => 100, "b" => 200 }
  *     h2 = { "b" => 254, "c" => 300 }
- *     h1.merge!(h2) { |key, v1, v2| v1 }
- *                     #=> {"a"=>100, "b"=>200, "c"=>300}
- *     h1              #=> {"a"=>100, "b"=>200, "c"=>300}
+ *     h3 = { "b" => 100, "d" => 400 }
+ *     h1.merge!(h2, h3)
+ *                     #=> {"a"=>100, "b"=>100, "c"=>300, "d"=>400}
+ *     h1              #=> {"a"=>100, "b"=>100, "c"=>300, "d"=>400}
+ *
+ *     h1 = { "a" => 100, "b" => 200 }
+ *     h2 = { "b" => 254, "c" => 300 }
+ *     h3 = { "b" => 100, "d" => 400 }
+ *     h1.merge!(h2, h3) { |key, v1, v2| v1 }
+ *                     #=> {"a"=>100, "b"=>200, "c"=>300, "d"=>400}
+ *     h1              #=> {"a"=>100, "b"=>200, "c"=>300, "d"=>400}
  */
 
 static VALUE
-rb_hash_update(VALUE hash1, VALUE hash2)
+rb_hash_update(int argc, VALUE *argv, VALUE self)
 {
-    rb_hash_modify(hash1);
-    hash2 = to_hash(hash2);
-    if (rb_block_given_p()) {
-	rb_hash_foreach(hash2, rb_hash_update_block_i, hash1);
-    }
-    else {
-	rb_hash_foreach(hash2, rb_hash_update_i, hash1);
+    int i;
+    bool block_given = rb_block_given_p();
+
+    rb_hash_modify(self);
+    for (i = 0; i < argc; i++){
+       VALUE hash = to_hash(argv[i]);
+       if (block_given) {
+          rb_hash_foreach(hash, rb_hash_update_block_i, self);
+       }
+       else {
+          rb_hash_foreach(hash, rb_hash_update_i, self);
+       }
     }
-    return hash1;
+    return self;
 }
 
 struct update_func_arg {
@@ -2641,28 +2661,38 @@ rb_hash_update_by(VALUE hash1, VALUE has https://github.com/ruby/ruby/blob/trunk/hash.c#L2661
 
 /*
  *  call-seq:
- *     hsh.merge(other_hash)                              -> new_hash
- *     hsh.merge(other_hash){|key, oldval, newval| block} -> new_hash
+ *     hsh.merge(other_hash1, other_hash2, ...)           -> new_hash
+ *     hsh.merge(other_hash1, other_hash2, ...){|key, oldval, newval| block}
+ *                                                        -> new_hash
  *
- *  Returns a new hash containing the contents of <i>other_hash</i> and
+ *  Returns a new hash containing the contents of <i>other_hash</i>s and
  *  the contents of <i>hsh</i>. If no block is specified, the value for
- *  entries with duplicate keys will be that of <i>other_hash</i>. Otherwise
- *  the value for each duplicate key is determined by calling the block
- *  with the key, its value in <i>hsh</i> and its value in <i>other_hash</i>.
+ *  entries with duplicate keys will be that of each <i>other_hash</i>.
+ *  Otherwise the value for each duplicate key is determined by calling
+ *  the block with the key, its value in <i>hsh</i> and its value
+ *  in each <i>other_hash</i>. The method also can be called with no argument,
+ *  then a new hash, whose content is same as that of the receiver,
+ *  will be returned;
  *
  *     h1 = { "a" => 100, "b" => 200 }
  *     h2 = { "b" => 254, "c" => 300 }
+ *     h3 = { "b" => 100, "d" => 400 }
+ *     h1.merge()     #=> {"a"=>100, "b"=>200}
  *     h1.merge(h2)   #=> {"a"=>100, "b"=>254, "c"=>300}
+ *     h1.merge(h2, h3)
+ *                    #=> {"a"=>100, "b"=>100, "c"=>300, "d"=>400}
  *     h1.merge(h2){|key, oldval, newval| newval - oldval}
  *                    #=> {"a"=>100, "b"=>54,  "c"=>300}
+ *     h1.merge(h2, h3){|key, oldval, newval| newval - oldval}
+ *                    #=> {"a"=>100, "b"=>46,  "c"=>300, "d"=>400}
  *     h1             #=> {"a"=>100, "b"=>200}
  *
  */
 
 static VALUE
-rb_hash_merge(VALUE hash1, VALUE hash2)
+rb_hash_merge(int argc, VALUE *argv, VALUE self)
 {
-    return rb_hash_update(rb_hash_dup(hash1), hash2);
+    return rb_hash_update(argc, argv, rb_hash_dup(self));
 }
 
 static int
@@ -4761,10 +4791,10 @@ Init_Hash(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L4791
     rb_define_method(rb_cHash, "slice", rb_hash_slice, -1);
     rb_define_method(rb_cHash, "clear", rb_hash_clear, 0);
     rb_define_method(rb_cHash, "invert", rb_hash_invert, 0);
-    rb_define_method(rb_cHash, "update", rb_hash_update, 1);
+    rb_define_method(rb_cHash, "update", rb_hash_update, -1);
     rb_define_method(rb_cHash, "replace", rb_hash_replace, 1);
-    rb_define_method(rb_cHash, "merge!", rb_hash_update, 1);
-    rb_define_method(rb_cHash, "merge", rb_hash_merge, 1);
+    rb_define_method(rb_cHash, "merge!", rb_hash_update, -1);
+    rb_define_method(rb_cHash, "merge", rb_hash_merge, -1);
     rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
     rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
     rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);

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

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