-
-
Save lyoshenka/4680297 to your computer and use it in GitHub Desktop.
Example of outputting YAML in Ruby using inline style (array is all on one line, not spread out with each element on its own line)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
full_data = { | |
response: {body: StyledYAML.literal(DATA.read), status: 200}, | |
person: StyledYAML.inline('name' => 'Steve', 'age' => 24), | |
array: StyledYAML.inline(%w[ apples bananas oranges ]) | |
} | |
StyledYAML.dump full_data, $stdout | |
__END__ | |
{ | |
"page": 1, | |
"results": [ | |
"item", "another" | |
], | |
"total_pages": 0 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# default boring output of Psych.dump | |
--- | |
:response: | |
:body: ! "{\n \"page\": 1,\n \"results\": [\n \"item\", \"another\"\n ],\n | |
\ \"total_pages\": 0\n}\n" | |
:status: 200 | |
:person: | |
name: Steve | |
age: 24 | |
:array: | |
- apples | |
- bananas | |
- oranges |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
:response: | |
# formatted string presented in literal style | |
:body: | | |
{ | |
"page": 1, | |
"results": [ | |
"item", "another" | |
], | |
"total_pages": 0 | |
} | |
:status: 200 | |
# inline hash | |
:person: {name: Steve, age: 24} | |
# inline array | |
:array: [apples, bananas, oranges] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'psych' | |
require 'stringio' | |
# Public: A Psych extension to enable choosing output styles for specific | |
# objects. | |
# | |
# Thanks to Tenderlove for help in <http://stackoverflow.com/q/9640277/11687> | |
# | |
# Examples | |
# | |
# data = { | |
# response: { body: StyledYAML.literal(json_string), status: 200 }, | |
# person: StyledYAML.inline({ 'name' => 'Stevie', 'age' => 12 }), | |
# array: StyledYAML.inline(%w[ apples bananas oranges ]) | |
# } | |
# | |
# StyledYAML.dump data, $stdout | |
# | |
module StyledYAML | |
# Tag strings to be output using literal style | |
def self.literal obj | |
obj.extend LiteralScalar | |
return obj | |
end | |
# http://www.yaml.org/spec/1.2/spec.html#id2795688 | |
module LiteralScalar | |
def yaml_style() Psych::Nodes::Scalar::LITERAL end | |
end | |
# Tag Hashes or Arrays to be output all on one line | |
def self.inline obj | |
case obj | |
when Hash then obj.extend FlowMapping | |
when Array then obj.extend FlowSequence | |
else | |
warn "#{self}: unrecognized type to inline (#{obj.class.name})" | |
end | |
return obj | |
end | |
# http://www.yaml.org/spec/1.2/spec.html#id2790832 | |
module FlowMapping | |
def yaml_style() Psych::Nodes::Mapping::FLOW end | |
end | |
# http://www.yaml.org/spec/1.2/spec.html#id2790320 | |
module FlowSequence | |
def yaml_style() Psych::Nodes::Sequence::FLOW end | |
end | |
# Custom tree builder class to recognize scalars tagged with `yaml_style` | |
class TreeBuilder < Psych::TreeBuilder | |
attr_writer :next_sequence_or_mapping_style | |
def initialize(*args) | |
super | |
@next_sequence_or_mapping_style = nil | |
end | |
def next_sequence_or_mapping_style default_style | |
style = @next_sequence_or_mapping_style || default_style | |
@next_sequence_or_mapping_style = nil | |
style | |
end | |
def scalar value, anchor, tag, plain, quoted, style | |
if style_any?(style) and value.respond_to?(:yaml_style) and style = value.yaml_style | |
if style_literal? style | |
plain = false | |
quoted = true | |
end | |
end | |
super | |
end | |
def style_any?(style) Psych::Nodes::Scalar::ANY == style end | |
def style_literal?(style) Psych::Nodes::Scalar::LITERAL == style end | |
%w[sequence mapping].each do |type| | |
class_eval <<-RUBY | |
def start_#{type}(anchor, tag, implicit, style) | |
style = next_sequence_or_mapping_style(style) | |
super | |
end | |
RUBY | |
end | |
end | |
# Custom tree class to handle Hashes and Arrays tagged with `yaml_style` | |
class YAMLTree < Psych::Visitors::YAMLTree | |
%w[Hash Array Psych_Set Psych_Omap].each do |klass| | |
class_eval <<-RUBY | |
def visit_#{klass} o | |
if o.respond_to? :yaml_style | |
@emitter.next_sequence_or_mapping_style = o.yaml_style | |
end | |
super | |
end | |
RUBY | |
end | |
end | |
# A Psych.dump alternative that uses the custom TreeBuilder | |
def self.dump obj, io = nil, options = {} | |
real_io = io || StringIO.new(''.encode('utf-8')) | |
visitor = YAMLTree.new(options, TreeBuilder.new) | |
visitor << obj | |
ast = visitor.tree | |
begin | |
ast.yaml real_io | |
rescue | |
# The `yaml` method was introduced in later versions, so fall back to | |
# constructing a visitor | |
Psych::Visitors::Emitter.new(real_io).accept ast | |
end | |
io ? io : real_io.string | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment