psych-shopifork 2.0.5 → 2.0.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,7 +37,7 @@ module Psych
37
37
  case string
38
38
  # Check for a String type, being careful not to get caught by hash keys, hex values, and
39
39
  # special floats (e.g., -.inf).
40
- when /^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/
40
+ when /^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/, /\n/
41
41
  if string.length > 5
42
42
  @string_cache[string] = true
43
43
  return string
@@ -32,7 +32,7 @@ module Psych
32
32
  return result if @domain_types.empty? || !target.tag
33
33
 
34
34
  key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
35
- key = "tag:#{key}" unless key =~ /^(tag:|x-private)/
35
+ key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/
36
36
 
37
37
  if @domain_types.key? key
38
38
  value, block = @domain_types[key]
@@ -61,7 +61,7 @@ module Psych
61
61
  case o.tag
62
62
  when '!binary', 'tag:yaml.org,2002:binary'
63
63
  o.value.unpack('m').first
64
- when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str'
64
+ when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str'
65
65
  klass = resolve_class($1)
66
66
  if klass
67
67
  klass.allocate.replace o.value
@@ -89,7 +89,7 @@ module Psych
89
89
  Float(@ss.tokenize(o.value))
90
90
  when "!ruby/regexp"
91
91
  klass = class_loader.regexp
92
- o.value =~ /^\/(.*)\/([mixn]*)$/
92
+ o.value =~ /^\/(.*)\/([mixn]*)$/m
93
93
  source = $1
94
94
  options = 0
95
95
  lang = nil
@@ -201,12 +201,14 @@ module Psych
201
201
  class_loader.rational
202
202
  h = Hash[*o.children.map { |c| accept c }]
203
203
  register o, Rational(h['numerator'], h['denominator'])
204
+ elsif name == 'Hash'
205
+ revive_hash(register(o, {}), o)
204
206
  else
205
207
  obj = revive((resolve_class(name) || class_loader.object), o)
206
208
  obj
207
209
  end
208
210
 
209
- when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str'
211
+ when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str'
210
212
  klass = resolve_class($1)
211
213
  members = {}
212
214
  string = nil
@@ -259,8 +261,23 @@ module Psych
259
261
  end
260
262
  set
261
263
 
264
+ when /^!ruby\/hash-with-ivars(?::(.*))?$/
265
+ hash = $1 ? resolve_class($1).allocate : {}
266
+ register o, hash
267
+ o.children.each_slice(2) do |key, value|
268
+ case key.value
269
+ when 'elements'
270
+ revive_hash hash, value
271
+ when 'ivars'
272
+ value.children.each_slice(2) do |k,v|
273
+ hash.instance_variable_set accept(k), accept(v)
274
+ end
275
+ end
276
+ end
277
+ hash
278
+
262
279
  when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/
263
- revive_hash register(o, resolve_class($1).new), o
280
+ revive_hash register(o, resolve_class($1).allocate), o
264
281
 
265
282
  when '!omap', 'tag:yaml.org,2002:omap'
266
283
  map = register(o, class_loader.psych_omap.new)
@@ -269,6 +286,21 @@ module Psych
269
286
  end
270
287
  map
271
288
 
289
+ when /^!ruby\/marshalable:(.*)$/
290
+ name = $1
291
+ klass = resolve_class(name)
292
+ obj = register(o, klass.allocate)
293
+
294
+ if obj.respond_to?(:init_with)
295
+ init_with(obj, revive_hash({}, o), o)
296
+ elsif obj.respond_to?(:marshal_load)
297
+ marshal_data = o.children.map(&method(:accept))
298
+ obj.marshal_load(marshal_data)
299
+ obj
300
+ else
301
+ raise ArgumentError, "Cannot deserialize #{name}"
302
+ end
303
+
272
304
  else
273
305
  revive_hash(register(o, {}), o)
274
306
  end
@@ -303,9 +335,9 @@ module Psych
303
335
  key = accept(k)
304
336
  val = accept(v)
305
337
 
306
- if key == '<<'
338
+ if key == '<<' && k.tag != "tag:yaml.org,2002:str"
307
339
  case v
308
- when Nodes::Alias
340
+ when Nodes::Alias, Nodes::Mapping
309
341
  begin
310
342
  hash.merge! val
311
343
  rescue TypeError
@@ -16,15 +16,20 @@ module Psych
16
16
  def initialize
17
17
  @obj_to_id = {}
18
18
  @obj_to_node = {}
19
+ @targets = []
19
20
  @counter = 0
20
21
  end
21
22
 
22
23
  def register target, node
24
+ return unless target.respond_to? :object_id
25
+ @targets << target
23
26
  @obj_to_node[target.object_id] = node
24
27
  end
25
28
 
26
29
  def key? target
27
30
  @obj_to_node.key? target.object_id
31
+ rescue NoMethodError
32
+ false
28
33
  end
29
34
 
30
35
  def id_for target
@@ -58,13 +63,14 @@ module Psych
58
63
 
59
64
  def initialize emitter, ss, options
60
65
  super()
61
- @started = false
62
- @finished = false
63
- @emitter = emitter
64
- @st = Registrar.new
65
- @ss = ss
66
- @options = options
67
- @coders = []
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 = []
68
74
 
69
75
  @dispatch_cache = Hash.new do |h,klass|
70
76
  method = "visit_#{(klass.name || '').split('::').join('_')}"
@@ -209,6 +215,25 @@ module Psych
209
215
  @emitter.end_mapping
210
216
  end
211
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
+
212
237
  def visit_Regexp o
213
238
  register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
214
239
  end
@@ -278,41 +303,46 @@ module Psych
278
303
  quote = true
279
304
  style = Nodes::Scalar::PLAIN
280
305
  tag = nil
281
- str = o
282
306
 
283
307
  if binary?(o)
284
- str = [o].pack('m').chomp
308
+ o = [o].pack('m').chomp
285
309
  tag = '!binary' # FIXME: change to below when syck is removed
286
310
  #tag = 'tag:yaml.org,2002:binary'
287
311
  style = Nodes::Scalar::LITERAL
288
312
  plain = false
289
313
  quote = false
290
- elsif o =~ /\n/
314
+ elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string
291
315
  style = Nodes::Scalar::LITERAL
292
- elsif o =~ /^\W[^"]*$/
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:]][^"]*$/
293
324
  style = Nodes::Scalar::DOUBLE_QUOTED
294
- else
295
- unless String === @ss.tokenize(o)
296
- style = Nodes::Scalar::SINGLE_QUOTED
297
- end
325
+ elsif not String === @ss.tokenize(o)
326
+ style = Nodes::Scalar::SINGLE_QUOTED
298
327
  end
299
328
 
300
- ivars = find_ivars o
329
+ is_primitive = o.class == ::String
330
+ ivars = find_ivars o, is_primitive
301
331
 
302
332
  if ivars.empty?
303
- unless o.class == ::String
333
+ unless is_primitive
304
334
  tag = "!ruby/string:#{o.class}"
305
335
  plain = false
306
336
  quote = false
307
337
  end
308
- @emitter.scalar str, nil, tag, plain, quote, style
338
+ @emitter.scalar o, nil, tag, plain, quote, style
309
339
  else
310
340
  maptag = '!ruby/string'
311
341
  maptag << ":#{o.class}" unless o.class == ::String
312
342
 
313
343
  register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK)
314
344
  @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY
315
- @emitter.scalar str, nil, tag, plain, quote, style
345
+ @emitter.scalar o, nil, tag, plain, quote, style
316
346
 
317
347
  dump_ivars o
318
348
 
@@ -339,17 +369,16 @@ module Psych
339
369
  end
340
370
 
341
371
  def visit_Hash o
342
- tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
343
- implicit = !tag
344
-
345
- register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK))
346
-
347
- o.each do |k,v|
348
- accept k
349
- accept v
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
350
381
  end
351
-
352
- @emitter.end_mapping
353
382
  end
354
383
 
355
384
  def visit_Psych_Set o
@@ -378,7 +407,23 @@ module Psych
378
407
  end
379
408
 
380
409
  def visit_Symbol o
381
- @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY
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
382
427
  end
383
428
 
384
429
  private
@@ -395,7 +440,8 @@ module Psych
395
440
 
396
441
  def visit_array_subclass o
397
442
  tag = "!ruby/array:#{o.class}"
398
- if o.instance_variables.empty?
443
+ ivars = o.instance_variables
444
+ if ivars.empty?
399
445
  node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK)
400
446
  register o, node
401
447
  o.each { |c| accept c }
@@ -413,12 +459,50 @@ module Psych
413
459
  # Dump the ivars
414
460
  accept 'ivars'
415
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
416
491
  o.instance_variables.each do |ivar|
417
492
  accept ivar
418
493
  accept o.instance_variable_get ivar
419
494
  end
420
495
  @emitter.end_mapping
421
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
422
506
  @emitter.end_mapping
423
507
  end
424
508
  end
@@ -451,7 +535,7 @@ module Psych
451
535
  end
452
536
 
453
537
  # FIXME: remove this method once "to_yaml_properties" is removed
454
- def find_ivars target
538
+ def find_ivars target, is_primitive=false
455
539
  begin
456
540
  loc = target.method(:to_yaml_properties).source_location.first
457
541
  unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb')
@@ -465,7 +549,7 @@ module Psych
465
549
  # and it's OK to skip it since it's only to emit a warning.
466
550
  end
467
551
 
468
- target.instance_variables
552
+ is_primitive ? [] : target.instance_variables
469
553
  end
470
554
 
471
555
  def register target, yaml_obj
@@ -483,10 +567,10 @@ module Psych
483
567
 
484
568
  c = Psych::Coder.new(tag)
485
569
  o.encode_with(c)
486
- emit_coder c
570
+ emit_coder c, o
487
571
  end
488
572
 
489
- def emit_coder c
573
+ def emit_coder c, o
490
574
  case c.type
491
575
  when :scalar
492
576
  @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
@@ -497,7 +581,7 @@ module Psych
497
581
  end
498
582
  @emitter.end_sequence
499
583
  when :map
500
- @emitter.start_mapping nil, c.tag, c.implicit, c.style
584
+ register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style)
501
585
  c.map.each do |k,v|
502
586
  accept k
503
587
  accept v
@@ -5,7 +5,13 @@ require 'date'
5
5
  require 'psych'
6
6
 
7
7
  module Psych
8
- class TestCase < MiniTest::Unit::TestCase
8
+ superclass = if defined?(Minitest::Test)
9
+ Minitest::Test
10
+ else
11
+ MiniTest::Unit::TestCase
12
+ end
13
+
14
+ class TestCase < superclass
9
15
  def self.suppress_warning
10
16
  verbose, $VERBOSE = $VERBOSE, nil
11
17
  yield
@@ -65,7 +65,7 @@ module Psych
65
65
  @stream.push list
66
66
 
67
67
  json = @io.string
68
- assert_match(/]$/, json)
68
+ assert_match(/\]$/, json)
69
69
  assert_match(/^--- \[/, json)
70
70
  assert_match(/["]one["]/, json)
71
71
  assert_match(/["]two["]/, json)
@@ -95,6 +95,28 @@ module Psych
95
95
  end
96
96
  end
97
97
 
98
+ class Referential
99
+ attr_reader :a
100
+
101
+ def initialize
102
+ @a = self
103
+ end
104
+
105
+ def encode_with(c)
106
+ c['a'] = @a
107
+ end
108
+
109
+ def init_with(c)
110
+ @a = c['a']
111
+ end
112
+ end
113
+
114
+ def test_self_referential
115
+ x = Referential.new
116
+ copy = Psych.load Psych.dump x
117
+ assert_equal copy, copy.a
118
+ end
119
+
98
120
  def test_represent_with_object
99
121
  thing = Psych.load(Psych.dump(RepresentWithObject.new))
100
122
  assert_equal 20, thing
@@ -11,8 +11,7 @@ module Psych
11
11
  end
12
12
 
13
13
  def test_line_width
14
- assert_equal 0, @emitter.line_width
15
- assert_equal 10, @emitter.line_width = 10
14
+ @emitter.line_width = 10
16
15
  assert_equal 10, @emitter.line_width
17
16
  end
18
17