Try
Rescues a block from an exception. The Try
monad is useful when you want to wrap some code that can raise exceptions of certain types. A common example is making an HTTP request or querying a database.
require 'dry-monads'
module ExceptionalLand
extend Dry::Monads::Try::Mixin
res = Try() { 10 / 2 }
res.value! if res.value?
# => 5
res = Try() { 10 / 0 }
res.exception if res.error?
# => #<ZeroDivisionError: divided by 0>
# By default Try catches all exceptions inherited from StandardError.
# However you can catch only certain exceptions like this
Try(NoMethodError, NotImplementedError) { 10 / 0 }
# => raised ZeroDivisionError: divided by 0 exception
end
It is better if you pass a list of expected exceptions which you are sure you can process. Catching exceptions of all types is considered bad practice.
The Try
monad consists of two types: Value
and Error
. The first is returned when code did not raise an error and the second is returned when the error was captured.
bind
Works exactly the same way as Result#bind
does.
require 'dry-monads'
module ExceptionalLand
extend Dry::Monads::Try::Mixin
Try() { 10 / 2 }.bind { |x| x * 3 }
# => 15
Try(ZeroDivisionError) { 10 / 0 }.bind { |x| x * 3 }
# => Failure(ZeroDivisionError: divided by 0)
end
fmap
Allows you to chain blocks that can raise exceptions.
Try(NetworkError, DBError) { grap_user_by_making_request }.fmap { |user| user_repo.save(user) }
# Possible outcomes:
# => Value(persisted_user)
# => Error(NetworkError: request timeout)
# => Error(DBError: unique constraint violated)
value!
and exception
Use value!
for unwrapping a Success
and exception
for getting error object from a Failure
.
to_result
and to_maybe
Try
's Value
and Error
can be transformed to Success
and Failure
correspondingly by calling to_result
and to Some
and None
by calling to_maybe
. Keep in mind that by transforming Try
to Maybe
you lose the information about an exception so be sure that you've processed the error before doing so.