rescue_from stores exception class names in a hash table, and
associates them with handlers.
When an exception is raised there's a name lookup, and if an entry is
found its handler is invoked. In particular rescue_from does not
emulate Ruby's rescue semantics with regard to inheritance.
Which is the rationale? Don't you think taking is_a? and declaration
order into account would provide a better (expected) usage? I could
write a patch in that case.
-- fxn
PS: A friend of mine and Google Groups didn't receive this email,
please excuse me if you get it more than once.
def rescue_from(*klasses, &block)
...
klasses.each do |klass|
rescue_handlers[klass.name] = options[:with]
end
end
so they have to be defined at the point of the declaration. Taking
that into account, why handler_for_rescue does this:
def handler_for_rescue(exception)
case handler = rescue_handlers[exception.class.name]
when Symbol
method(handler)
when Proc
handler.bind(self)
end
end
instead of this (off the top of my head):
def handler_for_rescue(exception)
pair = rescue_handlers.select do |pair|
exception.is_a?(pair.exception)
end
return unless pair
case pair.handler
when Symbol
method(pair.handler)
when Proc
pair.handler.bind(self)
end
end
assuming request_handlers in this alternative is an array of pairs of
some sort to preserve declaration order.
The diff has been computed from edge a few minutes ago.
I chose to provide rescue priority from right to left, bottom to top,
and up the hierarchy. Since the code that raises exceptions appears
usually below the declarations, and I would expect handlers in
children to be called before handlers in parents, I thought that could
be an intuitive order.
As per strings, since the objective was to be able to declare handlers
for exceptions whose definition has not yet been seen, when we loop
over the handlers when an exception is raised we do not complain if
some string-to-constant fails. Perhaps that's an early exception and
we have not yet seen the definition, so a NameError didn't seem
consistent with the original aim. Another objective was to be able to
declare handlers for classes that won't be loaded at all, we
accomplish that as well. Typos won't be apparent unfortunately, but we
can't be strict and tolerant at the same time.