lib/psych/visitors/yaml_tree.rb in psych-1.3.4 vs lib/psych/visitors/yaml_tree.rb in psych-2.0.0
- old
+ new
@@ -1,25 +1,60 @@
+require 'psych/tree_builder'
+require 'psych/scalar_scanner'
+require 'psych/class_loader'
+
module Psych
module Visitors
###
# YAMLTree builds a YAML ast given a ruby object. For example:
#
# builder = Psych::Visitors::YAMLTree.new
# builder << { :foo => 'bar' }
# builder.tree # => #<Psych::Nodes::Stream .. }
#
class YAMLTree < Psych::Visitors::Visitor
+ class Registrar # :nodoc:
+ def initialize
+ @obj_to_id = {}
+ @obj_to_node = {}
+ @counter = 0
+ end
+
+ def register target, node
+ @obj_to_node[target.object_id] = node
+ end
+
+ def key? target
+ @obj_to_node.key? target.object_id
+ end
+
+ def id_for target
+ @obj_to_id[target.object_id] ||= (@counter += 1)
+ end
+
+ def node_for target
+ @obj_to_node[target.object_id]
+ end
+ end
+
attr_reader :started, :finished
alias :finished? :finished
alias :started? :started
- def initialize options = {}, emitter = TreeBuilder.new, ss = ScalarScanner.new
+ def self.create options = {}, emitter = nil
+ emitter ||= TreeBuilder.new
+ class_loader = ClassLoader.new
+ ss = ScalarScanner.new class_loader
+ new(emitter, ss, options)
+ end
+
+ def initialize emitter, ss, options
super()
@started = false
@finished = false
@emitter = emitter
- @st = {}
+ @st = Registrar.new
@ss = ss
@options = options
@coders = []
@dispatch_cache = Hash.new do |h,klass|
@@ -45,10 +80,11 @@
end
end
def tree
finish unless finished?
+ @emitter.root
end
def push object
start unless started?
version = []
@@ -63,19 +99,19 @@
version = [1,1]
end if @options.key? :version
@emitter.start_document version, [], false
accept object
- @emitter.end_document
+ @emitter.end_document !@emitter.streaming?
end
alias :<< :push
def accept target
# return any aliases we find
- if @st.key? target.object_id
- oid = target.object_id
- node = @st[oid]
+ 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
@@ -218,31 +254,37 @@
def visit_BigDecimal o
@emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY
end
def binary? string
- string.encoding == Encoding::ASCII_8BIT ||
+ (string.encoding == Encoding::ASCII_8BIT && !string.ascii_only?) ||
string.index("\x00") ||
- string.count("\x00-\x7F", "^ -~\t\r\n").fdiv(string.length) > 0.3
+ string.count("\x00-\x7F", "^ -~\t\r\n").fdiv(string.length) > 0.3 ||
+ string.class != String
end
private :binary?
def visit_String o
- plain = false
- quote = false
- style = Nodes::Scalar::ANY
+ plain = true
+ quote = true
+ style = Nodes::Scalar::PLAIN
+ tag = nil
+ str = o
if binary?(o)
str = [o].pack('m').chomp
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 =~ /\n/
+ style = Nodes::Scalar::LITERAL
else
- str = o
- tag = nil
- quote = !(String === @ss.tokenize(o))
- plain = !quote
+ unless String === @ss.tokenize(o)
+ style = Nodes::Scalar::SINGLE_QUOTED
+ end
end
ivars = find_ivars o
if ivars.empty?
@@ -400,11 +442,11 @@
target.instance_variables
end
def register target, yaml_obj
- @st[target.object_id] = yaml_obj
+ @st.register target, yaml_obj
yaml_obj
end
def dump_coder o
@coders << o
@@ -430,10 +472,10 @@
end
@emitter.end_sequence
when :map
@emitter.start_mapping nil, c.tag, c.implicit, c.style
c.map.each do |k,v|
- @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
+ accept k
accept v
end
@emitter.end_mapping
when :object
accept c.object