Method: Psych.safe_load

Defined in:
lib/psych.rb

.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, freeze: false) ⇒ Object

Safely load the yaml string in yaml. By default, only the following classes are allowed to be deserialized:

  • TrueClass

  • FalseClass

  • NilClass

  • Numeric

  • String

  • Array

  • Hash

Recursive data structures are not allowed by default. Arbitrary classes can be allowed by adding those classes to the permitted_classes keyword argument. They are additive. For example, to allow Date deserialization:

Psych.safe_load(yaml, permitted_classes: [Date])

Now the Date class can be loaded in addition to the classes listed above.

Aliases can be explicitly allowed by changing the aliases keyword argument. For example:

x = []
x << x
yaml = Psych.dump x
Psych.safe_load yaml               # => raises an exception
Psych.safe_load yaml, aliases: true # => loads the aliases

A Psych::DisallowedClass exception will be raised if the yaml contains a class that isn’t in the permitted_classes list.

A Psych::BadAlias exception will be raised if the yaml contains aliases but the aliases keyword argument is set to false.

filename will be used in the exception message if any exception is raised while parsing.

When the optional symbolize_names keyword argument is set to a true value, returns symbols for keys in Hash objects (default: strings).

Psych.safe_load("---\n foo: bar")                         # => {"foo"=>"bar"}
Psych.safe_load("---\n foo: bar", symbolize_names: true)  # => {:foo=>"bar"}


329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/psych.rb', line 329

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, freeze: false
  if legacy_permitted_classes != NOT_GIVEN
    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
    permitted_classes = legacy_permitted_classes
  end

  if legacy_permitted_symbols != NOT_GIVEN
    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
    permitted_symbols = legacy_permitted_symbols
  end

  if legacy_aliases != NOT_GIVEN
    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
    aliases = legacy_aliases
  end

  if legacy_filename != NOT_GIVEN
    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
    filename = legacy_filename
  end

  result = parse(yaml, filename: filename)
  return fallback unless result

  class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
                                             permitted_symbols.map(&:to_s))
  scanner      = ScalarScanner.new class_loader
  visitor = if aliases
              Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
            else
              Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
            end
  result = visitor.accept result
  result
end