Flexible error handling
This project started with a StackOverflow discussion between Sergey Gopkalo and Michael Kohl,
which eventually lead to a prototype at sevenmaxis/tryit.
try_to
is an improved version based on the experience gained from that project,
but allows for much more sophisticated error handling.
Instead of using Rails’ Object#try
like this,
obj.try(:met1).try(:met2).try(:met3).to_s
you can do this:
try_to { obj.met1.met2.met3.to_s }
It’s possible to customize which exceptions to handle with add_exception
:
TryTo.add_exception(ZeroDivisionError)
#=> [NoMethodError, ZeroDivisionError]
try_to { 1/0 } # will not raise an exception
To remove an exception, use remove_exception!
:
TryTo.exceptions
#=> [NoMethodError, ZeroDivisionError]
TryTo.remove_exception!(ZeroDivisionError)
#=> [NoMethodError]
You can also use reset_exceptions!
to go back to only handle NoMethodError
s.
TryTo.exceptions
#=> [NoMethodError, RuntimeError, ZeroDivisionError]
TryTo.reset_exceptions!
#=> [NoMethodError]
The default error handling strategy is to just return nil
, but there are various
ways in which you can customize this behavior. All handlers can either be simple
values or an object responding to #call
, which should take one argument, the
exception object.
try_to(-> e { puts e.class }) { 1.foo }
# prints "NoMethodError"
# or provide a simple value:
try_to(42) { 1.foo }
#=> 42
TryTo.handlers
#=> {}
TryTo.add_handler(ZeroDivisionError, -> _ { puts "Ouch" })
try_to { 1/0 }
# prints "Ouch"
TryTo.add_handler(NoMethodError, -> _ { 23 })
try_to { 1.foo }
#=> 23
# or simply
TryTo.add_handler(NoMethodError, 42)
try_to { 1.foo } #=> 42
TryTo.handlers
#=> {ZeroDivisionError=>#<Proc:0x0000000108921d60@(irb):1 (lambda)>}
TryTo.remove_handler!(ZeroDivisionError)
#=> {}
This will be called for all the exceptions listed in TryTo.exceptions
.
TryTo.default_handler = 42
try_to { 1.foo } #=> 42
# or
TryTo.default_handler = -> _e { puts "Something went wrong!" }
try_to { 1.foo }
# Outputs: Something went wrong!
Here’s a complete example in the form of an IRB transcript:
# default behavior
try_to #=> nil
try_to {} #=> nil
Foo = Class.new
try_to { Foo.new.foo } #=> nil (instead of NoMethodError)
# this will raise an exception
try_to { 1 / 0 }
ZeroDivisionError: divided by 0
# let's fix that
TryTo.add_exception(ZeroDivisionError) #=> [NoMethodError, ZeroDivisionError]
try_to { 1 / 0 } #=> nil
# change the default handler
TryTo.default_handler = -> e { puts e.class }
try_to { 1 / 0 } # prints "ZeroDivisionError"
try_to { Foo.new.foo } # prints "NoMethodError"
# new behavior for ZeroDivisionError
TryTo.add_handler(ZeroDivisionError, -> _ { puts "You shouldn't divide by 0!"})
try_to { 1 / 0 } # prints: "You shouldn't divide by 0!"
try_to { Foo.new.foo} # still prints "NoMethodError"
# change handler at call site
try_to(-> _ {puts "Ouch!"}) { Foo.new.foo } # prints "Ouch!"
Add this line to your application’s Gemfile:
gem 'try_to'
And then execute:
$ bundle
Or install it yourself:
$ gem install try_to
Michael Kohl. There’s some leftover code (primarily in the specs) from sevenmaxis/tryit by Sergey Gopkalo.
Licensed under the MIT license. See the provided LICENSE file for details.
git checkout -b my-new-feature
)git commit -am 'Added some feature'
)git push origin my-new-feature
)