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