psych 2.0.14-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.autotest +18 -0
- data/.gemtest +0 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.rdoc +576 -0
- data/Manifest.txt +114 -0
- data/README.rdoc +71 -0
- data/Rakefile +123 -0
- data/ext/psych/depend +3 -0
- data/ext/psych/extconf.rb +38 -0
- data/ext/psych/psych.c +34 -0
- data/ext/psych/psych.h +20 -0
- data/ext/psych/psych_emitter.c +555 -0
- data/ext/psych/psych_emitter.h +8 -0
- data/ext/psych/psych_parser.c +597 -0
- data/ext/psych/psych_parser.h +6 -0
- data/ext/psych/psych_to_ruby.c +43 -0
- data/ext/psych/psych_to_ruby.h +8 -0
- data/ext/psych/psych_yaml_tree.c +24 -0
- data/ext/psych/psych_yaml_tree.h +8 -0
- data/ext/psych/yaml/LICENSE +19 -0
- data/ext/psych/yaml/api.c +1415 -0
- data/ext/psych/yaml/config.h +10 -0
- data/ext/psych/yaml/dumper.c +394 -0
- data/ext/psych/yaml/emitter.c +2329 -0
- data/ext/psych/yaml/loader.c +459 -0
- data/ext/psych/yaml/parser.c +1370 -0
- data/ext/psych/yaml/reader.c +469 -0
- data/ext/psych/yaml/scanner.c +3576 -0
- data/ext/psych/yaml/writer.c +141 -0
- data/ext/psych/yaml/yaml.h +1971 -0
- data/ext/psych/yaml/yaml_private.h +664 -0
- data/lib/psych.jar +0 -0
- data/lib/psych.rb +504 -0
- data/lib/psych/class_loader.rb +101 -0
- data/lib/psych/coder.rb +94 -0
- data/lib/psych/core_ext.rb +35 -0
- data/lib/psych/deprecated.rb +85 -0
- data/lib/psych/exception.rb +13 -0
- data/lib/psych/handler.rb +249 -0
- data/lib/psych/handlers/document_stream.rb +22 -0
- data/lib/psych/handlers/recorder.rb +39 -0
- data/lib/psych/json/ruby_events.rb +19 -0
- data/lib/psych/json/stream.rb +16 -0
- data/lib/psych/json/tree_builder.rb +12 -0
- data/lib/psych/json/yaml_events.rb +29 -0
- data/lib/psych/nodes.rb +77 -0
- data/lib/psych/nodes/alias.rb +18 -0
- data/lib/psych/nodes/document.rb +60 -0
- data/lib/psych/nodes/mapping.rb +56 -0
- data/lib/psych/nodes/node.rb +55 -0
- data/lib/psych/nodes/scalar.rb +67 -0
- data/lib/psych/nodes/sequence.rb +81 -0
- data/lib/psych/nodes/stream.rb +37 -0
- data/lib/psych/omap.rb +4 -0
- data/lib/psych/parser.rb +51 -0
- data/lib/psych/scalar_scanner.rb +149 -0
- data/lib/psych/set.rb +4 -0
- data/lib/psych/stream.rb +37 -0
- data/lib/psych/streaming.rb +27 -0
- data/lib/psych/syntax_error.rb +21 -0
- data/lib/psych/tree_builder.rb +96 -0
- data/lib/psych/versions.rb +3 -0
- data/lib/psych/visitors.rb +6 -0
- data/lib/psych/visitors/depth_first.rb +26 -0
- data/lib/psych/visitors/emitter.rb +51 -0
- data/lib/psych/visitors/json_tree.rb +24 -0
- data/lib/psych/visitors/to_ruby.rb +404 -0
- data/lib/psych/visitors/visitor.rb +19 -0
- data/lib/psych/visitors/yaml_tree.rb +605 -0
- data/lib/psych/y.rb +9 -0
- data/lib/psych_jars.rb +5 -0
- data/test/psych/handlers/test_recorder.rb +25 -0
- data/test/psych/helper.rb +121 -0
- data/test/psych/json/test_stream.rb +109 -0
- data/test/psych/nodes/test_enumerable.rb +43 -0
- data/test/psych/test_alias_and_anchor.rb +96 -0
- data/test/psych/test_array.rb +57 -0
- data/test/psych/test_boolean.rb +36 -0
- data/test/psych/test_class.rb +36 -0
- data/test/psych/test_coder.rb +206 -0
- data/test/psych/test_date_time.rb +38 -0
- data/test/psych/test_deprecated.rb +214 -0
- data/test/psych/test_document.rb +46 -0
- data/test/psych/test_emitter.rb +93 -0
- data/test/psych/test_encoding.rb +259 -0
- data/test/psych/test_exception.rb +157 -0
- data/test/psych/test_hash.rb +94 -0
- data/test/psych/test_json_tree.rb +65 -0
- data/test/psych/test_merge_keys.rb +180 -0
- data/test/psych/test_nil.rb +18 -0
- data/test/psych/test_null.rb +19 -0
- data/test/psych/test_numeric.rb +45 -0
- data/test/psych/test_object.rb +44 -0
- data/test/psych/test_object_references.rb +71 -0
- data/test/psych/test_omap.rb +75 -0
- data/test/psych/test_parser.rb +339 -0
- data/test/psych/test_psych.rb +168 -0
- data/test/psych/test_safe_load.rb +97 -0
- data/test/psych/test_scalar.rb +11 -0
- data/test/psych/test_scalar_scanner.rb +106 -0
- data/test/psych/test_serialize_subclasses.rb +38 -0
- data/test/psych/test_set.rb +49 -0
- data/test/psych/test_stream.rb +93 -0
- data/test/psych/test_string.rb +226 -0
- data/test/psych/test_struct.rb +49 -0
- data/test/psych/test_symbol.rb +25 -0
- data/test/psych/test_tainted.rb +130 -0
- data/test/psych/test_to_yaml_properties.rb +63 -0
- data/test/psych/test_tree_builder.rb +79 -0
- data/test/psych/test_yaml.rb +1292 -0
- data/test/psych/test_yamldbm.rb +193 -0
- data/test/psych/test_yamlstore.rb +85 -0
- data/test/psych/visitors/test_depth_first.rb +49 -0
- data/test/psych/visitors/test_emitter.rb +144 -0
- data/test/psych/visitors/test_to_ruby.rb +333 -0
- data/test/psych/visitors/test_yaml_tree.rb +173 -0
- metadata +240 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Psych
|
2
|
+
module Visitors
|
3
|
+
class Visitor
|
4
|
+
def accept target
|
5
|
+
visit target
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
DISPATCH = Hash.new do |hash, klass|
|
11
|
+
hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit target
|
15
|
+
send DISPATCH[target.class], target
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,605 @@
|
|
1
|
+
require 'psych/tree_builder'
|
2
|
+
require 'psych/scalar_scanner'
|
3
|
+
require 'psych/class_loader'
|
4
|
+
|
5
|
+
module Psych
|
6
|
+
module Visitors
|
7
|
+
###
|
8
|
+
# YAMLTree builds a YAML ast given a Ruby object. For example:
|
9
|
+
#
|
10
|
+
# builder = Psych::Visitors::YAMLTree.new
|
11
|
+
# builder << { :foo => 'bar' }
|
12
|
+
# builder.tree # => #<Psych::Nodes::Stream .. }
|
13
|
+
#
|
14
|
+
class YAMLTree < Psych::Visitors::Visitor
|
15
|
+
class Registrar # :nodoc:
|
16
|
+
def initialize
|
17
|
+
@obj_to_id = {}
|
18
|
+
@obj_to_node = {}
|
19
|
+
@targets = []
|
20
|
+
@counter = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def register target, node
|
24
|
+
return unless target.respond_to? :object_id
|
25
|
+
@targets << target
|
26
|
+
@obj_to_node[target.object_id] = node
|
27
|
+
end
|
28
|
+
|
29
|
+
def key? target
|
30
|
+
@obj_to_node.key? target.object_id
|
31
|
+
rescue NoMethodError
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def id_for target
|
36
|
+
@obj_to_id[target.object_id] ||= (@counter += 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def node_for target
|
40
|
+
@obj_to_node[target.object_id]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :started, :finished
|
45
|
+
alias :finished? :finished
|
46
|
+
alias :started? :started
|
47
|
+
|
48
|
+
def self.create options = {}, emitter = nil
|
49
|
+
emitter ||= TreeBuilder.new
|
50
|
+
class_loader = ClassLoader.new
|
51
|
+
ss = ScalarScanner.new class_loader
|
52
|
+
new(emitter, ss, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.new emitter = nil, ss = nil, options = nil
|
56
|
+
return super if emitter && ss && options
|
57
|
+
|
58
|
+
if $VERBOSE
|
59
|
+
warn "This API is deprecated, please pass an emitter, scalar scanner, and options or call #{self}.create() (#{caller.first})"
|
60
|
+
end
|
61
|
+
create emitter, ss
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize emitter, ss, options
|
65
|
+
super()
|
66
|
+
@started = false
|
67
|
+
@finished = false
|
68
|
+
@emitter = emitter
|
69
|
+
@st = Registrar.new
|
70
|
+
@ss = ss
|
71
|
+
@options = options
|
72
|
+
@line_width = options[:line_width]
|
73
|
+
@coders = []
|
74
|
+
|
75
|
+
@dispatch_cache = Hash.new do |h,klass|
|
76
|
+
method = "visit_#{(klass.name || '').split('::').join('_')}"
|
77
|
+
|
78
|
+
method = respond_to?(method) ? method : h[klass.superclass]
|
79
|
+
|
80
|
+
raise(TypeError, "Can't dump #{target.class}") unless method
|
81
|
+
|
82
|
+
h[klass] = method
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def start encoding = Nodes::Stream::UTF8
|
87
|
+
@emitter.start_stream(encoding).tap do
|
88
|
+
@started = true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def finish
|
93
|
+
@emitter.end_stream.tap do
|
94
|
+
@finished = true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def tree
|
99
|
+
finish unless finished?
|
100
|
+
@emitter.root
|
101
|
+
end
|
102
|
+
|
103
|
+
def push object
|
104
|
+
start unless started?
|
105
|
+
version = []
|
106
|
+
version = [1,1] if @options[:header]
|
107
|
+
|
108
|
+
case @options[:version]
|
109
|
+
when Array
|
110
|
+
version = @options[:version]
|
111
|
+
when String
|
112
|
+
version = @options[:version].split('.').map { |x| x.to_i }
|
113
|
+
else
|
114
|
+
version = [1,1]
|
115
|
+
end if @options.key? :version
|
116
|
+
|
117
|
+
@emitter.start_document version, [], false
|
118
|
+
accept object
|
119
|
+
@emitter.end_document !@emitter.streaming?
|
120
|
+
end
|
121
|
+
alias :<< :push
|
122
|
+
|
123
|
+
def accept target
|
124
|
+
# return any aliases we find
|
125
|
+
if @st.key? target
|
126
|
+
oid = @st.id_for target
|
127
|
+
node = @st.node_for target
|
128
|
+
anchor = oid.to_s
|
129
|
+
node.anchor = anchor
|
130
|
+
return @emitter.alias anchor
|
131
|
+
end
|
132
|
+
|
133
|
+
if target.respond_to?(:to_yaml)
|
134
|
+
begin
|
135
|
+
loc = target.method(:to_yaml).source_location.first
|
136
|
+
if loc !~ /(syck\/rubytypes.rb|psych\/core_ext.rb)/
|
137
|
+
unless target.respond_to?(:encode_with)
|
138
|
+
if $VERBOSE
|
139
|
+
warn "implementing to_yaml is deprecated, please implement \"encode_with\""
|
140
|
+
end
|
141
|
+
|
142
|
+
target.to_yaml(:nodump => true)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
rescue
|
146
|
+
# public_method or source_location might be overridden,
|
147
|
+
# and it's OK to skip it since it's only to emit a warning
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
if target.respond_to?(:encode_with)
|
152
|
+
dump_coder target
|
153
|
+
else
|
154
|
+
send(@dispatch_cache[target.class], target)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def visit_Psych_Omap o
|
159
|
+
seq = @emitter.start_sequence(nil, '!omap', false, Nodes::Sequence::BLOCK)
|
160
|
+
register(o, seq)
|
161
|
+
|
162
|
+
o.each { |k,v| visit_Hash k => v }
|
163
|
+
@emitter.end_sequence
|
164
|
+
end
|
165
|
+
|
166
|
+
def visit_Encoding o
|
167
|
+
tag = "!ruby/encoding"
|
168
|
+
@emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY
|
169
|
+
end
|
170
|
+
|
171
|
+
def visit_Object o
|
172
|
+
tag = Psych.dump_tags[o.class]
|
173
|
+
unless tag
|
174
|
+
klass = o.class == Object ? nil : o.class.name
|
175
|
+
tag = ['!ruby/object', klass].compact.join(':')
|
176
|
+
end
|
177
|
+
|
178
|
+
map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
|
179
|
+
register(o, map)
|
180
|
+
|
181
|
+
dump_ivars o
|
182
|
+
@emitter.end_mapping
|
183
|
+
end
|
184
|
+
|
185
|
+
def visit_Struct o
|
186
|
+
tag = ['!ruby/struct', o.class.name].compact.join(':')
|
187
|
+
|
188
|
+
register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
|
189
|
+
o.members.each do |member|
|
190
|
+
@emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
|
191
|
+
accept o[member]
|
192
|
+
end
|
193
|
+
|
194
|
+
dump_ivars o
|
195
|
+
|
196
|
+
@emitter.end_mapping
|
197
|
+
end
|
198
|
+
|
199
|
+
def visit_Exception o
|
200
|
+
tag = ['!ruby/exception', o.class.name].join ':'
|
201
|
+
|
202
|
+
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
|
203
|
+
|
204
|
+
{
|
205
|
+
'message' => private_iv_get(o, 'mesg'),
|
206
|
+
'backtrace' => private_iv_get(o, 'backtrace'),
|
207
|
+
}.each do |k,v|
|
208
|
+
next unless v
|
209
|
+
@emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
|
210
|
+
accept v
|
211
|
+
end
|
212
|
+
|
213
|
+
dump_ivars o
|
214
|
+
|
215
|
+
@emitter.end_mapping
|
216
|
+
end
|
217
|
+
|
218
|
+
def visit_NameError o
|
219
|
+
tag = ['!ruby/exception', o.class.name].join ':'
|
220
|
+
|
221
|
+
@emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
|
222
|
+
|
223
|
+
{
|
224
|
+
'message' => o.message.to_s,
|
225
|
+
'backtrace' => private_iv_get(o, 'backtrace'),
|
226
|
+
}.each do |k,v|
|
227
|
+
next unless v
|
228
|
+
@emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
|
229
|
+
accept v
|
230
|
+
end
|
231
|
+
|
232
|
+
dump_ivars o
|
233
|
+
|
234
|
+
@emitter.end_mapping
|
235
|
+
end
|
236
|
+
|
237
|
+
def visit_Regexp o
|
238
|
+
register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
|
239
|
+
end
|
240
|
+
|
241
|
+
def visit_DateTime o
|
242
|
+
formatted = if o.offset.zero?
|
243
|
+
o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze)
|
244
|
+
else
|
245
|
+
o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze)
|
246
|
+
end
|
247
|
+
tag = '!ruby/object:DateTime'
|
248
|
+
register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
|
249
|
+
end
|
250
|
+
|
251
|
+
def visit_Time o
|
252
|
+
formatted = format_time o
|
253
|
+
register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY)
|
254
|
+
end
|
255
|
+
|
256
|
+
def visit_Rational o
|
257
|
+
register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
|
258
|
+
|
259
|
+
[
|
260
|
+
'denominator', o.denominator.to_s,
|
261
|
+
'numerator', o.numerator.to_s
|
262
|
+
].each do |m|
|
263
|
+
@emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
|
264
|
+
end
|
265
|
+
|
266
|
+
@emitter.end_mapping
|
267
|
+
end
|
268
|
+
|
269
|
+
def visit_Complex o
|
270
|
+
register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
|
271
|
+
|
272
|
+
['real', o.real.to_s, 'image', o.imag.to_s].each do |m|
|
273
|
+
@emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
|
274
|
+
end
|
275
|
+
|
276
|
+
@emitter.end_mapping
|
277
|
+
end
|
278
|
+
|
279
|
+
def visit_Integer o
|
280
|
+
@emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
|
281
|
+
end
|
282
|
+
alias :visit_TrueClass :visit_Integer
|
283
|
+
alias :visit_FalseClass :visit_Integer
|
284
|
+
alias :visit_Date :visit_Integer
|
285
|
+
|
286
|
+
def visit_Float o
|
287
|
+
if o.nan?
|
288
|
+
@emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY
|
289
|
+
elsif o.infinite?
|
290
|
+
@emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'),
|
291
|
+
nil, nil, true, false, Nodes::Scalar::ANY)
|
292
|
+
else
|
293
|
+
@emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def visit_BigDecimal o
|
298
|
+
@emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY
|
299
|
+
end
|
300
|
+
|
301
|
+
def visit_String o
|
302
|
+
plain = true
|
303
|
+
quote = true
|
304
|
+
style = Nodes::Scalar::PLAIN
|
305
|
+
tag = nil
|
306
|
+
|
307
|
+
if binary?(o)
|
308
|
+
o = [o].pack('m').chomp
|
309
|
+
tag = '!binary' # FIXME: change to below when syck is removed
|
310
|
+
#tag = 'tag:yaml.org,2002:binary'
|
311
|
+
style = Nodes::Scalar::LITERAL
|
312
|
+
plain = false
|
313
|
+
quote = false
|
314
|
+
elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string
|
315
|
+
style = Nodes::Scalar::LITERAL
|
316
|
+
elsif o == '<<'
|
317
|
+
style = Nodes::Scalar::SINGLE_QUOTED
|
318
|
+
tag = 'tag:yaml.org,2002:str'
|
319
|
+
plain = false
|
320
|
+
quote = false
|
321
|
+
elsif @line_width && o.length > @line_width
|
322
|
+
style = Nodes::Scalar::FOLDED
|
323
|
+
elsif o =~ /^[^[:word:]][^"]*$/
|
324
|
+
style = Nodes::Scalar::DOUBLE_QUOTED
|
325
|
+
elsif not String === @ss.tokenize(o)
|
326
|
+
style = Nodes::Scalar::SINGLE_QUOTED
|
327
|
+
end
|
328
|
+
|
329
|
+
is_primitive = o.class == ::String
|
330
|
+
ivars = find_ivars o, is_primitive
|
331
|
+
|
332
|
+
if ivars.empty?
|
333
|
+
unless is_primitive
|
334
|
+
tag = "!ruby/string:#{o.class}"
|
335
|
+
plain = false
|
336
|
+
quote = false
|
337
|
+
end
|
338
|
+
@emitter.scalar o, nil, tag, plain, quote, style
|
339
|
+
else
|
340
|
+
maptag = '!ruby/string'
|
341
|
+
maptag << ":#{o.class}" unless o.class == ::String
|
342
|
+
|
343
|
+
register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK)
|
344
|
+
@emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY
|
345
|
+
@emitter.scalar o, nil, tag, plain, quote, style
|
346
|
+
|
347
|
+
dump_ivars o
|
348
|
+
|
349
|
+
@emitter.end_mapping
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def visit_Module o
|
354
|
+
raise TypeError, "can't dump anonymous module: #{o}" unless o.name
|
355
|
+
register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED)
|
356
|
+
end
|
357
|
+
|
358
|
+
def visit_Class o
|
359
|
+
raise TypeError, "can't dump anonymous class: #{o}" unless o.name
|
360
|
+
register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED)
|
361
|
+
end
|
362
|
+
|
363
|
+
def visit_Range o
|
364
|
+
register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK)
|
365
|
+
['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m|
|
366
|
+
accept m
|
367
|
+
end
|
368
|
+
@emitter.end_mapping
|
369
|
+
end
|
370
|
+
|
371
|
+
def visit_Hash o
|
372
|
+
if o.class == ::Hash
|
373
|
+
register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
|
374
|
+
o.each do |k,v|
|
375
|
+
accept k
|
376
|
+
accept v
|
377
|
+
end
|
378
|
+
@emitter.end_mapping
|
379
|
+
else
|
380
|
+
visit_hash_subclass o
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def visit_Psych_Set o
|
385
|
+
register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
|
386
|
+
|
387
|
+
o.each do |k,v|
|
388
|
+
accept k
|
389
|
+
accept v
|
390
|
+
end
|
391
|
+
|
392
|
+
@emitter.end_mapping
|
393
|
+
end
|
394
|
+
|
395
|
+
def visit_Array o
|
396
|
+
if o.class == ::Array
|
397
|
+
register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
|
398
|
+
o.each { |c| accept c }
|
399
|
+
@emitter.end_sequence
|
400
|
+
else
|
401
|
+
visit_array_subclass o
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def visit_NilClass o
|
406
|
+
@emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY)
|
407
|
+
end
|
408
|
+
|
409
|
+
def visit_Symbol o
|
410
|
+
if o.empty?
|
411
|
+
@emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY
|
412
|
+
else
|
413
|
+
@emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def visit_BasicObject o
|
418
|
+
tag = Psych.dump_tags[o.class]
|
419
|
+
tag ||= "!ruby/marshalable:#{o.class.name}"
|
420
|
+
|
421
|
+
map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
|
422
|
+
register(o, map)
|
423
|
+
|
424
|
+
o.marshal_dump.each(&method(:accept))
|
425
|
+
|
426
|
+
@emitter.end_mapping
|
427
|
+
end
|
428
|
+
|
429
|
+
private
|
430
|
+
# FIXME: Remove the index and count checks in Psych 3.0
|
431
|
+
NULL = "\x00"
|
432
|
+
BINARY_RANGE = "\x00-\x7F"
|
433
|
+
WS_RANGE = "^ -~\t\r\n"
|
434
|
+
|
435
|
+
def binary? string
|
436
|
+
(string.encoding == Encoding::ASCII_8BIT && !string.ascii_only?) ||
|
437
|
+
string.index(NULL) ||
|
438
|
+
string.count(BINARY_RANGE, WS_RANGE).fdiv(string.length) > 0.3
|
439
|
+
end
|
440
|
+
|
441
|
+
def visit_array_subclass o
|
442
|
+
tag = "!ruby/array:#{o.class}"
|
443
|
+
ivars = o.instance_variables
|
444
|
+
if ivars.empty?
|
445
|
+
node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK)
|
446
|
+
register o, node
|
447
|
+
o.each { |c| accept c }
|
448
|
+
@emitter.end_sequence
|
449
|
+
else
|
450
|
+
node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK)
|
451
|
+
register o, node
|
452
|
+
|
453
|
+
# Dump the internal list
|
454
|
+
accept 'internal'
|
455
|
+
@emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
|
456
|
+
o.each { |c| accept c }
|
457
|
+
@emitter.end_sequence
|
458
|
+
|
459
|
+
# Dump the ivars
|
460
|
+
accept 'ivars'
|
461
|
+
@emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK)
|
462
|
+
ivars.each do |ivar|
|
463
|
+
accept ivar
|
464
|
+
accept o.instance_variable_get ivar
|
465
|
+
end
|
466
|
+
@emitter.end_mapping
|
467
|
+
|
468
|
+
@emitter.end_mapping
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def visit_hash_subclass o
|
473
|
+
ivars = o.instance_variables
|
474
|
+
if ivars.any?
|
475
|
+
tag = "!ruby/hash-with-ivars:#{o.class}"
|
476
|
+
node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
|
477
|
+
register(o, node)
|
478
|
+
|
479
|
+
# Dump the elements
|
480
|
+
accept 'elements'
|
481
|
+
@emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
|
482
|
+
o.each do |k,v|
|
483
|
+
accept k
|
484
|
+
accept v
|
485
|
+
end
|
486
|
+
@emitter.end_mapping
|
487
|
+
|
488
|
+
# Dump the ivars
|
489
|
+
accept 'ivars'
|
490
|
+
@emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
|
491
|
+
o.instance_variables.each do |ivar|
|
492
|
+
accept ivar
|
493
|
+
accept o.instance_variable_get ivar
|
494
|
+
end
|
495
|
+
@emitter.end_mapping
|
496
|
+
|
497
|
+
@emitter.end_mapping
|
498
|
+
else
|
499
|
+
tag = "!ruby/hash:#{o.class}"
|
500
|
+
node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
|
501
|
+
register(o, node)
|
502
|
+
o.each do |k,v|
|
503
|
+
accept k
|
504
|
+
accept v
|
505
|
+
end
|
506
|
+
@emitter.end_mapping
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
def dump_list o
|
511
|
+
end
|
512
|
+
|
513
|
+
# '%:z' was no defined until 1.9.3
|
514
|
+
if RUBY_VERSION < '1.9.3'
|
515
|
+
def format_time time
|
516
|
+
formatted = time.strftime("%Y-%m-%d %H:%M:%S.%9N")
|
517
|
+
|
518
|
+
if time.utc?
|
519
|
+
formatted += " Z"
|
520
|
+
else
|
521
|
+
zone = time.strftime('%z')
|
522
|
+
formatted += " #{zone[0,3]}:#{zone[3,5]}"
|
523
|
+
end
|
524
|
+
|
525
|
+
formatted
|
526
|
+
end
|
527
|
+
else
|
528
|
+
def format_time time
|
529
|
+
if time.utc?
|
530
|
+
time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
|
531
|
+
else
|
532
|
+
time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
# FIXME: remove this method once "to_yaml_properties" is removed
|
538
|
+
def find_ivars target, is_primitive=false
|
539
|
+
begin
|
540
|
+
loc = target.method(:to_yaml_properties).source_location.first
|
541
|
+
unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb')
|
542
|
+
if $VERBOSE
|
543
|
+
warn "#{loc}: to_yaml_properties is deprecated, please implement \"encode_with(coder)\""
|
544
|
+
end
|
545
|
+
return target.to_yaml_properties
|
546
|
+
end
|
547
|
+
rescue
|
548
|
+
# public_method or source_location might be overridden,
|
549
|
+
# and it's OK to skip it since it's only to emit a warning.
|
550
|
+
end
|
551
|
+
|
552
|
+
is_primitive ? [] : target.instance_variables
|
553
|
+
end
|
554
|
+
|
555
|
+
def register target, yaml_obj
|
556
|
+
@st.register target, yaml_obj
|
557
|
+
yaml_obj
|
558
|
+
end
|
559
|
+
|
560
|
+
def dump_coder o
|
561
|
+
@coders << o
|
562
|
+
tag = Psych.dump_tags[o.class]
|
563
|
+
unless tag
|
564
|
+
klass = o.class == Object ? nil : o.class.name
|
565
|
+
tag = ['!ruby/object', klass].compact.join(':')
|
566
|
+
end
|
567
|
+
|
568
|
+
c = Psych::Coder.new(tag)
|
569
|
+
o.encode_with(c)
|
570
|
+
emit_coder c, o
|
571
|
+
end
|
572
|
+
|
573
|
+
def emit_coder c, o
|
574
|
+
case c.type
|
575
|
+
when :scalar
|
576
|
+
@emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
|
577
|
+
when :seq
|
578
|
+
@emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK
|
579
|
+
c.seq.each do |thing|
|
580
|
+
accept thing
|
581
|
+
end
|
582
|
+
@emitter.end_sequence
|
583
|
+
when :map
|
584
|
+
register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style)
|
585
|
+
c.map.each do |k,v|
|
586
|
+
accept k
|
587
|
+
accept v
|
588
|
+
end
|
589
|
+
@emitter.end_mapping
|
590
|
+
when :object
|
591
|
+
accept c.object
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def dump_ivars target
|
596
|
+
ivars = find_ivars target
|
597
|
+
|
598
|
+
ivars.each do |iv|
|
599
|
+
@emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY)
|
600
|
+
accept target.instance_variable_get(iv)
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|