Skip to content

Commit

Permalink
Merge pull request #621 from fnordfish/dump-stringify-names
Browse files Browse the repository at this point in the history
Add :stringify_names option to convert symbol keys to string for dumping
  • Loading branch information
tenderlove authored Jan 18, 2024
2 parents 100c579 + 3d051d8 commit be0ba74
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
14 changes: 14 additions & 0 deletions lib/psych.rb
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,10 @@ def self.parse_stream yaml, filename: nil, &block
#
# Default: <tt>false</tt>.
#
# [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
#
# Default: <tt>false</tt>.
#
# Example:
#
# # Dump an array, get back a YAML string
Expand All @@ -502,6 +506,9 @@ def self.parse_stream yaml, filename: nil, &block
#
# # Dump an array to an IO with indentation set
# Psych.dump(['a', ['b']], StringIO.new, indentation: 3)
#
# # Dump hash with symbol keys as string
# Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
def self.dump o, io = nil, options = {}
if Hash === io
options = io
Expand Down Expand Up @@ -562,6 +569,10 @@ def self.dump o, io = nil, options = {}
#
# Default: <tt>false</tt>.
#
# [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
#
# Default: <tt>false</tt>.
#
# Example:
#
# # Dump an array, get back a YAML string
Expand All @@ -575,6 +586,9 @@ def self.dump o, io = nil, options = {}
#
# # Dump an array to an IO with indentation set
# Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3)
#
# # Dump hash with symbol keys as string
# Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
def self.safe_dump o, io = nil, options = {}
if Hash === io
options = io
Expand Down
5 changes: 3 additions & 2 deletions lib/psych/visitors/yaml_tree.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def initialize emitter, ss, options
fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.")
end
end
@stringify_names = options[:stringify_names]
@coders = []

@dispatch_cache = Hash.new do |h,klass|
Expand Down Expand Up @@ -323,7 +324,7 @@ def visit_Hash o
if o.class == ::Hash
register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
o.each do |k,v|
accept k
accept(@stringify_names && Symbol === k ? k.to_s : k)
accept v
end
@emitter.end_mapping
Expand All @@ -336,7 +337,7 @@ def visit_Psych_Set o
register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))

o.each do |k,v|
accept k
accept(@stringify_names && Symbol === k ? k.to_s : k)
accept v
end

Expand Down
26 changes: 26 additions & 0 deletions test/psych/test_psych.rb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,32 @@ def test_safe_dump_symbols
assert_match(/\A--- :foo\n(?:\.\.\.\n)?\z/, Psych.safe_dump(:foo, permitted_symbols: [:foo]))
end

def test_safe_dump_stringify_names
yaml = <<-eoyml
---
foo:
bar: bar
'no': special escapes
123: number
eoyml

payload = Psych.safe_dump({
foo: {
bar: "bar",
no: "special escapes",
123 => "number"
}
}, stringify_names: true)
assert_equal yaml, payload

assert_equal("---\nfoo: :bar\n", Psych.safe_dump({foo: :bar}, stringify_names: true, permitted_symbols: [:bar]))

error = assert_raise Psych::DisallowedClass do
Psych.safe_dump({foo: :bar}, stringify_names: true)
end
assert_equal "Tried to dump unspecified class: Symbol(:bar)", error.message
end

def test_safe_dump_aliases
x = []
x << x
Expand Down
7 changes: 7 additions & 0 deletions test/psych/test_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,12 @@ def test_set_self_reference
@set['self'] = @set
assert_cycle(@set)
end

def test_stringify_names
@set[:symbol] = :value

assert_match(/^:symbol: :value/, Psych.dump(@set))
assert_match(/^symbol: :value/, Psych.dump(@set, stringify_names: true))
end
end
end

0 comments on commit be0ba74

Please sign in to comment.