2017-07-14 02:15:58 -04:00
# frozen_string_literal: true
2016-11-30 08:55:02 -05:00
require 'psych/versions'
2015-08-21 13:55:23 -04:00
case RUBY_ENGINE
when 'jruby'
require 'psych_jars'
2018-10-20 00:25:04 -04:00
if JRuby :: Util . respond_to? ( :load_ext )
JRuby :: Util . load_ext ( 'org.jruby.ext.psych.PsychLibrary' )
else
require 'java' ; require 'jruby'
org . jruby . ext . psych . PsychLibrary . new . load ( JRuby . runtime , false )
end
2015-08-21 13:55:23 -04:00
else
2019-07-20 23:21:27 -04:00
require 'psych.so'
2015-08-21 13:55:23 -04:00
end
2010-03-28 17:49:37 -04:00
require 'psych/nodes'
2011-02-21 13:09:38 -05:00
require 'psych/streaming'
2010-03-28 17:49:37 -04:00
require 'psych/visitors'
require 'psych/handler'
require 'psych/tree_builder'
require 'psych/parser'
require 'psych/omap'
require 'psych/set'
require 'psych/coder'
require 'psych/core_ext'
2011-11-21 14:47:09 -05:00
require 'psych/stream'
require 'psych/json/tree_builder'
require 'psych/json/stream'
2012-03-08 16:21:52 -05:00
require 'psych/handlers/document_stream'
2014-01-08 19:56:45 -05:00
require 'psych/class_loader'
2010-03-28 17:49:37 -04:00
###
# = Overview
#
2012-12-04 23:08:17 -05:00
# Psych is a YAML parser and emitter.
2018-10-20 00:25:04 -04:00
# Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML]
2014-04-12 20:59:40 -04:00
# or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing
2012-10-22 17:02:16 -04:00
# and emitting capabilities. In addition to wrapping libyaml, Psych also
# knows how to serialize and de-serialize most Ruby objects to and from
# the YAML format.
2010-03-28 17:49:37 -04:00
#
# = I NEED TO PARSE OR EMIT YAML RIGHT NOW!
#
# # Parse some YAML
# Psych.load("--- foo") # => "foo"
#
# # Emit some YAML
# Psych.dump("foo") # => "--- foo\n...\n"
# { :a => 'b'}.to_yaml # => "---\n:a: b\n"
#
# Got more time on your hands? Keep on reading!
#
# == YAML Parsing
#
# Psych provides a range of interfaces for parsing a YAML document ranging from
# low level to high level, depending on your parsing needs. At the lowest
# level, is an event based parser. Mid level is access to the raw YAML AST,
2013-07-18 22:27:25 -04:00
# and at the highest level is the ability to unmarshal YAML to Ruby objects.
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# == YAML Emitting
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# Psych provides a range of interfaces ranging from low to high level for
# producing YAML documents. Very similar to the YAML parsing interfaces, Psych
# provides at the lowest level, an event based system, mid-level is building
# a YAML AST, and the highest level is converting a Ruby object straight to
# a YAML document.
#
# == High-level API
#
# === Parsing
#
# The high level YAML parser provided by Psych simply takes YAML as input and
# returns a Ruby data structure. For information on using the high level parser
# see Psych.load
#
# ==== Reading from a string
#
# Psych.load("--- a") # => 'a'
# Psych.load("---\n - a\n - b") # => ['a', 'b']
#
# ==== Reading from a file
#
# Psych.load_file("database.yml")
#
# ==== Exception handling
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# begin
2014-01-19 00:48:33 -05:00
# # The second argument changes only the exception contents
2013-02-28 13:27:00 -05:00
# Psych.parse("--- `", "file.txt")
# rescue Psych::SyntaxError => ex
# ex.file # => 'file.txt'
# ex.message # => "(file.txt): found character that cannot start any token"
# end
#
# === Emitting
#
# The high level emitter has the easiest interface. Psych simply takes a Ruby
# data structure and converts it to a YAML document. See Psych.dump for more
# information on dumping a Ruby data structure.
#
# ==== Writing to a string
#
# # Dump an array, get back a YAML string
# Psych.dump(['a', 'b']) # => "---\n- a\n- b\n"
#
# # Dump an array to an IO object
# Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
#
# # Dump an array with indentation set
# Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n"
#
# # Dump an array to an IO with indentation set
# Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)
#
# ==== Writing to a file
#
# Currently there is no direct API for dumping Ruby structure to file:
#
# File.open('database.yml', 'w') do |file|
# file.write(Psych.dump(['a', 'b']))
# end
#
# == Mid-level API
#
# === Parsing
2010-03-28 17:49:37 -04:00
#
# Psych provides access to an AST produced from parsing a YAML document. This
# tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can
# be examined and manipulated freely. Please see Psych::parse_stream,
# Psych::Nodes, and Psych::Nodes::Node for more information on dealing with
# YAML syntax trees.
#
2013-02-28 13:27:00 -05:00
# ==== Reading from a string
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# # Returns Psych::Nodes::Stream
# Psych.parse_stream("---\n - a\n - b")
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# # Returns Psych::Nodes::Document
# Psych.parse("---\n - a\n - b")
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# ==== Reading from a file
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# # Returns Psych::Nodes::Stream
# Psych.parse_stream(File.read('database.yml'))
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# # Returns Psych::Nodes::Document
# Psych.parse_file('database.yml')
#
# ==== Exception handling
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# begin
2013-12-28 03:25:28 -05:00
# # The second argument changes only the exception contents
2013-02-28 13:27:00 -05:00
# Psych.parse("--- `", "file.txt")
# rescue Psych::SyntaxError => ex
# ex.file # => 'file.txt'
# ex.message # => "(file.txt): found character that cannot start any token"
# end
#
# === Emitting
2010-03-28 17:49:37 -04:00
#
# At the mid level is building an AST. This AST is exactly the same as the AST
# used when parsing a YAML document. Users can build an AST by hand and the
# AST knows how to emit itself as a YAML document. See Psych::Nodes,
# Psych::Nodes::Node, and Psych::TreeBuilder for more information on building
# a YAML AST.
#
2013-02-28 13:27:00 -05:00
# ==== Writing to a string
2010-03-28 17:49:37 -04:00
#
2013-02-28 13:27:00 -05:00
# # We need Psych::Nodes::Stream (not Psych::Nodes::Document)
# stream = Psych.parse_stream("---\n - a\n - b")
#
# stream.to_yaml # => "---\n- a\n- b\n"
#
# ==== Writing to a file
#
# # We need Psych::Nodes::Stream (not Psych::Nodes::Document)
# stream = Psych.parse_stream(File.read('database.yml'))
#
# File.open('database.yml', 'w') do |file|
# file.write(stream.to_yaml)
# end
#
# == Low-level API
#
# === Parsing
#
# The lowest level parser should be used when the YAML input is already known,
# and the developer does not want to pay the price of building an AST or
2013-07-18 22:27:25 -04:00
# automatic detection and conversion to Ruby objects. See Psych::Parser for
2013-02-28 13:27:00 -05:00
# more information on using the event based parser.
#
# ==== Reading to Psych::Nodes::Stream structure
#
# parser = Psych::Parser.new(TreeBuilder.new) # => #<Psych::Parser>
# parser = Psych.parser # it's an alias for the above
#
# parser.parse("---\n - a\n - b") # => #<Psych::Parser>
# parser.handler # => #<Psych::TreeBuilder>
# parser.handler.root # => #<Psych::Nodes::Stream>
#
# ==== Receiving an events stream
#
2017-11-26 22:11:18 -05:00
# recorder = Psych::Handlers::Recorder.new
# parser = Psych::Parser.new(recorder)
2013-02-28 13:27:00 -05:00
#
# parser.parse("---\n - a\n - b")
2017-11-26 22:11:18 -05:00
# recorder.events # => [list of [event, args] lists]
# # event is one of: Psych::Handler::EVENTS
# # args are the arguments passed to the event
2013-02-28 13:27:00 -05:00
#
# === Emitting
#
# The lowest level emitter is an event based system. Events are sent to a
# Psych::Emitter object. That object knows how to convert the events to a YAML
# document. This interface should be used when document format is known in
# advance or speed is a concern. See Psych::Emitter for more information.
#
2013-07-18 22:27:25 -04:00
# ==== Writing to a Ruby structure
2013-02-28 13:27:00 -05:00
#
# Psych.parser.parse("--- a") # => #<Psych::Parser>
#
# parser.handler.first # => #<Psych::Nodes::Stream>
# parser.handler.first.to_ruby # => ["a"]
#
# parser.handler.root.first # => #<Psych::Nodes::Document>
# parser.handler.root.first.to_ruby # => "a"
#
# # You can instantiate an Emitter manually
# Psych::Visitors::ToRuby.new.accept(parser.handler.root.first)
# # => "a"
2010-03-28 17:49:37 -04:00
module Psych
# The version of libyaml Psych is using
LIBYAML_VERSION = Psych . libyaml_version . join '.'
2018-08-26 20:44:04 -04:00
# Deprecation guard
NOT_GIVEN = Object . new
private_constant :NOT_GIVEN
2016-06-24 05:06:08 -04:00
2010-03-28 17:49:37 -04:00
###
# Load +yaml+ in to a Ruby data structure. If multiple documents are
# provided, the object contained in the first document will be returned.
2018-08-26 20:44:04 -04:00
# +filename+ will be used in the exception message if any exception
# is raised while parsing. If +yaml+ is empty, it returns
# the specified +fallback+ return value, which defaults to +false+.
2011-12-06 18:12:37 -05:00
#
# Raises a Psych::SyntaxError when a YAML syntax error is detected.
2010-03-28 17:49:37 -04:00
#
# Example:
#
2011-12-06 18:12:37 -05:00
# Psych.load("--- a") # => 'a'
# Psych.load("---\n - a\n - b") # => ['a', 'b']
#
# begin
2018-08-26 20:44:04 -04:00
# Psych.load("--- `", filename: "file.txt")
2011-12-06 18:12:37 -05:00
# rescue Psych::SyntaxError => ex
# ex.file # => 'file.txt'
2013-01-03 01:13:56 -05:00
# ex.message # => "(file.txt): found character that cannot start any token"
2011-12-06 18:12:37 -05:00
# end
2017-11-30 20:52:26 -05:00
#
# When the optional +symbolize_names+ keyword argument is set to a
# true value, returns symbols for keys in Hash objects (default: strings).
#
# Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
# Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
#
2018-08-26 20:44:04 -04:00
# Raises a TypeError when `yaml` parameter is NilClass
#
2019-10-17 16:48:24 -04:00
# NOTE: This method *should not* be used to parse untrusted documents, such as
# YAML documents that are supplied via user input. Instead, please use the
# safe_load method.
#
2018-08-26 20:44:04 -04:00
def self . load yaml , legacy_filename = NOT_GIVEN , filename : nil , fallback : false , symbolize_names : false
if legacy_filename != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
filename = legacy_filename
end
result = parse ( yaml , filename : filename )
return fallback unless result
2017-11-26 22:11:18 -05:00
result = result . to_ruby if result
symbolize_names! ( result ) if symbolize_names
result
2010-03-28 17:49:37 -04:00
end
2013-05-14 13:26:41 -04:00
###
# Safely load the yaml string in +yaml+. By default, only the following
# classes are allowed to be deserialized:
#
# * TrueClass
# * FalseClass
# * NilClass
# * Numeric
# * String
# * Array
# * Hash
#
# Recursive data structures are not allowed by default. Arbitrary classes
2018-11-10 19:20:27 -05:00
# can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are
2013-05-14 13:26:41 -04:00
# additive. For example, to allow Date deserialization:
#
2018-11-10 19:20:27 -05:00
# Psych.safe_load(yaml, permitted_classes: [Date])
2013-05-14 13:26:41 -04:00
#
# Now the Date class can be loaded in addition to the classes listed above.
#
2018-08-26 20:44:04 -04:00
# Aliases can be explicitly allowed by changing the +aliases+ keyword argument.
2013-05-14 13:26:41 -04:00
# For example:
#
# x = []
# x << x
# yaml = Psych.dump x
# Psych.safe_load yaml # => raises an exception
2018-08-26 20:44:04 -04:00
# Psych.safe_load yaml, aliases: true # => loads the aliases
2013-05-14 13:26:41 -04:00
#
# A Psych::DisallowedClass exception will be raised if the yaml contains a
2018-11-10 19:20:27 -05:00
# class that isn't in the +permitted_classes+ list.
2013-05-14 13:26:41 -04:00
#
# A Psych::BadAlias exception will be raised if the yaml contains aliases
2018-08-26 20:44:04 -04:00
# but the +aliases+ keyword argument is set to false.
2017-12-19 04:44:33 -05:00
#
# +filename+ will be used in the exception message if any exception is raised
# while parsing.
#
# When the optional +symbolize_names+ keyword argument is set to a
# true value, returns symbols for keys in Hash objects (default: strings).
#
# Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
# Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
#
2018-11-10 19:20:27 -05:00
def self . safe_load yaml , legacy_permitted_classes = NOT_GIVEN , legacy_permitted_symbols = NOT_GIVEN , legacy_aliases = NOT_GIVEN , legacy_filename = NOT_GIVEN , permitted_classes : [ ] , permitted_symbols : [ ] , aliases : false , filename : nil , fallback : nil , symbolize_names : false
if legacy_permitted_classes != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing permitted_classes with the 2nd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_classes: ...) instead.' , uplevel : 1 if $VERBOSE
2018-11-10 19:20:27 -05:00
permitted_classes = legacy_permitted_classes
2018-08-26 20:44:04 -04:00
end
2018-11-10 19:20:27 -05:00
if legacy_permitted_symbols != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing permitted_symbols with the 3rd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_symbols: ...) instead.' , uplevel : 1 if $VERBOSE
2018-11-10 19:20:27 -05:00
permitted_symbols = legacy_permitted_symbols
2018-08-26 20:44:04 -04:00
end
if legacy_aliases != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing aliases with the 4th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, aliases: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
aliases = legacy_aliases
end
if legacy_filename != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing filename with the 5th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, filename: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
filename = legacy_filename
end
result = parse ( yaml , filename : filename )
return fallback unless result
2013-05-14 13:26:41 -04:00
2018-11-10 19:20:27 -05:00
class_loader = ClassLoader :: Restricted . new ( permitted_classes . map ( & :to_s ) ,
permitted_symbols . map ( & :to_s ) )
2013-05-14 13:26:41 -04:00
scanner = ScalarScanner . new class_loader
2018-08-26 20:44:04 -04:00
visitor = if aliases
Visitors :: ToRuby . new scanner , class_loader
else
Visitors :: NoAliasRuby . new scanner , class_loader
end
2017-11-30 20:52:26 -05:00
result = visitor . accept result
symbolize_names! ( result ) if symbolize_names
result
2013-05-14 13:26:41 -04:00
end
2010-03-28 17:49:37 -04:00
###
2013-02-28 19:18:50 -05:00
# Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document.
2011-12-06 18:12:37 -05:00
# +filename+ is used in the exception message if a Psych::SyntaxError is
# raised.
#
# Raises a Psych::SyntaxError when a YAML syntax error is detected.
2010-03-28 17:49:37 -04:00
#
# Example:
#
2013-02-28 19:18:50 -05:00
# Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00>
2010-03-28 17:49:37 -04:00
#
2011-12-06 18:12:37 -05:00
# begin
2018-08-26 20:44:04 -04:00
# Psych.parse("--- `", filename: "file.txt")
2011-12-06 18:12:37 -05:00
# rescue Psych::SyntaxError => ex
# ex.file # => 'file.txt'
2013-01-03 01:13:56 -05:00
# ex.message # => "(file.txt): found character that cannot start any token"
2011-12-06 18:12:37 -05:00
# end
#
2010-03-28 17:49:37 -04:00
# See Psych::Nodes for more information about YAML AST.
2018-08-26 20:44:04 -04:00
def self . parse yaml , legacy_filename = NOT_GIVEN , filename : nil , fallback : NOT_GIVEN
if legacy_filename != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse is deprecated. Use keyword argument like Psych.parse(yaml, filename: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
filename = legacy_filename
end
parse_stream ( yaml , filename : filename ) do | node |
2012-03-08 16:31:05 -05:00
return node
end
2018-08-26 20:44:04 -04:00
if fallback != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing the `fallback` keyword argument of Psych.parse is deprecated.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
fallback
else
false
end
2010-03-28 17:49:37 -04:00
end
###
2013-02-28 19:18:50 -05:00
# Parse a file at +filename+. Returns the Psych::Nodes::Document.
2011-12-06 18:12:37 -05:00
#
# Raises a Psych::SyntaxError when a YAML syntax error is detected.
2018-08-26 20:44:04 -04:00
def self . parse_file filename , fallback : false
result = File . open filename , 'r:bom|utf-8' do | f |
parse f , filename : filename
2010-03-28 17:49:37 -04:00
end
2018-08-26 20:44:04 -04:00
result || fallback
2010-03-28 17:49:37 -04:00
end
###
# Returns a default parser
def self . parser
Psych :: Parser . new ( TreeBuilder . new )
end
###
2013-02-28 19:18:50 -05:00
# Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream.
2010-03-28 17:49:37 -04:00
# This method can handle multiple YAML documents contained in +yaml+.
2011-12-06 18:12:37 -05:00
# +filename+ is used in the exception message if a Psych::SyntaxError is
# raised.
#
2012-03-08 16:21:52 -05:00
# If a block is given, a Psych::Nodes::Document node will be yielded to the
# block as it's being parsed.
#
2011-12-06 18:12:37 -05:00
# Raises a Psych::SyntaxError when a YAML syntax error is detected.
2010-03-28 17:49:37 -04:00
#
# Example:
#
2010-03-29 16:33:22 -04:00
# Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00>
2010-03-28 17:49:37 -04:00
#
2012-03-08 16:21:52 -05:00
# Psych.parse_stream("--- a\n--- b") do |node|
# node # => #<Psych::Nodes::Document:0x00>
# end
#
2011-12-06 18:12:37 -05:00
# begin
2018-08-26 20:44:04 -04:00
# Psych.parse_stream("--- `", filename: "file.txt")
2011-12-06 18:12:37 -05:00
# rescue Psych::SyntaxError => ex
# ex.file # => 'file.txt'
2013-01-03 01:13:56 -05:00
# ex.message # => "(file.txt): found character that cannot start any token"
2011-12-06 18:12:37 -05:00
# end
#
2018-08-26 20:44:04 -04:00
# Raises a TypeError when NilClass is passed.
#
2010-03-28 17:49:37 -04:00
# See Psych::Nodes for more information about YAML AST.
2018-08-26 20:44:04 -04:00
def self . parse_stream yaml , legacy_filename = NOT_GIVEN , filename : nil , & block
if legacy_filename != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse_stream is deprecated. Use keyword argument like Psych.parse_stream(yaml, filename: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
filename = legacy_filename
end
2012-03-08 16:21:52 -05:00
if block_given?
parser = Psych :: Parser . new ( Handlers :: DocumentStream . new ( & block ) )
parser . parse yaml , filename
else
parser = self . parser
parser . parse yaml , filename
parser . handler . root
end
2010-03-28 17:49:37 -04:00
end
###
2010-07-07 19:05:45 -04:00
# call-seq:
# Psych.dump(o) -> string of yaml
# Psych.dump(o, options) -> string of yaml
# Psych.dump(o, io) -> io object passed in
# Psych.dump(o, io, options) -> io object passed in
#
# Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
# to control the output format. If an IO object is passed in, the YAML will
# be dumped to that IO object.
2010-03-28 17:49:37 -04:00
#
2018-04-27 21:47:58 -04:00
# Currently supported options are:
#
# [<tt>:indentation</tt>] Number of space characters used to indent.
# Acceptable value should be in <tt>0..9</tt> range,
# otherwise option is ignored.
#
# Default: <tt>2</tt>.
# [<tt>:line_width</tt>] Max character to wrap line at.
#
# Default: <tt>0</tt> (meaning "wrap at 81").
# [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
# strictly formal).
#
# Default: <tt>false</tt>.
# [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document.
#
# Default: <tt>false</tt>.
#
2010-03-28 17:49:37 -04:00
# Example:
#
2010-07-07 19:05:45 -04:00
# # Dump an array, get back a YAML string
2010-03-28 17:49:37 -04:00
# Psych.dump(['a', 'b']) # => "---\n- a\n- b\n"
2010-07-07 19:05:45 -04:00
#
# # Dump an array to an IO object
# Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
#
# # Dump an array with indentation set
2018-04-27 21:47:58 -04:00
# Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n"
2010-07-07 19:05:45 -04:00
#
# # Dump an array to an IO with indentation set
2018-04-27 21:47:58 -04:00
# Psych.dump(['a', ['b']], StringIO.new, indentation: 3)
2010-03-31 17:09:58 -04:00
def self . dump o , io = nil , options = { }
if Hash === io
options = io
io = nil
end
2013-05-14 13:26:41 -04:00
visitor = Psych :: Visitors :: YAMLTree . create options
2010-03-28 17:49:37 -04:00
visitor << o
2011-10-03 17:31:43 -04:00
visitor . tree . yaml io , options
2010-03-28 17:49:37 -04:00
end
###
# Dump a list of objects as separate documents to a document stream.
#
# Example:
#
# Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
def self . dump_stream * objects
2013-05-14 13:26:41 -04:00
visitor = Psych :: Visitors :: YAMLTree . create ( { } )
2010-03-28 17:49:37 -04:00
objects . each do | o |
visitor << o
end
2011-10-03 17:31:43 -04:00
visitor . tree . yaml
2010-03-28 17:49:37 -04:00
end
###
2013-05-14 12:58:50 -04:00
# Dump Ruby +object+ to a JSON string.
def self . to_json object
2013-05-14 13:26:41 -04:00
visitor = Psych :: Visitors :: JSONTree . create
2013-05-14 12:58:50 -04:00
visitor << object
2011-10-03 17:31:43 -04:00
visitor . tree . yaml
2010-03-28 17:49:37 -04:00
end
###
# Load multiple documents given in +yaml+. Returns the parsed documents
2013-07-18 22:27:25 -04:00
# as a list. If a block is given, each document will be converted to Ruby
2012-03-08 16:21:52 -05:00
# and passed to the block during parsing
#
# Example:
2010-03-28 17:49:37 -04:00
#
2010-04-23 20:20:08 -04:00
# Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
2010-03-28 17:49:37 -04:00
#
2012-03-08 16:21:52 -05:00
# list = []
# Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby|
# list << ruby
# end
# list # => ['foo', 'bar']
#
2018-08-26 20:44:04 -04:00
def self . load_stream yaml , legacy_filename = NOT_GIVEN , filename : nil , fallback : [ ]
if legacy_filename != NOT_GIVEN
2018-12-04 07:24:12 -05:00
warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load_stream is deprecated. Use keyword argument like Psych.load_stream(yaml, filename: ...) instead.' , uplevel : 1 if $VERBOSE
2018-08-26 20:44:04 -04:00
filename = legacy_filename
2012-03-08 16:21:52 -05:00
end
2018-08-26 20:44:04 -04:00
result = if block_given?
parse_stream ( yaml , filename : filename ) do | node |
yield node . to_ruby
end
else
parse_stream ( yaml , filename : filename ) . children . map ( & :to_ruby )
end
return fallback if result . is_a? ( Array ) && result . empty?
result
2010-03-28 17:49:37 -04:00
end
###
# Load the document contained in +filename+. Returns the yaml contained in
2016-06-24 05:06:08 -04:00
# +filename+ as a Ruby object, or if the file is empty, it returns
2018-04-27 21:47:58 -04:00
# the specified +fallback+ return value, which defaults to +false+.
2017-12-19 04:44:33 -05:00
def self . load_file filename , fallback : false
2016-06-24 05:06:08 -04:00
File . open ( filename , 'r:bom|utf-8' ) { | f |
2018-08-26 20:44:04 -04:00
self . load f , filename : filename , fallback : fallback
2016-06-24 05:06:08 -04:00
}
2010-03-28 17:49:37 -04:00
end
# :stopdoc:
@domain_types = { }
def self . add_domain_type domain , type_tag , & block
2010-04-24 00:11:27 -04:00
key = [ 'tag' , domain , type_tag ] . join ':'
@domain_types [ key ] = [ key , block ]
@domain_types [ " tag: #{ type_tag } " ] = [ key , block ]
2010-03-28 17:49:37 -04:00
end
def self . add_builtin_type type_tag , & block
2010-04-24 00:11:27 -04:00
domain = 'yaml.org,2002'
key = [ 'tag' , domain , type_tag ] . join ':'
@domain_types [ key ] = [ key , block ]
end
2010-03-28 17:49:37 -04:00
def self . remove_type type_tag
@domain_types . delete type_tag
end
@load_tags = { }
@dump_tags = { }
def self . add_tag tag , klass
2013-05-14 13:26:41 -04:00
@load_tags [ tag ] = klass . name
2010-03-28 17:49:37 -04:00
@dump_tags [ klass ] = tag
end
2017-11-26 22:11:18 -05:00
def self . symbolize_names! ( result )
case result
when Hash
result . keys . each do | key |
result [ key . to_sym ] = symbolize_names! ( result . delete ( key ) )
end
when Array
result . map! { | r | symbolize_names! ( r ) }
end
result
end
private_class_method :symbolize_names!
2018-12-04 07:24:12 -05:00
# Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
def self . warn_with_uplevel ( message , uplevel : 1 )
at = parse_caller ( caller [ uplevel ] ) . join ( ':' )
warn " #{ at } : #{ message } "
end
def self . parse_caller ( at )
if / ^(.+?):( \ d+)(?::in `.*')? / =~ at
file = $1
line = $2 . to_i
[ file , line ]
end
end
private_class_method :warn_with_uplevel , :parse_caller
2010-03-28 17:49:37 -04:00
class << self
attr_accessor :load_tags
attr_accessor :dump_tags
attr_accessor :domain_types
end
# :startdoc:
end