summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hash.c94
-rw-r--r--test/ruby/test_hash.rb24
2 files changed, 86 insertions, 32 deletions
diff --git a/hash.c b/hash.c
index 32efd02d5a..8204561bf1 100644
--- a/hash.c
+++ b/hash.c
@@ -2548,16 +2548,23 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
/*
* 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 value, VALUE hash)
*
* 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 hash2, rb_hash_update_func *func)
/*
* 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)
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);
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 088178defa..11735c5620 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1123,11 +1123,35 @@ class TestHash < Test::Unit::TestCase
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