psych 2.0.14-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +18 -0
  3. data/.gemtest +0 -0
  4. data/.travis.yml +16 -0
  5. data/CHANGELOG.rdoc +576 -0
  6. data/Manifest.txt +114 -0
  7. data/README.rdoc +71 -0
  8. data/Rakefile +123 -0
  9. data/ext/psych/depend +3 -0
  10. data/ext/psych/extconf.rb +38 -0
  11. data/ext/psych/psych.c +34 -0
  12. data/ext/psych/psych.h +20 -0
  13. data/ext/psych/psych_emitter.c +555 -0
  14. data/ext/psych/psych_emitter.h +8 -0
  15. data/ext/psych/psych_parser.c +597 -0
  16. data/ext/psych/psych_parser.h +6 -0
  17. data/ext/psych/psych_to_ruby.c +43 -0
  18. data/ext/psych/psych_to_ruby.h +8 -0
  19. data/ext/psych/psych_yaml_tree.c +24 -0
  20. data/ext/psych/psych_yaml_tree.h +8 -0
  21. data/ext/psych/yaml/LICENSE +19 -0
  22. data/ext/psych/yaml/api.c +1415 -0
  23. data/ext/psych/yaml/config.h +10 -0
  24. data/ext/psych/yaml/dumper.c +394 -0
  25. data/ext/psych/yaml/emitter.c +2329 -0
  26. data/ext/psych/yaml/loader.c +459 -0
  27. data/ext/psych/yaml/parser.c +1370 -0
  28. data/ext/psych/yaml/reader.c +469 -0
  29. data/ext/psych/yaml/scanner.c +3576 -0
  30. data/ext/psych/yaml/writer.c +141 -0
  31. data/ext/psych/yaml/yaml.h +1971 -0
  32. data/ext/psych/yaml/yaml_private.h +664 -0
  33. data/lib/psych.jar +0 -0
  34. data/lib/psych.rb +504 -0
  35. data/lib/psych/class_loader.rb +101 -0
  36. data/lib/psych/coder.rb +94 -0
  37. data/lib/psych/core_ext.rb +35 -0
  38. data/lib/psych/deprecated.rb +85 -0
  39. data/lib/psych/exception.rb +13 -0
  40. data/lib/psych/handler.rb +249 -0
  41. data/lib/psych/handlers/document_stream.rb +22 -0
  42. data/lib/psych/handlers/recorder.rb +39 -0
  43. data/lib/psych/json/ruby_events.rb +19 -0
  44. data/lib/psych/json/stream.rb +16 -0
  45. data/lib/psych/json/tree_builder.rb +12 -0
  46. data/lib/psych/json/yaml_events.rb +29 -0
  47. data/lib/psych/nodes.rb +77 -0
  48. data/lib/psych/nodes/alias.rb +18 -0
  49. data/lib/psych/nodes/document.rb +60 -0
  50. data/lib/psych/nodes/mapping.rb +56 -0
  51. data/lib/psych/nodes/node.rb +55 -0
  52. data/lib/psych/nodes/scalar.rb +67 -0
  53. data/lib/psych/nodes/sequence.rb +81 -0
  54. data/lib/psych/nodes/stream.rb +37 -0
  55. data/lib/psych/omap.rb +4 -0
  56. data/lib/psych/parser.rb +51 -0
  57. data/lib/psych/scalar_scanner.rb +149 -0
  58. data/lib/psych/set.rb +4 -0
  59. data/lib/psych/stream.rb +37 -0
  60. data/lib/psych/streaming.rb +27 -0
  61. data/lib/psych/syntax_error.rb +21 -0
  62. data/lib/psych/tree_builder.rb +96 -0
  63. data/lib/psych/versions.rb +3 -0
  64. data/lib/psych/visitors.rb +6 -0
  65. data/lib/psych/visitors/depth_first.rb +26 -0
  66. data/lib/psych/visitors/emitter.rb +51 -0
  67. data/lib/psych/visitors/json_tree.rb +24 -0
  68. data/lib/psych/visitors/to_ruby.rb +404 -0
  69. data/lib/psych/visitors/visitor.rb +19 -0
  70. data/lib/psych/visitors/yaml_tree.rb +605 -0
  71. data/lib/psych/y.rb +9 -0
  72. data/lib/psych_jars.rb +5 -0
  73. data/test/psych/handlers/test_recorder.rb +25 -0
  74. data/test/psych/helper.rb +121 -0
  75. data/test/psych/json/test_stream.rb +109 -0
  76. data/test/psych/nodes/test_enumerable.rb +43 -0
  77. data/test/psych/test_alias_and_anchor.rb +96 -0
  78. data/test/psych/test_array.rb +57 -0
  79. data/test/psych/test_boolean.rb +36 -0
  80. data/test/psych/test_class.rb +36 -0
  81. data/test/psych/test_coder.rb +206 -0
  82. data/test/psych/test_date_time.rb +38 -0
  83. data/test/psych/test_deprecated.rb +214 -0
  84. data/test/psych/test_document.rb +46 -0
  85. data/test/psych/test_emitter.rb +93 -0
  86. data/test/psych/test_encoding.rb +259 -0
  87. data/test/psych/test_exception.rb +157 -0
  88. data/test/psych/test_hash.rb +94 -0
  89. data/test/psych/test_json_tree.rb +65 -0
  90. data/test/psych/test_merge_keys.rb +180 -0
  91. data/test/psych/test_nil.rb +18 -0
  92. data/test/psych/test_null.rb +19 -0
  93. data/test/psych/test_numeric.rb +45 -0
  94. data/test/psych/test_object.rb +44 -0
  95. data/test/psych/test_object_references.rb +71 -0
  96. data/test/psych/test_omap.rb +75 -0
  97. data/test/psych/test_parser.rb +339 -0
  98. data/test/psych/test_psych.rb +168 -0
  99. data/test/psych/test_safe_load.rb +97 -0
  100. data/test/psych/test_scalar.rb +11 -0
  101. data/test/psych/test_scalar_scanner.rb +106 -0
  102. data/test/psych/test_serialize_subclasses.rb +38 -0
  103. data/test/psych/test_set.rb +49 -0
  104. data/test/psych/test_stream.rb +93 -0
  105. data/test/psych/test_string.rb +226 -0
  106. data/test/psych/test_struct.rb +49 -0
  107. data/test/psych/test_symbol.rb +25 -0
  108. data/test/psych/test_tainted.rb +130 -0
  109. data/test/psych/test_to_yaml_properties.rb +63 -0
  110. data/test/psych/test_tree_builder.rb +79 -0
  111. data/test/psych/test_yaml.rb +1292 -0
  112. data/test/psych/test_yamldbm.rb +193 -0
  113. data/test/psych/test_yamlstore.rb +85 -0
  114. data/test/psych/visitors/test_depth_first.rb +49 -0
  115. data/test/psych/visitors/test_emitter.rb +144 -0
  116. data/test/psych/visitors/test_to_ruby.rb +333 -0
  117. data/test/psych/visitors/test_yaml_tree.rb +173 -0
  118. 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