J
Joel VanderWerf
These are some extensions to Exception that I've found useful recently.
Maybe someone else will too.
The #details method outputs something like what ruby itself does when
you see an exception in stderr. However, it returns a string, and you
can control the threshold for removing informative lines with '...'.
Also, the output is formatted more nicely, IMO.
The #reraise_as method is useful when you want to catch something that's
fairly opaque, like NameError, or NoMethodErr, and, using a more
descriptive and app-specific exception class, raise it again, but with
the same backtrace.
Some example code is included.
class Exception
# More or less reproduces ruby's default exception reporting in
# the returned string, except truncation can be controlled with
# +maxlines+: +nil+ means no limit, an integer value means at
# most <tt>maxlines/2</tt> frames from each of the top and bottom
# of the stack are reported.
def details(maxlines=nil)
bt = backtrace.dup
bt0 = bt.shift
if maxlines and maxlines < bt.size
ml, r = maxlines.divmod(2)
bt = bt[0...ml+r] + ["..."] + bt[-(ml==0 ? 1 : ml)..-1]
end
[
"#{bt0}: #{self.class}:",
message,
" from " + bt.join("\n from ")
].join("\n")
end
# Raise the exception, preserving the backtrace, but with as an
# instance of class +cl+. The message is preserved by default,
# but may be set to +msg+.
def reraise_as(cl, msg = message)
e = cl.new(msg)
e.set_backtrace backtrace
raise e
end
end
class FooError < StandardError; end
def foo
bar(10)
rescue StandardError => e
puts e.details(5)
puts "*"*40
e.reraise_as(FooError)
end
def bar(try)
if try <= 0
raise " bar problem:\n can't find a bar\n anywhere around here"
else
bar(try-1)
end
end
foo
EXAMPLE OUTPUT:
reraise.rb:43:in `bar': RuntimeError:
bar problem:
can't find a bar
anywhere around here
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from ...
from reraise.rb:34:in `foo'
from reraise.rb:49
****************************************
reraise.rb:43:in `bar': bar problem: (FooError)
can't find a bar
anywhere around here from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:34:in `foo'
from reraise.rb:49
Maybe someone else will too.
The #details method outputs something like what ruby itself does when
you see an exception in stderr. However, it returns a string, and you
can control the threshold for removing informative lines with '...'.
Also, the output is formatted more nicely, IMO.
The #reraise_as method is useful when you want to catch something that's
fairly opaque, like NameError, or NoMethodErr, and, using a more
descriptive and app-specific exception class, raise it again, but with
the same backtrace.
Some example code is included.
class Exception
# More or less reproduces ruby's default exception reporting in
# the returned string, except truncation can be controlled with
# +maxlines+: +nil+ means no limit, an integer value means at
# most <tt>maxlines/2</tt> frames from each of the top and bottom
# of the stack are reported.
def details(maxlines=nil)
bt = backtrace.dup
bt0 = bt.shift
if maxlines and maxlines < bt.size
ml, r = maxlines.divmod(2)
bt = bt[0...ml+r] + ["..."] + bt[-(ml==0 ? 1 : ml)..-1]
end
[
"#{bt0}: #{self.class}:",
message,
" from " + bt.join("\n from ")
].join("\n")
end
# Raise the exception, preserving the backtrace, but with as an
# instance of class +cl+. The message is preserved by default,
# but may be set to +msg+.
def reraise_as(cl, msg = message)
e = cl.new(msg)
e.set_backtrace backtrace
raise e
end
end
class FooError < StandardError; end
def foo
bar(10)
rescue StandardError => e
puts e.details(5)
puts "*"*40
e.reraise_as(FooError)
end
def bar(try)
if try <= 0
raise " bar problem:\n can't find a bar\n anywhere around here"
else
bar(try-1)
end
end
foo
EXAMPLE OUTPUT:
reraise.rb:43:in `bar': RuntimeError:
bar problem:
can't find a bar
anywhere around here
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from ...
from reraise.rb:34:in `foo'
from reraise.rb:49
****************************************
reraise.rb:43:in `bar': bar problem: (FooError)
can't find a bar
anywhere around here from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:45:in `bar'
from reraise.rb:34:in `foo'
from reraise.rb:49