1

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

Community
  • 1
  • 1
Marko Avlijaš
  • 1,579
  • 13
  • 27

1 Answers1

2

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.

Community
  • 1
  • 1
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • What about the ERRNO::SOMETHING when you `YAML.load_file` that doesn't exist? – Marko Avlijaš Jan 31 '17 at 09:50
  • What about the sytax error when you don't close the quotes around the filename string? :) Basically anything can go wrong while loading a file. I understood the question as referring to Psych specific exceptions. – Eric Duminil Jan 31 '17 at 09:52
  • Sorry for wasting your time, I have just editted the question. – Marko Avlijaš Jan 31 '17 at 09:56
  • No offense meant, and you didn't waste my time. I just wanted to make a point, possibly too aggressively, though. – Eric Duminil Jan 31 '17 at 09:58
  • Upvoted. Thank you I wouldn't catch the StringScanner::Error and I like the code you used to discover exceptions. Still it feels weird as if you can never be sure that caught them all. – Marko Avlijaš Jan 31 '17 at 10:14
  • I'm not sure you could be sure to catch them all in any language. Surely not in Ruby, given its extremly dynamic nature. – Eric Duminil Jan 31 '17 at 10:20
  • You may want to mention that the specific exception for loading a nonexistent file is `ScriptError::LoadError`. – Matthew Schuchard Jan 31 '17 at 13:15
  • @MattSchuchard : As I wrote in the answer : `Anything could go wrong anywhere`. LoadError would be thrown when `require` cannot find another ruby file. It doesn't have much to do with YAML IMHO. – Eric Duminil Jan 31 '17 at 13:18
  • `YAML.load_file` throws `Errno::ENOENT` with a nonexistent file. Or did I misunderstand your comment? – Eric Duminil Jan 31 '17 at 13:19