Search code examples
rubystringyamlpsych

How to dump strings in YAML using literal scalar style?


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?


Solution:

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.


Solution

  • 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
    }