Can you give us a page reference to the "transient exceptions" line?
In any case, you can create a new exception any time, and it's commonly good to do so so that you can transfer more information about the fault. This is particularly good when you have alow level exception and want to make it into something more meaningful to the user.
Throw/Catch in Ruby are really a kind of nonlocal goto, like setjmp/longjmp in C, but better behaved. You'd use it anytime you want to tranfer execution a long ways.
Obviously, for the same reason you don't want to use goto
much, you don't want to do this. A big reason you might use it is in a case of a program that needs to stay running, so if you catch certain kinds of errors, you might dump the whole piece of work you're doing and go back to the start.
Okay, that doesn't seem to be on page 97 of either of the editions of the pickaxe book I've got, but I see what it means. ... oh, here it is, page 157 in the third edition.
First of all, on the business about "transient", there are some network problems that can occur, and then resolve themselves, say when the BOFH unplugs the network cable and plugs it back in. So, under some conditions, you might want to give it a few seconds to settle down and try again before panicking. how would you do that?
In this case, they have you define a new kind of exception. This is done just with inheritance:
class RetryException < RuntimeError
# so this is a kind of RuntimeError which is a kind of Exception
attr: ok_to_retry
def initialize(ok_to_retry)
@ok_to_retry
end
end
so then if something goes wrong, you can raise on of these new retryable exceptions
raise RetryException.new(true), "transient read error"
which now sends something that is a kind of RuntimeError up the stack, but now has additional information attached to it, ie, a flag that says "yes, this can be retried."
NOw, here's a really nifty thing in Ruby: it has a built in capability of retrying some things. So, someplace up the stack, you have this code:
begin
# do something that raises this exception
do_something()
rescue RetryException => detail
# if the exception is one of these retryable ones,
# catch it here, but it in detail
if detail.ok_to_retry
retry
end
# this means exactly the same as 'retry if detail.ok_to_retry`
# from the book, btw
# if it STILL doesn't work, send the exception on
raise # just re-raises the last exception
end