0

I want a class that will load and save settings in yaml file, and displays an error if something happens. I must catch exceptions and I must know what to catch. There is no guarantee what exception will be raised; user might press CTRL+C or memory may run out, but YAML.load_file can raise only a limited number of exceptions. There is nowhere listed what exceptions a function YAML.load_file might raise.

How can I catch only them when I don't know what those exceptions are?

This question has been asked, but there is no real answer:

Community
  • 1
  • 1
Marko Avlijaš
  • 1,579
  • 13
  • 27
  • 1
    The same you know in any language that doesn't have checked exceptions. Or even those that have and throw unchecked. Read the documentation. Read the tests. Read the code. You saw people ask that question multiple times and not get a silver bullet, yet you decided to ask it again. How do you know how to use any API for that matter? – ndnenkov Dec 23 '15 at 20:49
  • How do I find source or tests for http://ruby-doc.org/core-2.0.0/IO.html#method-i-write I am aware of the "click to toggle source" button, but it doesn't show anything useful. – Marko Avlijaš Dec 24 '15 at 07:17

3 Answers3

2

Sometimes you just don't know which kind of exception can be thrown, for that the generic rescue catching exists.

begin
    do_something
rescue KnownException
    treat_exception
# generic exception 
rescue Exception => e
    # you don't know which exception has been raised but all info is in e
    print "Ups I don't know this Exception:#{e.class} error: #{e.message}"
    raise
end
Pierre Michard
  • 1,341
  • 1
  • 12
  • 16
  • 1
    You get -1 for rescuing Exception :) – Sergio Tulentsev Dec 23 '15 at 21:02
  • Well, you don't reraise. – Sergio Tulentsev Dec 23 '15 at 21:04
  • I don't think this is a bad answer. If you're completely not sure then this will at least show you the one that is getting raised so you can deal with accordingly. – Trinculo Dec 23 '15 at 21:39
  • I think this is bad process. I don't want to swallow exceptions. What I am currently doing is trying to push code into extreme cases and making program fail, then reading exception name that is thrown. But I am sure I am missing stuff this way and there must be a more efficient way. – Marko Avlijaš Dec 24 '15 at 07:15
2

How can I catch only them when I don't know what those exceptions are?

What are you going to do when you catch them, I wonder? It makes little sense to catch exceptions for the sake of catching. Swallowing exceptions is especially bad practice.

My rule of thumb is: catch only those I can recover from (this implies already knowing what they are). Let the rest bubble up and crash the program or possibly be catched in one of outer scopes (which will know how to recover from this concrete one).

How to discover currently loaded exception classes

This almost 10 year old code snippet still works today:

exceptions = []
tree = {}
ObjectSpace.each_object(Class) do |cls|
  next unless cls.ancestors.include? Exception
  next if exceptions.include? cls
  exceptions << cls
  cls.ancestors.delete_if {|e| [Object, Kernel].include? e }.reverse.inject(tree) {|memo,cls| memo[cls] ||= {}}
end

indent = 0
tree_printer = Proc.new do |t|
  t.keys.sort { |c1,c2| c1.name <=> c2.name }.each do |k|
    space = (' ' * indent); space ||= ''
    puts space + k.to_s
    indent += 2; tree_printer.call t[k]; indent -= 2
  end
end
tree_printer.call tree

Run it in the rails console and you'll see a lot of exception classes. :)

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • It's not true that recovering from exception implies knowing what they are. I know how to recover from "you can't write to this folder" or "filename invalid" if I knew what those exceptions were named. And it's not listed anywhere I have looked. – Marko Avlijaš Dec 24 '15 at 07:13
  • @MarkoAvlijaš: check out this post: http://blog.nicksieger.com/articles/2006/09/06/rubys-exception-hierarchy/. If you run this code in a rails app, you get much bigger exception tree. There's your list. – Sergio Tulentsev Dec 24 '15 at 07:23
  • Particularly, "no such file" error is called `Errno::ENOENT`. – Sergio Tulentsev Dec 24 '15 at 07:30
  • Thanks, this is useful. Any idea how to apply this code to a (other people's) class? All I can think of now is run it before you include the class and output results into file, then run it after and do a diff. This way I'll catch unique exceptions, but miss those that standard ruby code is using. – Marko Avlijaš Dec 24 '15 at 07:32
  • do you want to figure it out and create an answer from it? This question is asked a lot and no real answers are given. – Marko Avlijaš Dec 24 '15 at 07:41
  • @MarkoAvlijaš: Nah, I'm good, thanks. But it seems that you got the pointers you needed, though. – Sergio Tulentsev Dec 24 '15 at 07:44
-2

The source code is the documentation.

-- Matz

Community
  • 1
  • 1
sawa
  • 165,429
  • 45
  • 277
  • 381
  • Where to find it? On ruby-doc.org code is useless - it's in C and partial. Take a look at IO#write. http://ruby-doc.org/core-2.0.0/IO.html#method-i-write – Marko Avlijaš Dec 24 '15 at 07:10
  • @MarkoAvlijaš Weren't you looking for `YAML.load_file`? – sawa Dec 24 '15 at 07:18
  • Yes to load and save settings. For save settings I am using File.write / IO.write – Marko Avlijaš Dec 24 '15 at 07:22
  • 1
    @MarkoAvlijaš: I'm afraid you'll have to read a good chunk of ruby codebase to learn which exceptions are thrown from core and stdlib. [This file](https://github.com/ruby/ruby/blob/ada76728f6e672a8b7366bf1f444387945af993b/error.c) will provide keywords for grepping (C function names). As an alternative, you can read rubinius code, much less C there :) – Sergio Tulentsev Dec 24 '15 at 08:00