diff options
-rw-r--r-- | lib/psych/visitors/to_ruby.rb | 24 | ||||
-rw-r--r-- | test/psych/test_hash.rb | 14 |
2 files changed, 37 insertions, 1 deletions
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb index c265acb..49447e1 100644 --- a/lib/psych/visitors/to_ruby.rb +++ b/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 2a563da..ba11b82 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 |