lib/finite_machine/observer.rb in finite_machine-0.1.0 vs lib/finite_machine/observer.rb in finite_machine-0.2.0

- old
+ new

@@ -16,16 +16,11 @@ # # @api public def initialize(machine) @machine = machine @machine.subscribe(self) - - @hooks = Hash.new { |events_hash, event_type| - events_hash[event_type] = Hash.new { |state_hash, name| - state_hash[name] = [] - } - } + @hooks = FiniteMachine::Hooks.new(machine) end # Evaluate in current context # # @api private @@ -39,45 +34,39 @@ # @param [Symbol] name # @param [Proc] callback # # @api public def on(event_type = ANY_EVENT, name = ANY_STATE, &callback) - ensure_valid_callback_name!(name) - hooks[event_type][name] << callback + sync_exclusive do + ensure_valid_callback_name!(name) + hooks.register event_type, name, callback + end end - def on_enter(*args, &callback) - if machine.states.any? { |state| state == args.first } - on :enterstate, *args, &callback - elsif machine.event_names.any? { |name| name == args.first } - on :enteraction, *args, &callback + def listen_on(type, *args, &callback) + name = args.first + events = [] + if machine.states.include?(name) || name == ANY_STATE_HOOK + events << :"#{type}state" + elsif machine.event_names.include?(name) || name == ANY_EVENT_HOOK + events << :"#{type}action" else - on :enterstate, *args, &callback - on :enteraction, *args, &callback + events << :"#{type}state" << :"#{type}action" end + events.each { |event| on event, *args, &callback } end + def on_enter(*args, &callback) + listen_on :enter, *args, &callback + end + def on_transition(*args, &callback) - if machine.states.any? { |state| state == args.first } - on :transitionstate, *args, &callback - elsif machine.event_names.any? { |name| name == args.first } - on :transitionaction, *args, &callback - else - on :transitionstate, *args, &callback - on :transitionaction, *args, &callback - end + listen_on :transition, *args, &callback end def on_exit(*args, &callback) - if machine.states.any? { |state| state == args.first } - on :exitstate, *args, &callback - elsif machine.event_names.any? { |name| name == args.first } - on :exitaction, *args, &callback - else - on :exitstate, *args, &callback - on :exitaction, *args, &callback - end + listen_on :exit, *args, &callback end def method_missing(method_name, *args, &block) _, event_name, callback_name = *method_name.to_s.match(/^(on_\w+?)_(\w+)$/) if callback_names.include?(callback_name.to_sym) @@ -92,27 +81,34 @@ callback_names.include?(callback_name.to_sym) end TransitionEvent = Struct.new(:from, :to, :name) do def build(_transition) - self.from = _transition.from.first + self.from = _transition.from_state self.to = _transition.to self.name = _transition.name end end def run_callback(hook, event) trans_event = TransitionEvent.new trans_event.build(event.transition) - hook.call(trans_event, *event.data) + data = event.data + deferred_hook = proc { |_trans_event, *_data| + machine.instance_exec(_trans_event, *_data, &hook) + } + deferred_hook.call(trans_event, *data) end - def trigger(event) - [event.type, ANY_EVENT].each do |event_type| - [event.state, ANY_STATE].each do |event_state| - hooks[event_type][event_state].each do |hook| - run_callback hook, event + def trigger(event, *args, &block) + sync_exclusive do + [event.type, ANY_EVENT].each do |event_type| + [event.state, ANY_STATE, + ANY_STATE_HOOK, ANY_EVENT_HOOK].each do |event_state| + hooks.call(event_type, event_state, event) do |hook| + run_callback(hook, event) + end end end end end @@ -121,15 +117,18 @@ def callback_names @callback_names = Set.new @callback_names.merge machine.event_names @callback_names.merge machine.states @callback_names.merge [ANY_STATE, ANY_EVENT] + @callback_names.merge [ANY_STATE_HOOK, ANY_EVENT_HOOK] end def ensure_valid_callback_name!(name) unless callback_names.include?(name) - raise InvalidCallbackNameError, "#{name} is not a valid callback name." + - " Valid callback names are #{callback_names.to_a.inspect}" + exception = InvalidCallbackNameError + machine.catch_error(exception) || + raise(InvalidCallbackNameError, "#{name} is not a valid callback name." + + " Valid callback names are #{callback_names.to_a.inspect}") end end end # Observer end # FiniteMachine