psych 3.1.0 → 5.2.3

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +24 -0
  3. data/{ext/psych/yaml/LICENSE → LICENSE} +9 -7
  4. data/README.md +22 -17
  5. data/ext/psych/depend +14 -0
  6. data/ext/psych/extconf.rb +42 -28
  7. data/ext/psych/psych.c +6 -4
  8. data/ext/psych/psych_emitter.c +155 -121
  9. data/ext/psych/psych_parser.c +274 -302
  10. data/ext/psych/psych_to_ruby.c +0 -1
  11. data/ext/psych/psych_yaml_tree.c +0 -13
  12. data/lib/psych/class_loader.rb +10 -8
  13. data/lib/psych/core_ext.rb +1 -1
  14. data/lib/psych/exception.rb +16 -2
  15. data/lib/psych/handler.rb +1 -1
  16. data/lib/psych/handlers/document_stream.rb +1 -1
  17. data/lib/psych/handlers/recorder.rb +1 -1
  18. data/lib/psych/json/stream.rb +2 -2
  19. data/lib/psych/json/tree_builder.rb +1 -1
  20. data/lib/psych/nodes/node.rb +5 -5
  21. data/lib/psych/nodes/scalar.rb +1 -1
  22. data/lib/psych/nodes.rb +7 -7
  23. data/lib/psych/parser.rb +13 -0
  24. data/lib/psych/scalar_scanner.rb +39 -47
  25. data/lib/psych/syntax_error.rb +1 -1
  26. data/lib/psych/tree_builder.rb +3 -3
  27. data/lib/psych/versions.rb +3 -3
  28. data/lib/psych/visitors/json_tree.rb +1 -1
  29. data/lib/psych/visitors/to_ruby.rb +60 -26
  30. data/lib/psych/visitors/visitor.rb +17 -3
  31. data/lib/psych/visitors/yaml_tree.rb +103 -71
  32. data/lib/psych/visitors.rb +6 -6
  33. data/lib/psych.rb +260 -138
  34. metadata +20 -53
  35. data/.gitignore +0 -16
  36. data/.travis.yml +0 -22
  37. data/CHANGELOG.rdoc +0 -583
  38. data/Gemfile +0 -3
  39. data/Mavenfile +0 -7
  40. data/Rakefile +0 -48
  41. data/bin/console +0 -7
  42. data/bin/setup +0 -6
  43. data/ext/psych/yaml/api.c +0 -1393
  44. data/ext/psych/yaml/config.h +0 -10
  45. data/ext/psych/yaml/dumper.c +0 -394
  46. data/ext/psych/yaml/emitter.c +0 -2324
  47. data/ext/psych/yaml/loader.c +0 -444
  48. data/ext/psych/yaml/parser.c +0 -1370
  49. data/ext/psych/yaml/reader.c +0 -469
  50. data/ext/psych/yaml/scanner.c +0 -3578
  51. data/ext/psych/yaml/writer.c +0 -141
  52. data/ext/psych/yaml/yaml.h +0 -1971
  53. data/ext/psych/yaml/yaml_private.h +0 -688
  54. data/psych.gemspec +0 -75
@@ -8,12 +8,26 @@ module Psych
8
8
 
9
9
  private
10
10
 
11
- DISPATCH = Hash.new do |hash, klass|
12
- hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
11
+ # @api private
12
+ def self.dispatch_cache
13
+ Hash.new do |hash, klass|
14
+ hash[klass] = :"visit_#{klass.name.gsub('::', '_')}"
15
+ end.compare_by_identity
16
+ end
17
+
18
+ if defined?(Ractor)
19
+ def dispatch
20
+ @dispatch_cache ||= (Ractor.current[:Psych_Visitors_Visitor] ||= Visitor.dispatch_cache)
21
+ end
22
+ else
23
+ DISPATCH = dispatch_cache
24
+ def dispatch
25
+ DISPATCH
26
+ end
13
27
  end
14
28
 
15
29
  def visit target
16
- send DISPATCH[target.class], target
30
+ send dispatch[target.class], target
17
31
  end
18
32
  end
19
33
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
- require 'psych/tree_builder'
3
- require 'psych/scalar_scanner'
4
- require 'psych/class_loader'
2
+ require_relative '../tree_builder'
3
+ require_relative '../scalar_scanner'
4
+ require_relative '../class_loader'
5
5
 
6
6
  module Psych
7
7
  module Visitors
@@ -15,30 +15,25 @@ module Psych
15
15
  class YAMLTree < Psych::Visitors::Visitor
16
16
  class Registrar # :nodoc:
17
17
  def initialize
18
- @obj_to_id = {}
19
- @obj_to_node = {}
20
- @targets = []
18
+ @obj_to_id = {}.compare_by_identity
19
+ @obj_to_node = {}.compare_by_identity
21
20
  @counter = 0
22
21
  end
23
22
 
24
23
  def register target, node
25
- return unless target.respond_to? :object_id
26
- @targets << target
27
- @obj_to_node[target.object_id] = node
24
+ @obj_to_node[target] = node
28
25
  end
29
26
 
30
27
  def key? target
31
- @obj_to_node.key? target.object_id
32
- rescue NoMethodError
33
- false
28
+ @obj_to_node.key? target
34
29
  end
35
30
 
36
31
  def id_for target
37
- @obj_to_id[target.object_id] ||= (@counter += 1)
32
+ @obj_to_id[target] ||= (@counter += 1)
38
33
  end
39
34
 
40
35
  def node_for target
41
- @obj_to_node[target.object_id]
36
+ @obj_to_node[target]
42
37
  end
43
38
  end
44
39
 
@@ -70,6 +65,7 @@ module Psych
70
65
  fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.")
71
66
  end
72
67
  end
68
+ @stringify_names = options[:stringify_names]
73
69
  @coders = []
74
70
 
75
71
  @dispatch_cache = Hash.new do |h,klass|
@@ -80,7 +76,7 @@ module Psych
80
76
  raise(TypeError, "Can't dump #{target.class}") unless method
81
77
 
82
78
  h[klass] = method
83
- end
79
+ end.compare_by_identity
84
80
  end
85
81
 
86
82
  def start encoding = Nodes::Stream::UTF8
@@ -181,53 +177,24 @@ module Psych
181
177
  end
182
178
 
183
179
  def visit_Exception o
184
- tag = ['!ruby/exception', o.class.name].join ':'
185
-
186
- @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
187
-
188
- {
189
- 'message' => private_iv_get(o, 'mesg'),
190
- 'backtrace' => private_iv_get(o, 'backtrace'),
191
- }.each do |k,v|
192
- next unless v
193
- @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
194
- accept v
195
- end
196
-
197
- dump_ivars o
198
-
199
- @emitter.end_mapping
180
+ dump_exception o, o.message.to_s
200
181
  end
201
182
 
202
183
  def visit_NameError o
203
- tag = ['!ruby/exception', o.class.name].join ':'
204
-
205
- @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
206
-
207
- {
208
- 'message' => o.message.to_s,
209
- 'backtrace' => private_iv_get(o, 'backtrace'),
210
- }.each do |k,v|
211
- next unless v
212
- @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
213
- accept v
214
- end
215
-
216
- dump_ivars o
217
-
218
- @emitter.end_mapping
184
+ dump_exception o, o.message.to_s
219
185
  end
220
186
 
221
187
  def visit_Regexp o
222
188
  register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
223
189
  end
224
190
 
191
+ def visit_Date o
192
+ register o, visit_Integer(o.gregorian)
193
+ end
194
+
225
195
  def visit_DateTime o
226
- formatted = if o.offset.zero?
227
- o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze)
228
- else
229
- o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze)
230
- end
196
+ t = o.italy
197
+ formatted = format_time t, t.offset.zero?
231
198
  tag = '!ruby/object:DateTime'
232
199
  register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
233
200
  end
@@ -265,7 +232,6 @@ module Psych
265
232
  end
266
233
  alias :visit_TrueClass :visit_Integer
267
234
  alias :visit_FalseClass :visit_Integer
268
- alias :visit_Date :visit_Integer
269
235
 
270
236
  def visit_Float o
271
237
  if o.nan?
@@ -295,18 +261,20 @@ module Psych
295
261
  style = Nodes::Scalar::LITERAL
296
262
  plain = false
297
263
  quote = false
298
- elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string
264
+ elsif o.match?(/\n(?!\Z)/) # match \n except blank line at the end of string
299
265
  style = Nodes::Scalar::LITERAL
300
266
  elsif o == '<<'
301
267
  style = Nodes::Scalar::SINGLE_QUOTED
302
268
  tag = 'tag:yaml.org,2002:str'
303
269
  plain = false
304
270
  quote = false
271
+ elsif o == 'y' || o == 'Y' || o == 'n' || o == 'N'
272
+ style = Nodes::Scalar::DOUBLE_QUOTED
305
273
  elsif @line_width && o.length > @line_width
306
274
  style = Nodes::Scalar::FOLDED
307
- elsif o =~ /^[^[:word:]][^"]*$/
275
+ elsif o.match?(/^[^[:word:]][^"]*$/)
308
276
  style = Nodes::Scalar::DOUBLE_QUOTED
309
- elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/ =~ o
277
+ elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/.match?(o)
310
278
  style = Nodes::Scalar::SINGLE_QUOTED
311
279
  end
312
280
 
@@ -356,7 +324,7 @@ module Psych
356
324
  if o.class == ::Hash
357
325
  register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
358
326
  o.each do |k,v|
359
- accept k
327
+ accept(@stringify_names && Symbol === k ? k.to_s : k)
360
328
  accept v
361
329
  end
362
330
  @emitter.end_mapping
@@ -369,7 +337,7 @@ module Psych
369
337
  register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
370
338
 
371
339
  o.each do |k,v|
372
- accept k
340
+ accept(@stringify_names && Symbol === k ? k.to_s : k)
373
341
  accept v
374
342
  end
375
343
 
@@ -458,15 +426,6 @@ module Psych
458
426
  node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
459
427
  register(o, node)
460
428
 
461
- # Dump the elements
462
- accept 'elements'
463
- @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
464
- o.each do |k,v|
465
- accept k
466
- accept v
467
- end
468
- @emitter.end_mapping
469
-
470
429
  # Dump the ivars
471
430
  accept 'ivars'
472
431
  @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
@@ -476,6 +435,15 @@ module Psych
476
435
  end
477
436
  @emitter.end_mapping
478
437
 
438
+ # Dump the elements
439
+ accept 'elements'
440
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
441
+ o.each do |k,v|
442
+ accept k
443
+ accept v
444
+ end
445
+ @emitter.end_mapping
446
+
479
447
  @emitter.end_mapping
480
448
  else
481
449
  tag = "!ruby/hash:#{o.class}"
@@ -492,8 +460,26 @@ module Psych
492
460
  def dump_list o
493
461
  end
494
462
 
495
- def format_time time
496
- if time.utc?
463
+ def dump_exception o, msg
464
+ tag = ['!ruby/exception', o.class.name].join ':'
465
+
466
+ @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
467
+
468
+ if msg
469
+ @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY
470
+ accept msg
471
+ end
472
+
473
+ @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY
474
+ accept o.backtrace
475
+
476
+ dump_ivars o
477
+
478
+ @emitter.end_mapping
479
+ end
480
+
481
+ def format_time time, utc = time.utc?
482
+ if utc
497
483
  time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
498
484
  else
499
485
  time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
@@ -521,9 +507,9 @@ module Psych
521
507
  def emit_coder c, o
522
508
  case c.type
523
509
  when :scalar
524
- @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
510
+ @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, c.style
525
511
  when :seq
526
- @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK
512
+ @emitter.start_sequence nil, c.tag, c.tag.nil?, c.style
527
513
  c.seq.each do |thing|
528
514
  accept thing
529
515
  end
@@ -547,5 +533,51 @@ module Psych
547
533
  end
548
534
  end
549
535
  end
536
+
537
+ class RestrictedYAMLTree < YAMLTree
538
+ DEFAULT_PERMITTED_CLASSES = {
539
+ TrueClass => true,
540
+ FalseClass => true,
541
+ NilClass => true,
542
+ Integer => true,
543
+ Float => true,
544
+ String => true,
545
+ Array => true,
546
+ Hash => true,
547
+ }.compare_by_identity.freeze
548
+
549
+ def initialize emitter, ss, options
550
+ super
551
+ @permitted_classes = DEFAULT_PERMITTED_CLASSES.dup
552
+ Array(options[:permitted_classes]).each do |klass|
553
+ @permitted_classes[klass] = true
554
+ end
555
+ @permitted_symbols = {}.compare_by_identity
556
+ Array(options[:permitted_symbols]).each do |symbol|
557
+ @permitted_symbols[symbol] = true
558
+ end
559
+ @aliases = options.fetch(:aliases, false)
560
+ end
561
+
562
+ def accept target
563
+ if !@aliases && @st.key?(target)
564
+ raise BadAlias, "Tried to dump an aliased object"
565
+ end
566
+
567
+ unless Symbol === target || @permitted_classes[target.class]
568
+ raise DisallowedClass.new('dump', target.class.name || target.class.inspect)
569
+ end
570
+
571
+ super
572
+ end
573
+
574
+ def visit_Symbol sym
575
+ unless @permitted_classes[Symbol] || @permitted_symbols[sym]
576
+ raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})")
577
+ end
578
+
579
+ super
580
+ end
581
+ end
550
582
  end
551
583
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
- require 'psych/visitors/visitor'
3
- require 'psych/visitors/to_ruby'
4
- require 'psych/visitors/emitter'
5
- require 'psych/visitors/yaml_tree'
6
- require 'psych/visitors/json_tree'
7
- require 'psych/visitors/depth_first'
2
+ require_relative 'visitors/visitor'
3
+ require_relative 'visitors/to_ruby'
4
+ require_relative 'visitors/emitter'
5
+ require_relative 'visitors/yaml_tree'
6
+ require_relative 'visitors/json_tree'
7
+ require_relative 'visitors/depth_first'