try_to

Build Status Gem Version

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.

Usage

Instead of using Rails' Object#try like this,

obj1.try(:met1).try(:met2).try(:met3).to_s

you can do this:

try_to { obj.met1.met2.met3.to_s }

Exceptions

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 NoMethodErrors.

TryTo.exceptions
#=> [NoMethodError, RuntimeError, ZeroDivisionError]
TryTo.reset_exceptions!
#=> [NoMethodError]

Handlers

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.

Specifying a handler with the call for one time use:

# use a handler function
try_to(-> e { puts e.class }) { 1.foo }
# prints "NoMethodError"
# or provide a simple value:
try_to(42) { 1.foo }
#=> 42

Registering handlers so they always are used:

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

Removing handler:

TryTo.handlers
#=> {ZeroDivisionError=>#<Proc:0x0000000108921d60@(irb):1 (lambda)>}
TryTo.remove_handler!(ZeroDivisionError)
#=> {}

Last but not least you can define a default handler for all the exceptions listed in TryTo.exceptions.

TryTo.default_handler = 42
try_to { 1.foo } #=> 42
# or
TryTo.default_handler = lambda { |_| 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
class Foo ; end
try_to { Foo.new.foo } #=> nil

# this will raise an exception
try_to { 1 / 0 }
ZeroDivisionError: divided by 0
# let's fix that
TryTo.exceptions << 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 "ZeroDivisionError"

# 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!"

Installation

Add this line to your application's Gemfile:

gem 'try_to'

And then execute:

$ bundle

Or install it yourself:

$ gem install try_to

Authors

Michael Kohl. There's some leftover code (primarily in the specs) from sevenmaxis/tryit by Sergey Gopkalo.

License

Licensed under the MIT license. See the provided LICENSE file for details.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request