psych 2.2.1 → 5.1.2

Sign up to get free protection for your applications and to get access to all the features.
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