Class: Substation::Dispatcher

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

Overview

Encapsulates all registered actions and their observers

The only protocol actions must support is #call(request). Actions are intended to be classes that handle one specific application use case.

Defined Under Namespace

Classes: Action

Constant Summary collapse

UnknownActionError =

Raised when trying to dispatch to an unregistered action

Class.new(StandardError)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.coerce(config, env) ⇒ Dispatcher

Coerce the given config to a Substation::Dispatcher instance

Examples:

setup code for all the other examples


module App
  class Environment
    def initialize(storage, logger)
      @storage, @logger = storage, logger
    end
  end

  class SomeUseCase
    def self.call(request)
      data = perform_work
      request.success(data)
    end
  end

  class SomeObserver
    def self.call(response)
      # do something
    end
  end

  class AnotherObserver
    def self.call(response)
      # do something
    end
  end
end

storage = SomeStorageAbstraction.new
env     = App::Environment.new(storage, Logger.new($stdout))

without observers (short form, symbol keys)


dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => App::SomeUseCase
}, env)

dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => 'App::SomeUseCase'
}, env)

dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => :App::SomeUseCase
}, env)

dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => Proc.new { |request| request.success(:data) }
}, env)

without observers (long form, string keys)


dispatcher = Substation::Dispatcher.coerce({
  'some_use_case' => { 'action' => 'SomeUseCase' }
}, env)

with a single observer


dispatcher = Substation::Dispatcher.coerce({
  'some_use_case' => {
    'action' => 'App::SomeUseCase',
    'observer' => 'App::SomeObserver'
  }
}, env)

with multiple observers


dispatcher = Substation::Dispatcher.coerce({
  'some_use_case' => {
    'action' => 'App::SomeUseCase',
    'observer' => [
      'App::SomeObserver',
      'App::AnotherObserver'
    ]
  }
}, env)

with Symbol keys and const handlers


dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => {
    :action   => App::SomeUseCase,
    :observer => App::SomeObserver
  }
}, env)

with Symbol keys and proc handlers


dispatcher = Substation::Dispatcher.coerce({
  :some_use_case => {
    :action   => Proc.new { |request| request.success(:foo) },
    :observer => Proc.new { |response| do_something }
  }
}, env)

Parameters:

  • config (Hash<#to_sym, Object>)

    the action configuration

  • env (Object)

    the application environment

Returns:

Raises:

  • (Action::MissingHandlerError)

    if no action handler is configured

  • (ArgumentError)

    if action or observer handlers are not coercible



181
182
183
# File 'lib/substation/dispatcher.rb', line 181

def self.coerce(config, env)
  new(normalize_config(config), env)
end

Instance Method Details

#action_namesSet<Symbol>

The names of all registered actions

Examples:


module App
  class Environment
    def initialize(storage, logger)
      @storage, @logger = storage, logger
    end
  end

  class SomeUseCase
    def self.call(request)
      data = perform_work
      request.success(data)
    end
  end
end

storage    = SomeStorageAbstraction.new
env        = App::Environment.new(storage, Logger.new($stdout))
config     = { :some_use_case => { :action => App::SomeUseCase } }
dispatcher = Substation::Dispatcher.coerce(config, env)

dispatcher.action_names # => #<Set: {:some_use_case}>

Returns:

  • (Set<Symbol>)

    the set of registered action names



285
286
287
# File 'lib/substation/dispatcher.rb', line 285

def action_names
  Set.new(actions.keys)
end

#call(name, input) ⇒ Response

Invoke the action identified by name

Examples:


module App
  class Environment
    def initialize(storage, logger)
      @storage, @logger = storage, logger
    end
  end

  class SomeUseCase
    def self.call(request)
      data = perform_work
      request.success(data)
    end
  end
end

storage    = SomeStorageAbstraction.new
env        = App::Environment.new(storage, Logger.new($stdout))
config     = { :some_use_case => { :action => App::SomeUseCase } }
dispatcher = Substation::Dispatcher.coerce(config, env)

response = dispatcher.call(:some_use_case, :some_input)
response.success? # => true

Parameters:

  • name (Symbol)

    a registered action name

  • input (Object)

    the input model instance to pass to the action

Returns:

  • (Response)

    the response returned when calling the action

Raises:



251
252
253
# File 'lib/substation/dispatcher.rb', line 251

def call(name, input)
  fetch(name).call(Request.new(env, input))
end