1require 'psych/handler'
2
3module Psych
4  ###
5  # This class works in conjunction with Psych::Parser to build an in-memory
6  # parse tree that represents a YAML document.
7  #
8  # == Example
9  #
10  #   parser = Psych::Parser.new Psych::TreeBuilder.new
11  #   parser.parse('--- foo')
12  #   tree = parser.handler.root
13  #
14  # See Psych::Handler for documentation on the event methods used in this
15  # class.
16  class TreeBuilder < Psych::Handler
17    # Returns the root node for the built tree
18    attr_reader :root
19
20    # Create a new TreeBuilder instance
21    def initialize
22      @stack = []
23      @last  = nil
24      @root  = nil
25    end
26
27    %w{
28      Sequence
29      Mapping
30    }.each do |node|
31      class_eval %{
32        def start_#{node.downcase}(anchor, tag, implicit, style)
33          n = Nodes::#{node}.new(anchor, tag, implicit, style)
34          @last.children << n
35          push n
36        end
37
38        def end_#{node.downcase}
39          pop
40        end
41      }
42    end
43
44    ###
45    # Handles start_document events with +version+, +tag_directives+,
46    # and +implicit+ styling.
47    #
48    # See Psych::Handler#start_document
49    def start_document version, tag_directives, implicit
50      n = Nodes::Document.new version, tag_directives, implicit
51      @last.children << n
52      push n
53    end
54
55    ###
56    # Handles end_document events with +version+, +tag_directives+,
57    # and +implicit+ styling.
58    #
59    # See Psych::Handler#start_document
60    def end_document implicit_end = !streaming?
61      @last.implicit_end = implicit_end
62      pop
63    end
64
65    def start_stream encoding
66      @root = Nodes::Stream.new(encoding)
67      push @root
68    end
69
70    def end_stream
71      pop
72    end
73
74    def scalar value, anchor, tag, plain, quoted, style
75      s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
76      @last.children << s
77      s
78    end
79
80    def alias anchor
81      @last.children << Nodes::Alias.new(anchor)
82    end
83
84    private
85    def push value
86      @stack.push value
87      @last = value
88    end
89
90    def pop
91      x = @stack.pop
92      @last = @stack.last
93      x
94    end
95  end
96end
97