I have a big string of formatted data (e.g. JSON) that I want to dump to YAML using Psych in ruby while preserving formatting.
Basically, I want for JSON to appear in YAML using literal style:
---
json: |
{
"page": 1,
"results": [
"item", "another"
],
"total_pages": 0
}
However, when I use YAML.dump
it doesn't use literal style. I get something like this:
---
json: ! "{\n \"page\": 1,\n \"results\": [\n \"item\", \"another\"\n ],\n \"total_pages\":
0\n}\n"
How can I tell Psych to dump scalars in wanted style?
Big thanks to Aaron Patterson for his solution that I'm expanding on here: https://gist.github.com/2023978
Although a bit verbose, that gist is a working way of tagging certain strings in ruby to be output using literal style in YAML.
Multi-line blocks and long strings. YAML also supports writing strings on multiple lines in your YAML, with two different styles: literal and folded. Those are represented by a | (for literal style) or > (for folded style) header line (see examples below), and we will go into their differences soon.
Scalars in YAML are written in block format using a literal type which is denoted as(|). It denotes line breaks count. In YAML, scalars are written in folded style (>) where each line denotes a folded space which ends with an empty line or more indented line.
If you would like them to be kept as newlines, use the literal style, indicated by a pipe ( | ). If instead you want them to be replaced by spaces, use the folded style, indicated by a right angle bracket ( > ). (To get a newline using the folded style, leave a blank line by putting two newlines in.
require 'psych'
# Construct an AST
visitor = Psych::Visitors::YAMLTree.new({})
visitor << DATA.read
ast = visitor.tree
# Find all scalars and modify their formatting
ast.grep(Psych::Nodes::Scalar).each do |node|
node.plain = false
node.quoted = true
node.style = Psych::Nodes::Scalar::LITERAL
end
begin
# Call the `yaml` method on the ast to convert to yaml
puts ast.yaml
rescue
# The `yaml` method was introduced in later versions, so fall back to
# constructing a visitor
Psych::Visitors::Emitter.new($stdout).accept ast
end
__END__
{
"page": 1,
"results": [
"item", "another"
],
"total_pages": 0
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With