Class: Substation::Chain

Inherits:
Object
  • Object
show all
Includes:
Adamantium::Flat
Defined in:
lib/substation/chain.rb,
lib/substation/chain/dsl.rb,
lib/substation/chain/definition.rb,
lib/substation/chain/dsl/config.rb,
lib/substation/chain/dsl/module_builder.rb

Overview

Implements a chain of responsibility for an action

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

Examples:

chain processors (used in instance method examples)


module App

  class Processor

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

    protected

    attr_reader :handler

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

    class Outgoing < self
      include Substation::Processor::Outgoing

      private

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

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

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

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

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

Defined Under Namespace

Classes: DSL, Definition

Constant Summary collapse

EMPTY =

Empty chain

new(Definition::EMPTY, EMPTY_ARRAY)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.exception_response(state, data, exception) ⇒ Response::Exception

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return an exception response

Parameters:

  • state (Request, Response)

    the initial state passed into the chain

  • data (Object)

    the processed data available when the exception was raised

  • exception (Class<StandardError>)

    the exception instance that was raised

Returns:



90
91
92
93
# File 'lib/substation/chain.rb', line 90

def self.exception_response(state, data, exception)
  output = Response::Exception::Output.new(data, exception)
  Response::Exception.new(state.to_request(data), output)
end

Instance Method Details

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

Call the chain

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

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:



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/substation/chain.rb', line 137

def call(request)
  reduce(request) { |result, processor|
    begin
      response = processor.call(result)
      return response unless processor.success?(response)
      processor.result(response)
    rescue => exception
      return on_exception(request, result.data, exception)
    end
  }
end