finite_machine 0.11.3 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|