YAML(tm) (rhymes with ‘camel’) is a straightforward machine parsable data serialization format designed for human readability and interaction with scripting languages such as Perl and Python. YAML is optimized for data serialization, formatted dumping, configuration files, log files, Internet messaging and filtering. This specification describes the YAML information model and serialization format. Together with the Unicode standard for characters, it provides all the information necessary to understand YAML Version 1.0 and construct computer programs to process it.
See yaml.org/ for more information. For a quick tutorial, please visit YAML In Five Minutes (yaml.kwiki.org/?YamlInFiveMinutes).
The YAML 1.0 specification outlines four stages of YAML loading and dumping. This library honors all four of those stages, although data is really only available to you in three stages.
The four stages are: native, representation, serialization, and presentation.
The native stage refers to data which has been loaded completely into Ruby‘s own types. (See +YAML::load+.)
The representation stage means data which has been composed into +YAML::BaseNode+ objects. In this stage, the document is available as a tree of node objects. You can perform YPath queries and transformations at this level. (See +YAML::parse+.)
The serialization stage happens inside the parser. The YAML parser used in Ruby is called Syck. Serialized nodes are available in the extension as SyckNode structs.
The presentation stage is the YAML document itself. This is accessible to you as a string. (See +YAML::dump+.)
For more information about the various information models, see Chapter 3 of the YAML 1.0 Specification (yaml.org/spec/#id2491269).
The YAML module provides quick access to the most common loading (YAML::load) and dumping (YAML::dump) tasks. This module also provides an API for registering global types (YAML::add_domain_type).
A simple round-trip (load and dump) of an object.
require "yaml" test_obj = ["dogs", "cats", "badgers"] yaml_obj = YAML::dump( test_obj ) # -> --- - dogs - cats - badgers ruby_obj = YAML::load( yaml_obj ) # => ["dogs", "cats", "badgers"] ruby_obj == test_obj # => true
To register your custom types with the global resolver, use add_domain_type.
YAML::add_domain_type( "your-site.com,2004", "widget" ) do |type, val| Widget.new( val ) end
ERROR_NO_HEADER_NODE | = | "With UseHeader=false, the node Array or Hash must have elements" | Error messages | |
ERROR_NEED_HEADER | = | "With UseHeader=false, the node must be an Array or Hash" | ||
ERROR_BAD_EXPLICIT | = | "Unsupported explicit transfer: '%s'" | ||
ERROR_MANY_EXPLICIT | = | "More than one explicit transfer" | ||
ERROR_MANY_IMPLICIT | = | "More than one implicit request" | ||
ERROR_NO_ANCHOR | = | "No anchor for alias '%s'" | ||
ERROR_BAD_ANCHOR | = | "Invalid anchor: %s" | ||
ERROR_MANY_ANCHOR | = | "More than one anchor" | ||
ERROR_ANCHOR_ALIAS | = | "Can't define both an anchor and an alias" | ||
ERROR_BAD_ALIAS | = | "Invalid alias: %s" | ||
ERROR_MANY_ALIAS | = | "More than one alias" | ||
ERROR_ZERO_INDENT | = | "Can't use zero as an indentation width" | ||
ERROR_UNSUPPORTED_VERSION | = | "This release of YAML.rb does not support YAML version %s" | ||
ERROR_UNSUPPORTED_ENCODING | = | "Attempt to use unsupported encoding: %s" | ||
VERSION | = | '0.60' | Constants | |
SUPPORTED_YAML_VERSIONS | = | ['1.0'] | ||
WORD_CHAR | = | 'A-Za-z0-9' | Parser tokens | |
PRINTABLE_CHAR | = | '-_A-Za-z0-9!?/()$\'". ' | ||
NOT_PLAIN_CHAR | = | '\x7f\x0-\x1f\x80-\x9f' | ||
ESCAPE_CHAR | = | '[\\x00-\\x09\\x0b-\\x1f]' | ||
INDICATOR_CHAR | = | '*&!|\\\\^@%{}[]=' | ||
SPACE_INDICATORS | = | '-#:,?' | ||
RESTRICTED_INDICATORS | = | '#:,}]' | ||
DNS_COMP_RE | = | "\\w(?:[-\\w]*\\w)?" | ||
DNS_NAME_RE | = | "(?:(?:#{DNS_COMP_RE}\\.)+#{DNS_COMP_RE}|#{DNS_COMP_RE})" | ||
ESCAPES | = | %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f } | ||
UNESCAPES | = | { 'a' => "\x07", 'b' => "\x08", 't' => "\x09", 'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c", 'r' => "\x0d", 'e' => "\x1b", '\\' => '\\', } | ||
DEFAULTS | = | { :Indent => 2, :UseHeader => false, :UseVersion => false, :Version => '1.0', :SortKeys => false, :AnchorFormat => 'id%03d', :ExplicitTypes => false, :WidthType => 'absolute', :BestWidth => 80, :UseBlock => false, :UseFold => false, :Encoding => :None | Default settings | |
Resolver | = | YAML::Syck::Resolver | ||
DefaultResolver | = | YAML::Syck::DefaultResolver | ||
GenericResolver | = | YAML::Syck::GenericResolver | ||
Parser | = | YAML::Syck::Parser | ||
Emitter | = | YAML::Syck::Emitter |
Add a private document type
# File lib/yaml.rb, line 320 320: def YAML.add_private_type( type_re, &transfer_proc ) 321: resolver.add_type( "x-private:" + type_re, transfer_proc ) 322: end
Detect typing of a string
# File lib/yaml.rb, line 327 327: def YAML.detect_implicit( val ) 328: resolver.detect_implicit( val ) 329: end
Converts obj to YAML and writes the YAML result to io.
File.open( 'animals.yaml', 'w' ) do |out| YAML.dump( ['badger', 'elephant', 'tiger'], out ) end
If no io is provided, a string containing the dumped YAML is returned.
YAML.dump( :locked ) #=> "--- :locked"
# File lib/yaml.rb, line 116 116: def YAML.dump( obj, io = nil ) 117: obj.to_yaml( io || io2 = StringIO.new ) 118: io || ( io2.rewind; io2.read ) 119: end
Returns a YAML stream containing each of the items in objs, each having their own document.
YAML.dump_stream( 0, [], {} ) #=> --- 0 --- [] --- {}
# File lib/yaml.rb, line 288 288: def YAML.dump_stream( *objs ) 289: d = YAML::Stream.new 290: objs.each do |doc| 291: d.add( doc ) 292: end 293: d.emit 294: end
Calls block with each consecutive document in the YAML stream contained in io.
File.open( 'many-docs.yaml' ) do |yf| YAML.each_document( yf ) do |ydoc| ## ydoc contains the single object ## from the YAML document end end
# File lib/yaml.rb, line 216 216: def YAML.each_document( io, &block ) 217: yp = parser.load_documents( io, &block ) 218: end
Calls block with a tree of +YAML::BaseNodes+, one tree for each consecutive document in the YAML stream contained in io.
File.open( 'many-docs.yaml' ) do |yf| YAML.each_node( yf ) do |ydoc| ## ydoc contains a tree of nodes ## from the YAML document end end
# File lib/yaml.rb, line 246 246: def YAML.each_node( io, &doc_proc ) 247: yp = generic_parser.load_documents( io, &doc_proc ) 248: end
Escape the string, condensing common escapes
# File lib/yaml/encoding.rb, line 10 10: def YAML.escape( value, skip = "" ) 11: value.gsub( /\\/, "\\\\\\" ). 12: gsub( /"/, "\\\"" ). 13: gsub( /([\x00-\x1f])/ ) do 14: skip[$&] || ESCAPES[ $&.unpack("C")[0] ] 15: end 16: end
Load a document from the current io stream.
File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } #=> ['badger', 'elephant', 'tiger']
Can also load from a string.
YAML.load( "--- :locked" ) #=> :locked
# File lib/yaml.rb, line 132 132: def YAML.load( io ) 133: yp = parser.load( io ) 134: end
Calls block with each consecutive document in the YAML stream contained in io.
File.open( 'many-docs.yaml' ) do |yf| YAML.load_documents( yf ) do |ydoc| ## ydoc contains the single object ## from the YAML document end end
# File lib/yaml.rb, line 231 231: def YAML.load_documents( io, &doc_proc ) 232: YAML.each_document( io, &doc_proc ) 233: end
Load a document from the file located at filepath.
YAML.load_file( 'animals.yaml' ) #=> ['badger', 'elephant', 'tiger']
# File lib/yaml.rb, line 142 142: def YAML.load_file( filepath ) 143: File.open( filepath ) do |f| 144: load( f ) 145: end 146: end
Loads all documents from the current io stream, returning a +YAML::Stream+ object containing all loaded documents.
# File lib/yaml.rb, line 270 270: def YAML.load_stream( io ) 271: d = nil 272: parser.load_documents( io ) do |doc| 273: d = YAML::Stream.new if not d 274: d.add( doc ) 275: end 276: return d 277: end
Class method for creating streams
# File lib/yaml/stringio.rb, line 55 55: def YAML.make_stream( io ) 56: if String === io 57: io = StringIO.new( io ) 58: elsif not IO === io 59: raise YAML::Error, "YAML stream must be an IO or String object." 60: end 61: if YAML::unicode 62: def io.readline 63: YAML.utf_to_internal( readline( @ln_sep ), @utf_encoding ) 64: end 65: def io.check_unicode 66: @utf_encoding = YAML.sniff_encoding( read( 4 ) ) 67: @ln_sep = YAML.enc_separator( @utf_encoding ) 68: seek( -4, IO::SEEK_CUR ) 69: end 70: def io.utf_encoding 71: @utf_encoding 72: end 73: io.check_unicode 74: else 75: def io.utf_encoding 76: :None 77: end 78: end 79: io 80: end
Allocate blank object
# File lib/yaml.rb, line 365 365: def YAML.object_maker( obj_class, val ) 366: if Hash === val 367: o = obj_class.allocate 368: val.each_pair { |k,v| 369: o.instance_variable_set("@#{k}", v) 370: } 371: o 372: else 373: raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect 374: end 375: end
Parse the first document from the current io stream
File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) } #=> #<YAML::Syck::Node:0x82ccce0 @kind=:seq, @value= [#<YAML::Syck::Node:0x82ccd94 @kind=:scalar, @type_id="str", @value="badger">, #<YAML::Syck::Node:0x82ccd58 @kind=:scalar, @type_id="str", @value="elephant">, #<YAML::Syck::Node:0x82ccd1c @kind=:scalar, @type_id="str", @value="tiger">]>
Can also load from a string.
YAML.parse( "--- :locked" ) #=> #<YAML::Syck::Node:0x82edddc @type_id="tag:ruby.yaml.org,2002:sym", @value=":locked", @kind=:scalar>
# File lib/yaml.rb, line 175 175: def YAML.parse( io ) 176: yp = generic_parser.load( io ) 177: end
Calls block with a tree of +YAML::BaseNodes+, one tree for each consecutive document in the YAML stream contained in io.
File.open( 'many-docs.yaml' ) do |yf| YAML.parse_documents( yf ) do |ydoc| ## ydoc contains a tree of nodes ## from the YAML document end end
# File lib/yaml.rb, line 261 261: def YAML.parse_documents( io, &doc_proc ) 262: YAML.each_node( io, &doc_proc ) 263: end
Parse a document from the file located at filepath.
YAML.parse_file( 'animals.yaml' ) #=> #<YAML::Syck::Node:0x82ccce0 @kind=:seq, @value= [#<YAML::Syck::Node:0x82ccd94 @kind=:scalar, @type_id="str", @value="badger">, #<YAML::Syck::Node:0x82ccd58 @kind=:scalar, @type_id="str", @value="elephant">, #<YAML::Syck::Node:0x82ccd1c @kind=:scalar, @type_id="str", @value="tiger">]>
# File lib/yaml.rb, line 199 199: def YAML.parse_file( filepath ) 200: File.open( filepath ) do |f| 201: parse( f ) 202: end 203: end
Allocate an Emitter if needed
# File lib/yaml.rb, line 380 380: def YAML.quick_emit( oid, opts = {}, &e ) 381: out = 382: if opts.is_a? YAML::Emitter 383: opts 384: else 385: emitter.reset( opts ) 386: end 387: oid = 388: case oid when Fixnum, NilClass; oid 389: else oid = "#{oid.object_id}-#{oid.hash}" 390: end 391: out.emit( oid, &e ) 392: end
Method to extract colon-seperated type and class, returning the type and the constant of the class
# File lib/yaml.rb, line 356 356: def YAML.read_type_class( type, obj_class ) 357: scheme, domain, type, tclass = type.split( ':', 4 ) 358: tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass 359: return [ type, obj_class ] 360: end
Associates a taguri tag with a Ruby class cls. The taguri is used to give types to classes when loading YAML. Taguris are of the form:
tag:authorityName,date:specific
The authorityName is a domain name or email address. The date is the date the type was issued in YYYY or YYYY-MM or YYYY-MM-DD format. The specific is a name for the type being added.
For example, built-in YAML types have ‘yaml.org’ as the authorityName and ‘2002’ as the date. The specific is simply the name of the type:
tag:yaml.org,2002:int tag:yaml.org,2002:float tag:yaml.org,2002:timestamp
The domain must be owned by you on the date declared. If you don‘t own any domains on the date you declare the type, you can simply use an e-mail address.
tag:why@ruby-lang.org,2004:notes/personal
# File lib/yaml/tag.rb, line 35 35: def YAML.tag_class( tag, cls ) 36: if @@tagged_classes.has_key? tag 37: warn "class #{ @@tagged_classes[tag] } held ownership of the #{ tag } tag" 38: end 39: @@tagged_classes[tag] = cls 40: end
Returns the complete dictionary of taguris, paired with classes. The key for the dictionary is the full taguri. The value for each key is the class constant associated to that taguri.
YAML.tagged_classes["tag:yaml.org,2002:int"] => Integer
# File lib/yaml/tag.rb, line 48 48: def YAML.tagged_classes 49: @@tagged_classes 50: end
Convert a type_id to a taguri
# File lib/yaml.rb, line 334 334: def YAML.tagurize( val ) 335: resolver.tagurize( val ) 336: end
Apply any implicit a node may qualify for
# File lib/yaml.rb, line 348 348: def YAML.try_implicit( obj ) 349: YAML.transfer( YAML.detect_implicit( obj ), obj ) 350: end
Unescape the condenses escapes
# File lib/yaml/encoding.rb, line 21 21: def YAML.unescape( value ) 22: value.gsub( /\\(?:([nevfbart\\])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { 23: if $3 24: ["#$3".hex ].pack('U*') 25: elsif $2 26: [$2].pack( "H2" ) 27: else 28: UNESCAPES[$1] 29: end 30: } 31: end