summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2019-07-24 16:01:20 -0400
committerNobuyoshi Nakada <nobu@ruby-lang.org>2020-06-05 11:49:56 +0900
commitf641d78a6fcf0b96c50077503a763478d0599fe5 (patch)
tree0a67ca59d70a6b3c195e1c395c1c812c0c422e23
parent4085c51a5175aeff2aeb8b849214c2899a79eb19 (diff)
[ruby/psych] Implement `freeze` option for Pysch.load
https://github.com/ruby/psych/commit/7dae24894d
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3188
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb18
-rw-r--r--test/psych/test_psych.rb16
2 files changed, 27 insertions, 7 deletions
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index 68452e5c3e..a922f90831 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -32,16 +32,18 @@ module Psych
def accept target
result = super
- return result if @domain_types.empty? || !target.tag
- key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
- key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/
+ unless @domain_types.empty? || !target.tag
+ key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
+ key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/
- if @domain_types.key? key
- value, block = @domain_types[key]
- return block.call value, result
+ if @domain_types.key? key
+ value, block = @domain_types[key]
+ result = block.call value, result
+ end
end
+ result = deduplicate(result).freeze if @freeze
result
end
@@ -341,7 +343,7 @@ module Psych
key = accept(k)
if @symbolize_names
key = key.to_sym
- else
+ elsif !@freeze
key = deduplicate(key)
end
val = accept(v)
@@ -378,6 +380,8 @@ module Psych
if RUBY_VERSION < '2.7'
def deduplicate key
if key.is_a?(String)
+ # It is important to untaint the string, otherwise it won't
+ # be deduplicated into an fstring, but simply frozen.
-(key.untaint)
else
key
diff --git a/test/psych/test_psych.rb b/test/psych/test_psych.rb
index eeadc864ef..8fd9d278b5 100644
--- a/test/psych/test_psych.rb
+++ b/test/psych/test_psych.rb
@@ -192,6 +192,22 @@ class TestPsych < Psych::TestCase
assert_equal({ 'hello' => 'world' }, got)
end
+ def test_load_freeze
+ data = Psych.load("--- {foo: ['a']}", freeze: true)
+ assert_predicate data, :frozen?
+ assert_predicate data['foo'], :frozen?
+ assert_predicate data['foo'].first, :frozen?
+ end
+
+ def test_load_freeze_deduplication
+ unless String.method_defined?(:-@) && (-("a" * 20)).equal?((-("a" * 20)))
+ skip "This Ruby implementation doesn't support string deduplication"
+ end
+
+ data = Psych.load("--- ['a']", freeze: true)
+ assert_same 'a', data.first
+ end
+
def test_load_default_fallback
assert_equal false, Psych.load("")
end