Justified - add missing causes to exceptions
I've just published a new gem called justified
which is adding missing causes to Ruby exceptions.
When an exception is risen because of another one it is stored in the new one, and backtrace is appended with following:
from caused by: (AnError) an ugly bug
from justified.rb:83:in `bad_code'
from ... skipped 4 lines
Example
Let's have following snippet:
class AnError < StadardError; end
def bad_code
raise AnError, 'an ugly bug'
end
def handle_error(error)
raise AnError, 'something went wrong'
end
def do_something
bad_code
rescue => error
handle_error error
end
do_something
When called it will produce:
justified.rb:93:in `handle_error': something went wrong (AnError)
from justified.rb:89:in `rescue in do_something'
from justified.rb:87:in `do_something'
from justified.rb:96:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
The real problem an ugly bug
is hidden. What will happen when justified
is used?
require 'justified/stadard_error'
# ... rest of the snipper
It will produce:
justified.rb:93:in `handle_error': something went wrong (AnError)
from justified.rb:89:in `rescue in do_something'
from justified.rb:87:in `do_something'
from justified.rb:96:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
from caused by: (AnError) an ugly bug
from justified.rb:83:in `bad_code'
from ... skipped 4 lines
Of course causes can be concatenated.
Usage
-
require 'justified'
to includeJustified::Error
to any exception you need manually -
require 'justified/standard_error'
to have causes in all exceptions which are kind ofStandardError
Behavior
When an exception is risen inside rescue block a cause is automatically recorded.
e = begin
raise 'bug'
rescue => error
raise 'this does not work'
end rescue $!
e.cause.message == 'bug' # => true
Cause can be set explicitly.
e = begin
raise 'bug'
rescue => error
raise StandardError.new('this does not work', error)
end rescue $!
e.cause.message == 'bug' # => true
Or if signature of .new
is changed cause can be set with a setter #cause=
class InspectingError < StandardError
def initialize(object)
super object.inspect
end
end
e = begin
raise 'bug'
rescue => error
raise InspectingError.new(a: 'b').tap { |e| e.cause = error }
end rescue $!
e.cause.message == 'bug' # => true
and
e = begin
raise 'bug'
rescue => error
raise InspectingError.new(a: 'b')
end rescue $!
e.cause.message == 'bug' # => true
will work as well.
Do you wish to know more?
- Documentation: http://blog.pitr.ch/justified
- Source: https://github.com/pitr-ch/justified
- Blog: http://blog.pitr.ch/blog/categories/justified/