Class: Substation::Chain

Inherits:
Object
  • Object
show all
Includes:
Adamantium::Flat, Outgoing
Defined in:
lib/substation/chain.rb

Overview

Implements a chain of responsibility for an action

An instance of this class will typically contain (in that order) a few handlers that process the incoming Request object, one handler that calls an action (Pivot), and some handlers that process the outgoing Response object.

Both Incoming and Outgoing handlers must respond to ‘#call(response)` and `#result(response)`.

Examples:

chain handlers (used in instance method examples)


module App

  class Handler

    def initialize(handler = nil)
      @handler = handler
    end

    protected

    attr_reader :handler

    class Incoming < self
      include Substation::Chain::Incoming
    end

    class Outgoing < self
      include Substation::Chain::Outgoing

      private

      def respond_with(response, output)
        response.class.new(response.request, output)
      end
    end
  end

  class Validator < Handler::Incoming
    def call(request)
      result = handler.call(request.input)
      if result.valid?
        request.success(request.input)
      else
        request.error(result.violations)
      end
    end
  end

  class Pivot < Handler
    include Substation::Chain::Pivot

    def call(request)
      handler.call(request)
    end
  end

  class Presenter < Handler::Outgoing
    def call(response)
      respond_with(response, handler.new(response.output))
    end
  end
end

Defined Under Namespace

Modules: Incoming, Outgoing

Constant Summary collapse

Pivot =

Supports chaining the Pivot handler

Outgoing

Instance Method Summary collapse

Methods included from Outgoing

#result

Instance Method Details

#call(request) ⇒ Response::Success, Response::Failure

Call the chain

Invokes all handlers and returns either the first Response::Failure that it encounters, or if all goes well, the Response::Success returned from the last handler.

Examples:


module App
  SOME_ACTION = Substation::Chain.new [
    Validator.new(MY_VALIDATOR),
    Pivot.new(Actions::SOME_ACTION),
    Presenter.new(Presenters::SomePresenter)
  ]

  env     = Object.new # your env would obviously differ
  input   = { 'name' => 'John' }
  request = Substation::Request.new(env, input)

  response = SOME_ACTION.call(request)

  if response.success?
    response.output # => the output wrapped in a presenter
  else
    response.output # => if validation, pivot or presenter failed
  end
end

Parameters:

  • request (Request)

    the request to handle

Returns:

Raises:

  • (Exception)

    any exception that isn’t explicitly rescued in client code



155
156
157
158
159
160
161
# File 'lib/substation/chain.rb', line 155

def call(request)
  handlers.inject(request) { |result, handler|
    response = handler.call(result)
    return response unless response.success?
    handler.result(response)
  }
end