# class Psych::Visitors::YAMLTree

`YAMLTree` builds a `YAML` ast given a Ruby object. For example:

    builder = Psych::Visitors::YAMLTree.new
    builder << { :foo => 'bar' }
    builder.tree # => #<Psych::Nodes::Stream .. }

### Attributes

finished [R]
finished? [R]
started [R]
started? [R]

### Public Class Methods

create (options = {})
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 44
    def self.create options = {}, emitter = nil
      emitter      ||= TreeBuilder.new
      class_loader = ClassLoader.new
      ss           = ScalarScanner.new class_loader
      new(emitter, ss, options)
    end

new (emitter, ss, options)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 51
    def initialize emitter, ss, options
      super()
      @started    = false
      @finished   = false
      @emitter    = emitter
      @st         = Registrar.new
      @ss         = ss
      @options    = options
      @line_width = options[:line_width]
      if @line_width && @line_width < 0
        if @line_width == -1
          # Treat -1 as unlimited line-width, same as libyaml does.
          @line_width = nil
        else
          fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.")
        end
      end
      @stringify_names = options[:stringify_names]
      @coders     = []

      @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.compare_by_identity
    end

Calls superclass method `BasicObject::new`

### Public Instance Methods

<< (object)
Alias for: push
accept (target)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 119
    def accept target
      # return any aliases we find
      if @st.key? target
        oid         = @st.id_for target
        node        = @st.node_for target
        anchor      = oid.to_s
        node.anchor = anchor
        return @emitter.alias anchor
      end

      if target.respond_to?(:encode_with)
        dump_coder target
      else
        send(@dispatch_cache[target.class], target)
      end
    end

finish ()
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 88
    def finish
      @emitter.end_stream.tap do
        @finished = true
      end
    end

push (object)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 99
    def push object
      start unless started?
      version = []
      version = [1,1] if @options[:header]

      case @options[:version]
      when Array
        version = @options[:version]
      when String
        version = @options[:version].split('.').map { |x| x.to_i }
      else
        version = [1,1]
      end if @options.key? :version

      @emitter.start_document version, [], false
      accept object
      @emitter.end_document !@emitter.streaming?
    end

Also aliased as: <<
start (encoding = Nodes::Stream::UTF8)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 82
    def start encoding = Nodes::Stream::UTF8
      @emitter.start_stream(encoding).tap do
        @started = true
      end
    end

tree ()
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 94
    def tree
      finish unless finished?
      @emitter.root
    end

visit_Array (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 347
    def visit_Array o
      if o.class == ::Array
        visit_Enumerator o
      else
        visit_array_subclass o
      end
    end

visit_BasicObject (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 373
    def visit_BasicObject o
      tag = Psych.dump_tags[o.class]
      tag ||= "!ruby/marshalable:#{o.class.name}"

      map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
      register(o, map)

      o.marshal_dump.each(&method(:accept))

      @emitter.end_mapping
    end

visit_BigDecimal (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 247
    def visit_BigDecimal o
      @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY
    end

visit_Class (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 310
    def visit_Class o
      raise TypeError, "can't dump anonymous class: #{o}" unless o.name
      register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED)
    end

visit_Complex (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 220
    def visit_Complex o
      register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)

      ['real', o.real.to_s, 'image', o.imag.to_s].each do |m|
        @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
      end

      @emitter.end_mapping
    end

visit_Date (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 191
    def visit_Date o
      register o, visit_Integer(o.gregorian)
    end

visit_DateTime (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 195
    def visit_DateTime o
      t = o.italy
      formatted = format_time t, t.offset.zero?
      tag = '!ruby/object:DateTime'
      register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
    end

visit_Delegator (o)
Alias for: visit_Object
visit_Encoding (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 144
    def visit_Encoding o
      tag = "!ruby/encoding"
      @emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY
    end

visit_Enumerator (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 355
    def visit_Enumerator o
      register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
      o.each { |c| accept c }
      @emitter.end_sequence
    end

visit_Exception (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 179
    def visit_Exception o
      dump_exception o, o.message.to_s
    end

visit_FalseClass (o)
Alias for: visit_Integer
visit_Float (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 236
    def visit_Float o
      if o.nan?
        @emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY
      elsif o.infinite?
        @emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'),
          nil, nil, true, false, Nodes::Scalar::ANY)
      else
        @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
      end
    end

visit_Hash (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 323
    def visit_Hash o
      if o.class == ::Hash
        register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
        o.each do |k,v|
          accept(@stringify_names && Symbol === k ? k.to_s : k)
          accept v
        end
        @emitter.end_mapping
      else
        visit_hash_subclass o
      end
    end

visit_Integer (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 230
    def visit_Integer o
      @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
    end

Also aliased as: visit_TrueClass, visit_FalseClass
visit_Module (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 305
    def visit_Module o
      raise TypeError, "can't dump anonymous module: #{o}" unless o.name
      register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED)
    end

visit_NameError (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 183
    def visit_NameError o
      dump_exception o, o.message.to_s
    end

visit_NilClass (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 361
    def visit_NilClass o
      @emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY)
    end

visit_Object (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 149
    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 = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
      register(o, map)

      dump_ivars o
      @emitter.end_mapping
    end

Also aliased as: visit_Delegator
visit_Psych_Omap (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 136
    def visit_Psych_Omap o
      seq = @emitter.start_sequence(nil, 'tag:yaml.org,2002:omap', false, Nodes::Sequence::BLOCK)
      register(o, seq)

      o.each { |k,v| visit_Hash k => v }
      @emitter.end_sequence
    end

visit_Psych_Set (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 336
    def visit_Psych_Set o
      register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))

      o.each do |k,v|
        accept(@stringify_names && Symbol === k ? k.to_s : k)
        accept v
      end

      @emitter.end_mapping
    end

visit_Range (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 315
    def visit_Range o
      register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK)
      ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m|
        accept m
      end
      @emitter.end_mapping
    end

visit_Rational (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 207
    def visit_Rational o
      register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)

      [
        'denominator', o.denominator.to_s,
        'numerator', o.numerator.to_s
      ].each do |m|
        @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
      end

      @emitter.end_mapping
    end

visit_Regexp (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 187
    def visit_Regexp o
      register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
    end

visit_String (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 251
    def visit_String o
      plain = true
      quote = true
      style = Nodes::Scalar::PLAIN
      tag   = nil

      if binary?(o)
        o     = [o].pack('m0')
        tag   = '!binary' # FIXME: change to below when syck is removed
        #tag   = 'tag:yaml.org,2002:binary'
        style = Nodes::Scalar::LITERAL
        plain = false
        quote = false
      elsif o.match?(/\n(?!\Z)/)  # match \n except blank line at the end of string
        style = Nodes::Scalar::LITERAL
      elsif o == '<<'
        style = Nodes::Scalar::SINGLE_QUOTED
        tag   = 'tag:yaml.org,2002:str'
        plain = false
        quote = false
      elsif o == 'y' || o == 'Y' || o == 'n' || o == 'N'
        style = Nodes::Scalar::DOUBLE_QUOTED
      elsif @line_width && o.length > @line_width
        style = Nodes::Scalar::FOLDED
      elsif o.match?(/^[^[:word:]][^"]*$/)
        style = Nodes::Scalar::DOUBLE_QUOTED
      elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/.match?(o)
        style = Nodes::Scalar::SINGLE_QUOTED
      end

      is_primitive = o.class == ::String
      ivars = is_primitive ? [] : o.instance_variables

      if ivars.empty?
        unless is_primitive
          tag = "!ruby/string:#{o.class}"
          plain = false
          quote = false
        end
        @emitter.scalar o, nil, tag, plain, quote, style
      else
        maptag = '!ruby/string'.dup
        maptag << ":#{o.class}" unless o.class == ::String

        register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK)
        @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY
        @emitter.scalar o, nil, tag, plain, quote, style

        dump_ivars o

        @emitter.end_mapping
      end
    end

visit_Struct (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 165
    def visit_Struct o
      tag = ['!ruby/struct', o.class.name].compact.join(':')

      register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
      o.members.each do |member|
        @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
        accept o[member]
      end

      dump_ivars o

      @emitter.end_mapping
    end

visit_Symbol (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 365
    def visit_Symbol o
      if o.empty?
        @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY
      else
        @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY
      end
    end

visit_Time (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 202
    def visit_Time o
      formatted = format_time o
      register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY)
    end

visit_TrueClass (o)
Alias for: visit_Integer

### Private Instance Methods

binary? (string)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 387
    def binary? string
      string.encoding == Encoding::ASCII_8BIT && !string.ascii_only?
    end

dump_coder (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 494
    def dump_coder o
      @coders << 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, o
    end

dump_exception (o, msg)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 463
    def dump_exception o, msg
      tag = ['!ruby/exception', o.class.name].join ':'

      @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK

      if msg
        @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY
        accept msg
      end

      @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY
      accept o.backtrace

      dump_ivars o

      @emitter.end_mapping
    end

dump_ivars (target)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 529
    def dump_ivars target
      target.instance_variables.each do |iv|
        @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY)
        accept target.instance_variable_get(iv)
      end
    end

dump_list (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 460
    def dump_list o
    end

emit_coder (c, o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 507
    def emit_coder c, o
      case c.type
      when :scalar
        @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, c.style
      when :seq
        @emitter.start_sequence nil, c.tag, c.tag.nil?, c.style
        c.seq.each do |thing|
          accept thing
        end
        @emitter.end_sequence
      when :map
        register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style)
        c.map.each do |k,v|
          accept k
          accept v
        end
        @emitter.end_mapping
      when :object
        accept c.object
      end
    end

format_time (time, utc = time.utc?)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 481
    def format_time time, utc = time.utc?
      if utc
        time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
      else
        time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
      end
    end

register (target, yaml_obj)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 489
    def register target, yaml_obj
      @st.register target, yaml_obj
      yaml_obj
    end

visit_array_subclass (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 391
    def visit_array_subclass o
      tag = "!ruby/array:#{o.class}"
      ivars = o.instance_variables
      if ivars.empty?
        node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK)
        register o, node
        o.each { |c| accept c }
        @emitter.end_sequence
      else
        node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK)
        register o, node

        # Dump the internal list
        accept 'internal'
        @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
        o.each { |c| accept c }
        @emitter.end_sequence

        # Dump the ivars
        accept 'ivars'
        @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK)
        ivars.each do |ivar|
          accept ivar
          accept o.instance_variable_get ivar
        end
        @emitter.end_mapping

        @emitter.end_mapping
      end
    end

visit_hash_subclass (o)
Source

    # File ext/psych/lib/psych/visitors/yaml_tree.rb, line 422
    def visit_hash_subclass o
      ivars = o.instance_variables
      if ivars.any?
        tag = "!ruby/hash-with-ivars:#{o.class}"
        node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
        register(o, node)

        # Dump the ivars
        accept 'ivars'
        @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
        o.instance_variables.each do |ivar|
          accept ivar
          accept o.instance_variable_get ivar
        end
        @emitter.end_mapping

        # Dump the elements
        accept 'elements'
        @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
        o.each do |k,v|
          accept k
          accept v
        end
        @emitter.end_mapping

        @emitter.end_mapping
      else
        tag = "!ruby/hash:#{o.class}"
        node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
        register(o, node)
        o.each do |k,v|
          accept k
          accept v
        end
        @emitter.end_mapping
      end
    end