ruby-changes:15230
From: nobu <ko1@a...>
Date: Tue, 30 Mar 2010 19:47:09 +0900 (JST)
Subject: [ruby-changes:15230] Ruby:r27112 (trunk): * ext/psych/lib: moved external library dependent files from lib.
nobu 2010-03-30 19:46:06 +0900 (Tue, 30 Mar 2010) New Revision: 27112 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27112 Log: * ext/psych/lib: moved external library dependent files from lib. [ruby-core:29129] Added directories: trunk/ext/psych/lib/ trunk/ext/psych/lib/psych/ trunk/ext/psych/lib/psych/nodes/ trunk/ext/psych/lib/psych/visitors/ Added files: trunk/ext/psych/lib/psych/coder.rb trunk/ext/psych/lib/psych/core_ext.rb trunk/ext/psych/lib/psych/emitter.rb trunk/ext/psych/lib/psych/handler.rb trunk/ext/psych/lib/psych/nodes/alias.rb trunk/ext/psych/lib/psych/nodes/document.rb trunk/ext/psych/lib/psych/nodes/mapping.rb trunk/ext/psych/lib/psych/nodes/node.rb trunk/ext/psych/lib/psych/nodes/scalar.rb trunk/ext/psych/lib/psych/nodes/sequence.rb trunk/ext/psych/lib/psych/nodes/stream.rb trunk/ext/psych/lib/psych/nodes.rb trunk/ext/psych/lib/psych/omap.rb trunk/ext/psych/lib/psych/parser.rb trunk/ext/psych/lib/psych/scalar_scanner.rb trunk/ext/psych/lib/psych/set.rb trunk/ext/psych/lib/psych/tree_builder.rb trunk/ext/psych/lib/psych/visitors/emitter.rb trunk/ext/psych/lib/psych/visitors/json_tree.rb trunk/ext/psych/lib/psych/visitors/to_ruby.rb trunk/ext/psych/lib/psych/visitors/visitor.rb trunk/ext/psych/lib/psych/visitors/yaml_tree.rb trunk/ext/psych/lib/psych/visitors.rb trunk/ext/psych/lib/psych.rb Removed files: trunk/lib/psych/coder.rb trunk/lib/psych/core_ext.rb trunk/lib/psych/emitter.rb trunk/lib/psych/handler.rb trunk/lib/psych/nodes/alias.rb trunk/lib/psych/nodes/document.rb trunk/lib/psych/nodes/mapping.rb trunk/lib/psych/nodes/node.rb trunk/lib/psych/nodes/scalar.rb trunk/lib/psych/nodes/sequence.rb trunk/lib/psych/nodes/stream.rb trunk/lib/psych/nodes.rb trunk/lib/psych/omap.rb trunk/lib/psych/parser.rb trunk/lib/psych/scalar_scanner.rb trunk/lib/psych/set.rb trunk/lib/psych/tree_builder.rb trunk/lib/psych/visitors/emitter.rb trunk/lib/psych/visitors/json_tree.rb trunk/lib/psych/visitors/to_ruby.rb trunk/lib/psych/visitors/visitor.rb trunk/lib/psych/visitors/yaml_tree.rb trunk/lib/psych/visitors.rb trunk/lib/psych.rb Modified files: trunk/ChangeLog Index: ChangeLog =================================================================== --- ChangeLog (revision 27111) +++ ChangeLog (revision 27112) @@ -1,3 +1,8 @@ +Tue Mar 30 19:46:00 2010 Nobuyoshi Nakada <nobu@r...> + + * ext/psych/lib: moved external library dependent files from lib. + [ruby-core:29129] + Tue Mar 30 18:25:52 2010 Nobuyoshi Nakada <nobu@r...> * file.c (rb_file_dirname): split from rb_file_s_dirname. Index: lib/psych.rb =================================================================== --- lib/psych.rb (revision 27111) +++ lib/psych.rb (revision 27112) @@ -1,238 +0,0 @@ -require 'psych/psych' -require 'psych/nodes' -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' - -### -# = Overview -# -# Psych is a YAML parser and emitter. Psych leverages -# libyaml[http://libyaml.org] for it's YAML parsing 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. -# -# = 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, -# and at the highest level is the ability to unmarshal YAML to ruby objects. -# -# === Low level 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 -# automatic detection and conversion to ruby objects. See Psych::Parser for -# more information on using the event based parser. -# -# === Mid level parsing -# -# 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. -# -# === High level 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 -# -# == YAML Emitting -# -# 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. -# -# === Low level 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. -# -# === Mid level emitting -# -# 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. -# -# === High level 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. - -module Psych - # The version is Psych you're using - VERSION = '1.0.0' - - # The version of libyaml Psych is using - LIBYAML_VERSION = Psych.libyaml_version.join '.' - - ### - # Load +yaml+ in to a Ruby data structure. If multiple documents are - # provided, the object contained in the first document will be returned. - # - # Example: - # - # Psych.load("--- a") # => 'a' - # Psych.load("---\n - a\n - b") # => ['a', 'b'] - def self.load yaml - result = parse(yaml) - result ? result.to_ruby : result - end - - ### - # Parse a YAML string in +yaml+. Returns the first object of a YAML AST. - # - # Example: - # - # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00> - # - # See Psych::Nodes for more information about YAML AST. - def self.parse yaml - children = parse_stream(yaml).children - children.empty? ? false : children.first.children.first - end - - ### - # Parse a file at +filename+. Returns the YAML AST. - def self.parse_file filename - File.open filename do |f| - parse f - end - end - - ### - # Returns a default parser - def self.parser - Psych::Parser.new(TreeBuilder.new) - end - - ### - # Parse a YAML string in +yaml+. Returns the full AST for the YAML document. - # This method can handle multiple YAML documents contained in +yaml+. - # - # Example: - # - # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00> - # - # See Psych::Nodes for more information about YAML AST. - def self.parse_stream yaml - parser = self.parser - parser.parse yaml - parser.handler.root - end - - ### - # Dump Ruby object +o+ to a YAML string using +options+. - # - # Example: - # - # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" - def self.dump o, options = {} - visitor = Psych::Visitors::YAMLTree.new options - visitor << o - visitor.tree.to_yaml - 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 - visitor = Psych::Visitors::YAMLTree.new {} - objects.each do |o| - visitor << o - end - visitor.tree.to_yaml - end - - ### - # Dump Ruby object +o+ to a JSON string. - def self.to_json o - visitor = Psych::Visitors::JSONTree.new(:json => true) - visitor << o - visitor.tree.to_yaml - end - - ### - # Load multiple documents given in +yaml+. Returns the parsed documents - # as a list. For example: - # - # Psych.load_documents("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] - # - def self.load_stream yaml - parse_stream(yaml).children.map { |child| child.to_ruby } - end - - def self.load_documents yaml, &block - if $VERBOSE - warn "#{caller[0]}: load_documents is deprecated, use load_stream" - end - list = load_stream yaml - return list unless block_given? - list.each(&block) - end - - ### - # Load the document contained in +filename+. Returns the yaml contained in - # +filename+ as a ruby object - def self.load_file filename - self.load File.open(filename) - end - - # :stopdoc: - @domain_types = {} - def self.add_domain_type domain, type_tag, &block - @domain_types[type_tag] = ["http://#{domain}", block] - end - - def self.add_builtin_type type_tag, &block - @domain_types[type_tag] = ['yaml.org', block] - end - - def self.remove_type type_tag - @domain_types.delete type_tag - end - - @load_tags = {} - @dump_tags = {} - def self.add_tag tag, klass - @load_tags[tag] = klass - @dump_tags[klass] = tag - end - - class << self - attr_accessor :load_tags - attr_accessor :dump_tags - attr_accessor :domain_types - end - - # :startdoc: -end Index: lib/psych/handler.rb =================================================================== --- lib/psych/handler.rb (revision 27111) +++ lib/psych/handler.rb (revision 27112) @@ -1,215 +0,0 @@ -module Psych - ### - # Psych::Handler is an abstract base class that defines the events used - # when dealing with Psych::Parser. Clients who want to use Psych::Parser - # should implement a class that inherits from Psych::Handler and define - # events that they can handle. - # - # Psych::Handler defines all events that Psych::Parser can possibly send to - # event handlers. - # - # See Psych::Parser for more details - class Handler - ### - # Called with +encoding+ when the YAML stream starts. This method is - # called once per stream. A stream may contain multiple documents. - # - # See the constants in Psych::Parser for the possible values of +encoding+. - def start_stream encoding - end - - ### - # Called when the document starts with the declared +version+, - # +tag_directives+, if the document is +implicit+. - # - # +version+ will be an array of integers indicating the YAML version being - # dealt with, +tag_directives+ is a list of tuples indicating the prefix - # and suffix of each tag, and +implicit+ is a boolean indicating whether - # the document is started implicitly. - # - # === Example - # - # Given the following YAML: - # - # %YAML 1.1 - # %TAG ! tag:tenderlovemaking.com,2009: - # --- !squee - # - # The parameters for start_document must be this: - # - # version # => [1, 1] - # tag_directives # => [["!", "tag:tenderlovemaking.com,2009:"]] - # implicit # => false - def start_document version, tag_directives, implicit - end - - ### - # Called with the document ends. +implicit+ is a boolean value indicating - # whether or not the document has an implicit ending. - # - # === Example - # - # Given the following YAML: - # - # --- - # hello world - # - # +implicit+ will be true. Given this YAML: - # - # --- - # hello world - # ... - # - # +implicit+ will be false. - def end_document implicit - end - - ### - # Called when an alias is found to +anchor+. +anchor+ will be the name - # of the anchor found. - # - # === Example - # - # Here we have an example of an array that references itself in YAML: - # - # --- &ponies - # - first element - # - *ponies - # - # &ponies is the achor, *ponies is the alias. In this case, alias is - # called with "ponies". - def alias anchor - end - - ### - # Called when a scalar +value+ is found. The scalar may have an - # +anchor+, a +tag+, be implicitly +plain+ or implicitly +quoted+ - # - # +value+ is the string value of the scalar - # +anchor+ is an associated anchor or nil - # +tag+ is an associated tag or nil - # +plain+ is a boolean value - # +quoted+ is a boolean value - # +style+ is an integer idicating the string style - # - # See the constants in Psych::Nodes::Scalar for the possible values of - # +style+ - # - # === Example - # - # Here is a YAML document that exercises most of the possible ways this - # method can be called: - # - # --- - # - !str "foo" - # - &anchor fun - # - many - # lines - # - | - # many - # newlines - # - # The above YAML document contains a list with four strings. Here are - # the parameters sent to this method in the same order: - # - # # value anchor tag plain quoted style - # ["foo", nil, "!str", false, false, 3 ] - # ["fun", "anchor", nil, true, false, 1 ] - # ["many lines", nil, nil, true, false, 1 ] - # ["many\nnewlines\n", nil, nil, false, true, 4 ] - # - def scalar value, anchor, tag, plain, quoted, style - end - - ### - # Called when a sequence is started. - # - # +anchor+ is the anchor associated with the sequence or nil. - # +tag+ is the tag associated with the sequence or nil. - # +implicit+ a boolean indicating whether or not the sequence was implicitly - # started. - # +style+ is an integer indicating the list style. - # - # See the constants in Psych::Nodes::Sequence for the possible values of - # +style+. - # - # === Example - # - # Here is a YAML document that exercises most of the possible ways this - # method can be called: - # - # --- - # - !!seq [ - # a - # ] - # - &pewpew - # - b - # - # The above YAML document consists of three lists, an outer list that - # contains two inner lists. Here is a matrix of the parameters sent - # to represent these lists: - # - # # anchor tag implicit style - # [nil, nil, true, 1 ] - # [nil, "tag:yaml.org,2002:seq", false, 2 ] - # ["pewpew", nil, true, 1 ] - - def start_sequence anchor, tag, implicit, style - end - - ### - # Called when a sequence ends. - def end_sequence - end - - ### - # Called when a map starts. - # - # +anchor+ is the anchor associated with the map or +nil+. - # +tag+ is the tag associated with the map or +nil+. - # +implicit+ is a boolean indicating whether or not the map was implicitly - # started. - # +style+ is an integer indicating the mapping style. - # - # See the constants in Psych::Nodes::Mapping for the possible values of - # +style+. - # - # === Example - # - # Here is a YAML document that exercises most of the possible ways this - # method can be called: - # - # --- - # k: !!map { hello: world } - # v: &pewpew - # hello: world - # - # The above YAML document consists of three maps, an outer map that contains - # two inner maps. Below is a matrix of the parameters sent in order to - # represent these three maps: - # - # # anchor tag implicit style - # [nil, nil, true, 1 ] - # [nil, "tag:yaml.org,2002:map", false, 2 ] - # ["pewpew", nil, true, 1 ] - - def start_mapping anchor, tag, implicit, style - end - - ### - # Called when a map ends - def end_mapping - end - - ### - # Called when an empty event happens. (Which, as far as I can tell, is - # never). - def empty - end - - ### - # Called when the YAML stream ends - def end_stream - end - end -end Index: lib/psych/scalar_scanner.rb =================================================================== --- lib/psych/scalar_scanner.rb (revision 27111) +++ lib/psych/scalar_scanner.rb (revision 27112) @@ -1,90 +0,0 @@ -require 'strscan' - -module Psych - ### - # Scan scalars for built in types - class ScalarScanner - # Taken from http://yaml.org/type/timestamp.html - TIME = /^\d{4}-\d{1,2}-\d{1,2}([Tt]|\s+)\d{1,2}:\d\d:\d\d(\.\d*)?(\s*Z|[-+]\d{1,2}(:\d\d)?)?/ - - # Create a new scanner - def initialize - @string_cache = {} - end - - # Tokenize +string+ returning the ruby object - def tokenize string - return nil if string.empty? - return string if @string_cache.key?(string) - - case string - when /^[A-Za-z~]/ - if string.length > 5 - @string_cache[string] = true - return string - end - - case string - when /^[^ytonf~]/i - @string_cache[string] = true - string - when '~', /^null$/i - nil - when /^(yes|true|on)$/i - true - when /^(no|false|off)$/i - false - else - @string_cache[string] = true - string - end - when TIME - date, time = *(string.split(/[ tT]/, 2)) - (yy, m, dd) = date.split('-').map { |x| x.to_i } - md = time.match(/(\d+:\d+:\d+)(\.\d*)?\s*(Z|[-+]\d+(:\d\d)?)?/) - - (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } - us = (md[2] ? Rational(md[2].sub(/^\./, '0.')) : 0) * 1000000 - - time = Time.utc(yy, m, dd, hh, mm, ss, us) - - return time if 'Z' == md[3] - - tz = md[3] ? Integer(md[3].split(':').first.sub(/([-+])0/, '\1')) : 0 - Time.at((time - (tz * 3600)).to_i, us) - when /^\d{4}-\d{1,2}-\d{1,2}$/ - require 'date' - Date.strptime(string, '%Y-%m-%d') - when /^\.inf$/i - 1 / 0.0 - when /^-\.inf$/i - -1 / 0.0 - when /^\.nan$/i - 0.0 / 0.0 - when /^:./ - if string =~ /^:(["'])(.*)\1/ - $2.sub(/^:/, '').to_sym - else - string.sub(/^:/, '').to_sym - end - when /^[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+$/ - i = 0 - string.split(':').each_with_index do |n,e| - i += (n.to_i * 60 ** (e - 2).abs) - end - i - when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*$/ - i = 0 - string.split(':').each_with_index do |n,e| - i += (n.to_f * 60 ** (e - 2).abs) - end - i - else - return Integer(string.gsub(/[,_]/, '')) rescue ArgumentError - return Float(string.gsub(/[,_]/, '')) rescue ArgumentError - @string_cache[string] = true - string - end - end - end -end Index: lib/psych/visitors.rb =================================================================== --- lib/psych/visitors.rb (revision 27111) +++ lib/psych/visitors.rb (revision 27112) @@ -1,5 +0,0 @@ -require 'psych/visitors/visitor' -require 'psych/visitors/to_ruby' -require 'psych/visitors/emitter' -require 'psych/visitors/yaml_tree' -require 'psych/visitors/json_tree' Index: lib/psych/tree_builder.rb =================================================================== --- lib/psych/tree_builder.rb (revision 27111) +++ lib/psych/tree_builder.rb (revision 27112) @@ -1,89 +0,0 @@ -require 'psych/handler' - -module Psych - ### - # This class works in conjunction with Psych::Parser to build an in-memory - # parse tree that represents a YAML document. - # - # == Example - # - # parser = Psych::Parser.new Psych::TreeBuilder.new - # parser.parse('--- foo') - # tree = parser.handler.root - # - # See Psych::Handler for documentation on the event methods used in this - # class. - class TreeBuilder < Psych::Handler - # Create a new TreeBuilder instance - def initialize - @stack = [] - @last = nil - end - - # Returns the root node for the built tree - def root - @stack.first - end - - %w{ - Sequence - Mapping - }.each do |node| - class_eval %{ - def start_#{node.downcase}(anchor, tag, implicit, style) - n = Nodes::#{node}.new(anchor, tag, implicit, style) - @last.children << n - push n - end - - def end_#{node.downcase} - pop - end - } - end - - ### - # Handles start_document events with +version+, +tag_directives+, - # and +implicit+ styling. - # - # See Psych::Handler#start_document - def start_document version, tag_directives, implicit - n = Nodes::Document.new(version, tag_directives, implicit) - @last.children << n - push n - end - - ### - # Handles end_document events with +version+, +tag_directives+, - # and +implicit+ styling. - # - # See Psych::Handler#start_document - def end_document implicit_end - @last.implicit_end = implicit_end - pop - end - - def start_stream encoding - push Nodes::Stream.new(encoding) - end - - def scalar value, anchor, tag, plain, quoted, style - @last.children << Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) - end - - def alias anchor - @last.children << Nodes::Alias.new(anchor) - end - - private - def push value - @stack.push value - @last = value - end - - def pop - @stack.pop - @last = @stack.last - end - end -end Index: lib/psych/core_ext.rb =================================================================== --- lib/psych/core_ext.rb (revision 27111) +++ lib/psych/core_ext.rb (revision 27112) @@ -1,22 +0,0 @@ -class Object - def self.yaml_tag url - Psych.add_tag(url, self) - end - - # FIXME: rename this to "to_yaml" when syck is removed - - ### - # call-seq: to_yaml - # - # Convert an object to YAML - def psych_to_yaml options = {} - Psych.dump self, options - end - alias :to_yaml :psych_to_yaml -end - -module Kernel - def y *objects - puts Psych.dump_stream(*objects) - end -end Index: lib/psych/nodes.rb =================================================================== --- lib/psych/nodes.rb (revision 27111) +++ lib/psych/nodes.rb (revision 27112) @@ -1,77 +0,0 @@ -require 'psych/nodes/node' -require 'psych/nodes/stream' -require 'psych/nodes/document' -require 'psych/nodes/sequence' -require 'psych/nodes/scalar' -require 'psych/nodes/mapping' -require 'psych/nodes/alias' - -module Psych - ### - # = Overview - # - # When using Psych.load to deserialize a YAML document, the document is - # translated to an intermediary AST. That intermediary AST is then - # translated in to a Ruby object graph. - # - # In the opposite direction, when using Psych.dump, the Ruby object graph is - # translated to an intermediary AST which is then converted to a YAML - # document. - # - # Psych::Nodes contains all of the classes that make up the nodes of a YAML - # AST. You can manually build an AST and use one of the visitors (see - # Psych::Visitors) to convert that AST to either a YAML document or to a - # Ruby object graph. - # - # Here is an example of building an AST that represents a list with one - # scalar: - # - # # Create our nodes - # stream = Psych::Nodes::Stream.new - # doc = Psych::Nodes::Document.new - # seq = Psych::Nodes::Sequence.new - # scalar = Psych::Nodes::Scalar.new('foo') - # - # # Build up our tree - # stream.children << doc - # doc.children << seq - # seq.children << scalar - # - # The stream is the root of the tree. We can then convert the tree to YAML: - # - # stream.to_yaml => "---\n- foo\n" - # - # Or convert it to Ruby: - # - # stream.to_ruby => [["foo"]] - # - # == YAML AST Requirements - # - # A valid YAML AST *must* have one Psych::Nodes::Stream at the root. A - # Psych::Nodes::Stream node must have 1 or more Psych::Nodes::Document nodes - # as children. - # - # Psych::Nodes::Document nodes must have one and *only* one child. That child - # may be one of: - # - # * Psych::Nodes::Sequence - # * Psych::Nodes::Mapping - # * Psych::Nodes::Scalar - # - # Psych::Nodes::Sequence and Psych::Nodes::Mapping nodes may have many - # children, but Psych::Nodes::Mapping nodes should have an even number of - # children. - # - # All of these are valid children for Psych::Nodes::Sequence and - # Psych::Nodes::Mapping nodes: - # - # * Psych::Nodes::Sequence - # * Psych::Nodes::Mapping - # * Psych::Nodes::Scalar - # * Psych::Nodes::Alias - # - # Psych::Nodes::Scalar and Psych::Nodes::Alias are both terminal nodes and - # should not have any children. - module Nodes - end -end Index: lib/psych/emitter.rb =================================================================== --- lib/psych/emitter.rb (revision 27111) +++ lib/psych/emitter.rb (revision 27112) @@ -1,4 +0,0 @@ -module Psych - class Emitter < Psych::Handler - end -end Index: lib/psych/set.rb =================================================================== --- lib/psych/set.rb (revision 27111) +++ lib/psych/set.rb (revision 27112) @@ -1,4 +0,0 @@ -module Psych - class Set < ::Hash - end -end Index: lib/psych/coder.rb =================================================================== --- lib/psych/coder.rb (revision 27111) +++ lib/psych/coder.rb (revision 27112) @@ -1,68 +0,0 @@ -module Psych - ### - # If an object defines +encode_with+, then an instance of Psych::Coder will - # be passed to the method when the object is being serialized. The Coder - # automatically assumes a Psych::Nodes::Mapping is being emitted. Other - # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are - # called, respectively. - class Coder - attr_accessor :tag, :style, :implicit - attr_reader :type, :map, :scalar, :seq - - def initialize tag - @map = {} - @seq = [] - @implicit = false - @type = :map - @tag = tag - @style = Psych::Nodes::Mapping::BLOCK - @scalar = nil - end - - # Emit a scalar with +value+ and +tag+ - def represent_scalar tag, value - self.tag = tag - self.scalar = value - end - - # Emit a sequence with +list+ and +tag+ - def represent_seq tag, list - @tag = tag - self.seq = list - end - - # Emit a sequence with +map+ and +tag+ - def represent_map tag, map - @tag = tag - self.map = map - end - - # Emit a scalar with +value+ - def scalar= value - @type = :scalar - @scalar = value - end - - # Emit a map with +value+ - def map= map - @type = :map - @map = map - end - - def []= k, v - @type = :map - @map[k] = v - end - - def [] k - @type = :map - @map[k] - end - - # Emit a sequence of +list+ - def seq= list - @type = :seq - @seq = list - end - end -end Index: lib/psych/omap.rb =================================================================== --- lib/psych/omap.rb (revision 27111) +++ lib/psych/omap.rb (revision 27112) @@ -1,4 +0,0 @@ -module Psych - class Omap < ::Hash - end -end Index: lib/psych/parser.rb =================================================================== --- lib/psych/parser.rb (revision 27111) +++ lib/psych/parser.rb (revision 27112) @@ -1,44 +0,0 @@ -module Psych - ### - # YAML event parser class. This class parses a YAML document and calls - # events on the handler that is passed to the constructor. The events can - # be used for things such as constructing a YAML AST or deserializing YAML - # documents. It can even be fed back to Psych::Emitter to emit the same - # document that was parsed. - # - # See Psych::Handler for documentation on the events that Psych::Parser emits. - # - # Here is an example that prints out ever scalar found in a YAML document: - # - # # Handler for detecting scalar values - # class ScalarHandler < Psych::Handler - # def scalar value, anchor, tag, plain, quoted, style - # puts value - # end - # end - # - # parser = Psych::Parser.new(ScalarHandler.new) - # parser.parse(yaml_document) - # - # Here is an example that feeds the parser back in to Psych::Emitter. The - # YAML document is read from STDIN and written back out to STDERR: - # - # parser = Psych::Parser.new(Psych::Emitter.new($stderr)) - # parser.parse($stdin) - # - # Psych uses Psych::Parser in combination with Psych::TreeBuilder to - # construct an AST of the parsed YAML document. - - class Parser - # The handler on which events will be called - attr_accessor :handler - - ### - # Creates a new Psych::Parser instance with +handler+. YAML events will - # be called on +handler+. See Psych::Parser for more details. - - def initialize handler = Handler.new - @handler = handler - end - end -end Index: lib/psych/visitors/visitor.rb =================================================================== --- lib/psych/visitors/visitor.rb (revision 27111) +++ lib/psych/visitors/visitor.rb (revision 27112) @@ -1,18 +0,0 @@ -module Psych - module Visitors - class Visitor - def accept target - case target - when Psych::Nodes::Scalar then visit_Psych_Nodes_Scalar target - when Psych::Nodes::Mapping then visit_Psych_Nodes_Mapping target - when Psych::Nodes::Sequence then visit_Psych_Nodes_Sequence target - when Psych::Nodes::Alias then visit_Psych_Nodes_Alias target - when Psych::Nodes::Document then visit_Psych_Nodes_Document target - when Psych::Nodes::Stream then visit_Psych_Nodes_Stream target - else - raise "Can't handle #{target}" - end - end - end - end -end Index: lib/psych/visitors/yaml_tree.rb =================================================================== --- lib/psych/visitors/yaml_tree.rb (revision 27111) +++ lib/psych/visitors/yaml_tree.rb (revision 27112) @@ -1,312 +0,0 @@ -module Psych - module Visitors - class YAMLTree < Psych::Visitors::Visitor - attr_reader :tree - - def initialize options = {} - super() - @json = options[:json] - @tree = Nodes::Stream.new - @stack = [] - @st = {} - @ss = ScalarScanner.new - - @dispatch_cache = Hash.new do |h,klass| - method = "visit_#{(klass.name || '').split('::').join('_')}" - - method = respond_to?(method) ? method : h[klass.superclass] - - raise(TypeError, "Can't dump #{target.class}") unless method - - h[klass] = method - end - end - - def << object - doc = create_document - @stack << doc - @tree.children << doc - accept object - end - - def accept target - # return any aliases we find - if node = @st[target.object_id] - node.anchor = target.object_id.to_s - return append Nodes::Alias.new target.object_id.to_s - end - - if target.respond_to?(:encode_with) - dump_coder target - else - send(@dispatch_cache[target.class], target) - end - end - - def visit_Psych_Omap o - seq = Nodes::Sequence.new(nil, '!omap', false) - register(o, seq) - - @stack.push append seq - o.each { |k,v| visit_Hash k => v } - @stack.pop - end - - def visit_Object o - tag = Psych.dump_tags[o.class] - unless tag - klass = o.class == Object ? nil : o.class.name - tag = ['!ruby/object', klass].compact.join(':') - end - - map = append Nodes::Mapping.new(nil, tag, false) - register(o, map) - - @stack.push map - dump_ivars(o, map) - @stack.pop - end - - def visit_Struct o - tag = ['!ruby/struct', o.class.name].compact.join(':') - - map = register(o, Nodes::Mapping.new(nil, tag, false)) - - @stack.push append map - - o.members.each do |member| - map.children << Nodes::Scalar.new("#{member}") - accept o[member] - end - - dump_ivars(o, map) - - @stack.pop - end - - def visit_Exception o - tag = ['!ruby/exception', o.class.name].join ':' - - map = append Nodes::Mapping.new(nil, tag, false) - - @stack.push map - - { - 'message' => private_iv_get(o, 'mesg'), - 'backtrace' => private_iv_get(o, 'backtrace'), - }.each do |k,v| - next unless v - map.children << Nodes::Scalar.new(k) - accept v - end - - dump_ivars(o, map) - - @stack.pop - end - - def visit_Regexp o - append Nodes::Scalar.new(o.inspect, nil, '!ruby/regexp', false) - end - - def visit_Time o - formatted = o.strftime("%Y-%m-%d %H:%M:%S") - if o.utc? - formatted += ".%06dZ" % [o.usec] - else - formatted += ".%06d %+.2d:00" % [o.usec, o.gmt_offset / 3600] - end - - append Nodes::Scalar.new formatted - end - - def visit_Rational o - map = append Nodes::Mapping.new(nil, '!ruby/object:Rational', false) - [ - 'denominator', o.denominator.to_s, - 'numerator', o.numerator.to_s - ].each do |m| - map.children << Nodes::Scalar.new(m) - end - end - - def visit_Complex o - map = append Nodes::Mapping.new(nil, '!ruby/object:Complex', false) - - ['real', o.real.to_s, 'image', o.imag.to_s].each do |m| - map.children << Nodes::Scalar.new(m) - end - end - - def visit_Integer o - append Nodes::Scalar.new o.to_s - end - alias :visit_TrueClass :visit_Integer - alias :visit_FalseClass :visit_Integer - alias :visit_Date :visit_Integer - - def visit_Float o - if o.nan? - append Nodes::Scalar.new '.nan' - elsif o.infinite? - append Nodes::Scalar.new(o.infinite? > 0 ? '.inf' : '-.inf') - else - append Nodes::Scalar.new o.to_s - end - end - - def visit_String o - plain = false - quote = false - - if o.index("\x00") || o.count("^ -~\t\r\n").fdiv(o.length) > 0.3 - str = [o].pack('m').chomp - tag = '!binary' - else - str = o - tag = nil - quote = !(String === @ss.tokenize(o)) - plain = !quote - end - - ivars = o.respond_to?(:to_yaml_properties) ? - o.to_yaml_properties : - o.instance_variables - - scalar = create_scalar str, nil, tag, plain, quote - - if ivars.empty? - append scalar - else - mapping = append Nodes::Mapping.new(nil, '!str', false) - - mapping.children << Nodes::Scalar.new('str') - mapping.children << scalar - - @stack.push mapping - dump_ivars o, mapping - @stack.pop - end - end - - def visit_Class o - raise TypeError, "can't dump anonymous class #{o.class}" - end - - def visit_Range o - @stack.push append Nodes::Mapping.new(nil, '!ruby/range', false) - ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m| - accept m - end - @stack.pop - end - - def visit_Hash o - @stack.push append register(o, create_mapping) - - o.each do |k,v| - accept k - accept v - end - - @stack.pop - end - - def visit_Psych_Set o - @stack.push append register(o, Nodes::Mapping.new(nil, '!set', false)) - - o.each do |k,v| - accept k - accept v - end - - @stack.pop - end - - def visit_Array o - @stack.push append register(o, create_sequence) - o.each { |c| accept c } - @stack.pop - end - - def visit_NilClass o - append Nodes::Scalar.new('', nil, 'tag:yaml.org,2002:null', false) - end - - def visit_Symbol o - append create_scalar ":#{o}" - end - - private - def append o - @stack.last.children << o - o - end - - def register target, yaml_obj - @st[target.object_id] = yaml_obj - yaml_obj - end - - def dump_coder o - tag = Psych.dump_tags[o.class] - unless tag - klass = o.class == Object ? nil : o.class.name - tag = ['!ruby/object', klass].compact.join(':') - end - - c = Psych::Coder.new(tag) - o.encode_with(c) - emit_coder c - end - - def emit_coder c - case c.type - when :scalar - append create_scalar(c.scalar, nil, c.tag, c.tag.nil?) - when :seq - @stack.push append create_sequence(nil, c.tag, c.tag.nil?) - c.seq.each do |thing| - accept thing - end - @stack.pop - when :map - map = append Nodes::Mapping.new(nil, c.tag, c.implicit, c.style) - @stack.push map - c.map.each do |k,v| - map.children << create_scalar(k) - accept v - end - @stack.pop - end - end - - def dump_ivars target, map - ivars = target.respond_to?(:to_yaml_properties) ? - target.to_yaml_properties : - target.instance_variables - - ivars.each do |iv| - map.children << create_scalar("#{iv.to_s.sub(/^@/, '')}") - accept target.instance_variable_get(iv) - end - end - - def create_document - Nodes::Document.new - end - - def create_mapping - Nodes::Mapping.new - end - - def create_scalar value, anchor = nil, tag = nil, plain = true, quoted = false, style = Nodes::Scalar::ANY - Nodes::Scalar.new(value, anchor, tag, plain, quoted, style) - end - - def create_sequence anchor = nil, tag = nil, implicit = true, style = Nodes::Sequence::BLOCK - Nodes::Sequence.new(anchor, tag, implicit, style) - end - end - end -end Index: lib/psych/visitors/to_ruby.rb =================================================================== --- lib/psych/visitors/to_ruby.rb (revision 27111) +++ lib/psych/visitors/to_ruby.rb (revision 27112) @@ -1,252 +0,0 @@ -require 'psych/scalar_scanner' - -module Psych - module Visitors - ### - # This class walks a YAML AST, converting each node to ruby - class ToRuby < Psych::Visitors::Visitor - def initialize - super - @st = {} - @ss = ScalarScanner.new - @domain_types = Psych.domain_types - end - - def accept target - result = super - return result if @domain_types.empty? || !target.tag - - short_name = target.tag.sub(/^!/, '').split('/', 2).last - if Psych.domain_types.key? short_name - url, block = Psych.domain_types[short_name] - return block.call "#{url}:#{short_name}", result - end - - result - end - - def visit_Psych_Nodes_Scalar o - @st[o.anchor] = o.value if o.anchor - - if klass = Psych.load_tags[o.tag] - instance = klass.allocate - - if instance.respond_to?(:init_with) - coder = Psych::Coder.new(o.tag) - coder.scalar = o.value - instance.init_with coder - end - - return instance - end - - return o.value if o.quoted - return @ss.tokenize(o.value) unless o.tag - - case o.tag - when '!binary', 'tag:yaml.org,2002:binary' - o.value.unpack('m').first - when '!str', 'tag:yaml.org,2002:str' - o.value - when "!ruby/object:Complex" - Complex(o.value) - when "!ruby/object:Rational" - Rational(o.value) - when "tag:yaml.org,2002:float", "!float" - Float(@ss.tokenize(o.value)) - when "!ruby/regexp" - o.value =~ /^\/(.*)\/([mix]*)$/ - source = $1 - options = 0 - lang = nil - ($2 || '').split('').each do |option| - case option - when 'x' then options |= Regexp::EXTENDED - when 'i' then options |= Regexp::IGNORECASE - when 'm' then options |= Regexp::MULTILINE - else lang = option - end - end - Regexp.new(*[source, options, lang].compact) - when "!ruby/range" - args = o.value.split(/([.]{2,3})/, 2).map { |s| - accept Nodes::Scalar.new(s) - } - args.push(args.delete_at(1) == '...') - Range.new(*args) - when /^!ruby\/sym(bol)?:?(.*)?$/ - o.value.to_sym - else - @ss.tokenize o.value - end - end - - def visit_Psych_Nodes_Sequence o - if klass = Psych.load_tags[o.tag] - instance = klass.allocate - - if instance.respond_to?(:init_with) - coder = Psych::Coder.new(o.tag) - coder.seq = o.children.map { |c| accept c } - instance.init_with coder - end - - return instance - end - - case o.tag - when '!omap', 'tag:yaml.org,2002:omap' - map = Psych::Omap.new - @st[o.anchor] = map if o.anchor - o.children.each { |a| - map[accept(a.children.first)] = accept a.children.last - } - map - else - list = [] - @st[o.anchor] = list if o.anchor - o.children.each { |c| list.push accept c } - list - end - end - - def visit_Psych_Nodes_Mapping o - return revive(Psych.load_tags[o.tag], o) if Psych.load_tags[o.tag] - - case o.tag - when '!str', 'tag:yaml.org,2002:str' - members = Hash[*o.children.map { |c| accept c }] - string = members.delete 'str' - init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) - when /^!ruby\/struct:?(.*)?$/ - klass = resolve_class($1) - - if klass - s = klass.allocate - @st[o.anchor] = s if o.anchor - - members = {} - struct_members = s.members.map { |x| x.to_sym } - o.children.each_slice(2) do |k,v| - member = accept(k) - value = accept(v) - if struct_members.include?(member.to_sym) - s.send("#{member}=", value) - else - members[member.to_s.sub(/^@/, '')] = value - end - end - init_with(s, members, o) - else - members = o.children.map { |c| accept c } - h = Hash[*members] - Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v }) - end - - when '!ruby/range' - h = Hash[*o.children.map { |c| accept c }] - Range.new(h['begin'], h['end'], h['excl']) - - when /^!ruby\/exception:?(.*)?$/ - h = Hash[*o.children.map { |c| accept c }] - - e = build_exception((resolve_class($1) || Exception), - h.delete('message')) - init_with(e, h, o) - - when '!set', 'tag:yaml.org,2002:set' - set = Psych::Set.new - @st[o.anchor] = set if o.anchor - o.children.each_slice(2) do |k,v| - set[accept(k)] = accept(v) - end - set - - when '!ruby/object:Complex' - h = Hash[*o.children.map { |c| accept c }] - Complex(h['real'], h['image']) - - when '!ruby/object:Rational' - h = Hash[*o.children.map { |c| accept c }] - Rational(h['numerator'], h['denominator']) - - when /^!ruby\/object:?(.*)?$/ - name = $1 || 'Object' - obj = revive((resolve_class(name) || Object), o) - @st[o.anchor] = obj if o.anchor - obj - else - hash = {} - @st[o.anchor] = hash if o.anchor - - o.children.each_slice(2) { |k,v| - key = accept(k) - - if key == '<<' && Nodes::Alias === v - # FIXME: remove this when "<<" syntax is deprecated - if $VERBOSE - where = caller.find { |x| x !~ /psych/ } - warn where - warn "\"<<: *#{v.anchor}\" is no longer supported, please switch to \"*#{v.anchor}\"" - end - return accept(v) - else - hash[key] = accept(v) - end - - } - hash - end - end - - def visit_Psych_Nodes_Document o - accept o.root - end - - def visit_Psych_Nodes_Stream o - o.children.map { |c| accept c } - end - - def visit_Psych_Nodes_Alias o - @st[o.anchor] - end - - private - def revive klass, node - s = klass.allocate - h = Hash[*node.children.map { |c| accept c }] - init_with(s, h, node) - end - - def init_with o, h, node - if o.respond_to?(:init_with) - c = Psych::Coder.new(node.tag) - c.map = h - o.init_with c - else - h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } - end - o - end - - # Convert +klassname+ to a Class - def resolve_class klassname - return nil unless klassname and not klassname.empty? - - name = klassname - retried = false - - begin - path2class(name) - rescue ArgumentError => ex - name = "Struct::#{name}" - unless retried - retried = true - retry - end - raise ex - end - end - end - end -end Index: lib/psych/visitors/json_tree.rb =================================================================== --- lib/psych/visitors/json_tree.rb (revision 27111) +++ lib/psych/visitors/json_tree.rb (revision 27112) @@ -1,37 +0,0 @@ -module Psych - module Visitors - class JSONTree < YAMLTree - def visit_Symbol o - append create_scalar o.to_s - end - - def visit_NilClass o - scalar = Nodes::Scalar.new( - 'null', nil, nil, true, false, Nodes::Scalar::PLAIN) - append scalar - end - - private - def create_document - doc = super - doc.implicit = true - doc.implicit_end = true - doc - end - - def create_mapping - map = super - map.style = Nodes::Mapping::FLOW - map - end - - def create_scalar value, anchor = nil, tag = nil, plain = false, quoted = true, style = Nodes::Scalar::ANY - super(value, anchor, tag, false, true, style) - end - - def create_sequence anchor = nil, tag = nil, implicit = true, style = Nodes::Sequence::FLOW - super - end - end - end -end Index: lib/psych/visitors/emitter.rb =================================================================== --- lib/psych/visitors/emitter.rb (revision 27111) +++ lib/psych/visitors/emitter.rb (revision 27112) @@ -1,41 +0,0 @@ -module Psych - module Visitors - class Emitter < Psych::Visitors::Visitor - def initialize io - @handler = Psych::Emitter.new io - end - - def visit_Psych_Nodes_Stream o - @handler.start_stream o.encoding - o.children.each { |c| accept c } - @handler.end_stream - end - - def visit_Psych_Nodes_Document o - @handler.start_document o.version, o.tag_directives, o.implicit - o.children.each { |c| accept c } - @handler.end_document o.implicit_end - end - - def visit_Psych_Nodes_Scalar o - @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style - end - - def visit_Psych_Nodes_Sequence o - @handler.start_sequence o.anchor, o.tag, o.implicit, o.style - o.children.each { |c| accept c } - @handler.end_sequence - end - - def visit_Psych_Nodes_Mapping o - @handler.start_mapping o.anchor, o.tag, o.implicit, o.style - o.children.each { |c| accept c } - @handler.end_mapping - end - - def visit_Psych_Nodes_Alias o - @handler.alias o.anchor - end - end - end -end Index: lib/psych/nodes/document.rb =================================================================== --- lib/psych/nodes/document.rb (revision 27111) +++ lib/psych/nodes/document.rb (revision 27112) @@ -1,60 +0,0 @@ -module Psych - module Nodes - ### - # This represents a YAML Document. This node must be a child of - # Psych::Nodes::Stream. A Psych::Nodes::Document must have one child, - # and that child may be one of the following: - # - # * Psych::Nodes::Sequence - # * Psych::Nodes::Mapping - # * Psych::Nodes::Scalar - class Document < Psych::Nodes::Node - # The version of the YAML document - attr_accessor :version - - # A list of tag directives for this document - attr_accessor :tag_directives - - # Was this document implicitly created? - attr_accessor :implicit - - # Is the end of the document implicit? - attr_accessor :implicit_end - - ### - # Create a new Psych::Nodes::Document object. - # - # +version+ is a list indicating the YAML version. - # +tags_directives+ is a list of tag directive declarations - # +implicit+ is a flag indicating whether the document will be implicitly - # started. - # - # == Example: - # This creates a YAML document object that represents a YAML 1.1 document - # with one tag directive, and has an implicit start: - # - # Psych::Nodes::Document.new( - # [1,1], - # [["!", "tag:tenderlovemaking.com,2009:"]], - # true - # ) - # - # == See Also - # See also Psych::Handler#start_document - def initialize version = [], tag_directives = [], implicit = false - super() - @version = version - @tag_directives = tag_directives - @implicit = implicit - @implicit_end = true - end - - ### - # Returns the root node. A Document may only have one root node: - # http://yaml.org/spec/1.1/#id898031 - def root - children.first - end - end - end -end Index: lib/psych/nodes/node.rb =================================================================== --- lib/psych/nodes/node.rb (revision 27111) +++ lib/psych/nodes/node.rb (revision 27112) @@ -1,40 +0,0 @@ -require 'stringio' - -module Psych - module Nodes - ### - # The base class for any Node in a YAML parse tree. This class should - # never be instantiated. - class Node - # The children of this node - attr_reader :children - - # An associated tag - attr_reader :tag - - # Create a new Psych::Nodes::Node - def initialize - @children = [] - end - - ### - # Convert this node to Ruby. - # - # See also Psych::Visitors::ToRuby - def to_ruby - Visitors::ToRuby.new.accept self - end - alias :transform :to_ruby - - ### - # Convert this node to YAML. - # - # See also Psych::Visitors::Emitter - def to_yaml - io = StringIO.new - Visitors::Emitter.new(io).accept self - io.string - end - end - end -end Index: lib/psych/nodes/scalar.rb =================================================================== --- lib/psych/nodes/scalar.rb (revision 27111) +++ lib/psych/nodes/scalar.rb (revision 27112) @@ -1,67 +0,0 @@ -module Psych - module Nodes - ### - # This class represents a {YAML Scalar}[http://yaml.org/spec/1.1/#id858081]. - # - # This node type is a terminal node and should not have any children. - class Scalar < Psych::Nodes::Node - # Any style scalar, the emitter chooses - ANY = 0 - - # Plain scalar style - PLAIN = 1 - - # Single quoted style - SINGLE_QUOTED = 2 - - # Double quoted style - DOUBLE_QUOTED = 3 - - # Literal style - LITERAL = 4 - - # Folded style - FOLDED = 5 - - # The scalar value - attr_accessor :value - - # The anchor value (if there is one) - attr_accessor :anchor - - # The tag value (if there is one) - attr_accessor :tag - - # Is this a plain scalar? - attr_accessor :plain - - # Is this scalar quoted? - attr_accessor :quoted - - # The style of this scalar - attr_accessor :style - - ### - # Create a new Psych::Nodes::Scalar object. - # - # +value+ is the string value of the scalar - # +anchor+ is an associated anchor or nil - # +tag+ is an associated tag or nil - # +plain+ is a boolean value - # +quoted+ is a boolean value - # +style+ is an integer idicating the string style - # - # == See Also - # - # See also Psych::Handler#scalar - def initialize value, anchor = nil, tag = nil, plain = true, quoted = false, style = ANY - @value = value - @anchor = anchor - @tag = tag - @plain = plain - @quoted = quoted - @style = style - end - end - end -end Index: lib/psych/nodes/sequence.rb =================================================================== --- lib/psych/nodes/sequence.rb (revision 27111) +++ lib/psych/nodes/sequence.rb (revision 27112) @@ -1,81 +0,0 @@ -module Psych - module Nodes - ### - # This class represents a - # {YAML sequence}[http://yaml.org/spec/1.1/#sequence/syntax]. - # - # A YAML sequence is basically a list, and looks like this: - # - # %YAML 1.1 - # --- - # - I am - # - a Sequence - # - # A YAML sequence may have an anchor like this: - # - # %YAML 1.1 - # --- - # &A [ - # "This sequence", - # "has an anchor" - # ] - # - # A YAML sequence may also have a tag like this: - # - # %YAML 1.1 - # --- - # !!seq [ - # "This sequence", - # "has a tag" - # ] - # - # This class represents a sequence in a YAML document. A - # Psych::Nodes::Sequence node may have 0 or more children. Valid children - # for this node are: - # - # * Psych::Nodes::Sequence - # * Psych::Nodes::Mapping - # * Psych::Nodes::Scalar - # * Psych::Nodes::Alias - class Sequence < Psych::Nodes::Node - # Any Styles, emitter chooses - ANY = 0 - - # Block style sequence - BLOCK = 1 - - # Flow style sequence - FLOW = 2 - - # The anchor for this sequence (if any) - attr_accessor :anchor - - # The tag name for this sequence (if any) - attr_accessor :tag - - # Is this sequence started implicitly? - attr_accessor :implicit - - # The sequece style used - attr_accessor :style - - ### - # Create a new object representing a YAML sequence. - # - # +anchor+ is the anchor associated with the sequence or nil. - # +tag+ is the tag associated with the sequence or nil. - # +implicit+ a boolean indicating whether or not the sequence was - # implicitly started. - # +style+ is an integer indicating the list style. - # - # See Psych::Handler#start_sequence - def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK - super() - @anchor = anchor - @tag = tag - @implicit = implicit - @style = style - end - end - end -end Index: lib/psych/nodes/alias.rb =================================================================== --- lib/psych/nodes/alias.rb (revision 27111) +++ lib/psych/nodes/alias.rb (revision 27112) @@ -1,18 +0,0 @@ -module Psych - module Nodes - ### - # This class represents a {YAML Alias}[http://yaml.org/spec/1.1/#alias]. - # It points to an +anchor+. - # - # A Psych::Nodes::Alias is a terminal node and may have no children. - class Alias < Psych::Nodes::Node - # The anchor this alias links to - attr_accessor :anchor - - # Create a new Alias that points to an +anchor+ - def initialize anchor - @anchor = anchor - end - end - end -end Index: lib/psych/nodes/mapping.rb =================================================================== --- lib/psych/nodes/mapping.rb (revision 27111) +++ lib/psych/nodes/mapping.rb (revision 27112) @@ -1,56 +0,0 @@ -module Psych - module Nodes - ### - # This class represents a {YAML Mapping}[http://yaml.org/spec/1.1/#mapping]. - # - # A Psych::Nodes::Mapping node may have 0 or more children, but must have - # an even number of children. Here are the valid children a - # Psych::Nodes::Mapping node may have: - # - # * Psych::Nodes::Sequence - # * Psych::Nodes::Mapping - # * Psych::Nodes::Scalar - # * Psych::Nodes::Alias - class Mapping < Psych::Nodes::Node - # Any Map Style - ANY = 0 - - # Block Map Style - BLOCK = 1 - - # Flow Map Style - FLOW = 2 - - # The optional anchor for this mapping - attr_accessor :anchor - - # The optional tag for this mapping - attr_accessor :tag - - # Is this an implicit mapping? - attr_accessor :implicit - - # The style of this mapping - attr_accessor :style - - ### - # Create a new Psych::Nodes::Mapping object. - # - # +anchor+ is the anchor associated with the map or +nil+. - # +tag+ is the tag associated with the map or +nil+. - # +implicit+ is a boolean indicating whether or not the map was implicitly - # started. - # +style+ is an integer indicating the mapping style. - # - # == See Also - # See also Psych::Handler#start_mapping - def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK - super() - @anchor = anchor - @tag = tag - @implicit = implicit - @style = style - end - end - end -end Index: lib/psych/nodes/stream.rb =================================================================== --- lib/psych/nodes/stream.rb (revision 27111) +++ lib/psych/nodes/stream.rb (revision 27112) @@ -1,37 +0,0 @@ -module Psych - module Nodes - ### - # Represents a YAML stream. This is the root node for any YAML parse - # tree. This node must have one or more child nodes. The only valid - # child node for a Psych::Nodes::Stream node is Psych::Nodes::Document. - class Stream < Psych::Nodes::Node - - # Encodings supported by Psych (and libyaml) - - # Any encoding - ANY = Psych::Parser::ANY - - # UTF-8 encoding - UTF8 = Psych::Parser::UTF8 - - # UTF-16LE encoding - UTF16LE = Psych::Parser::UTF16LE - - # UTF-16BE encoding - UTF16BE = Psych::Parser::UTF16BE - - # The encoding used for this stream - attr_reader :encoding - - ### - # Create a new Psych::Nodes::Stream node with an +encoding+ that - # defaults to Psych::Nodes::Stream::UTF8. - # - # See also Psych::Handler#start_stream - def initialize encoding = UTF8 - super() - @encoding = encoding - end - end - end -end Index: ext/psych/lib/psych/handler.rb =================================================================== --- ext/psych/lib/psych/handler.rb (revision 0) +++ ext/psych/lib/psych/handler.rb (revision 27112) @@ -0,0 +1,215 @@ +module Psych + ### + # Psych::Handler is an abstract base class that defines the events used + # when dealing with Psych::Parser. Clients who want to use Psych::Parser + # should implement a class that inherits from Psych::Handler and define + # events that they can handle. + # + # Psych::Handler defines all events that Psych::Parser can possibly send to + # event handlers. + # + # See Psych::Parser for more details + class Handler + ### + # Called with +encoding+ when the YAML stream starts. This method is + # called once per stream. A stream may contain multiple documents. + # + # See the constants in Psych::Parser for the possible values of +encoding+. + def start_stream encoding + end + + ### + # Called when the document starts with the declared +version+, + # +tag_directives+, if the document is +implicit+. + # + # +version+ will be an array of integers indicating the YAML version being + # dealt with, +tag_directives+ is a list of tuples indicating the prefix + # and suffix of each tag, and +implicit+ is a boolean indicating whether + # the document is started implicitly. + # + # === Example + # + # Given the following YAML: + # + # %YAML 1.1 + # %TAG ! tag:tenderlovemaking.com,2009: + # --- !squee + # + # The parameters for start_document must be this: + # + # version # => [1, 1] + # tag_directives # => [["!", "tag:tenderlovemaking.com,2009:"]] + # implicit # => false + def start_document version, tag_directives, implicit + end + + ### + # Called with the document ends. +implicit+ is a boolean value indicating + # whether or not the document has an implicit ending. + # + # === Example + # + # Given the following YAML: + # + # --- + # hello world + # + # +implicit+ will be true. Given this YAML: + # + # --- + # hello world + # ... + # + # +implicit+ will be false. + def end_document implicit + end + + ### + # Called when an alias is found to +anchor+. +anchor+ will be the name + # of the anchor found. + # + # === Example + # + # Here we have an example of an array that references itself in YAML: + # + # --- &ponies + # - first element + # - *ponies + # + # &ponies is the achor, *ponies is the alias. In this case, alias is + # called with "ponies". + def alias anchor + end + + ### + # Called when a scalar +value+ is found. The scalar may have an + # +anchor+, a +tag+, be implicitly +plain+ or implicitly +quoted+ + # + # +value+ is the string value of the scalar + # +anchor+ is an associated anchor or nil + # +tag+ is an associated tag or nil + # +plain+ is a boolean value + # +quoted+ is a boolean value + # +style+ is an integer idicating the string style + # + # See the constants in Psych::Nodes::Scalar for the possible values of + # +style+ + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # - !str "foo" + # - &anchor fun + # - many + # lines + # - | + # many + # newlines + # + # The above YAML document contains a list with four strings. Here are + # the parameters sent to this method in the same order: + # + # # value anchor tag plain quoted style + # ["foo", nil, "!str", false, false, 3 ] + # ["fun", "anchor", nil, true, false, 1 ] + # ["many lines", nil, nil, true, false, 1 ] + # ["many\nnewlines\n", nil, nil, false, true, 4 ] + # + def scalar value, anchor, tag, plain, quoted, style + end + + ### + # Called when a sequence is started. + # + # +anchor+ is the anchor associated with the sequence or nil. + # +tag+ is the tag associated with the sequence or nil. + # +implicit+ a boolean indicating whether or not the sequence was implicitly + # started. + # +style+ is an integer indicating the list style. + # + # See the constants in Psych::Nodes::Sequence for the possible values of + # +style+. + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # - !!seq [ + # a + # ] + # - &pewpew + # - b + # + # The above YAML document consists of three lists, an outer list that + # contains two inner lists. Here is a matrix of the parameters sent + # to represent these lists: + # + # # anchor tag implicit style + # [nil, nil, true, 1 ] + # [nil, "tag:yaml.org,2002:seq", false, 2 ] + # ["pewpew", nil, true, 1 ] + + def start_sequence anchor, tag, implicit, style + end + + ### + # Called when a sequence ends. + def end_sequence + end + + ### + # Called when a map starts. + # + # +anchor+ is the anchor associated with the map or +nil+. + # +tag+ is the tag associated with the map or +nil+. + # +implicit+ is a boolean indicating whether or not the map was implicitly + # started. + # +style+ is an integer indicating the mapping style. + # + # See the constants in Psych::Nodes::Mapping for the possible values of + # +style+. + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # k: !!map { hello: world } + # v: &pewpew + # hello: world + # + # The above YAML document consists of three maps, an outer map that contains + # two inner maps. Below is a matrix of the parameters sent in order to + # represent these three maps: + # + # # anchor tag implicit style + # [nil, nil, true, 1 ] + # [nil, "tag:yaml.org,2002:map", false, 2 ] + # ["pewpew", nil, true, 1 ] + + def start_mapping anchor, tag, implicit, style + end + + ### + # Called when a map ends + def end_mapping + end + + ### + # Called when an empty event happens. (Which, as far as I can tell, is + # never). + def empty + end + + ### + # Called when the YAML stream ends + def end_stream + end + end +end Property changes on: ext/psych/lib/psych/handler.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/scalar_scanner.rb =================================================================== --- ext/psych/lib/psych/scalar_scanner.rb (revision 0) +++ ext/psych/lib/psych/scalar_scanner.rb (revision 27112) @@ -0,0 +1,90 @@ +require 'strscan' + +module Psych + ### + # Scan scalars for built in types + class ScalarScanner + # Taken from http://yaml.org/type/timestamp.html + TIME = /^\d{4}-\d{1,2}-\d{1,2}([Tt]|\s+)\d{1,2}:\d\d:\d\d(\.\d*)?(\s*Z|[-+]\d{1,2}(:\d\d)?)?/ + + # Create a new scanner + def initialize + @string_cache = {} + end + + # Tokenize +string+ returning the ruby object + def tokenize string + return nil if string.empty? + return string if @string_cache.key?(string) + + case string + when /^[A-Za-z~]/ + if string.length > 5 + @string_cache[string] = true + return string + end + + case string + when /^[^ytonf~]/i + @string_cache[string] = true + string + when '~', /^null$/i + nil + when /^(yes|true|on)$/i + true + when /^(no|false|off)$/i + false + else + @string_cache[string] = true + string + end + when TIME + date, time = *(string.split(/[ tT]/, 2)) + (yy, m, dd) = date.split('-').map { |x| x.to_i } + md = time.match(/(\d+:\d+:\d+)(\.\d*)?\s*(Z|[-+]\d+(:\d\d)?)?/) + + (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } + us = (md[2] ? Rational(md[2].sub(/^\./, '0.')) : 0) * 1000000 + + time = Time.utc(yy, m, dd, hh, mm, ss, us) + + return time if 'Z' == md[3] + + tz = md[3] ? Integer(md[3].split(':').first.sub(/([-+])0/, '\1')) : 0 + Time.at((time - (tz * 3600)).to_i, us) + when /^\d{4}-\d{1,2}-\d{1,2}$/ + require 'date' + Date.strptime(string, '%Y-%m-%d') + when /^\.inf$/i + 1 / 0.0 + when /^-\.inf$/i + -1 / 0.0 + when /^\.nan$/i + 0.0 / 0.0 + when /^:./ + if string =~ /^:(["'])(.*)\1/ + $2.sub(/^:/, '').to_sym + else + string.sub(/^:/, '').to_sym + end + when /^[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+$/ + i = 0 + string.split(':').each_with_index do |n,e| + i += (n.to_i * 60 ** (e - 2).abs) + end + i + when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*$/ + i = 0 + string.split(':').each_with_index do |n,e| + i += (n.to_f * 60 ** (e - 2).abs) + end + i + else + return Integer(string.gsub(/[,_]/, '')) rescue ArgumentError + return Float(string.gsub(/[,_]/, '')) rescue ArgumentError + @string_cache[string] = true + string + end + end + end +end Property changes on: ext/psych/lib/psych/scalar_scanner.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors/visitor.rb =================================================================== --- ext/psych/lib/psych/visitors/visitor.rb (revision 0) +++ ext/psych/lib/psych/visitors/visitor.rb (revision 27112) @@ -0,0 +1,18 @@ +module Psych + module Visitors + class Visitor + def accept target + case target + when Psych::Nodes::Scalar then visit_Psych_Nodes_Scalar target + when Psych::Nodes::Mapping then visit_Psych_Nodes_Mapping target + when Psych::Nodes::Sequence then visit_Psych_Nodes_Sequence target + when Psych::Nodes::Alias then visit_Psych_Nodes_Alias target + when Psych::Nodes::Document then visit_Psych_Nodes_Document target + when Psych::Nodes::Stream then visit_Psych_Nodes_Stream target + else + raise "Can't handle #{target}" + end + end + end + end +end Property changes on: ext/psych/lib/psych/visitors/visitor.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors/yaml_tree.rb =================================================================== --- ext/psych/lib/psych/visitors/yaml_tree.rb (revision 0) +++ ext/psych/lib/psych/visitors/yaml_tree.rb (revision 27112) @@ -0,0 +1,312 @@ +module Psych + module Visitors + class YAMLTree < Psych::Visitors::Visitor + attr_reader :tree + + def initialize options = {} + super() + @json = options[:json] + @tree = Nodes::Stream.new + @stack = [] + @st = {} + @ss = ScalarScanner.new + + @dispatch_cache = Hash.new do |h,klass| + method = "visit_#{(klass.name || '').split('::').join('_')}" + + method = respond_to?(method) ? method : h[klass.superclass] + + raise(TypeError, "Can't dump #{target.class}") unless method + + h[klass] = method + end + end + + def << object + doc = create_document + @stack << doc + @tree.children << doc + accept object + end + + def accept target + # return any aliases we find + if node = @st[target.object_id] + node.anchor = target.object_id.to_s + return append Nodes::Alias.new target.object_id.to_s + end + + if target.respond_to?(:encode_with) + dump_coder target + else + send(@dispatch_cache[target.class], target) + end + end + + def visit_Psych_Omap o + seq = Nodes::Sequence.new(nil, '!omap', false) + register(o, seq) + + @stack.push append seq + o.each { |k,v| visit_Hash k => v } + @stack.pop + end + + def visit_Object o + tag = Psych.dump_tags[o.class] + unless tag + klass = o.class == Object ? nil : o.class.name + tag = ['!ruby/object', klass].compact.join(':') + end + + map = append Nodes::Mapping.new(nil, tag, false) + register(o, map) + + @stack.push map + dump_ivars(o, map) + @stack.pop + end + + def visit_Struct o + tag = ['!ruby/struct', o.class.name].compact.join(':') + + map = register(o, Nodes::Mapping.new(nil, tag, false)) + + @stack.push append map + + o.members.each do |member| + map.children << Nodes::Scalar.new("#{member}") + accept o[member] + end + + dump_ivars(o, map) + + @stack.pop + end + + def visit_Exception o + tag = ['!ruby/exception', o.class.name].join ':' + + map = append Nodes::Mapping.new(nil, tag, false) + + @stack.push map + + { + 'message' => private_iv_get(o, 'mesg'), + 'backtrace' => private_iv_get(o, 'backtrace'), + }.each do |k,v| + next unless v + map.children << Nodes::Scalar.new(k) + accept v + end + + dump_ivars(o, map) + + @stack.pop + end + + def visit_Regexp o + append Nodes::Scalar.new(o.inspect, nil, '!ruby/regexp', false) + end + + def visit_Time o + formatted = o.strftime("%Y-%m-%d %H:%M:%S") + if o.utc? + formatted += ".%06dZ" % [o.usec] + else + formatted += ".%06d %+.2d:00" % [o.usec, o.gmt_offset / 3600] + end + + append Nodes::Scalar.new formatted + end + + def visit_Rational o + map = append Nodes::Mapping.new(nil, '!ruby/object:Rational', false) + [ + 'denominator', o.denominator.to_s, + 'numerator', o.numerator.to_s + ].each do |m| + map.children << Nodes::Scalar.new(m) + end + end + + def visit_Complex o + map = append Nodes::Mapping.new(nil, '!ruby/object:Complex', false) + + ['real', o.real.to_s, 'image', o.imag.to_s].each do |m| + map.children << Nodes::Scalar.new(m) + end + end + + def visit_Integer o + append Nodes::Scalar.new o.to_s + end + alias :visit_TrueClass :visit_Integer + alias :visit_FalseClass :visit_Integer + alias :visit_Date :visit_Integer + + def visit_Float o + if o.nan? + append Nodes::Scalar.new '.nan' + elsif o.infinite? + append Nodes::Scalar.new(o.infinite? > 0 ? '.inf' : '-.inf') + else + append Nodes::Scalar.new o.to_s + end + end + + def visit_String o + plain = false + quote = false + + if o.index("\x00") || o.count("^ -~\t\r\n").fdiv(o.length) > 0.3 + str = [o].pack('m').chomp + tag = '!binary' + else + str = o + tag = nil + quote = !(String === @ss.tokenize(o)) + plain = !quote + end + + ivars = o.respond_to?(:to_yaml_properties) ? + o.to_yaml_properties : + o.instance_variables + + scalar = create_scalar str, nil, tag, plain, quote + + if ivars.empty? + append scalar + else + mapping = append Nodes::Mapping.new(nil, '!str', false) + + mapping.children << Nodes::Scalar.new('str') + mapping.children << scalar + + @stack.push mapping + dump_ivars o, mapping + @stack.pop + end + end + + def visit_Class o + raise TypeError, "can't dump anonymous class #{o.class}" + end + + def visit_Range o + @stack.push append Nodes::Mapping.new(nil, '!ruby/range', false) + ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m| + accept m + end + @stack.pop + end + + def visit_Hash o + @stack.push append register(o, create_mapping) + + o.each do |k,v| + accept k + accept v + end + + @stack.pop + end + + def visit_Psych_Set o + @stack.push append register(o, Nodes::Mapping.new(nil, '!set', false)) + + o.each do |k,v| + accept k + accept v + end + + @stack.pop + end + + def visit_Array o + @stack.push append register(o, create_sequence) + o.each { |c| accept c } + @stack.pop + end + + def visit_NilClass o + append Nodes::Scalar.new('', nil, 'tag:yaml.org,2002:null', false) + end + + def visit_Symbol o + append create_scalar ":#{o}" + end + + private + def append o + @stack.last.children << o + o + end + + def register target, yaml_obj + @st[target.object_id] = yaml_obj + yaml_obj + end + + def dump_coder o + tag = Psych.dump_tags[o.class] + unless tag + klass = o.class == Object ? nil : o.class.name + tag = ['!ruby/object', klass].compact.join(':') + end + + c = Psych::Coder.new(tag) + o.encode_with(c) + emit_coder c + end + + def emit_coder c + case c.type + when :scalar + append create_scalar(c.scalar, nil, c.tag, c.tag.nil?) + when :seq + @stack.push append create_sequence(nil, c.tag, c.tag.nil?) + c.seq.each do |thing| + accept thing + end + @stack.pop + when :map + map = append Nodes::Mapping.new(nil, c.tag, c.implicit, c.style) + @stack.push map + c.map.each do |k,v| + map.children << create_scalar(k) + accept v + end + @stack.pop + end + end + + def dump_ivars target, map + ivars = target.respond_to?(:to_yaml_properties) ? + target.to_yaml_properties : + target.instance_variables + + ivars.each do |iv| + map.children << create_scalar("#{iv.to_s.sub(/^@/, '')}") + accept target.instance_variable_get(iv) + end + end + + def create_document + Nodes::Document.new + end + + def create_mapping + Nodes::Mapping.new + end + + def create_scalar value, anchor = nil, tag = nil, plain = true, quoted = false, style = Nodes::Scalar::ANY + Nodes::Scalar.new(value, anchor, tag, plain, quoted, style) + end + + def create_sequence anchor = nil, tag = nil, implicit = true, style = Nodes::Sequence::BLOCK + Nodes::Sequence.new(anchor, tag, implicit, style) + end + end + end +end Property changes on: ext/psych/lib/psych/visitors/yaml_tree.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors/to_ruby.rb =================================================================== --- ext/psych/lib/psych/visitors/to_ruby.rb (revision 0) +++ ext/psych/lib/psych/visitors/to_ruby.rb (revision 27112) @@ -0,0 +1,252 @@ +require 'psych/scalar_scanner' + +module Psych + module Visitors + ### + # This class walks a YAML AST, converting each node to ruby + class ToRuby < Psych::Visitors::Visitor + def initialize + super + @st = {} + @ss = ScalarScanner.new + @domain_types = Psych.domain_types + end + + def accept target + result = super + return result if @domain_types.empty? || !target.tag + + short_name = target.tag.sub(/^!/, '').split('/', 2).last + if Psych.domain_types.key? short_name + url, block = Psych.domain_types[short_name] + return block.call "#{url}:#{short_name}", result + end + + result + end + + def visit_Psych_Nodes_Scalar o + @st[o.anchor] = o.value if o.anchor + + if klass = Psych.load_tags[o.tag] + instance = klass.allocate + + if instance.respond_to?(:init_with) + coder = Psych::Coder.new(o.tag) + coder.scalar = o.value + instance.init_with coder + end + + return instance + end + + return o.value if o.quoted + return @ss.tokenize(o.value) unless o.tag + + case o.tag + when '!binary', 'tag:yaml.org,2002:binary' + o.value.unpack('m').first + when '!str', 'tag:yaml.org,2002:str' + o.value + when "!ruby/object:Complex" + Complex(o.value) + when "!ruby/object:Rational" + Rational(o.value) + when "tag:yaml.org,2002:float", "!float" + Float(@ss.tokenize(o.value)) + when "!ruby/regexp" + o.value =~ /^\/(.*)\/([mix]*)$/ + source = $1 + options = 0 + lang = nil + ($2 || '').split('').each do |option| + case option + when 'x' then options |= Regexp::EXTENDED + when 'i' then options |= Regexp::IGNORECASE + when 'm' then options |= Regexp::MULTILINE + else lang = option + end + end + Regexp.new(*[source, options, lang].compact) + when "!ruby/range" + args = o.value.split(/([.]{2,3})/, 2).map { |s| + accept Nodes::Scalar.new(s) + } + args.push(args.delete_at(1) == '...') + Range.new(*args) + when /^!ruby\/sym(bol)?:?(.*)?$/ + o.value.to_sym + else + @ss.tokenize o.value + end + end + + def visit_Psych_Nodes_Sequence o + if klass = Psych.load_tags[o.tag] + instance = klass.allocate + + if instance.respond_to?(:init_with) + coder = Psych::Coder.new(o.tag) + coder.seq = o.children.map { |c| accept c } + instance.init_with coder + end + + return instance + end + + case o.tag + when '!omap', 'tag:yaml.org,2002:omap' + map = Psych::Omap.new + @st[o.anchor] = map if o.anchor + o.children.each { |a| + map[accept(a.children.first)] = accept a.children.last + } + map + else + list = [] + @st[o.anchor] = list if o.anchor + o.children.each { |c| list.push accept c } + list + end + end + + def visit_Psych_Nodes_Mapping o + return revive(Psych.load_tags[o.tag], o) if Psych.load_tags[o.tag] + + case o.tag + when '!str', 'tag:yaml.org,2002:str' + members = Hash[*o.children.map { |c| accept c }] + string = members.delete 'str' + init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) + when /^!ruby\/struct:?(.*)?$/ + klass = resolve_class($1) + + if klass + s = klass.allocate + @st[o.anchor] = s if o.anchor + + members = {} + struct_members = s.members.map { |x| x.to_sym } + o.children.each_slice(2) do |k,v| + member = accept(k) + value = accept(v) + if struct_members.include?(member.to_sym) + s.send("#{member}=", value) + else + members[member.to_s.sub(/^@/, '')] = value + end + end + init_with(s, members, o) + else + members = o.children.map { |c| accept c } + h = Hash[*members] + Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v }) + end + + when '!ruby/range' + h = Hash[*o.children.map { |c| accept c }] + Range.new(h['begin'], h['end'], h['excl']) + + when /^!ruby\/exception:?(.*)?$/ + h = Hash[*o.children.map { |c| accept c }] + + e = build_exception((resolve_class($1) || Exception), + h.delete('message')) + init_with(e, h, o) + + when '!set', 'tag:yaml.org,2002:set' + set = Psych::Set.new + @st[o.anchor] = set if o.anchor + o.children.each_slice(2) do |k,v| + set[accept(k)] = accept(v) + end + set + + when '!ruby/object:Complex' + h = Hash[*o.children.map { |c| accept c }] + Complex(h['real'], h['image']) + + when '!ruby/object:Rational' + h = Hash[*o.children.map { |c| accept c }] + Rational(h['numerator'], h['denominator']) + + when /^!ruby\/object:?(.*)?$/ + name = $1 || 'Object' + obj = revive((resolve_class(name) || Object), o) + @st[o.anchor] = obj if o.anchor + obj + else + hash = {} + @st[o.anchor] = hash if o.anchor + + o.children.each_slice(2) { |k,v| + key = accept(k) + + if key == '<<' && Nodes::Alias === v + # FIXME: remove this when "<<" syntax is deprecated + if $VERBOSE + where = caller.find { |x| x !~ /psych/ } + warn where + warn "\"<<: *#{v.anchor}\" is no longer supported, please switch to \"*#{v.anchor}\"" + end + return accept(v) + else + hash[key] = accept(v) + end + + } + hash + end + end + + def visit_Psych_Nodes_Document o + accept o.root + end + + def visit_Psych_Nodes_Stream o + o.children.map { |c| accept c } + end + + def visit_Psych_Nodes_Alias o + @st[o.anchor] + end + + private + def revive klass, node + s = klass.allocate + h = Hash[*node.children.map { |c| accept c }] + init_with(s, h, node) + end + + def init_with o, h, node + if o.respond_to?(:init_with) + c = Psych::Coder.new(node.tag) + c.map = h + o.init_with c + else + h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } + end + o + end + + # Convert +klassname+ to a Class + def resolve_class klassname + return nil unless klassname and not klassname.empty? + + name = klassname + retried = false + + begin + path2class(name) + rescue ArgumentError => ex + name = "Struct::#{name}" + unless retried + retried = true + retry + end + raise ex + end + end + end + end +end Property changes on: ext/psych/lib/psych/visitors/to_ruby.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors/json_tree.rb =================================================================== --- ext/psych/lib/psych/visitors/json_tree.rb (revision 0) +++ ext/psych/lib/psych/visitors/json_tree.rb (revision 27112) @@ -0,0 +1,37 @@ +module Psych + module Visitors + class JSONTree < YAMLTree + def visit_Symbol o + append create_scalar o.to_s + end + + def visit_NilClass o + scalar = Nodes::Scalar.new( + 'null', nil, nil, true, false, Nodes::Scalar::PLAIN) + append scalar + end + + private + def create_document + doc = super + doc.implicit = true + doc.implicit_end = true + doc + end + + def create_mapping + map = super + map.style = Nodes::Mapping::FLOW + map + end + + def create_scalar value, anchor = nil, tag = nil, plain = false, quoted = true, style = Nodes::Scalar::ANY + super(value, anchor, tag, false, true, style) + end + + def create_sequence anchor = nil, tag = nil, implicit = true, style = Nodes::Sequence::FLOW + super + end + end + end +end Property changes on: ext/psych/lib/psych/visitors/json_tree.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors/emitter.rb =================================================================== --- ext/psych/lib/psych/visitors/emitter.rb (revision 0) +++ ext/psych/lib/psych/visitors/emitter.rb (revision 27112) @@ -0,0 +1,41 @@ +module Psych + module Visitors + class Emitter < Psych::Visitors::Visitor + def initialize io + @handler = Psych::Emitter.new io + end + + def visit_Psych_Nodes_Stream o + @handler.start_stream o.encoding + o.children.each { |c| accept c } + @handler.end_stream + end + + def visit_Psych_Nodes_Document o + @handler.start_document o.version, o.tag_directives, o.implicit + o.children.each { |c| accept c } + @handler.end_document o.implicit_end + end + + def visit_Psych_Nodes_Scalar o + @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style + end + + def visit_Psych_Nodes_Sequence o + @handler.start_sequence o.anchor, o.tag, o.implicit, o.style + o.children.each { |c| accept c } + @handler.end_sequence + end + + def visit_Psych_Nodes_Mapping o + @handler.start_mapping o.anchor, o.tag, o.implicit, o.style + o.children.each { |c| accept c } + @handler.end_mapping + end + + def visit_Psych_Nodes_Alias o + @handler.alias o.anchor + end + end + end +end Property changes on: ext/psych/lib/psych/visitors/emitter.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/visitors.rb =================================================================== --- ext/psych/lib/psych/visitors.rb (revision 0) +++ ext/psych/lib/psych/visitors.rb (revision 27112) @@ -0,0 +1,5 @@ +require 'psych/visitors/visitor' +require 'psych/visitors/to_ruby' +require 'psych/visitors/emitter' +require 'psych/visitors/yaml_tree' +require 'psych/visitors/json_tree' Property changes on: ext/psych/lib/psych/visitors.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/tree_builder.rb =================================================================== --- ext/psych/lib/psych/tree_builder.rb (revision 0) +++ ext/psych/lib/psych/tree_builder.rb (revision 27112) @@ -0,0 +1,89 @@ +require 'psych/handler' + +module Psych + ### + # This class works in conjunction with Psych::Parser to build an in-memory + # parse tree that represents a YAML document. + # + # == Example + # + # parser = Psych::Parser.new Psych::TreeBuilder.new + # parser.parse('--- foo') + # tree = parser.handler.root + # + # See Psych::Handler for documentation on the event methods used in this + # class. + class TreeBuilder < Psych::Handler + # Create a new TreeBuilder instance + def initialize + @stack = [] + @last = nil + end + + # Returns the root node for the built tree + def root + @stack.first + end + + %w{ + Sequence + Mapping + }.each do |node| + class_eval %{ + def start_#{node.downcase}(anchor, tag, implicit, style) + n = Nodes::#{node}.new(anchor, tag, implicit, style) + @last.children << n + push n + end + + def end_#{node.downcase} + pop + end + } + end + + ### + # Handles start_document events with +version+, +tag_directives+, + # and +implicit+ styling. + # + # See Psych::Handler#start_document + def start_document version, tag_directives, implicit + n = Nodes::Document.new(version, tag_directives, implicit) + @last.children << n + push n + end + + ### + # Handles end_document events with +version+, +tag_directives+, + # and +implicit+ styling. + # + # See Psych::Handler#start_document + def end_document implicit_end + @last.implicit_end = implicit_end + pop + end + + def start_stream encoding + push Nodes::Stream.new(encoding) + end + + def scalar value, anchor, tag, plain, quoted, style + @last.children << Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) + end + + def alias anchor + @last.children << Nodes::Alias.new(anchor) + end + + private + def push value + @stack.push value + @last = value + end + + def pop + @stack.pop + @last = @stack.last + end + end +end Property changes on: ext/psych/lib/psych/tree_builder.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/document.rb =================================================================== --- ext/psych/lib/psych/nodes/document.rb (revision 0) +++ ext/psych/lib/psych/nodes/document.rb (revision 27112) @@ -0,0 +1,60 @@ +module Psych + module Nodes + ### + # This represents a YAML Document. This node must be a child of + # Psych::Nodes::Stream. A Psych::Nodes::Document must have one child, + # and that child may be one of the following: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + class Document < Psych::Nodes::Node + # The version of the YAML document + attr_accessor :version + + # A list of tag directives for this document + attr_accessor :tag_directives + + # Was this document implicitly created? + attr_accessor :implicit + + # Is the end of the document implicit? + attr_accessor :implicit_end + + ### + # Create a new Psych::Nodes::Document object. + # + # +version+ is a list indicating the YAML version. + # +tags_directives+ is a list of tag directive declarations + # +implicit+ is a flag indicating whether the document will be implicitly + # started. + # + # == Example: + # This creates a YAML document object that represents a YAML 1.1 document + # with one tag directive, and has an implicit start: + # + # Psych::Nodes::Document.new( + # [1,1], + # [["!", "tag:tenderlovemaking.com,2009:"]], + # true + # ) + # + # == See Also + # See also Psych::Handler#start_document + def initialize version = [], tag_directives = [], implicit = false + super() + @version = version + @tag_directives = tag_directives + @implicit = implicit + @implicit_end = true + end + + ### + # Returns the root node. A Document may only have one root node: + # http://yaml.org/spec/1.1/#id898031 + def root + children.first + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/document.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/node.rb =================================================================== --- ext/psych/lib/psych/nodes/node.rb (revision 0) +++ ext/psych/lib/psych/nodes/node.rb (revision 27112) @@ -0,0 +1,40 @@ +require 'stringio' + +module Psych + module Nodes + ### + # The base class for any Node in a YAML parse tree. This class should + # never be instantiated. + class Node + # The children of this node + attr_reader :children + + # An associated tag + attr_reader :tag + + # Create a new Psych::Nodes::Node + def initialize + @children = [] + end + + ### + # Convert this node to Ruby. + # + # See also Psych::Visitors::ToRuby + def to_ruby + Visitors::ToRuby.new.accept self + end + alias :transform :to_ruby + + ### + # Convert this node to YAML. + # + # See also Psych::Visitors::Emitter + def to_yaml + io = StringIO.new + Visitors::Emitter.new(io).accept self + io.string + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/node.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/scalar.rb =================================================================== --- ext/psych/lib/psych/nodes/scalar.rb (revision 0) +++ ext/psych/lib/psych/nodes/scalar.rb (revision 27112) @@ -0,0 +1,67 @@ +module Psych + module Nodes + ### + # This class represents a {YAML Scalar}[http://yaml.org/spec/1.1/#id858081]. + # + # This node type is a terminal node and should not have any children. + class Scalar < Psych::Nodes::Node + # Any style scalar, the emitter chooses + ANY = 0 + + # Plain scalar style + PLAIN = 1 + + # Single quoted style + SINGLE_QUOTED = 2 + + # Double quoted style + DOUBLE_QUOTED = 3 + + # Literal style + LITERAL = 4 + + # Folded style + FOLDED = 5 + + # The scalar value + attr_accessor :value + + # The anchor value (if there is one) + attr_accessor :anchor + + # The tag value (if there is one) + attr_accessor :tag + + # Is this a plain scalar? + attr_accessor :plain + + # Is this scalar quoted? + attr_accessor :quoted + + # The style of this scalar + attr_accessor :style + + ### + # Create a new Psych::Nodes::Scalar object. + # + # +value+ is the string value of the scalar + # +anchor+ is an associated anchor or nil + # +tag+ is an associated tag or nil + # +plain+ is a boolean value + # +quoted+ is a boolean value + # +style+ is an integer idicating the string style + # + # == See Also + # + # See also Psych::Handler#scalar + def initialize value, anchor = nil, tag = nil, plain = true, quoted = false, style = ANY + @value = value + @anchor = anchor + @tag = tag + @plain = plain + @quoted = quoted + @style = style + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/scalar.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/sequence.rb =================================================================== --- ext/psych/lib/psych/nodes/sequence.rb (revision 0) +++ ext/psych/lib/psych/nodes/sequence.rb (revision 27112) @@ -0,0 +1,81 @@ +module Psych + module Nodes + ### + # This class represents a + # {YAML sequence}[http://yaml.org/spec/1.1/#sequence/syntax]. + # + # A YAML sequence is basically a list, and looks like this: + # + # %YAML 1.1 + # --- + # - I am + # - a Sequence + # + # A YAML sequence may have an anchor like this: + # + # %YAML 1.1 + # --- + # &A [ + # "This sequence", + # "has an anchor" + # ] + # + # A YAML sequence may also have a tag like this: + # + # %YAML 1.1 + # --- + # !!seq [ + # "This sequence", + # "has a tag" + # ] + # + # This class represents a sequence in a YAML document. A + # Psych::Nodes::Sequence node may have 0 or more children. Valid children + # for this node are: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + class Sequence < Psych::Nodes::Node + # Any Styles, emitter chooses + ANY = 0 + + # Block style sequence + BLOCK = 1 + + # Flow style sequence + FLOW = 2 + + # The anchor for this sequence (if any) + attr_accessor :anchor + + # The tag name for this sequence (if any) + attr_accessor :tag + + # Is this sequence started implicitly? + attr_accessor :implicit + + # The sequece style used + attr_accessor :style + + ### + # Create a new object representing a YAML sequence. + # + # +anchor+ is the anchor associated with the sequence or nil. + # +tag+ is the tag associated with the sequence or nil. + # +implicit+ a boolean indicating whether or not the sequence was + # implicitly started. + # +style+ is an integer indicating the list style. + # + # See Psych::Handler#start_sequence + def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK + super() + @anchor = anchor + @tag = tag + @implicit = implicit + @style = style + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/sequence.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/alias.rb =================================================================== --- ext/psych/lib/psych/nodes/alias.rb (revision 0) +++ ext/psych/lib/psych/nodes/alias.rb (revision 27112) @@ -0,0 +1,18 @@ +module Psych + module Nodes + ### + # This class represents a {YAML Alias}[http://yaml.org/spec/1.1/#alias]. + # It points to an +anchor+. + # + # A Psych::Nodes::Alias is a terminal node and may have no children. + class Alias < Psych::Nodes::Node + # The anchor this alias links to + attr_accessor :anchor + + # Create a new Alias that points to an +anchor+ + def initialize anchor + @anchor = anchor + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/alias.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/mapping.rb =================================================================== --- ext/psych/lib/psych/nodes/mapping.rb (revision 0) +++ ext/psych/lib/psych/nodes/mapping.rb (revision 27112) @@ -0,0 +1,56 @@ +module Psych + module Nodes + ### + # This class represents a {YAML Mapping}[http://yaml.org/spec/1.1/#mapping]. + # + # A Psych::Nodes::Mapping node may have 0 or more children, but must have + # an even number of children. Here are the valid children a + # Psych::Nodes::Mapping node may have: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + class Mapping < Psych::Nodes::Node + # Any Map Style + ANY = 0 + + # Block Map Style + BLOCK = 1 + + # Flow Map Style + FLOW = 2 + + # The optional anchor for this mapping + attr_accessor :anchor + + # The optional tag for this mapping + attr_accessor :tag + + # Is this an implicit mapping? + attr_accessor :implicit + + # The style of this mapping + attr_accessor :style + + ### + # Create a new Psych::Nodes::Mapping object. + # + # +anchor+ is the anchor associated with the map or +nil+. + # +tag+ is the tag associated with the map or +nil+. + # +implicit+ is a boolean indicating whether or not the map was implicitly + # started. + # +style+ is an integer indicating the mapping style. + # + # == See Also + # See also Psych::Handler#start_mapping + def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK + super() + @anchor = anchor + @tag = tag + @implicit = implicit + @style = style + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/mapping.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes/stream.rb =================================================================== --- ext/psych/lib/psych/nodes/stream.rb (revision 0) +++ ext/psych/lib/psych/nodes/stream.rb (revision 27112) @@ -0,0 +1,37 @@ +module Psych + module Nodes + ### + # Represents a YAML stream. This is the root node for any YAML parse + # tree. This node must have one or more child nodes. The only valid + # child node for a Psych::Nodes::Stream node is Psych::Nodes::Document. + class Stream < Psych::Nodes::Node + + # Encodings supported by Psych (and libyaml) + + # Any encoding + ANY = Psych::Parser::ANY + + # UTF-8 encoding + UTF8 = Psych::Parser::UTF8 + + # UTF-16LE encoding + UTF16LE = Psych::Parser::UTF16LE + + # UTF-16BE encoding + UTF16BE = Psych::Parser::UTF16BE + + # The encoding used for this stream + attr_reader :encoding + + ### + # Create a new Psych::Nodes::Stream node with an +encoding+ that + # defaults to Psych::Nodes::Stream::UTF8. + # + # See also Psych::Handler#start_stream + def initialize encoding = UTF8 + super() + @encoding = encoding + end + end + end +end Property changes on: ext/psych/lib/psych/nodes/stream.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/core_ext.rb =================================================================== --- ext/psych/lib/psych/core_ext.rb (revision 0) +++ ext/psych/lib/psych/core_ext.rb (revision 27112) @@ -0,0 +1,22 @@ +class Object + def self.yaml_tag url + Psych.add_tag(url, self) + end + + # FIXME: rename this to "to_yaml" when syck is removed + + ### + # call-seq: to_yaml + # + # Convert an object to YAML + def psych_to_yaml options = {} + Psych.dump self, options + end + alias :to_yaml :psych_to_yaml +end + +module Kernel + def y *objects + puts Psych.dump_stream(*objects) + end +end Property changes on: ext/psych/lib/psych/core_ext.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/nodes.rb =================================================================== --- ext/psych/lib/psych/nodes.rb (revision 0) +++ ext/psych/lib/psych/nodes.rb (revision 27112) @@ -0,0 +1,77 @@ +require 'psych/nodes/node' +require 'psych/nodes/stream' +require 'psych/nodes/document' +require 'psych/nodes/sequence' +require 'psych/nodes/scalar' +require 'psych/nodes/mapping' +require 'psych/nodes/alias' + +module Psych + ### + # = Overview + # + # When using Psych.load to deserialize a YAML document, the document is + # translated to an intermediary AST. That intermediary AST is then + # translated in to a Ruby object graph. + # + # In the opposite direction, when using Psych.dump, the Ruby object graph is + # translated to an intermediary AST which is then converted to a YAML + # document. + # + # Psych::Nodes contains all of the classes that make up the nodes of a YAML + # AST. You can manually build an AST and use one of the visitors (see + # Psych::Visitors) to convert that AST to either a YAML document or to a + # Ruby object graph. + # + # Here is an example of building an AST that represents a list with one + # scalar: + # + # # Create our nodes + # stream = Psych::Nodes::Stream.new + # doc = Psych::Nodes::Document.new + # seq = Psych::Nodes::Sequence.new + # scalar = Psych::Nodes::Scalar.new('foo') + # + # # Build up our tree + # stream.children << doc + # doc.children << seq + # seq.children << scalar + # + # The stream is the root of the tree. We can then convert the tree to YAML: + # + # stream.to_yaml => "---\n- foo\n" + # + # Or convert it to Ruby: + # + # stream.to_ruby => [["foo"]] + # + # == YAML AST Requirements + # + # A valid YAML AST *must* have one Psych::Nodes::Stream at the root. A + # Psych::Nodes::Stream node must have 1 or more Psych::Nodes::Document nodes + # as children. + # + # Psych::Nodes::Document nodes must have one and *only* one child. That child + # may be one of: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # + # Psych::Nodes::Sequence and Psych::Nodes::Mapping nodes may have many + # children, but Psych::Nodes::Mapping nodes should have an even number of + # children. + # + # All of these are valid children for Psych::Nodes::Sequence and + # Psych::Nodes::Mapping nodes: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + # + # Psych::Nodes::Scalar and Psych::Nodes::Alias are both terminal nodes and + # should not have any children. + module Nodes + end +end Property changes on: ext/psych/lib/psych/nodes.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/emitter.rb =================================================================== --- ext/psych/lib/psych/emitter.rb (revision 0) +++ ext/psych/lib/psych/emitter.rb (revision 27112) @@ -0,0 +1,4 @@ +module Psych + class Emitter < Psych::Handler + end +end Property changes on: ext/psych/lib/psych/emitter.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/set.rb =================================================================== --- ext/psych/lib/psych/set.rb (revision 0) +++ ext/psych/lib/psych/set.rb (revision 27112) @@ -0,0 +1,4 @@ +module Psych + class Set < ::Hash + end +end Property changes on: ext/psych/lib/psych/set.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/coder.rb =================================================================== --- ext/psych/lib/psych/coder.rb (revision 0) +++ ext/psych/lib/psych/coder.rb (revision 27112) @@ -0,0 +1,68 @@ +module Psych + ### + # If an object defines +encode_with+, then an instance of Psych::Coder will + # be passed to the method when the object is being serialized. The Coder + # automatically assumes a Psych::Nodes::Mapping is being emitted. Other + # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are + # called, respectively. + class Coder + attr_accessor :tag, :style, :implicit + attr_reader :type, :map, :scalar, :seq + + def initialize tag + @map = {} + @seq = [] + @implicit = false + @type = :map + @tag = tag + @style = Psych::Nodes::Mapping::BLOCK + @scalar = nil + end + + # Emit a scalar with +value+ and +tag+ + def represent_scalar tag, value + self.tag = tag + self.scalar = value + end + + # Emit a sequence with +list+ and +tag+ + def represent_seq tag, list + @tag = tag + self.seq = list + end + + # Emit a sequence with +map+ and +tag+ + def represent_map tag, map + @tag = tag + self.map = map + end + + # Emit a scalar with +value+ + def scalar= value + @type = :scalar + @scalar = value + end + + # Emit a map with +value+ + def map= map + @type = :map + @map = map + end + + def []= k, v + @type = :map + @map[k] = v + end + + def [] k + @type = :map + @map[k] + end + + # Emit a sequence of +list+ + def seq= list + @type = :seq + @seq = list + end + end +end Property changes on: ext/psych/lib/psych/coder.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/omap.rb =================================================================== --- ext/psych/lib/psych/omap.rb (revision 0) +++ ext/psych/lib/psych/omap.rb (revision 27112) @@ -0,0 +1,4 @@ +module Psych + class Omap < ::Hash + end +end Property changes on: ext/psych/lib/psych/omap.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych/parser.rb =================================================================== --- ext/psych/lib/psych/parser.rb (revision 0) +++ ext/psych/lib/psych/parser.rb (revision 27112) @@ -0,0 +1,44 @@ +module Psych + ### + # YAML event parser class. This class parses a YAML document and calls + # events on the handler that is passed to the constructor. The events can + # be used for things such as constructing a YAML AST or deserializing YAML + # documents. It can even be fed back to Psych::Emitter to emit the same + # document that was parsed. + # + # See Psych::Handler for documentation on the events that Psych::Parser emits. + # + # Here is an example that prints out ever scalar found in a YAML document: + # + # # Handler for detecting scalar values + # class ScalarHandler < Psych::Handler + # def scalar value, anchor, tag, plain, quoted, style + # puts value + # end + # end + # + # parser = Psych::Parser.new(ScalarHandler.new) + # parser.parse(yaml_document) + # + # Here is an example that feeds the parser back in to Psych::Emitter. The + # YAML document is read from STDIN and written back out to STDERR: + # + # parser = Psych::Parser.new(Psych::Emitter.new($stderr)) + # parser.parse($stdin) + # + # Psych uses Psych::Parser in combination with Psych::TreeBuilder to + # construct an AST of the parsed YAML document. + + class Parser + # The handler on which events will be called + attr_accessor :handler + + ### + # Creates a new Psych::Parser instance with +handler+. YAML events will + # be called on +handler+. See Psych::Parser for more details. + + def initialize handler = Handler.new + @handler = handler + end + end +end Property changes on: ext/psych/lib/psych/parser.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: ext/psych/lib/psych.rb =================================================================== --- ext/psych/lib/psych.rb (revision 0) +++ ext/psych/lib/psych.rb (revision 27112) @@ -0,0 +1,238 @@ +require 'psych/psych' +require 'psych/nodes' +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' + +### +# = Overview +# +# Psych is a YAML parser and emitter. Psych leverages +# libyaml[http://libyaml.org] for it's YAML parsing 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. +# +# = 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, +# and at the highest level is the ability to unmarshal YAML to ruby objects. +# +# === Low level 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 +# automatic detection and conversion to ruby objects. See Psych::Parser for +# more information on using the event based parser. +# +# === Mid level parsing +# +# 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. +# +# === High level 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 +# +# == YAML Emitting +# +# 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. +# +# === Low level 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. +# +# === Mid level emitting +# +# 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. +# +# === High level 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. + +module Psych + # The version is Psych you're using + VERSION = '1.0.0' + + # The version of libyaml Psych is using + LIBYAML_VERSION = Psych.libyaml_version.join '.' + + ### + # Load +yaml+ in to a Ruby data structure. If multiple documents are + # provided, the object contained in the first document will be returned. + # + # Example: + # + # Psych.load("--- a") # => 'a' + # Psych.load("---\n - a\n - b") # => ['a', 'b'] + def self.load yaml + result = parse(yaml) + result ? result.to_ruby : result + end + + ### + # Parse a YAML string in +yaml+. Returns the first object of a YAML AST. + # + # Example: + # + # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00> + # + # See Psych::Nodes for more information about YAML AST. + def self.parse yaml + children = parse_stream(yaml).children + children.empty? ? false : children.first.children.first + end + + ### + # Parse a file at +filename+. Returns the YAML AST. + def self.parse_file filename + File.open filename do |f| + parse f + end + end + + ### + # Returns a default parser + def self.parser + Psych::Parser.new(TreeBuilder.new) + end + + ### + # Parse a YAML string in +yaml+. Returns the full AST for the YAML document. + # This method can handle multiple YAML documents contained in +yaml+. + # + # Example: + # + # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00> + # + # See Psych::Nodes for more information about YAML AST. + def self.parse_stream yaml + parser = self.parser + parser.parse yaml + parser.handler.root + end + + ### + # Dump Ruby object +o+ to a YAML string using +options+. + # + # Example: + # + # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" + def self.dump o, options = {} + visitor = Psych::Visitors::YAMLTree.new options + visitor << o + visitor.tree.to_yaml + 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 + visitor = Psych::Visitors::YAMLTree.new {} + objects.each do |o| + visitor << o + end + visitor.tree.to_yaml + end + + ### + # Dump Ruby object +o+ to a JSON string. + def self.to_json o + visitor = Psych::Visitors::JSONTree.new(:json => true) + visitor << o + visitor.tree.to_yaml + end + + ### + # Load multiple documents given in +yaml+. Returns the parsed documents + # as a list. For example: + # + # Psych.load_documents("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] + # + def self.load_stream yaml + parse_stream(yaml).children.map { |child| child.to_ruby } + end + + def self.load_documents yaml, &block + if $VERBOSE + warn "#{caller[0]}: load_documents is deprecated, use load_stream" + end + list = load_stream yaml + return list unless block_given? + list.each(&block) + end + + ### + # Load the document contained in +filename+. Returns the yaml contained in + # +filename+ as a ruby object + def self.load_file filename + self.load File.open(filename) + end + + # :stopdoc: + @domain_types = {} + def self.add_domain_type domain, type_tag, &block + @domain_types[type_tag] = ["http://#{domain}", block] + end + + def self.add_builtin_type type_tag, &block + @domain_types[type_tag] = ['yaml.org', block] + end + + def self.remove_type type_tag + @domain_types.delete type_tag + end + + @load_tags = {} + @dump_tags = {} + def self.add_tag tag, klass + @load_tags[tag] = klass + @dump_tags[klass] = tag + end + + class << self + attr_accessor :load_tags + attr_accessor :dump_tags + attr_accessor :domain_types + end + + # :startdoc: +end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/