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
data/lib/psych.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
- require 'psych/versions'
2
+ require 'date'
3
+
4
+ require_relative 'psych/versions'
3
5
  case RUBY_ENGINE
4
6
  when 'jruby'
5
- require 'psych_jars'
7
+ require_relative 'psych_jars'
6
8
  if JRuby::Util.respond_to?(:load_ext)
7
9
  JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary')
8
10
  else
@@ -10,34 +12,30 @@ when 'jruby'
10
12
  org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
11
13
  end
12
14
  else
13
- begin
14
- require "#{RUBY_VERSION[/\d+\.\d+/]}/psych.so"
15
- rescue LoadError
16
- require 'psych.so'
17
- end
15
+ require 'psych.so'
18
16
  end
19
- require 'psych/nodes'
20
- require 'psych/streaming'
21
- require 'psych/visitors'
22
- require 'psych/handler'
23
- require 'psych/tree_builder'
24
- require 'psych/parser'
25
- require 'psych/omap'
26
- require 'psych/set'
27
- require 'psych/coder'
28
- require 'psych/core_ext'
29
- require 'psych/stream'
30
- require 'psych/json/tree_builder'
31
- require 'psych/json/stream'
32
- require 'psych/handlers/document_stream'
33
- require 'psych/class_loader'
17
+ require_relative 'psych/nodes'
18
+ require_relative 'psych/streaming'
19
+ require_relative 'psych/visitors'
20
+ require_relative 'psych/handler'
21
+ require_relative 'psych/tree_builder'
22
+ require_relative 'psych/parser'
23
+ require_relative 'psych/omap'
24
+ require_relative 'psych/set'
25
+ require_relative 'psych/coder'
26
+ require_relative 'psych/core_ext'
27
+ require_relative 'psych/stream'
28
+ require_relative 'psych/json/tree_builder'
29
+ require_relative 'psych/json/stream'
30
+ require_relative 'psych/handlers/document_stream'
31
+ require_relative 'psych/class_loader'
34
32
 
35
33
  ###
36
34
  # = Overview
37
35
  #
38
36
  # Psych is a YAML parser and emitter.
39
37
  # Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML]
40
- # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing
38
+ # or [git repo: https://github.com/yaml/libyaml] for its YAML parsing
41
39
  # and emitting capabilities. In addition to wrapping libyaml, Psych also
42
40
  # knows how to serialize and de-serialize most Ruby objects to and from
43
41
  # the YAML format.
@@ -78,14 +76,17 @@ require 'psych/class_loader'
78
76
  #
79
77
  # ==== Reading from a string
80
78
  #
81
- # Psych.load("--- a") # => 'a'
82
- # Psych.load("---\n - a\n - b") # => ['a', 'b']
79
+ # Psych.safe_load("--- a") # => 'a'
80
+ # Psych.safe_load("---\n - a\n - b") # => ['a', 'b']
81
+ # # From a trusted string:
82
+ # Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42
83
83
  #
84
84
  # ==== Reading from a file
85
85
  #
86
- # Psych.load_file("database.yml")
86
+ # Psych.safe_load_file("data.yml", permitted_classes: [Date])
87
+ # Psych.load_file("trusted_database.yml")
87
88
  #
88
- # ==== Exception handling
89
+ # ==== \Exception handling
89
90
  #
90
91
  # begin
91
92
  # # The second argument changes only the exception contents
@@ -149,7 +150,7 @@ require 'psych/class_loader'
149
150
  # # Returns Psych::Nodes::Document
150
151
  # Psych.parse_file('database.yml')
151
152
  #
152
- # ==== Exception handling
153
+ # ==== \Exception handling
153
154
  #
154
155
  # begin
155
156
  # # The second argument changes only the exception contents
@@ -234,10 +235,7 @@ require 'psych/class_loader'
234
235
 
235
236
  module Psych
236
237
  # The version of libyaml Psych is using
237
- LIBYAML_VERSION = Psych.libyaml_version.join '.'
238
- # Deprecation guard
239
- NOT_GIVEN = Object.new
240
- private_constant :NOT_GIVEN
238
+ LIBYAML_VERSION = Psych.libyaml_version.join('.').freeze
241
239
 
242
240
  ###
243
241
  # Load +yaml+ in to a Ruby data structure. If multiple documents are
@@ -250,11 +248,11 @@ module Psych
250
248
  #
251
249
  # Example:
252
250
  #
253
- # Psych.load("--- a") # => 'a'
254
- # Psych.load("---\n - a\n - b") # => ['a', 'b']
251
+ # Psych.unsafe_load("--- a") # => 'a'
252
+ # Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b']
255
253
  #
256
254
  # begin
257
- # Psych.load("--- `", filename: "file.txt")
255
+ # Psych.unsafe_load("--- `", filename: "file.txt")
258
256
  # rescue Psych::SyntaxError => ex
259
257
  # ex.file # => 'file.txt'
260
258
  # ex.message # => "(file.txt): found character that cannot start any token"
@@ -263,22 +261,19 @@ module Psych
263
261
  # When the optional +symbolize_names+ keyword argument is set to a
264
262
  # true value, returns symbols for keys in Hash objects (default: strings).
265
263
  #
266
- # Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
267
- # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
264
+ # Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"}
265
+ # Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
268
266
  #
269
267
  # Raises a TypeError when `yaml` parameter is NilClass
270
268
  #
271
- def self.load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false
272
- if legacy_filename != NOT_GIVEN
273
- warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
274
- filename = legacy_filename
275
- end
276
-
269
+ # NOTE: This method *should not* be used to parse untrusted documents, such as
270
+ # YAML documents that are supplied via user input. Instead, please use the
271
+ # load method or the safe_load method.
272
+ #
273
+ def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false
277
274
  result = parse(yaml, filename: filename)
278
275
  return fallback unless result
279
- result = result.to_ruby if result
280
- symbolize_names!(result) if symbolize_names
281
- result
276
+ result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer)
282
277
  end
283
278
 
284
279
  ###
@@ -288,7 +283,8 @@ module Psych
288
283
  # * TrueClass
289
284
  # * FalseClass
290
285
  # * NilClass
291
- # * Numeric
286
+ # * Integer
287
+ # * Float
292
288
  # * String
293
289
  # * Array
294
290
  # * Hash
@@ -313,7 +309,7 @@ module Psych
313
309
  # A Psych::DisallowedClass exception will be raised if the yaml contains a
314
310
  # class that isn't in the +permitted_classes+ list.
315
311
  #
316
- # A Psych::BadAlias exception will be raised if the yaml contains aliases
312
+ # A Psych::AliasesNotEnabled exception will be raised if the yaml contains aliases
317
313
  # but the +aliases+ keyword argument is set to false.
318
314
  #
319
315
  # +filename+ will be used in the exception message if any exception is raised
@@ -325,43 +321,63 @@ module Psych
325
321
  # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
326
322
  # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
327
323
  #
328
- def self.safe_load yaml, legacy_permitted_classes = NOT_GIVEN, legacy_permitted_symbols = NOT_GIVEN, legacy_aliases = NOT_GIVEN, legacy_filename = NOT_GIVEN, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false
329
- if legacy_permitted_classes != NOT_GIVEN
330
- warn_with_uplevel 'Passing permitted_classes with the 2nd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_classes: ...) instead.', uplevel: 1 if $VERBOSE
331
- permitted_classes = legacy_permitted_classes
332
- end
333
-
334
- if legacy_permitted_symbols != NOT_GIVEN
335
- warn_with_uplevel 'Passing permitted_symbols with the 3rd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_symbols: ...) instead.', uplevel: 1 if $VERBOSE
336
- permitted_symbols = legacy_permitted_symbols
337
- end
338
-
339
- if legacy_aliases != NOT_GIVEN
340
- warn_with_uplevel 'Passing aliases with the 4th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, aliases: ...) instead.', uplevel: 1 if $VERBOSE
341
- aliases = legacy_aliases
342
- end
343
-
344
- if legacy_filename != NOT_GIVEN
345
- warn_with_uplevel 'Passing filename with the 5th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
346
- filename = legacy_filename
347
- end
348
-
324
+ def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
349
325
  result = parse(yaml, filename: filename)
350
326
  return fallback unless result
351
327
 
352
328
  class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
353
329
  permitted_symbols.map(&:to_s))
354
- scanner = ScalarScanner.new class_loader
330
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
355
331
  visitor = if aliases
356
- Visitors::ToRuby.new scanner, class_loader
332
+ Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
357
333
  else
358
- Visitors::NoAliasRuby.new scanner, class_loader
334
+ Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
359
335
  end
360
336
  result = visitor.accept result
361
- symbolize_names!(result) if symbolize_names
362
337
  result
363
338
  end
364
339
 
340
+ ###
341
+ # Load +yaml+ in to a Ruby data structure. If multiple documents are
342
+ # provided, the object contained in the first document will be returned.
343
+ # +filename+ will be used in the exception message if any exception
344
+ # is raised while parsing. If +yaml+ is empty, it returns
345
+ # the specified +fallback+ return value, which defaults to +nil+.
346
+ #
347
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
348
+ #
349
+ # Example:
350
+ #
351
+ # Psych.load("--- a") # => 'a'
352
+ # Psych.load("---\n - a\n - b") # => ['a', 'b']
353
+ #
354
+ # begin
355
+ # Psych.load("--- `", filename: "file.txt")
356
+ # rescue Psych::SyntaxError => ex
357
+ # ex.file # => 'file.txt'
358
+ # ex.message # => "(file.txt): found character that cannot start any token"
359
+ # end
360
+ #
361
+ # When the optional +symbolize_names+ keyword argument is set to a
362
+ # true value, returns symbols for keys in Hash objects (default: strings).
363
+ #
364
+ # Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
365
+ # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
366
+ #
367
+ # Raises a TypeError when `yaml` parameter is NilClass. This method is
368
+ # similar to `safe_load` except that `Symbol` objects are allowed by default.
369
+ #
370
+ def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
371
+ safe_load yaml, permitted_classes: permitted_classes,
372
+ permitted_symbols: permitted_symbols,
373
+ aliases: aliases,
374
+ filename: filename,
375
+ fallback: fallback,
376
+ symbolize_names: symbolize_names,
377
+ freeze: freeze,
378
+ strict_integer: strict_integer
379
+ end
380
+
365
381
  ###
366
382
  # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document.
367
383
  # +filename+ is used in the exception message if a Psych::SyntaxError is
@@ -381,22 +397,12 @@ module Psych
381
397
  # end
382
398
  #
383
399
  # See Psych::Nodes for more information about YAML AST.
384
- def self.parse yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: NOT_GIVEN
385
- if legacy_filename != NOT_GIVEN
386
- warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse is deprecated. Use keyword argument like Psych.parse(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
387
- filename = legacy_filename
388
- end
389
-
400
+ def self.parse yaml, filename: nil
390
401
  parse_stream(yaml, filename: filename) do |node|
391
402
  return node
392
403
  end
393
404
 
394
- if fallback != NOT_GIVEN
395
- warn_with_uplevel 'Passing the `fallback` keyword argument of Psych.parse is deprecated.', uplevel: 1 if $VERBOSE
396
- fallback
397
- else
398
- false
399
- end
405
+ false
400
406
  end
401
407
 
402
408
  ###
@@ -445,12 +451,7 @@ module Psych
445
451
  # Raises a TypeError when NilClass is passed.
446
452
  #
447
453
  # See Psych::Nodes for more information about YAML AST.
448
- def self.parse_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, &block
449
- if legacy_filename != NOT_GIVEN
450
- warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse_stream is deprecated. Use keyword argument like Psych.parse_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
451
- filename = legacy_filename
452
- end
453
-
454
+ def self.parse_stream yaml, filename: nil, &block
454
455
  if block_given?
455
456
  parser = Psych::Parser.new(Handlers::DocumentStream.new(&block))
456
457
  parser.parse yaml, filename
@@ -480,6 +481,7 @@ module Psych
480
481
  #
481
482
  # Default: <tt>2</tt>.
482
483
  # [<tt>:line_width</tt>] Max character to wrap line at.
484
+ # For unlimited line width use <tt>-1</tt>.
483
485
  #
484
486
  # Default: <tt>0</tt> (meaning "wrap at 81").
485
487
  # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
@@ -490,6 +492,10 @@ module Psych
490
492
  #
491
493
  # Default: <tt>false</tt>.
492
494
  #
495
+ # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
496
+ #
497
+ # Default: <tt>false</tt>.
498
+ #
493
499
  # Example:
494
500
  #
495
501
  # # Dump an array, get back a YAML string
@@ -503,6 +509,9 @@ module Psych
503
509
  #
504
510
  # # Dump an array to an IO with indentation set
505
511
  # Psych.dump(['a', ['b']], StringIO.new, indentation: 3)
512
+ #
513
+ # # Dump hash with symbol keys as string
514
+ # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
506
515
  def self.dump o, io = nil, options = {}
507
516
  if Hash === io
508
517
  options = io
@@ -514,6 +523,87 @@ module Psych
514
523
  visitor.tree.yaml io, options
515
524
  end
516
525
 
526
+ ###
527
+ # call-seq:
528
+ # Psych.safe_dump(o) -> string of yaml
529
+ # Psych.safe_dump(o, options) -> string of yaml
530
+ # Psych.safe_dump(o, io) -> io object passed in
531
+ # Psych.safe_dump(o, io, options) -> io object passed in
532
+ #
533
+ # Safely dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
534
+ # to control the output format. If an IO object is passed in, the YAML will
535
+ # be dumped to that IO object. By default, only the following
536
+ # classes are allowed to be serialized:
537
+ #
538
+ # * TrueClass
539
+ # * FalseClass
540
+ # * NilClass
541
+ # * Integer
542
+ # * Float
543
+ # * String
544
+ # * Array
545
+ # * Hash
546
+ #
547
+ # Arbitrary classes can be allowed by adding those classes to the +permitted_classes+
548
+ # keyword argument. They are additive. For example, to allow Date serialization:
549
+ #
550
+ # Psych.safe_dump(yaml, permitted_classes: [Date])
551
+ #
552
+ # Now the Date class can be dumped in addition to the classes listed above.
553
+ #
554
+ # A Psych::DisallowedClass exception will be raised if the object contains a
555
+ # class that isn't in the +permitted_classes+ list.
556
+ #
557
+ # Currently supported options are:
558
+ #
559
+ # [<tt>:indentation</tt>] Number of space characters used to indent.
560
+ # Acceptable value should be in <tt>0..9</tt> range,
561
+ # otherwise option is ignored.
562
+ #
563
+ # Default: <tt>2</tt>.
564
+ # [<tt>:line_width</tt>] Max character to wrap line at.
565
+ # For unlimited line width use <tt>-1</tt>.
566
+ #
567
+ # Default: <tt>0</tt> (meaning "wrap at 81").
568
+ # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
569
+ # strictly formal).
570
+ #
571
+ # Default: <tt>false</tt>.
572
+ # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document.
573
+ #
574
+ # Default: <tt>false</tt>.
575
+ #
576
+ # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
577
+ #
578
+ # Default: <tt>false</tt>.
579
+ #
580
+ # Example:
581
+ #
582
+ # # Dump an array, get back a YAML string
583
+ # Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n"
584
+ #
585
+ # # Dump an array to an IO object
586
+ # Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
587
+ #
588
+ # # Dump an array with indentation set
589
+ # Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n"
590
+ #
591
+ # # Dump an array to an IO with indentation set
592
+ # Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3)
593
+ #
594
+ # # Dump hash with symbol keys as string
595
+ # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
596
+ def self.safe_dump o, io = nil, options = {}
597
+ if Hash === io
598
+ options = io
599
+ io = nil
600
+ end
601
+
602
+ visitor = Psych::Visitors::RestrictedYAMLTree.create options
603
+ visitor << o
604
+ visitor.tree.yaml io, options
605
+ end
606
+
517
607
  ###
518
608
  # Dump a list of objects as separate documents to a document stream.
519
609
  #
@@ -551,18 +641,13 @@ module Psych
551
641
  # end
552
642
  # list # => ['foo', 'bar']
553
643
  #
554
- def self.load_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: []
555
- if legacy_filename != NOT_GIVEN
556
- warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load_stream is deprecated. Use keyword argument like Psych.load_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
557
- filename = legacy_filename
558
- end
559
-
644
+ def self.load_stream yaml, filename: nil, fallback: [], **kwargs
560
645
  result = if block_given?
561
646
  parse_stream(yaml, filename: filename) do |node|
562
- yield node.to_ruby
647
+ yield node.to_ruby(**kwargs)
563
648
  end
564
649
  else
565
- parse_stream(yaml, filename: filename).children.map(&:to_ruby)
650
+ parse_stream(yaml, filename: filename).children.map { |node| node.to_ruby(**kwargs) }
566
651
  end
567
652
 
568
653
  return fallback if result.is_a?(Array) && result.empty?
@@ -573,69 +658,106 @@ module Psych
573
658
  # Load the document contained in +filename+. Returns the yaml contained in
574
659
  # +filename+ as a Ruby object, or if the file is empty, it returns
575
660
  # the specified +fallback+ return value, which defaults to +false+.
576
- def self.load_file filename, fallback: false
661
+ #
662
+ # NOTE: This method *should not* be used to parse untrusted documents, such as
663
+ # YAML documents that are supplied via user input. Instead, please use the
664
+ # safe_load_file method.
665
+ def self.unsafe_load_file filename, **kwargs
666
+ File.open(filename, 'r:bom|utf-8') { |f|
667
+ self.unsafe_load f, filename: filename, **kwargs
668
+ }
669
+ end
670
+
671
+ ###
672
+ # Safely loads the document contained in +filename+. Returns the yaml contained in
673
+ # +filename+ as a Ruby object, or if the file is empty, it returns
674
+ # the specified +fallback+ return value, which defaults to +nil+.
675
+ # See safe_load for options.
676
+ def self.safe_load_file filename, **kwargs
577
677
  File.open(filename, 'r:bom|utf-8') { |f|
578
- self.load f, filename: filename, fallback: fallback
678
+ self.safe_load f, filename: filename, **kwargs
679
+ }
680
+ end
681
+
682
+ ###
683
+ # Loads the document contained in +filename+. Returns the yaml contained in
684
+ # +filename+ as a Ruby object, or if the file is empty, it returns
685
+ # the specified +fallback+ return value, which defaults to +nil+.
686
+ # See load for options.
687
+ def self.load_file filename, **kwargs
688
+ File.open(filename, 'r:bom|utf-8') { |f|
689
+ self.load f, filename: filename, **kwargs
579
690
  }
580
691
  end
581
692
 
582
693
  # :stopdoc:
583
- @domain_types = {}
584
694
  def self.add_domain_type domain, type_tag, &block
585
695
  key = ['tag', domain, type_tag].join ':'
586
- @domain_types[key] = [key, block]
587
- @domain_types["tag:#{type_tag}"] = [key, block]
696
+ domain_types[key] = [key, block]
697
+ domain_types["tag:#{type_tag}"] = [key, block]
588
698
  end
589
699
 
590
700
  def self.add_builtin_type type_tag, &block
591
701
  domain = 'yaml.org,2002'
592
702
  key = ['tag', domain, type_tag].join ':'
593
- @domain_types[key] = [key, block]
703
+ domain_types[key] = [key, block]
594
704
  end
595
705
 
596
706
  def self.remove_type type_tag
597
- @domain_types.delete type_tag
707
+ domain_types.delete type_tag
598
708
  end
599
709
 
600
- @load_tags = {}
601
- @dump_tags = {}
602
710
  def self.add_tag tag, klass
603
- @load_tags[tag] = klass.name
604
- @dump_tags[klass] = tag
711
+ load_tags[tag] = klass.name
712
+ dump_tags[klass] = tag
605
713
  end
606
714
 
607
- def self.symbolize_names!(result)
608
- case result
609
- when Hash
610
- result.keys.each do |key|
611
- result[key.to_sym] = symbolize_names!(result.delete(key))
715
+ class << self
716
+ if defined?(Ractor)
717
+ class Config
718
+ attr_accessor :load_tags, :dump_tags, :domain_types
719
+ def initialize
720
+ @load_tags = {}
721
+ @dump_tags = {}
722
+ @domain_types = {}
723
+ end
612
724
  end
613
- when Array
614
- result.map! { |r| symbolize_names!(r) }
615
- end
616
- result
617
- end
618
- private_class_method :symbolize_names!
619
725
 
620
- # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
621
- def self.warn_with_uplevel(message, uplevel: 1)
622
- at = parse_caller(caller[uplevel]).join(':')
623
- warn "#{at}: #{message}"
624
- end
726
+ def config
727
+ Ractor.current[:PsychConfig] ||= Config.new
728
+ end
625
729
 
626
- def self.parse_caller(at)
627
- if /^(.+?):(\d+)(?::in `.*')?/ =~ at
628
- file = $1
629
- line = $2.to_i
630
- [file, line]
631
- end
632
- end
633
- private_class_method :warn_with_uplevel, :parse_caller
730
+ def load_tags
731
+ config.load_tags
732
+ end
634
733
 
635
- class << self
636
- attr_accessor :load_tags
637
- attr_accessor :dump_tags
638
- attr_accessor :domain_types
734
+ def dump_tags
735
+ config.dump_tags
736
+ end
737
+
738
+ def domain_types
739
+ config.domain_types
740
+ end
741
+
742
+ def load_tags=(value)
743
+ config.load_tags = value
744
+ end
745
+
746
+ def dump_tags=(value)
747
+ config.dump_tags = value
748
+ end
749
+
750
+ def domain_types=(value)
751
+ config.domain_types = value
752
+ end
753
+ else
754
+ attr_accessor :load_tags
755
+ attr_accessor :dump_tags
756
+ attr_accessor :domain_types
757
+ end
639
758
  end
759
+ self.load_tags = {}
760
+ self.dump_tags = {}
761
+ self.domain_types = {}
640
762
  # :startdoc:
641
763
  end