finite_machine 0.11.3 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +34 -0
- data/README.md +564 -569
- data/Rakefile +5 -1
- data/benchmarks/memory_profile.rb +11 -0
- data/benchmarks/memory_usage.rb +16 -9
- data/finite_machine.gemspec +10 -3
- data/lib/finite_machine.rb +34 -46
- data/lib/finite_machine/async_call.rb +5 -21
- data/lib/finite_machine/callable.rb +4 -4
- data/lib/finite_machine/catchable.rb +4 -2
- data/lib/finite_machine/choice_merger.rb +19 -19
- data/lib/finite_machine/const.rb +16 -0
- data/lib/finite_machine/definition.rb +2 -2
- data/lib/finite_machine/dsl.rb +66 -149
- data/lib/finite_machine/env.rb +4 -2
- data/lib/finite_machine/event_definition.rb +7 -15
- data/lib/finite_machine/{events_chain.rb → events_map.rb} +39 -51
- data/lib/finite_machine/hook_event.rb +60 -61
- data/lib/finite_machine/hooks.rb +44 -36
- data/lib/finite_machine/listener.rb +2 -2
- data/lib/finite_machine/logger.rb +5 -4
- data/lib/finite_machine/message_queue.rb +39 -30
- data/lib/finite_machine/observer.rb +55 -37
- data/lib/finite_machine/safety.rb +12 -10
- data/lib/finite_machine/state_definition.rb +3 -5
- data/lib/finite_machine/state_machine.rb +83 -64
- data/lib/finite_machine/state_parser.rb +51 -79
- data/lib/finite_machine/subscribers.rb +1 -1
- data/lib/finite_machine/threadable.rb +3 -1
- data/lib/finite_machine/transition.rb +30 -31
- data/lib/finite_machine/transition_builder.rb +23 -32
- data/lib/finite_machine/transition_event.rb +12 -11
- data/lib/finite_machine/two_phase_lock.rb +3 -1
- data/lib/finite_machine/undefined_transition.rb +5 -6
- data/lib/finite_machine/version.rb +2 -2
- data/spec/integration/system_spec.rb +36 -38
- data/spec/performance/benchmark_spec.rb +13 -21
- data/spec/unit/alias_target_spec.rb +22 -41
- data/spec/unit/async_callbacks_spec.rb +8 -13
- data/spec/unit/auto_methods_spec.rb +44 -0
- data/spec/unit/callable/call_spec.rb +1 -3
- data/spec/unit/callbacks_spec.rb +372 -463
- data/spec/unit/can_spec.rb +13 -23
- data/spec/unit/cancel_callbacks_spec.rb +46 -0
- data/spec/unit/choice_spec.rb +105 -141
- data/spec/unit/define_spec.rb +31 -31
- data/spec/unit/definition_spec.rb +24 -41
- data/spec/unit/event_names_spec.rb +6 -10
- data/spec/unit/events_map/add_spec.rb +23 -0
- data/spec/unit/events_map/choice_transition_spec.rb +25 -0
- data/spec/unit/events_map/clear_spec.rb +13 -0
- data/spec/unit/events_map/events_spec.rb +16 -0
- data/spec/unit/events_map/inspect_spec.rb +22 -0
- data/spec/unit/{events_chain → events_map}/match_transition_spec.rb +12 -14
- data/spec/unit/{events_chain → events_map}/move_to_spec.rb +14 -17
- data/spec/unit/events_map/states_for_spec.rb +17 -0
- data/spec/unit/events_spec.rb +91 -160
- data/spec/unit/handlers_spec.rb +34 -66
- data/spec/unit/hook_event/any_state_or_event_spec.rb +13 -0
- data/spec/unit/hook_event/build_spec.rb +1 -3
- data/spec/unit/hook_event/eql_spec.rb +1 -3
- data/spec/unit/hook_event/initialize_spec.rb +2 -4
- data/spec/unit/hook_event/notify_spec.rb +2 -4
- data/spec/unit/hooks/clear_spec.rb +1 -1
- data/spec/unit/hooks/{call_spec.rb → find_spec.rb} +4 -9
- data/spec/unit/hooks/inspect_spec.rb +16 -8
- data/spec/unit/hooks/register_spec.rb +4 -9
- data/spec/unit/if_unless_spec.rb +76 -115
- data/spec/unit/initial_spec.rb +50 -82
- data/spec/unit/inspect_spec.rb +14 -9
- data/spec/unit/is_spec.rb +12 -18
- data/spec/unit/log_transitions_spec.rb +4 -10
- data/spec/unit/logger_spec.rb +1 -3
- data/spec/unit/{event_queue_spec.rb → message_queue_spec.rb} +15 -8
- data/spec/unit/new_spec.rb +50 -0
- data/spec/unit/respond_to_spec.rb +2 -6
- data/spec/unit/state_parser/parse_spec.rb +9 -12
- data/spec/unit/states_spec.rb +12 -18
- data/spec/unit/subscribers_spec.rb +1 -3
- data/spec/unit/target_spec.rb +60 -93
- data/spec/unit/terminated_spec.rb +15 -25
- data/spec/unit/transition/check_conditions_spec.rb +16 -15
- data/spec/unit/transition/inspect_spec.rb +6 -6
- data/spec/unit/transition/matches_spec.rb +5 -7
- data/spec/unit/transition/states_spec.rb +5 -7
- data/spec/unit/transition/to_state_spec.rb +5 -13
- data/spec/unit/trigger_spec.rb +5 -9
- data/spec/unit/undefined_transition/eql_spec.rb +1 -3
- metadata +86 -49
- data/.gitignore +0 -18
- data/.rspec +0 -5
- data/.travis.yml +0 -27
- data/Gemfile +0 -16
- data/assets/finite_machine_logo.png +0 -0
- data/lib/finite_machine/async_proxy.rb +0 -55
- data/spec/unit/async_events_spec.rb +0 -107
- data/spec/unit/events_chain/add_spec.rb +0 -25
- data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
- data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
- data/spec/unit/events_chain/clear_spec.rb +0 -15
- data/spec/unit/events_chain/events_spec.rb +0 -18
- data/spec/unit/events_chain/inspect_spec.rb +0 -24
- data/spec/unit/events_chain/states_for_spec.rb +0 -17
- data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
- data/spec/unit/state_parser/inspect_spec.rb +0 -25
data/lib/finite_machine/hooks.rb
CHANGED
@@ -1,92 +1,93 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent/map'
|
4
|
+
|
5
|
+
require_relative 'hook_event'
|
2
6
|
|
3
7
|
module FiniteMachine
|
4
8
|
# A class reponsible for registering callbacks
|
5
9
|
class Hooks
|
6
|
-
|
7
|
-
|
8
|
-
attr_threadsafe :collection
|
10
|
+
attr_reader :hooks_map
|
9
11
|
|
10
|
-
# Initialize a
|
12
|
+
# Initialize a hooks_map of hooks
|
11
13
|
#
|
12
14
|
# @example
|
13
15
|
# Hoosk.new(machine)
|
14
16
|
#
|
15
17
|
# @api public
|
16
18
|
def initialize
|
17
|
-
@
|
18
|
-
events_hash[
|
19
|
+
@hooks_map = Concurrent::Map.new do |events_hash, hook_event|
|
20
|
+
events_hash[hook_event] = Concurrent::Map.new do |state_hash, name|
|
19
21
|
state_hash[name] = []
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
#
|
26
|
+
# Finds all hooks for the event type
|
25
27
|
#
|
26
|
-
# @param [
|
27
|
-
# @param [String] name
|
28
|
-
# @param [Proc] callback
|
28
|
+
# @param [Symbol] name
|
29
29
|
#
|
30
30
|
# @example
|
31
|
-
# hooks
|
31
|
+
# hooks[HookEvent::Enter][:go] # => [-> { }]
|
32
32
|
#
|
33
|
-
# @
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# @return [Hash]
|
33
|
+
# @return [Array[Transition]]
|
34
|
+
# the transitions matching event name
|
37
35
|
#
|
38
36
|
# @api public
|
39
|
-
def
|
40
|
-
|
37
|
+
def find(name)
|
38
|
+
@hooks_map[name]
|
41
39
|
end
|
40
|
+
alias [] find
|
42
41
|
|
43
|
-
#
|
42
|
+
# Register callback
|
44
43
|
#
|
45
|
-
# @param [String]
|
44
|
+
# @param [String] hook_event
|
46
45
|
# @param [String] name
|
47
46
|
# @param [Proc] callback
|
48
47
|
#
|
49
48
|
# @example
|
50
|
-
# hooks.
|
49
|
+
# hooks.register HookEvent::Enter, :green do ... end
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# hooks.register HookEvent::Before, any_state do ... end
|
51
53
|
#
|
52
54
|
# @return [Hash]
|
53
55
|
#
|
54
56
|
# @api public
|
55
|
-
def
|
56
|
-
|
57
|
-
callbacks.delete(callback)
|
57
|
+
def register(hook_event, name, callback)
|
58
|
+
@hooks_map[hook_event][name] << callback
|
58
59
|
end
|
59
60
|
|
60
|
-
#
|
61
|
+
# Unregister callback
|
61
62
|
#
|
62
|
-
# @param [String]
|
63
|
-
# @param [String]
|
64
|
-
# @param [
|
63
|
+
# @param [String] hook_event
|
64
|
+
# @param [String] name
|
65
|
+
# @param [Proc] callback
|
65
66
|
#
|
66
67
|
# @example
|
67
|
-
# hooks.
|
68
|
+
# hooks.unregister HookEvent::Enter, :green do ... end
|
68
69
|
#
|
69
70
|
# @return [Hash]
|
70
71
|
#
|
71
72
|
# @api public
|
72
|
-
def
|
73
|
-
|
73
|
+
def unregister(hook_event, name, callback)
|
74
|
+
@hooks_map[hook_event][name].delete(callback)
|
74
75
|
end
|
75
76
|
|
76
|
-
# Check if
|
77
|
+
# Check if hooks_map has any elements
|
77
78
|
#
|
78
79
|
# @return [Boolean]
|
79
80
|
#
|
80
81
|
# @api public
|
81
82
|
def empty?
|
82
|
-
|
83
|
+
@hooks_map.empty?
|
83
84
|
end
|
84
85
|
|
85
86
|
# Remove all callbacks
|
86
87
|
#
|
87
88
|
# @api public
|
88
89
|
def clear
|
89
|
-
|
90
|
+
@hooks_map.clear
|
90
91
|
end
|
91
92
|
|
92
93
|
# String representation
|
@@ -95,7 +96,14 @@ module FiniteMachine
|
|
95
96
|
#
|
96
97
|
# @api public
|
97
98
|
def to_s
|
98
|
-
|
99
|
+
hash = {}
|
100
|
+
@hooks_map.each_pair do |hook_event, nested_hash|
|
101
|
+
hash[hook_event] = {}
|
102
|
+
nested_hash.each_pair do |name, callbacks|
|
103
|
+
hash[hook_event][name] = callbacks
|
104
|
+
end
|
105
|
+
end
|
106
|
+
hash.to_s
|
99
107
|
end
|
100
108
|
|
101
109
|
# String representation
|
@@ -104,7 +112,7 @@ module FiniteMachine
|
|
104
112
|
#
|
105
113
|
# @api public
|
106
114
|
def inspect
|
107
|
-
"<##{self.class}:0x#{object_id.to_s(16)} @
|
115
|
+
"<##{self.class}:0x#{object_id.to_s(16)} @hooks_map=#{self}>"
|
108
116
|
end
|
109
117
|
end # Hooks
|
110
118
|
end # FiniteMachine
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module FiniteMachine
|
4
4
|
# A generic listener interface
|
@@ -24,6 +24,6 @@ module FiniteMachine
|
|
24
24
|
def call(*args)
|
25
25
|
@on_delivery.call(*args) if @on_delivery
|
26
26
|
end
|
27
|
-
|
27
|
+
alias handle_delivery call
|
28
28
|
end # Listener
|
29
29
|
end # FiniteMachine
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module FiniteMachine
|
4
4
|
module Logger
|
@@ -21,21 +21,22 @@ module FiniteMachine
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def format_error(error)
|
24
|
-
message = "#{error.class}: #{error.message}\n\t"
|
24
|
+
message = ["#{error.class}: #{error.message}\n\t"]
|
25
25
|
if error.backtrace
|
26
26
|
message << "occured at #{error.backtrace.join("\n\t")}"
|
27
27
|
else
|
28
28
|
message << "EMPTY BACKTRACE\n\t"
|
29
29
|
end
|
30
|
+
message.join
|
30
31
|
end
|
31
32
|
|
32
33
|
def report_transition(name, from, to, *args)
|
33
|
-
message = "Transition: @event=#{name} "
|
34
|
+
message = ["Transition: @event=#{name} "]
|
34
35
|
unless args.empty?
|
35
36
|
message << "@with=[#{args.join(',')}] "
|
36
37
|
end
|
37
38
|
message << "#{from} -> #{to}"
|
38
|
-
info(message)
|
39
|
+
info(message.join)
|
39
40
|
end
|
40
41
|
end # Logger
|
41
42
|
end # FiniteMachine
|
@@ -1,4 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'listener'
|
4
|
+
require 'thread'
|
2
5
|
|
3
6
|
module FiniteMachine
|
4
7
|
# Allows for storage of asynchronous messages such as events
|
@@ -8,15 +11,15 @@ module FiniteMachine
|
|
8
11
|
#
|
9
12
|
# @api private
|
10
13
|
class MessageQueue
|
11
|
-
|
12
|
-
|
13
|
-
# Initialize an event queue
|
14
|
+
# Initialize an event queue in separate thread
|
14
15
|
#
|
15
16
|
# @example
|
16
17
|
# MessageQueue.new
|
17
18
|
#
|
18
19
|
# @api public
|
19
20
|
def initialize
|
21
|
+
@not_empty = ConditionVariable.new
|
22
|
+
@mutex = Mutex.new
|
20
23
|
@queue = Queue.new
|
21
24
|
@dead = false
|
22
25
|
@listeners = []
|
@@ -28,7 +31,13 @@ module FiniteMachine
|
|
28
31
|
# @api private
|
29
32
|
def start
|
30
33
|
return if running?
|
34
|
+
@mutex.synchronize { spawn_thread }
|
35
|
+
end
|
31
36
|
|
37
|
+
# Spawn new background thread
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
def spawn_thread
|
32
41
|
@thread = Thread.new do
|
33
42
|
Thread.current.abort_on_exception = true
|
34
43
|
process_events
|
@@ -39,16 +48,7 @@ module FiniteMachine
|
|
39
48
|
!@thread.nil? && alive?
|
40
49
|
end
|
41
50
|
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# @return [AsyncCall]
|
45
|
-
#
|
46
|
-
# @api private
|
47
|
-
def next_event
|
48
|
-
sync_shared { @queue.pop }
|
49
|
-
end
|
50
|
-
|
51
|
-
# Add asynchronous event to the event queue
|
51
|
+
# Add asynchronous event to the event queue to process
|
52
52
|
#
|
53
53
|
# @example
|
54
54
|
# event_queue << AsyncCall.build(...)
|
@@ -59,21 +59,21 @@ module FiniteMachine
|
|
59
59
|
#
|
60
60
|
# @api public
|
61
61
|
def <<(event)
|
62
|
-
|
62
|
+
@mutex.synchronize do
|
63
63
|
if @dead
|
64
64
|
discard_message(event)
|
65
65
|
else
|
66
66
|
@queue << event
|
67
|
+
@not_empty.signal
|
67
68
|
end
|
68
69
|
end
|
69
|
-
self
|
70
70
|
end
|
71
71
|
|
72
72
|
# Add listener to the queue to receive messages
|
73
73
|
#
|
74
74
|
# @api public
|
75
75
|
def subscribe(*args, &block)
|
76
|
-
|
76
|
+
@mutex.synchronize do
|
77
77
|
listener = Listener.new(*args)
|
78
78
|
listener.on_delivery(&block)
|
79
79
|
@listeners << listener
|
@@ -87,7 +87,7 @@ module FiniteMachine
|
|
87
87
|
#
|
88
88
|
# @api public
|
89
89
|
def empty?
|
90
|
-
|
90
|
+
@mutex.synchronize { @queue.empty? }
|
91
91
|
end
|
92
92
|
|
93
93
|
# Check if the event queue is alive
|
@@ -99,7 +99,7 @@ module FiniteMachine
|
|
99
99
|
#
|
100
100
|
# @api public
|
101
101
|
def alive?
|
102
|
-
|
102
|
+
@mutex.synchronize { !@dead }
|
103
103
|
end
|
104
104
|
|
105
105
|
# Join the event queue from current thread
|
@@ -129,10 +129,12 @@ module FiniteMachine
|
|
129
129
|
fail EventQueueDeadError, 'event queue already dead' if @dead
|
130
130
|
|
131
131
|
queue = []
|
132
|
-
|
132
|
+
@mutex.synchronize do
|
133
|
+
@dead = true
|
134
|
+
@not_empty.broadcast
|
135
|
+
|
133
136
|
queue = @queue
|
134
137
|
@queue.clear
|
135
|
-
@dead = true
|
136
138
|
end
|
137
139
|
while !queue.empty?
|
138
140
|
discard_message(queue.pop)
|
@@ -149,24 +151,24 @@ module FiniteMachine
|
|
149
151
|
#
|
150
152
|
# @api public
|
151
153
|
def size
|
152
|
-
|
154
|
+
@mutex.synchronize { @queue.size }
|
153
155
|
end
|
154
156
|
|
155
157
|
def inspect
|
156
|
-
|
158
|
+
@mutex.synchronize do
|
159
|
+
"#<#{self.class}:#{object_id.to_s(16)} @size=#{size}, @dead=#{@dead}>"
|
160
|
+
end
|
157
161
|
end
|
158
162
|
|
159
163
|
private
|
160
164
|
|
161
165
|
# Notify consumers about process event
|
162
166
|
#
|
163
|
-
# @param [
|
167
|
+
# @param [AsyncCall] event
|
164
168
|
#
|
165
169
|
# @api private
|
166
170
|
def notify_listeners(event)
|
167
|
-
|
168
|
-
@listeners.each { |listener| listener.handle_delivery(event) }
|
169
|
-
end
|
171
|
+
@listeners.each { |listener| listener.handle_delivery(event) }
|
170
172
|
end
|
171
173
|
|
172
174
|
# Process all the events
|
@@ -176,9 +178,16 @@ module FiniteMachine
|
|
176
178
|
# @api private
|
177
179
|
def process_events
|
178
180
|
until @dead
|
179
|
-
|
180
|
-
|
181
|
-
|
181
|
+
@mutex.synchronize do
|
182
|
+
while @queue.empty?
|
183
|
+
break if @dead
|
184
|
+
@not_empty.wait(@mutex)
|
185
|
+
end
|
186
|
+
event = @queue.pop
|
187
|
+
break unless event
|
188
|
+
notify_listeners(event)
|
189
|
+
event.dispatch
|
190
|
+
end
|
182
191
|
end
|
183
192
|
rescue Exception => ex
|
184
193
|
Logger.error "Error while running event: #{Logger.format_error(ex)}"
|
@@ -1,18 +1,37 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'async_call'
|
4
|
+
require_relative 'callable'
|
5
|
+
require_relative 'hook_event'
|
6
|
+
require_relative 'hooks'
|
7
|
+
require_relative 'message_queue'
|
8
|
+
require_relative 'safety'
|
9
|
+
require_relative 'transition_event'
|
4
10
|
|
5
11
|
module FiniteMachine
|
6
12
|
# A class responsible for observing state changes
|
7
|
-
class Observer
|
8
|
-
include Threadable
|
13
|
+
class Observer < GenericDSL
|
9
14
|
include Safety
|
10
15
|
|
16
|
+
# Clean up callback queue
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def self.cleanup_callback_queue
|
20
|
+
proc do
|
21
|
+
begin
|
22
|
+
if callback_queue.alive?
|
23
|
+
callback_queue.shutdown
|
24
|
+
end
|
25
|
+
rescue MessageQueueDeadError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
11
30
|
# The current state machine
|
12
|
-
|
31
|
+
attr_reader :machine
|
13
32
|
|
14
33
|
# The hooks to trigger around the transition lifecycle.
|
15
|
-
|
34
|
+
attr_reader :hooks
|
16
35
|
|
17
36
|
# Initialize an Observer
|
18
37
|
#
|
@@ -21,12 +40,15 @@ module FiniteMachine
|
|
21
40
|
#
|
22
41
|
# @api public
|
23
42
|
def initialize(machine)
|
24
|
-
@machine
|
25
|
-
@hooks
|
26
|
-
@callback_queue = MessageQueue.new
|
43
|
+
@machine = machine
|
44
|
+
@hooks = Hooks.new
|
27
45
|
|
28
46
|
@machine.subscribe(self)
|
29
|
-
ObjectSpace.define_finalizer(self, self.class.
|
47
|
+
ObjectSpace.define_finalizer(self, self.class.cleanup_callback_queue)
|
48
|
+
end
|
49
|
+
|
50
|
+
def callback_queue
|
51
|
+
@callback_queue ||= MessageQueue.new
|
30
52
|
end
|
31
53
|
|
32
54
|
# Evaluate in current context
|
@@ -49,7 +71,7 @@ module FiniteMachine
|
|
49
71
|
def on(hook_type, state_or_event_name = nil, async = nil, &callback)
|
50
72
|
sync_exclusive do
|
51
73
|
if state_or_event_name.nil?
|
52
|
-
state_or_event_name = HookEvent.
|
74
|
+
state_or_event_name = HookEvent.any_state_or_event(hook_type)
|
53
75
|
end
|
54
76
|
async = false if async.nil?
|
55
77
|
ensure_valid_callback_name!(hook_type, state_or_event_name)
|
@@ -124,8 +146,9 @@ module FiniteMachine
|
|
124
146
|
def emit(event, *data)
|
125
147
|
sync_exclusive do
|
126
148
|
[event.type].each do |hook_type|
|
127
|
-
|
128
|
-
|
149
|
+
any_state_or_event = HookEvent.any_state_or_event(hook_type)
|
150
|
+
[any_state_or_event, event.name].each do |event_name|
|
151
|
+
hooks[hook_type][event_name].each do |hook|
|
129
152
|
handle_callback(hook, event, *data)
|
130
153
|
off(hook_type, event_name, &hook) if hook.is_a?(Once)
|
131
154
|
end
|
@@ -134,6 +157,19 @@ module FiniteMachine
|
|
134
157
|
end
|
135
158
|
end
|
136
159
|
|
160
|
+
# Cancel the current event
|
161
|
+
#
|
162
|
+
# This should be called inside a on_before or on_exit callbacks
|
163
|
+
# to prevent event transition.
|
164
|
+
#
|
165
|
+
# @param [String] msg
|
166
|
+
# the message used for failure
|
167
|
+
#
|
168
|
+
# @api public
|
169
|
+
def cancel_event(msg = nil)
|
170
|
+
raise CallbackError.new(msg)
|
171
|
+
end
|
172
|
+
|
137
173
|
private
|
138
174
|
|
139
175
|
# Handle callback and decide if run synchronously or asynchronously
|
@@ -148,20 +184,14 @@ module FiniteMachine
|
|
148
184
|
#
|
149
185
|
# @api private
|
150
186
|
def handle_callback(hook, event, *data)
|
151
|
-
to = machine.
|
152
|
-
trans_event = TransitionEvent.new(event, to)
|
187
|
+
to = machine.events_map.move_to(event.event_name, event.from, *data)
|
188
|
+
trans_event = TransitionEvent.new(event.event_name, event.from, to)
|
153
189
|
callable = create_callable(hook)
|
154
190
|
|
155
191
|
if hook.is_a?(Async)
|
156
192
|
defer(callable, trans_event, *data)
|
157
|
-
result = nil
|
158
193
|
else
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
if result == CANCELLED
|
163
|
-
hooks.clear
|
164
|
-
machine.events_chain.cancel_transitions(event.event_name)
|
194
|
+
callable.(trans_event, *data)
|
165
195
|
end
|
166
196
|
end
|
167
197
|
|
@@ -170,8 +200,8 @@ module FiniteMachine
|
|
170
200
|
# @api private
|
171
201
|
def defer(callable, trans_event, *data)
|
172
202
|
async_call = AsyncCall.new(machine, callable, trans_event, *data)
|
173
|
-
|
174
|
-
|
203
|
+
callback_queue.start unless callback_queue.running?
|
204
|
+
callback_queue << async_call
|
175
205
|
end
|
176
206
|
|
177
207
|
# Create callable instance
|
@@ -191,7 +221,7 @@ module FiniteMachine
|
|
191
221
|
#
|
192
222
|
# @api private
|
193
223
|
def callback_names
|
194
|
-
machine.states + machine.
|
224
|
+
machine.states + machine.events + [ANY_EVENT, ANY_STATE]
|
195
225
|
end
|
196
226
|
|
197
227
|
# Forward the message to observer
|
@@ -225,17 +255,5 @@ module FiniteMachine
|
|
225
255
|
*_, callback_name = *method_name.to_s.match(/^(\w*?on_\w+?)_(\w+)$/)
|
226
256
|
callback_name && callback_names.include?(:"#{callback_name}")
|
227
257
|
end
|
228
|
-
|
229
|
-
# Clean up callback queue
|
230
|
-
#
|
231
|
-
# @api private
|
232
|
-
def self.cleanup(queue)
|
233
|
-
proc do
|
234
|
-
begin
|
235
|
-
queue && queue.shutdown
|
236
|
-
rescue MessageQueueDeadError
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
258
|
end # Observer
|
241
259
|
end # FiniteMachine
|