lib/emittance/dispatcher.rb in emittance-1.1.0 vs lib/emittance/dispatcher.rb in emittance-2.0.0.pre.1
- old
+ new
@@ -1,31 +1,86 @@
# frozen_string_literal: true
require 'set'
require 'emittance/dispatcher/registration_map'
+require 'emittance/dispatcher/topic_registration_map'
module Emittance
##
- # Abstract class for dispatchers. Subclasses must implement the following methods:
+ # Abstract class for dispatchers. Subclasses must implement the following class methods:
#
# - +._process_event+
# - +._register+
# - +._register_method_call+
#
# These methods can be private. These methods will have access to +.registrations_for+, which takes an identifier
# and returns an enumerable object with each object registered to that identifier. These objects can be anything
# you want, but typically represent the callback you would like to run whenever an event of a certain type is
# emitted.
#
+ # == Example
+ #
+ # Suppose we have a simple dispatcher. We're not going to worry about method calls, so we're just going to focus on
+ # implementing +._register+ and +._process_event+.
+ #
+ # class SimpleDispatcher < Emittance::Dispatcher
+ # class << self
+ # private
+ #
+ # # +._register+ takes the original identifier/topic, an optional params hash, and a block. To register the
+ # # callback, push it on to the collection returned by the +.registrations_for+ method. You can format the
+ # # callback in any way you like.
+ # def _register(identifier, _params = {}, &callback)
+ # registrations_for(event) << format_callback(callback)
+ # callback
+ # end
+ #
+ # # +._process_event+ is simple -- we just need to fetch the registrations related to the event, and process
+ # # them. The registrations are returned in the exact same format as they were stored in +._register+. So, in
+ # # this case, we will get a set of +CallbackWrapper+ objects, each of which responds to +#call+.
+ # #
+ # # IMPORTANT: You also need to make sure that the +down+ middleware stack is called in the process.
+ # def _process_event(event)
+ # event = Emittance::Middleware.down(event)
+ # registrations_for(event).each { |registration| registration.call(event) }
+ # end
+ #
+ # def format_callback(callback)
+ # CallbackWrapper.new(callback)
+ # end
+ # end
+ # end
+ #
class Dispatcher
+ ROUTING_STRATEGIES = {
+ classical: RegistrationMap,
+ topical: TopicRegistrationMap
+ }.freeze
+
+ @routing_strategy = RegistrationMap
+
class << self
- # @private
- def inherited(subklass)
- subklass.instance_variable_set '@registrations', RegistrationMap.new
+ def routing_strategy
+ @routing_strategy || ::Emittance::Dispatcher.instance_variable_get('@routing_strategy')
end
+ alias registration_router_klass routing_strategy
+
+ def routing_strategy=(new_strategy_name)
+ new_strategy =
+ if new_strategy_name.is_a?(Module)
+ new_strategy_name
+ else
+ ROUTING_STRATEGIES[new_strategy_name.to_sym]
+ end
+
+ raise ArgumentError, 'Could not find a routing strategy with that name' unless new_strategy
+
+ @routing_strategy = new_strategy
+ end
+
# Calls the subclass's +_process_event+ method.
def process_event(event)
_process_event(event)
end
@@ -45,11 +100,11 @@
registrations[identifier]
end
# @return [RegistrationMap] the registrations
def clear_registrations!
- registrations.each_key { |key| clear_registrations_for! key }
+ registrations.clear
registrations
end
# @param identifier the identifier the registrations for hwich you would like to clear
# @return [RegistrationCollectionProxy] the cleared registration proxy
@@ -57,10 +112,12 @@
registrations_for(identifier).clear
end
private
- attr_reader :registrations
+ def registrations
+ @registrations ||= registration_router_klass.new
+ end
def _process_event(_event)
raise NotImplementedError
end