Marko Avlijaš
Marko Avlijaš

Reputation: 1659

How to rescue Psych Yaml exceptions?

This is actually 3 part question:

  1. What are all the exceptions Psych throws?
  2. How do you know which ones they are when documentation doesn't bother to list them?
  3. Sample code to catch all possible YAML.load_file exceptions?

I wouldn't ask for no 3 but this question suggests I will encounter wierd issues: Can't rescue YAML.load exception

Based on this question How to know what exceptions to rescue

I got:

Psych::Exception
      Psych::BadAlias
      Psych::DisallowedClass
      Psych::SyntaxError

But when I try to catch that code still fails

irb(main):002:0> begin
irb(main):003:1* YAML.load_file('test_file_does_not_exist')
irb(main):004:1> rescue Psych::Exception
irb(main):005:1> puts $!.message
irb(main):006:1> end
Errno::ENOENT: No such file or directory @ rb_sysopen - test
    from /home/marko/.gem/ruby/2.3.1/gems/psych-2.1.0/lib/psych.rb:474:in `initialize'
    from /home/marko/.gem/ruby/2.3.1/gems/psych-2.1.0/lib/psych.rb:474:in `open'
    from /home/marko/.gem/ruby/2.3.1/gems/psych-2.1.0/lib/psych.rb:474:in `load_file'
    from (irb):3
    from /home/marko/.rubies/ruby-2.3.1/bin/irb:11:in `<main>'

I am looking for ways to catch all of that nonsense. Regardless for the reason of failure, I want to catch it and display a message before it falls back to main exception handling code.

Microsoft, which I don't particularly like, shows all exceptions for every class they ever wrote. Example: https://msdn.microsoft.com/en-us/library/b9skfh7s(v=vs.110).aspx

Upvotes: 1

Views: 556

Answers (1)

Eric Duminil
Eric Duminil

Reputation: 54243

Psych exceptions

One way to check would be :

exceptions_before = ObjectSpace.each_object(Class).select{|klass| klass < Exception}
require 'yaml'
exceptions_after  = ObjectSpace.each_object(Class).select{|klass| klass < Exception}

It might miss Exceptions that are dynamically generated. Still, here's the difference between the 2, and their ancestors :

(exceptions_after - exceptions_before).each do |yaml_exception|
  p yaml_exception.ancestors
end

# [Psych::SyntaxError, Psych::Exception, RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
# [Psych::DisallowedClass, Psych::Exception, RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
# [Psych::BadAlias, Psych::Exception, RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
# [Psych::Exception, RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
# [StringScanner::Error, StandardError, Exception, Object, Kernel, BasicObject]

It seems that Psych::Exception and StringScanner::Error cover all the exceptions thrown by Psych.

Other exceptions

Anything could go wrong anywhere. Still, the most common exception will be :

Errno::ENOENT

if your .yml isn't found. You could either rescue the exception or just check that File.exist? before reading the yaml file.

IMHO, you shouldn't try to rescue every exception.

Even though it looks like you're looking for rescue => e or even rescue Exception => e, it's not a good idea.

Upvotes: 2

Related Questions