summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2019-07-22 12:02:23 +0200
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-07-25 07:52:16 +0900
commit6ca7dc69effddeb63a8fb8f759e29ff8649907ec (patch)
tree494129204c3267867ceb74731f397b93bfe00466
parent50076903ab06e2301051e459925afea20325ba7c (diff)
[ruby/psych] Deduplicate hash keys if they're strings
https://github.com/ruby/psych/commit/0414982ffd
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb24
-rw-r--r--test/psych/test_hash.rb14
2 files changed, 37 insertions, 1 deletions
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index c265acb8191..49447e124ab 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -336,7 +336,7 @@ module Psych
SHOVEL = '<<'
def revive_hash hash, o
o.children.each_slice(2) { |k,v|
- key = accept(k)
+ key = deduplicate(accept(k))
val = accept(v)
if key == SHOVEL && k.tag != "tag:yaml.org,2002:str"
@@ -368,6 +368,28 @@ module Psych
hash
end
+ if String.method_defined?(:-@)
+ def deduplicate key
+ if key.is_a?(String)
+ # It is important to untaint the string, otherwise it won't
+ # be deduplicated into and fstring, but simply frozen.
+ -(key.untaint)
+ else
+ key
+ end
+ end
+ else
+ def deduplicate key
+ if key.is_a?(String)
+ # Deduplication is not supported by this implementation,
+ # but we emulate it's side effects
+ key.untaint.freeze
+ else
+ key
+ end
+ end
+ end
+
def merge_key hash, key, val
end
diff --git a/test/psych/test_hash.rb b/test/psych/test_hash.rb
index 2a563da1da7..ba11b827da2 100644
--- a/test/psych/test_hash.rb
+++ b/test/psych/test_hash.rb
@@ -111,5 +111,19 @@ bar:
eoyml
assert_equal({"foo"=>{"hello"=>"world"}, "bar"=>{"hello"=>"world"}}, hash)
end
+
+ def test_key_deduplication
+ unless String.method_defined?(:-@) && (-("a" * 20)).equal?((-("a" * 20)))
+ skip "This Ruby implementation doesn't support string deduplication"
+ end
+
+ hashes = Psych.load(<<-eoyml)
+---
+- unique_identifier: 1
+- unique_identifier: 2
+eoyml
+
+ assert_same hashes[0].keys.first, hashes[1].keys.first
+ end
end
end