Interactors in Hanami 2.1

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)
4 Likes