Here’s a helper method I make extensive use of: it’s called either
and its purpose is to facilitate wrapping error results in tuples.
My Failure results always take the form of Failure[:error_name, *args]
unless I am wrapping an exception. This makes pattern-matching errors from the outside much easier.
# Utility helper to avoid .to_monad.or {} chaining
#
# @param [#to_monad] result, Dry::Monads::Result or object that responds to `to_monad`
# @param [Dry::Monads::Result::Failure, #to_proc, { :error => Symbol }] error
#
# @example With Yield
# user = yield fetch_user.(id).or { |err| Failure[:not_found, err] }
#
# @example With Either
# user = either fetch_user.(id), Failure(:not_found)
# user = either fetch_user.(id), ->(err) { Failure[:not_found, err] }
# user = either fetch_user.(ud), error: :not_found
#
# @raise [Dry::Monads::Do::Halt]
#
# @return the unwrapped successful value
def either(result, error)
failure =
case error
in { error: error_name }
proc { |err| Failure[error_name, err] }
in T::Procable
error
else
proc { error }
end
Dry::Monads::Do.bind result.to_monad.or(&failure)
end
T::Procable
is just a type defined as
Procable = Interface(:to_proc)