summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-22 07:00:17 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-22 07:00:17 +0000
commit547176267f8378a193774c4ca529e854e811c928 (patch)
treed9d792c7d4cd23045d2daef4d9476da5e1940ddf
parentf4aea9108d19b304e8a7f9d2ec4763eadf4a64ba (diff)
merge revision(s) 62042,62044: [Backport #14380]
hash.c: support key swapping in Hash#transform_keys! * hash.c (rb_hash_transform_keys_bang): support key swapping in Hash#transform_keys! [Bug #14380] [ruby-core:84951] * test/ruby/test_hash.rb (test_transform_keys_bang): add assertions for this change Fix rubyspec against the change in Hash#transform_keys! [Bug #14380] [ruby-core:84951] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@62889 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--hash.c16
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb6
-rw-r--r--test/ruby/test_hash.rb8
-rw-r--r--version.h2
4 files changed, 22 insertions, 10 deletions
diff --git a/hash.c b/hash.c
index 285f6118b1..29b8289c98 100644
--- a/hash.c
+++ b/hash.c
@@ -1910,6 +1910,8 @@ rb_hash_transform_keys(VALUE hash)
return result;
}
+static VALUE rb_hash_flatten(int argc, VALUE *argv, VALUE hash);
+
/*
* call-seq:
* hsh.transform_keys! {|key| block } -> hsh
@@ -1933,12 +1935,14 @@ rb_hash_transform_keys_bang(VALUE hash)
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (RHASH(hash)->ntbl) {
- long i;
- VALUE keys = rb_hash_keys(hash);
- for (i = 0; i < RARRAY_LEN(keys); ++i) {
- VALUE key = RARRAY_AREF(keys, i), new_key = rb_yield(key);
- rb_hash_aset(hash, new_key, rb_hash_delete(hash, key));
- }
+ long i;
+ VALUE pairs = rb_hash_flatten(0, NULL, hash);
+ rb_hash_clear(hash);
+ for (i = 0; i < RARRAY_LEN(pairs); i += 2) {
+ VALUE key = RARRAY_AREF(pairs, i), new_key = rb_yield(key),
+ val = RARRAY_AREF(pairs, i+1);
+ rb_hash_aset(hash, new_key, val);
+ }
}
return hash;
}
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index 379638bd4b..cf42f17e51 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -60,9 +60,9 @@ ruby_version_is "2.5" do
@hash.should == { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 }
end
- it "does not prevent conflicts between new keys and old ones" do
+ it "prevents conflicts between new keys and old ones" do
@hash.transform_keys!(&:succ)
- @hash.should == { e: 1 }
+ @hash.should == { b: 1, c: 2, d: 3, e: 4 }
end
it "partially modifies the contents if we broke from the block" do
@@ -70,7 +70,7 @@ ruby_version_is "2.5" do
break if v == :c
v.succ
end
- @hash.should == { c: 1, d: 4 }
+ @hash.should == { b: 1, c: 2 }
end
it "keeps later pair if new keys conflict" do
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 4223aa8140..bdcf022668 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1573,6 +1573,14 @@ class TestHash < Test::Unit::TestCase
x.transform_keys!.with_index {|k, i| "#{k}.#{i}" }
assert_equal(%w(a!.0 b!.1 c!.2), x.keys)
+
+ x = @cls[1 => :a, -1 => :b]
+ x.transform_keys! {|k| -k }
+ assert_equal([-1, :a, 1, :b], x.flatten)
+
+ x = @cls[true => :a, false => :b]
+ x.transform_keys! {|k| !k }
+ assert_equal([false, :a, true, :b], x.flatten)
end
def test_transform_values
diff --git a/version.h b/version.h
index b28c6461e2..28cff34c19 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.5.0"
#define RUBY_RELEASE_DATE "2018-03-20"
-#define RUBY_PATCHLEVEL 47
+#define RUBY_PATCHLEVEL 48
#define RUBY_RELEASE_YEAR 2018
#define RUBY_RELEASE_MONTH 3