Class: FiniteMachine::Observer

Inherits:
GenericDSL show all
Includes:
Safety
Defined in:
lib/finite_machine/observer.rb

Overview

A class responsible for observing state changes

Defined Under Namespace

Modules: Async, Once

Constant Summary

Constants included from Safety

Safety::CALLBACK_INVALID_MESSAGE, Safety::EVENT_CALLBACK_CONFLICT_MESSAGE, Safety::EVENT_CONFLICT_MESSAGE, Safety::STATE_CALLBACK_CONFLICT_MESSAGE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Safety

#detect_event_conflict!, #ensure_valid_callback_name!

Methods inherited from GenericDSL

#any_event, #any_state

Constructor Details

#initialize(machine) ⇒ Observer

Initialize an Observer

Parameters:

  • machine (StateMachine)

    reference to the current machine



30
31
32
33
34
35
# File 'lib/finite_machine/observer.rb', line 30

def initialize(machine)
  @machine = machine
  @hooks   = Hooks.new

  @machine.subscribe(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ self (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Forward the message to observer

Parameters:

  • method_name (String)
  • args (Array)

Returns:

  • (self)


248
249
250
251
252
253
254
255
# File 'lib/finite_machine/observer.rb', line 248

def method_missing(method_name, *args, &block)
  _, event_name, callback_name = *method_name.to_s.match(/^(\w*?on_\w+?)_(\w+)$/)
  if callback_name && callback_names.include?(callback_name.to_sym)
    public_send(event_name, :"#{callback_name}", *args, &block)
  else
    super
  end
end

Instance Attribute Details

#hooksObject (readonly)

The hooks to trigger around the transition lifecycle.



22
23
24
# File 'lib/finite_machine/observer.rb', line 22

def hooks
  @hooks
end

#machineObject (readonly)

The current state machine



19
20
21
# File 'lib/finite_machine/observer.rb', line 19

def machine
  @machine
end

Instance Method Details

#call(&block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Evaluate in current context



40
41
42
# File 'lib/finite_machine/observer.rb', line 40

def call(&block)
  instance_eval(&block)
end

#cancel_event(msg = nil) ⇒ Object

Cancel the current event

This should be called inside a on_before or on_exit callbacks to prevent event transition.

Parameters:

  • msg (String) (defaults to: nil)

    the message used for failure

Raises:



152
153
154
# File 'lib/finite_machine/observer.rb', line 152

def cancel_event(msg = nil)
  raise CallbackError.new(msg)
end

#emit(event, *data) ⇒ nil

Execute each of the hooks in order with supplied data

Parameters:

  • event (HookEvent)

    the hook event

  • data (Array[Object])

Returns:

  • (nil)


129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/finite_machine/observer.rb', line 129

def emit(event, *data)
  sync_exclusive do
    [event.type].each do |hook_type|
      any_state_or_event = HookEvent.any_state_or_event(hook_type)
      [any_state_or_event, event.name].each do |event_name|
        hooks[hook_type][event_name].each do |hook|
          handle_callback(hook, event, *data)
          off(hook_type, event_name, &hook) if hook.is_a?(Once)
        end
      end
    end
  end
end

#off(hook_type, name = ANY_STATE, &callback) ⇒ Object

Unregister callback for a given event



69
70
71
72
73
# File 'lib/finite_machine/observer.rb', line 69

def off(hook_type, name = ANY_STATE, &callback)
  sync_exclusive do
    hooks.unregister hook_type, name, callback
  end
end

#on(hook_type, state_or_event_name = nil, async = nil, &callback) ⇒ Object

Register callback for a given hook type

Examples:

observer.on HookEvent::Enter, :green

Parameters:

  • hook_type (HookEvent)
  • state_or_event_name (Symbol) (defaults to: nil)
  • callback (Proc)


54
55
56
57
58
59
60
61
62
63
64
# File 'lib/finite_machine/observer.rb', line 54

def on(hook_type, state_or_event_name = nil, async = nil, &callback)
  sync_exclusive do
    if state_or_event_name.nil?
      state_or_event_name = HookEvent.any_state_or_event(hook_type)
    end
    async = false if async.nil?
    ensure_valid_callback_name!(hook_type, state_or_event_name)
    callback.extend(Async) if async == :async
    hooks.register(hook_type, state_or_event_name, callback)
  end
end

#on_after(*args, &callback) ⇒ Object



107
108
109
# File 'lib/finite_machine/observer.rb', line 107

def on_after(*args, &callback)
  on HookEvent::After, *args, &callback
end

#on_before(*args, &callback) ⇒ Object



103
104
105
# File 'lib/finite_machine/observer.rb', line 103

def on_before(*args, &callback)
  on HookEvent::Before, *args, &callback
end

#on_enter(*args, &callback) ⇒ Object



79
80
81
# File 'lib/finite_machine/observer.rb', line 79

def on_enter(*args, &callback)
  on HookEvent::Enter, *args, &callback
end

#on_exit(*args, &callback) ⇒ Object



87
88
89
# File 'lib/finite_machine/observer.rb', line 87

def on_exit(*args, &callback)
  on HookEvent::Exit, *args, &callback
end

#on_transition(*args, &callback) ⇒ Object



83
84
85
# File 'lib/finite_machine/observer.rb', line 83

def on_transition(*args, &callback)
  on HookEvent::Transition, *args, &callback
end

#once_on_after(*args, &callback) ⇒ Object



115
116
117
# File 'lib/finite_machine/observer.rb', line 115

def once_on_after(*args, &callback)
  on HookEvent::After, *args, &callback.extend(Once)
end

#once_on_before(*args, &callback) ⇒ Object



111
112
113
# File 'lib/finite_machine/observer.rb', line 111

def once_on_before(*args, &callback)
  on HookEvent::Before, *args, &callback.extend(Once)
end

#once_on_enter(*args, &callback) ⇒ Object



91
92
93
# File 'lib/finite_machine/observer.rb', line 91

def once_on_enter(*args, &callback)
  on HookEvent::Enter, *args, &callback.extend(Once)
end

#once_on_exit(*args, &callback) ⇒ Object



99
100
101
# File 'lib/finite_machine/observer.rb', line 99

def once_on_exit(*args, &callback)
  on HookEvent::Exit, *args, &callback.extend(Once)
end

#once_on_transition(*args, &callback) ⇒ Object



95
96
97
# File 'lib/finite_machine/observer.rb', line 95

def once_on_transition(*args, &callback)
  on HookEvent::Transition, *args, &callback.extend(Once)
end