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

- old
+ new

@@ -26,11 +26,11 @@ # @api private def call(&block) instance_eval(&block) end - # Register callback for a given event. + # Register callback for a given event # # @param [Symbol] event_type # @param [Symbol] name # @param [Proc] callback # @@ -40,10 +40,21 @@ ensure_valid_callback_name!(name) hooks.register event_type, name, callback end end + # Unregister callback for a given event + # + # @api public + def off(event_type = ANY_EVENT, name = ANY_STATE, &callback) + sync_exclusive do + hooks.unregister event_type, name, callback + end + end + + module Once; end + def listen_on(type, *args, &callback) name = args.first events = [] if machine.states.include?(name) || name == ANY_STATE_HOOK events << :"#{type}state" @@ -65,24 +76,22 @@ def on_exit(*args, &callback) 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) - send(event_name, callback_name.to_sym, *args, &block) - else - super - end + def once_on_enter(*args, &callback) + listen_on :enter, *args, &callback.extend(Once) end - def respond_to_missing?(method_name, include_private = false) - _, callback_name = *method_name.to_s.match(/^(on_\w+?)_(\w+)$/) - callback_names.include?(callback_name.to_sym) + def once_on_transition(*args, &callback) + listen_on :transition, *args, &callback.extend(Once) end + def once_on_exit(*args, &callback) + listen_on :exit, *args, &callback.extend(Once) + end + TransitionEvent = Struct.new(:from, :to, :name) do def build(_transition) self.from = _transition.from_state self.to = _transition.to self.name = _transition.name @@ -104,10 +113,11 @@ [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) + off(event_type, event_state, &hook) if hook.is_a?(Once) end end end end end @@ -127,9 +137,41 @@ 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 + + # Forward the message to observer + # + # @param [String] method_name + # + # @param [Array] args + # + # @return [self] + # + # @api private + def method_missing(method_name, *args, &block) + _, event_name, callback_name = *method_name.to_s.match(/^(\w*?on_\w+?)_(\w+)$/) + if callback_names.include?(callback_name.to_sym) + public_send(event_name, :"#{callback_name}", *args, &block) + else + super + end + end + + # Test if a message can be handled by observer + # + # @param [String] method_name + # + # @param [Boolean] include_private + # + # @return [Boolean] + # + # @api private + def respond_to_missing?(method_name, include_private = false) + *_, callback_name = *method_name.to_s.match(/^(\w*?on_\w+?)_(\w+)$/) + callback_names.include?(:"#{callback_name}") end end # Observer end # FiniteMachine