psych 2.2.1 → 5.1.2

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 (70) hide show
  1. checksums.yaml +5 -5
  2. data/CONTRIBUTING.md +24 -0
  3. data/{ext/psych/yaml/LICENSE → LICENSE} +9 -7
  4. data/README.md +13 -13
  5. data/ext/psych/depend +14 -0
  6. data/ext/psych/extconf.rb +43 -29
  7. data/ext/psych/psych.c +6 -3
  8. data/ext/psych/psych_emitter.c +10 -9
  9. data/ext/psych/psych_parser.c +69 -72
  10. data/ext/psych/psych_yaml_tree.c +0 -12
  11. data/lib/psych/class_loader.rb +11 -9
  12. data/lib/psych/coder.rb +1 -1
  13. data/lib/psych/core_ext.rb +3 -20
  14. data/lib/psych/exception.rb +17 -3
  15. data/lib/psych/handler.rb +8 -3
  16. data/lib/psych/handlers/document_stream.rb +2 -2
  17. data/lib/psych/handlers/recorder.rb +2 -2
  18. data/lib/psych/json/ruby_events.rb +1 -1
  19. data/lib/psych/json/stream.rb +3 -3
  20. data/lib/psych/json/tree_builder.rb +2 -2
  21. data/lib/psych/json/yaml_events.rb +1 -1
  22. data/lib/psych/nodes/alias.rb +3 -1
  23. data/lib/psych/nodes/document.rb +3 -1
  24. data/lib/psych/nodes/mapping.rb +3 -1
  25. data/lib/psych/nodes/node.rb +24 -5
  26. data/lib/psych/nodes/scalar.rb +4 -2
  27. data/lib/psych/nodes/sequence.rb +3 -1
  28. data/lib/psych/nodes/stream.rb +3 -1
  29. data/lib/psych/nodes.rb +8 -8
  30. data/lib/psych/omap.rb +1 -1
  31. data/lib/psych/parser.rb +14 -1
  32. data/lib/psych/scalar_scanner.rb +39 -47
  33. data/lib/psych/set.rb +1 -1
  34. data/lib/psych/stream.rb +1 -1
  35. data/lib/psych/streaming.rb +1 -1
  36. data/lib/psych/syntax_error.rb +2 -2
  37. data/lib/psych/tree_builder.rb +48 -8
  38. data/lib/psych/versions.rb +5 -4
  39. data/lib/psych/visitors/depth_first.rb +1 -1
  40. data/lib/psych/visitors/emitter.rb +1 -1
  41. data/lib/psych/visitors/json_tree.rb +2 -2
  42. data/lib/psych/visitors/to_ruby.rb +61 -31
  43. data/lib/psych/visitors/visitor.rb +18 -4
  44. data/lib/psych/visitors/yaml_tree.rb +111 -123
  45. data/lib/psych/visitors.rb +7 -7
  46. data/lib/psych/y.rb +1 -1
  47. data/lib/psych.rb +333 -96
  48. metadata +16 -52
  49. data/.gitignore +0 -14
  50. data/.travis.yml +0 -18
  51. data/CHANGELOG.rdoc +0 -576
  52. data/Gemfile +0 -3
  53. data/Mavenfile +0 -7
  54. data/Rakefile +0 -33
  55. data/bin/console +0 -7
  56. data/bin/setup +0 -6
  57. data/ext/psych/.gitignore +0 -11
  58. data/ext/psych/yaml/api.c +0 -1392
  59. data/ext/psych/yaml/config.h +0 -10
  60. data/ext/psych/yaml/dumper.c +0 -394
  61. data/ext/psych/yaml/emitter.c +0 -2329
  62. data/ext/psych/yaml/loader.c +0 -444
  63. data/ext/psych/yaml/parser.c +0 -1374
  64. data/ext/psych/yaml/reader.c +0 -469
  65. data/ext/psych/yaml/scanner.c +0 -3576
  66. data/ext/psych/yaml/writer.c +0 -141
  67. data/ext/psych/yaml/yaml.h +0 -1971
  68. data/ext/psych/yaml/yaml_private.h +0 -662
  69. data/lib/psych/deprecated.rb +0 -86
  70. data/psych.gemspec +0 -43
data/lib/psych.rb CHANGED
@@ -1,35 +1,39 @@
1
- # frozen_string_literal: false
2
- require 'psych/versions'
1
+ # frozen_string_literal: true
2
+ require_relative 'psych/versions'
3
3
  case RUBY_ENGINE
4
4
  when 'jruby'
5
- require 'psych_jars'
6
- org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
5
+ require_relative 'psych_jars'
6
+ if JRuby::Util.respond_to?(:load_ext)
7
+ JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary')
8
+ else
9
+ require 'java'; require 'jruby'
10
+ org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
11
+ end
7
12
  else
8
13
  require 'psych.so'
9
14
  end
10
- require 'psych/nodes'
11
- require 'psych/streaming'
12
- require 'psych/visitors'
13
- require 'psych/handler'
14
- require 'psych/tree_builder'
15
- require 'psych/parser'
16
- require 'psych/omap'
17
- require 'psych/set'
18
- require 'psych/coder'
19
- require 'psych/core_ext'
20
- require 'psych/deprecated'
21
- require 'psych/stream'
22
- require 'psych/json/tree_builder'
23
- require 'psych/json/stream'
24
- require 'psych/handlers/document_stream'
25
- require 'psych/class_loader'
15
+ require_relative 'psych/nodes'
16
+ require_relative 'psych/streaming'
17
+ require_relative 'psych/visitors'
18
+ require_relative 'psych/handler'
19
+ require_relative 'psych/tree_builder'
20
+ require_relative 'psych/parser'
21
+ require_relative 'psych/omap'
22
+ require_relative 'psych/set'
23
+ require_relative 'psych/coder'
24
+ require_relative 'psych/core_ext'
25
+ require_relative 'psych/stream'
26
+ require_relative 'psych/json/tree_builder'
27
+ require_relative 'psych/json/stream'
28
+ require_relative 'psych/handlers/document_stream'
29
+ require_relative 'psych/class_loader'
26
30
 
27
31
  ###
28
32
  # = Overview
29
33
  #
30
34
  # Psych is a YAML parser and emitter.
31
- # Psych leverages libyaml [Home page: http://pyyaml.org/wiki/LibYAML]
32
- # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing
35
+ # Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML]
36
+ # or [git repo: https://github.com/yaml/libyaml] for its YAML parsing
33
37
  # and emitting capabilities. In addition to wrapping libyaml, Psych also
34
38
  # knows how to serialize and de-serialize most Ruby objects to and from
35
39
  # the YAML format.
@@ -70,12 +74,15 @@ require 'psych/class_loader'
70
74
  #
71
75
  # ==== Reading from a string
72
76
  #
73
- # Psych.load("--- a") # => 'a'
74
- # Psych.load("---\n - a\n - b") # => ['a', 'b']
77
+ # Psych.safe_load("--- a") # => 'a'
78
+ # Psych.safe_load("---\n - a\n - b") # => ['a', 'b']
79
+ # # From a trusted string:
80
+ # Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42
75
81
  #
76
82
  # ==== Reading from a file
77
83
  #
78
- # Psych.load_file("database.yml")
84
+ # Psych.safe_load_file("data.yml", permitted_classes: [Date])
85
+ # Psych.load_file("trusted_database.yml")
79
86
  #
80
87
  # ==== Exception handling
81
88
  #
@@ -195,12 +202,13 @@ require 'psych/class_loader'
195
202
  #
196
203
  # ==== Receiving an events stream
197
204
  #
198
- # parser = Psych::Parser.new(Psych::Handlers::Recorder.new)
205
+ # recorder = Psych::Handlers::Recorder.new
206
+ # parser = Psych::Parser.new(recorder)
199
207
  #
200
208
  # parser.parse("---\n - a\n - b")
201
- # parser.events # => [list of [event, args] lists]
202
- # # event is one of: Psych::Handler::EVENTS
203
- # # args are the arguments passed to the event
209
+ # recorder.events # => [list of [event, args] lists]
210
+ # # event is one of: Psych::Handler::EVENTS
211
+ # # args are the arguments passed to the event
204
212
  #
205
213
  # === Emitting
206
214
  #
@@ -225,32 +233,45 @@ require 'psych/class_loader'
225
233
 
226
234
  module Psych
227
235
  # The version of libyaml Psych is using
228
- LIBYAML_VERSION = Psych.libyaml_version.join '.'
229
-
230
- FALLBACK = Struct.new :to_ruby # :nodoc:
236
+ LIBYAML_VERSION = Psych.libyaml_version.join('.').freeze
231
237
 
232
238
  ###
233
239
  # Load +yaml+ in to a Ruby data structure. If multiple documents are
234
240
  # provided, the object contained in the first document will be returned.
235
- # +filename+ will be used in the exception message if any exception is raised
236
- # while parsing.
241
+ # +filename+ will be used in the exception message if any exception
242
+ # is raised while parsing. If +yaml+ is empty, it returns
243
+ # the specified +fallback+ return value, which defaults to +false+.
237
244
  #
238
245
  # Raises a Psych::SyntaxError when a YAML syntax error is detected.
239
246
  #
240
247
  # Example:
241
248
  #
242
- # Psych.load("--- a") # => 'a'
243
- # Psych.load("---\n - a\n - b") # => ['a', 'b']
249
+ # Psych.unsafe_load("--- a") # => 'a'
250
+ # Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b']
244
251
  #
245
252
  # begin
246
- # Psych.load("--- `", "file.txt")
253
+ # Psych.unsafe_load("--- `", filename: "file.txt")
247
254
  # rescue Psych::SyntaxError => ex
248
255
  # ex.file # => 'file.txt'
249
256
  # ex.message # => "(file.txt): found character that cannot start any token"
250
257
  # end
251
- def self.load yaml, filename = nil, fallback = false
252
- result = parse(yaml, filename, fallback)
253
- result ? result.to_ruby : result
258
+ #
259
+ # When the optional +symbolize_names+ keyword argument is set to a
260
+ # true value, returns symbols for keys in Hash objects (default: strings).
261
+ #
262
+ # Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"}
263
+ # Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
264
+ #
265
+ # Raises a TypeError when `yaml` parameter is NilClass
266
+ #
267
+ # NOTE: This method *should not* be used to parse untrusted documents, such as
268
+ # YAML documents that are supplied via user input. Instead, please use the
269
+ # load method or the safe_load method.
270
+ #
271
+ def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false
272
+ result = parse(yaml, filename: filename)
273
+ return fallback unless result
274
+ result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer)
254
275
  end
255
276
 
256
277
  ###
@@ -260,46 +281,99 @@ module Psych
260
281
  # * TrueClass
261
282
  # * FalseClass
262
283
  # * NilClass
263
- # * Numeric
284
+ # * Integer
285
+ # * Float
264
286
  # * String
265
287
  # * Array
266
288
  # * Hash
267
289
  #
268
290
  # Recursive data structures are not allowed by default. Arbitrary classes
269
- # can be allowed by adding those classes to the +whitelist+. They are
291
+ # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are
270
292
  # additive. For example, to allow Date deserialization:
271
293
  #
272
- # Psych.safe_load(yaml, [Date])
294
+ # Psych.safe_load(yaml, permitted_classes: [Date])
273
295
  #
274
296
  # Now the Date class can be loaded in addition to the classes listed above.
275
297
  #
276
- # Aliases can be explicitly allowed by changing the +aliases+ parameter.
298
+ # Aliases can be explicitly allowed by changing the +aliases+ keyword argument.
277
299
  # For example:
278
300
  #
279
301
  # x = []
280
302
  # x << x
281
303
  # yaml = Psych.dump x
282
304
  # Psych.safe_load yaml # => raises an exception
283
- # Psych.safe_load yaml, [], [], true # => loads the aliases
305
+ # Psych.safe_load yaml, aliases: true # => loads the aliases
284
306
  #
285
307
  # A Psych::DisallowedClass exception will be raised if the yaml contains a
286
- # class that isn't in the whitelist.
287
- #
288
- # A Psych::BadAlias exception will be raised if the yaml contains aliases
289
- # but the +aliases+ parameter is set to false.
290
- def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil
291
- result = parse(yaml, filename)
292
- return unless result
293
-
294
- class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s),
295
- whitelist_symbols.map(&:to_s))
296
- scanner = ScalarScanner.new class_loader
297
- if aliases
298
- visitor = Visitors::ToRuby.new scanner, class_loader
299
- else
300
- visitor = Visitors::NoAliasRuby.new scanner, class_loader
301
- end
302
- visitor.accept result
308
+ # class that isn't in the +permitted_classes+ list.
309
+ #
310
+ # A Psych::AliasesNotEnabled exception will be raised if the yaml contains aliases
311
+ # but the +aliases+ keyword argument is set to false.
312
+ #
313
+ # +filename+ will be used in the exception message if any exception is raised
314
+ # while parsing.
315
+ #
316
+ # When the optional +symbolize_names+ keyword argument is set to a
317
+ # true value, returns symbols for keys in Hash objects (default: strings).
318
+ #
319
+ # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
320
+ # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
321
+ #
322
+ def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
323
+ result = parse(yaml, filename: filename)
324
+ return fallback unless result
325
+
326
+ class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
327
+ permitted_symbols.map(&:to_s))
328
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
329
+ visitor = if aliases
330
+ Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
331
+ else
332
+ Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
333
+ end
334
+ result = visitor.accept result
335
+ result
336
+ end
337
+
338
+ ###
339
+ # Load +yaml+ in to a Ruby data structure. If multiple documents are
340
+ # provided, the object contained in the first document will be returned.
341
+ # +filename+ will be used in the exception message if any exception
342
+ # is raised while parsing. If +yaml+ is empty, it returns
343
+ # the specified +fallback+ return value, which defaults to +false+.
344
+ #
345
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
346
+ #
347
+ # Example:
348
+ #
349
+ # Psych.load("--- a") # => 'a'
350
+ # Psych.load("---\n - a\n - b") # => ['a', 'b']
351
+ #
352
+ # begin
353
+ # Psych.load("--- `", filename: "file.txt")
354
+ # rescue Psych::SyntaxError => ex
355
+ # ex.file # => 'file.txt'
356
+ # ex.message # => "(file.txt): found character that cannot start any token"
357
+ # end
358
+ #
359
+ # When the optional +symbolize_names+ keyword argument is set to a
360
+ # true value, returns symbols for keys in Hash objects (default: strings).
361
+ #
362
+ # Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
363
+ # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
364
+ #
365
+ # Raises a TypeError when `yaml` parameter is NilClass. This method is
366
+ # similar to `safe_load` except that `Symbol` objects are allowed by default.
367
+ #
368
+ def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
369
+ safe_load yaml, permitted_classes: permitted_classes,
370
+ permitted_symbols: permitted_symbols,
371
+ aliases: aliases,
372
+ filename: filename,
373
+ fallback: fallback,
374
+ symbolize_names: symbolize_names,
375
+ freeze: freeze,
376
+ strict_integer: strict_integer
303
377
  end
304
378
 
305
379
  ###
@@ -314,28 +388,30 @@ module Psych
314
388
  # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00>
315
389
  #
316
390
  # begin
317
- # Psych.parse("--- `", "file.txt")
391
+ # Psych.parse("--- `", filename: "file.txt")
318
392
  # rescue Psych::SyntaxError => ex
319
393
  # ex.file # => 'file.txt'
320
394
  # ex.message # => "(file.txt): found character that cannot start any token"
321
395
  # end
322
396
  #
323
397
  # See Psych::Nodes for more information about YAML AST.
324
- def self.parse yaml, filename = nil, fallback = false
325
- parse_stream(yaml, filename) do |node|
398
+ def self.parse yaml, filename: nil
399
+ parse_stream(yaml, filename: filename) do |node|
326
400
  return node
327
401
  end
328
- fallback
402
+
403
+ false
329
404
  end
330
405
 
331
406
  ###
332
407
  # Parse a file at +filename+. Returns the Psych::Nodes::Document.
333
408
  #
334
409
  # Raises a Psych::SyntaxError when a YAML syntax error is detected.
335
- def self.parse_file filename
336
- File.open filename, 'r:bom|utf-8' do |f|
337
- parse f, filename
410
+ def self.parse_file filename, fallback: false
411
+ result = File.open filename, 'r:bom|utf-8' do |f|
412
+ parse f, filename: filename
338
413
  end
414
+ result || fallback
339
415
  end
340
416
 
341
417
  ###
@@ -364,14 +440,16 @@ module Psych
364
440
  # end
365
441
  #
366
442
  # begin
367
- # Psych.parse_stream("--- `", "file.txt")
443
+ # Psych.parse_stream("--- `", filename: "file.txt")
368
444
  # rescue Psych::SyntaxError => ex
369
445
  # ex.file # => 'file.txt'
370
446
  # ex.message # => "(file.txt): found character that cannot start any token"
371
447
  # end
372
448
  #
449
+ # Raises a TypeError when NilClass is passed.
450
+ #
373
451
  # See Psych::Nodes for more information about YAML AST.
374
- def self.parse_stream yaml, filename = nil, &block
452
+ def self.parse_stream yaml, filename: nil, &block
375
453
  if block_given?
376
454
  parser = Psych::Parser.new(Handlers::DocumentStream.new(&block))
377
455
  parser.parse yaml, filename
@@ -393,6 +471,24 @@ module Psych
393
471
  # to control the output format. If an IO object is passed in, the YAML will
394
472
  # be dumped to that IO object.
395
473
  #
474
+ # Currently supported options are:
475
+ #
476
+ # [<tt>:indentation</tt>] Number of space characters used to indent.
477
+ # Acceptable value should be in <tt>0..9</tt> range,
478
+ # otherwise option is ignored.
479
+ #
480
+ # Default: <tt>2</tt>.
481
+ # [<tt>:line_width</tt>] Max character to wrap line at.
482
+ #
483
+ # Default: <tt>0</tt> (meaning "wrap at 81").
484
+ # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
485
+ # strictly formal).
486
+ #
487
+ # Default: <tt>false</tt>.
488
+ # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document.
489
+ #
490
+ # Default: <tt>false</tt>.
491
+ #
396
492
  # Example:
397
493
  #
398
494
  # # Dump an array, get back a YAML string
@@ -402,10 +498,10 @@ module Psych
402
498
  # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
403
499
  #
404
500
  # # Dump an array with indentation set
405
- # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n"
501
+ # Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n"
406
502
  #
407
503
  # # Dump an array to an IO with indentation set
408
- # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)
504
+ # Psych.dump(['a', ['b']], StringIO.new, indentation: 3)
409
505
  def self.dump o, io = nil, options = {}
410
506
  if Hash === io
411
507
  options = io
@@ -417,6 +513,79 @@ module Psych
417
513
  visitor.tree.yaml io, options
418
514
  end
419
515
 
516
+ ###
517
+ # call-seq:
518
+ # Psych.safe_dump(o) -> string of yaml
519
+ # Psych.safe_dump(o, options) -> string of yaml
520
+ # Psych.safe_dump(o, io) -> io object passed in
521
+ # Psych.safe_dump(o, io, options) -> io object passed in
522
+ #
523
+ # Safely dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
524
+ # to control the output format. If an IO object is passed in, the YAML will
525
+ # be dumped to that IO object. By default, only the following
526
+ # classes are allowed to be serialized:
527
+ #
528
+ # * TrueClass
529
+ # * FalseClass
530
+ # * NilClass
531
+ # * Integer
532
+ # * Float
533
+ # * String
534
+ # * Array
535
+ # * Hash
536
+ #
537
+ # Arbitrary classes can be allowed by adding those classes to the +permitted_classes+
538
+ # keyword argument. They are additive. For example, to allow Date serialization:
539
+ #
540
+ # Psych.safe_dump(yaml, permitted_classes: [Date])
541
+ #
542
+ # Now the Date class can be dumped in addition to the classes listed above.
543
+ #
544
+ # A Psych::DisallowedClass exception will be raised if the object contains a
545
+ # class that isn't in the +permitted_classes+ list.
546
+ #
547
+ # Currently supported options are:
548
+ #
549
+ # [<tt>:indentation</tt>] Number of space characters used to indent.
550
+ # Acceptable value should be in <tt>0..9</tt> range,
551
+ # otherwise option is ignored.
552
+ #
553
+ # Default: <tt>2</tt>.
554
+ # [<tt>:line_width</tt>] Max character to wrap line at.
555
+ #
556
+ # Default: <tt>0</tt> (meaning "wrap at 81").
557
+ # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
558
+ # strictly formal).
559
+ #
560
+ # Default: <tt>false</tt>.
561
+ # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document.
562
+ #
563
+ # Default: <tt>false</tt>.
564
+ #
565
+ # Example:
566
+ #
567
+ # # Dump an array, get back a YAML string
568
+ # Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n"
569
+ #
570
+ # # Dump an array to an IO object
571
+ # Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
572
+ #
573
+ # # Dump an array with indentation set
574
+ # Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n"
575
+ #
576
+ # # Dump an array to an IO with indentation set
577
+ # Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3)
578
+ def self.safe_dump o, io = nil, options = {}
579
+ if Hash === io
580
+ options = io
581
+ io = nil
582
+ end
583
+
584
+ visitor = Psych::Visitors::RestrictedYAMLTree.create options
585
+ visitor << o
586
+ visitor.tree.yaml io, options
587
+ end
588
+
420
589
  ###
421
590
  # Dump a list of objects as separate documents to a document stream.
422
591
  #
@@ -454,55 +623,123 @@ module Psych
454
623
  # end
455
624
  # list # => ['foo', 'bar']
456
625
  #
457
- def self.load_stream yaml, filename = nil
458
- if block_given?
459
- parse_stream(yaml, filename) do |node|
460
- yield node.to_ruby
461
- end
462
- else
463
- parse_stream(yaml, filename).children.map { |child| child.to_ruby }
464
- end
626
+ def self.load_stream yaml, filename: nil, fallback: [], **kwargs
627
+ result = if block_given?
628
+ parse_stream(yaml, filename: filename) do |node|
629
+ yield node.to_ruby(**kwargs)
630
+ end
631
+ else
632
+ parse_stream(yaml, filename: filename).children.map { |node| node.to_ruby(**kwargs) }
633
+ end
634
+
635
+ return fallback if result.is_a?(Array) && result.empty?
636
+ result
465
637
  end
466
638
 
467
639
  ###
468
640
  # Load the document contained in +filename+. Returns the yaml contained in
469
641
  # +filename+ as a Ruby object, or if the file is empty, it returns
470
- # the specified default return value, which defaults to an empty Hash
471
- def self.load_file filename, fallback = false
642
+ # the specified +fallback+ return value, which defaults to +false+.
643
+ #
644
+ # NOTE: This method *should not* be used to parse untrusted documents, such as
645
+ # YAML documents that are supplied via user input. Instead, please use the
646
+ # safe_load_file method.
647
+ def self.unsafe_load_file filename, **kwargs
648
+ File.open(filename, 'r:bom|utf-8') { |f|
649
+ self.unsafe_load f, filename: filename, **kwargs
650
+ }
651
+ end
652
+
653
+ ###
654
+ # Safely loads the document contained in +filename+. Returns the yaml contained in
655
+ # +filename+ as a Ruby object, or if the file is empty, it returns
656
+ # the specified +fallback+ return value, which defaults to +false+.
657
+ # See safe_load for options.
658
+ def self.safe_load_file filename, **kwargs
472
659
  File.open(filename, 'r:bom|utf-8') { |f|
473
- self.load f, filename, FALLBACK.new(fallback)
660
+ self.safe_load f, filename: filename, **kwargs
661
+ }
662
+ end
663
+
664
+ ###
665
+ # Loads the document contained in +filename+. Returns the yaml contained in
666
+ # +filename+ as a Ruby object, or if the file is empty, it returns
667
+ # the specified +fallback+ return value, which defaults to +false+.
668
+ # See load for options.
669
+ def self.load_file filename, **kwargs
670
+ File.open(filename, 'r:bom|utf-8') { |f|
671
+ self.load f, filename: filename, **kwargs
474
672
  }
475
673
  end
476
674
 
477
675
  # :stopdoc:
478
- @domain_types = {}
479
676
  def self.add_domain_type domain, type_tag, &block
480
677
  key = ['tag', domain, type_tag].join ':'
481
- @domain_types[key] = [key, block]
482
- @domain_types["tag:#{type_tag}"] = [key, block]
678
+ domain_types[key] = [key, block]
679
+ domain_types["tag:#{type_tag}"] = [key, block]
483
680
  end
484
681
 
485
682
  def self.add_builtin_type type_tag, &block
486
683
  domain = 'yaml.org,2002'
487
684
  key = ['tag', domain, type_tag].join ':'
488
- @domain_types[key] = [key, block]
685
+ domain_types[key] = [key, block]
489
686
  end
490
687
 
491
688
  def self.remove_type type_tag
492
- @domain_types.delete type_tag
689
+ domain_types.delete type_tag
493
690
  end
494
691
 
495
- @load_tags = {}
496
- @dump_tags = {}
497
692
  def self.add_tag tag, klass
498
- @load_tags[tag] = klass.name
499
- @dump_tags[klass] = tag
693
+ load_tags[tag] = klass.name
694
+ dump_tags[klass] = tag
500
695
  end
501
696
 
502
697
  class << self
503
- attr_accessor :load_tags
504
- attr_accessor :dump_tags
505
- attr_accessor :domain_types
698
+ if defined?(Ractor)
699
+ class Config
700
+ attr_accessor :load_tags, :dump_tags, :domain_types
701
+ def initialize
702
+ @load_tags = {}
703
+ @dump_tags = {}
704
+ @domain_types = {}
705
+ end
706
+ end
707
+
708
+ def config
709
+ Ractor.current[:PsychConfig] ||= Config.new
710
+ end
711
+
712
+ def load_tags
713
+ config.load_tags
714
+ end
715
+
716
+ def dump_tags
717
+ config.dump_tags
718
+ end
719
+
720
+ def domain_types
721
+ config.domain_types
722
+ end
723
+
724
+ def load_tags=(value)
725
+ config.load_tags = value
726
+ end
727
+
728
+ def dump_tags=(value)
729
+ config.dump_tags = value
730
+ end
731
+
732
+ def domain_types=(value)
733
+ config.domain_types = value
734
+ end
735
+ else
736
+ attr_accessor :load_tags
737
+ attr_accessor :dump_tags
738
+ attr_accessor :domain_types
739
+ end
506
740
  end
741
+ self.load_tags = {}
742
+ self.dump_tags = {}
743
+ self.domain_types = {}
507
744
  # :startdoc:
508
745
  end