曾与蒿藜同雨露,한때 잡초와 쑥과 함께 비와 이슬을 나누던 곳이 이제는 소나무와 삼나무와 함께 서리와 눈을 견뎌내고 있다.终随松柏到冰霜.かつては雑草やヨモギと共に雨や露を分かち合っていたが、今では松やヒノキと共に霜や雪に耐えている。曾与蒿藜同雨露,Once sharing rain and dew with weeds and wormwood, now enduring frost and snow with pines and cypresses.终随松柏到冰霜.曾与蒿藜同雨露한때 잡초와 쑥과 함께 비와 이슬을 나누던 곳이 이제는 소나무와 삼나무와 함께 서리와 눈을 견뎌내고 있다.,终随松柏到冰霜.譖セ荳手珍阯懷酔髮ィ髴イ�檎サ磯囂譚セ譟丞芦蜀ー髴�曾与蒿藜同雨露,鏇句笌钂胯棞鍚岄洦闇诧紝缁堥殢鏉炬煆鍒板啺闇�终随松柏到冰霜.曾与蒿藜同雨露,한때 잡초와 쑥과 함께 비와 이슬을 나누던 곳이 이제는 소나무와 삼나무와 함께 서리와 눈을 견뎌내고 있다.终随松柏到冰霜.曾与蒿藜同雨露,终随松柏到冰霜.
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 self.create options = {}, emitter = nil
emitter ||= TreeBuilder.new
class_loader = ClassLoader.new
ss = ScalarScanner.new class_loader
new(emitter, ss, options)
end
def self.new emitter = nil, ss = nil, options = nil
return super if emitter && ss && options
if $VERBOSE
warn "This API is deprecated, please pass an emitter, scalar scanner, and options or call #{self}.create() (#{caller.first})"
end
create emitter, ss
end
def initialize emitter, ss, options
super()
@started = false
@finished = false
@emitter = emitter
@st = Registrar.new
@ss = ss
@options = options
@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
end
def start encoding = Nodes::Stream::UTF8
@emitter.start_stream(encoding).tap do
@started = true
end
end
def finish
@emitter.end_stream.tap do
@finished = true
end
end
def tree
finish unless finished?
@emitter.root
end
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
alias :<< :push
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?(:to_yaml)
begin
loc = target.method(:to_yaml).source_location.first
if loc !~ /(syck\/rubytypes.rb|psych\/core_ext.rb)/
unless target.respond_to?(:encode_with)
if $VERBOSE
warn "implementing to_yaml is deprecated, please implement \"encode_with\""
end
target.to_yaml(:nodump => true)
end
end
rescue
# public_method or source_location might be overridden,
# and it's OK to skip it since it's only to emit a warning
end
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 = @emitter.start_sequence(nil, '!omap', false, Nodes::Sequence::BLOCK)
register(o, seq)
o.each { |k,v| visit_Hash k => v }
@emitter.end_sequence
end
def visit_Encoding o
tag = "!ruby/encoding"
@emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY
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 = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
register(o, map)
dump_ivars o
@emitter.end_mapping
end
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
def visit_Exception o
tag = ['!ruby/exception', o.class.name].join ':'
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
{
'message' => private_iv_get(o, 'mesg'),
'backtrace' => private_iv_get(o, 'backtrace'),
}.each do |k,v|
next unless v
@emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
accept v
end
dump_ivars o
@emitter.end_mapping
end
def visit_Regexp o
register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
end
def visit_DateTime o
formatted = if o.offset.zero?
o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze)
else
o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze)
end
tag = '!ruby/object:DateTime'
register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
end
def visit_Time o
formatted = format_time o
register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY)
end
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
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
def visit_Integer o
@emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
end
alias :visit_TrueClass :visit_Integer
alias :visit_FalseClass :visit_Integer
alias :visit_Date :visit_Integer
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
def visit_BigDecimal o
@emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY
end
def visit_String o
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
elsif o =~ /^\W[^"]*$/
style = Nodes::Scalar::DOUBLE_QUOTED
else
unless String === @ss.tokenize(o)
style = Nodes::Scalar::SINGLE_QUOTED
end
end
ivars = find_ivars o
if ivars.empty?
unless o.class == ::String
tag = "!ruby/string:#{o.class}"
plain = false
quote = false
end
@emitter.scalar str, nil, tag, plain, quote, style
else
maptag = '!ruby/string'
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 str, nil, tag, plain, quote, style
dump_ivars o
@emitter.end_mapping
end
end
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
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
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
def visit_Hash o
tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
implicit = !tag
register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK))
o.each do |k,v|
accept k
accept v
end
@emitter.end_mapping
end
def visit_Psych_Set o
register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
o.each do |k,v|
accept k
accept v
end
@emitter.end_mapping
end
def visit_Array o
if o.class == ::Array
register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
o.each { |c| accept c }
@emitter.end_sequence
else
visit_array_subclass o
end
end
def visit_NilClass o
@emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY)
end
def visit_Symbol o
@emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY
end
private
# FIXME: Remove the index and count checks in Psych 3.0
NULL = "\x00"
BINARY_RANGE = "\x00-\x7F"
WS_RANGE = "^ -~\t\r\n"
def binary? string
(string.encoding == Encoding::ASCII_8BIT && !string.ascii_only?) ||
string.index(NULL) ||
string.count(BINARY_RANGE, WS_RANGE).fdiv(string.length) > 0.3
end
def visit_array_subclass o
tag = "!ruby/array:#{o.class}"
if o.instance_variables.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)
o.instance_variables.each do |ivar|
accept ivar
accept o.instance_variable_get ivar
end
@emitter.end_mapping
@emitter.end_mapping
end
end
def dump_list o
end
# '%:z' was no defined until 1.9.3
if RUBY_VERSION < '1.9.3'
def format_time time
formatted = time.strftime("%Y-%m-%d %H:%M:%S.%9N")
if time.utc?
formatted += " Z"
else
zone = time.strftime('%z')
formatted += " #{zone[0,3]}:#{zone[3,5]}"
end
formatted
end
else
def format_time time
if time.utc?
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
else
time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
end
end
end
# FIXME: remove this method once "to_yaml_properties" is removed
def find_ivars target
begin
loc = target.method(:to_yaml_properties).source_location.first
unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb')
if $VERBOSE
warn "#{loc}: to_yaml_properties is deprecated, please implement \"encode_with(coder)\""
end
return target.to_yaml_properties
end
rescue
# public_method or source_location might be overridden,
# and it's OK to skip it since it's only to emit a warning.
end
target.instance_variables
end
def register target, yaml_obj
@st.register target, yaml_obj
yaml_obj
end
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
end
def emit_coder c
case c.type
when :scalar
@emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
when :seq
@emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK
c.seq.each do |thing|
accept thing
end
@emitter.end_sequence
when :map
@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
def dump_ivars target
ivars = find_ivars target
ivars.each do |iv|
@emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY)
accept target.instance_variable_get(iv)
end
end
end
end
end