finite_machine 0.6.1 → 0.7.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 +7 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +17 -0
- data/README.md +85 -50
- data/lib/finite_machine.rb +5 -4
- data/lib/finite_machine/dsl.rb +8 -8
- data/lib/finite_machine/event.rb +63 -47
- data/lib/finite_machine/hook_event.rb +65 -0
- data/lib/finite_machine/hooks.rb +35 -7
- data/lib/finite_machine/observer.rb +37 -56
- data/lib/finite_machine/safety.rb +113 -0
- data/lib/finite_machine/state_machine.rb +61 -34
- data/lib/finite_machine/state_parser.rb +5 -2
- data/lib/finite_machine/transition.rb +54 -16
- data/lib/finite_machine/version.rb +1 -1
- data/spec/unit/async_events_spec.rb +6 -6
- data/spec/unit/callbacks_spec.rb +197 -186
- data/spec/unit/define_spec.rb +2 -0
- data/spec/unit/event/add_spec.rb +18 -0
- data/spec/unit/event/inspect_spec.rb +17 -0
- data/spec/unit/event/next_transition_spec.rb +48 -0
- data/spec/unit/events_spec.rb +41 -2
- data/spec/unit/hooks/call_spec.rb +24 -0
- data/spec/unit/hooks/inspect_spec.rb +17 -0
- data/spec/unit/hooks/register_spec.rb +22 -0
- data/spec/unit/if_unless_spec.rb +28 -0
- data/spec/unit/inspect_spec.rb +9 -16
- data/spec/unit/respond_to_spec.rb +37 -0
- data/spec/unit/target_spec.rb +1 -1
- data/spec/unit/transition/inspect_spec.rb +25 -0
- data/spec/unit/transition/parse_states_spec.rb +8 -25
- metadata +31 -18
@@ -21,18 +21,21 @@ module FiniteMachine
|
|
21
21
|
|
22
22
|
# Extract states from attributes
|
23
23
|
#
|
24
|
+
# @param [Proc] block
|
25
|
+
#
|
24
26
|
# @example
|
25
27
|
# StateParpser.new(attr).parase_states
|
26
28
|
#
|
27
29
|
# @return [Hash[Symbol]] states
|
28
30
|
#
|
29
31
|
# @api public
|
30
|
-
def parse_states
|
31
|
-
if contains_from_to_keys?
|
32
|
+
def parse_states(&block)
|
33
|
+
transitions = if contains_from_to_keys?
|
32
34
|
convert_from_to_attributes_to_states_hash
|
33
35
|
else
|
34
36
|
convert_attributes_to_states_hash
|
35
37
|
end
|
38
|
+
block ? transitions.each(&block) : transitions
|
36
39
|
end
|
37
40
|
|
38
41
|
# Check if attributes contain :from or :to key
|
@@ -4,6 +4,7 @@ module FiniteMachine
|
|
4
4
|
# Class describing a transition associated with a given event
|
5
5
|
class Transition
|
6
6
|
include Threadable
|
7
|
+
include Safety
|
7
8
|
|
8
9
|
attr_threadsafe :name
|
9
10
|
|
@@ -37,7 +38,7 @@ module FiniteMachine
|
|
37
38
|
def initialize(machine, attrs = {})
|
38
39
|
@machine = machine
|
39
40
|
@name = attrs.fetch(:name, DEFAULT_STATE)
|
40
|
-
@map =
|
41
|
+
@map = attrs.fetch(:parsed_states, {})
|
41
42
|
@from_states = @map.keys
|
42
43
|
@to_states = @map.values
|
43
44
|
@from_state = @from_states.first
|
@@ -47,6 +48,25 @@ module FiniteMachine
|
|
47
48
|
@cancelled = false
|
48
49
|
end
|
49
50
|
|
51
|
+
# Create transition with associated helper methods
|
52
|
+
#
|
53
|
+
# @param [FiniteMachine::StateMachine] machine
|
54
|
+
# @param [Hash] attrs
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# Transition.create(machine, {})
|
58
|
+
#
|
59
|
+
# @return [FiniteMachine::Transition]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def self.create(machine, attrs = {})
|
63
|
+
_transition = self.new(machine, attrs)
|
64
|
+
_transition.update_transitions
|
65
|
+
_transition.define_state_methods
|
66
|
+
_transition.define_event
|
67
|
+
_transition
|
68
|
+
end
|
69
|
+
|
50
70
|
# Decide :to state from available transitions for this event
|
51
71
|
#
|
52
72
|
# @return [Symbol]
|
@@ -64,7 +84,7 @@ module FiniteMachine
|
|
64
84
|
@unless.map { |c| Callable.new(c).invert }
|
65
85
|
end
|
66
86
|
|
67
|
-
# Check if moved to different state
|
87
|
+
# Check if moved to different state or not
|
68
88
|
#
|
69
89
|
# @param [Symbol] state
|
70
90
|
# the current state name
|
@@ -72,8 +92,23 @@ module FiniteMachine
|
|
72
92
|
# @return [Boolean]
|
73
93
|
#
|
74
94
|
# @api public
|
75
|
-
def
|
76
|
-
map[state] == state || map[ANY_STATE] == state
|
95
|
+
def same?(state)
|
96
|
+
map[state] == state || (map[ANY_STATE] == state && from_state == state)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Check if transition can be performed according to constraints
|
100
|
+
#
|
101
|
+
# @param [Array] args
|
102
|
+
#
|
103
|
+
# @param [Proc] block
|
104
|
+
#
|
105
|
+
# @return [Boolean]
|
106
|
+
#
|
107
|
+
# @api public
|
108
|
+
def valid?(*args, &block)
|
109
|
+
conditions.all? do |condition|
|
110
|
+
condition.call(machine.target, *args, &block)
|
111
|
+
end
|
77
112
|
end
|
78
113
|
|
79
114
|
# Add transition to the machine
|
@@ -81,7 +116,7 @@ module FiniteMachine
|
|
81
116
|
# @return [Transition]
|
82
117
|
#
|
83
118
|
# @api private
|
84
|
-
def
|
119
|
+
def update_transitions
|
85
120
|
from_states.each do |from|
|
86
121
|
machine.transitions[name][from] = map[from] || ANY_STATE
|
87
122
|
end
|
@@ -110,24 +145,25 @@ module FiniteMachine
|
|
110
145
|
#
|
111
146
|
# @api private
|
112
147
|
def define_event
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
148
|
+
detect_event_conflict!(name)
|
149
|
+
if machine.singleton_class.send(:method_defined?, name)
|
150
|
+
machine.events_chain[name] << self
|
151
|
+
else
|
152
|
+
define_event_transition(name)
|
153
|
+
define_event_bang(name)
|
119
154
|
end
|
120
|
-
define_transition(name)
|
121
|
-
define_event_bang(name)
|
122
155
|
end
|
123
156
|
|
124
157
|
# Define transition event
|
125
158
|
#
|
126
159
|
# @api private
|
127
|
-
def
|
128
|
-
|
160
|
+
def define_event_transition(name)
|
161
|
+
_event = FiniteMachine::Event.new(machine, name: name)
|
162
|
+
_event << self
|
163
|
+
machine.events_chain[name] = _event
|
164
|
+
|
129
165
|
machine.send(:define_singleton_method, name) do |*args, &block|
|
130
|
-
|
166
|
+
_event.call(*args, &block)
|
131
167
|
end
|
132
168
|
end
|
133
169
|
|
@@ -158,6 +194,8 @@ module FiniteMachine
|
|
158
194
|
|
159
195
|
# Return transition name
|
160
196
|
#
|
197
|
+
# @return [String]
|
198
|
+
#
|
161
199
|
# @api public
|
162
200
|
def to_s
|
163
201
|
@name.to_s
|
@@ -79,10 +79,10 @@ describe FiniteMachine, 'async_events' do
|
|
79
79
|
}
|
80
80
|
|
81
81
|
callbacks {
|
82
|
-
on_enter
|
83
|
-
|
84
|
-
on_exit
|
85
|
-
|
82
|
+
on_enter :green, :async do |event| called << 'on_enter_green' end
|
83
|
+
on_before :slow, :async do |event| called << 'on_before_slow' end
|
84
|
+
on_exit :yellow, :async do |event| called << 'on_exit_yellow' end
|
85
|
+
on_after :go, :async do |event| called << 'on_after_go' end
|
86
86
|
}
|
87
87
|
end
|
88
88
|
fsm.slow
|
@@ -90,8 +90,8 @@ describe FiniteMachine, 'async_events' do
|
|
90
90
|
sleep 0.1
|
91
91
|
expect(called).to match_array([
|
92
92
|
'on_enter_green',
|
93
|
-
'
|
94
|
-
'
|
93
|
+
'on_before_slow',
|
94
|
+
'on_after_go',
|
95
95
|
'on_exit_yellow'
|
96
96
|
])
|
97
97
|
end
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -9,26 +9,15 @@ describe FiniteMachine, 'callbacks' do
|
|
9
9
|
fsm = FiniteMachine.define do
|
10
10
|
initial state: :green, defer: true
|
11
11
|
|
12
|
-
events {
|
13
|
-
event :slow, :green => :yellow
|
14
|
-
event :stop, :yellow => :red
|
15
|
-
event :ready, :red => :yellow
|
16
|
-
event :go, :yellow => :green
|
17
|
-
}
|
18
|
-
|
19
12
|
callbacks {
|
20
|
-
# generic callbacks
|
21
|
-
on_enter
|
22
|
-
|
23
|
-
on_enter_event do |event| called << 'on_enter_event' end
|
24
|
-
|
25
|
-
on_transition do |event| called << 'on_transition' end
|
26
|
-
on_transition_state do |event| called << 'on_transition_state' end
|
27
|
-
on_transition_event do |event| called << 'on_transition_event' end
|
28
|
-
|
13
|
+
# generic state callbacks
|
14
|
+
on_enter do |event| called << 'on_enter' end
|
15
|
+
on_transition do |event| called << 'on_transition' end
|
29
16
|
on_exit do |event| called << 'on_exit' end
|
30
|
-
|
31
|
-
|
17
|
+
|
18
|
+
# generic event callbacks
|
19
|
+
on_before do |event| called << 'on_before' end
|
20
|
+
on_after do |event| called << 'on_after' end
|
32
21
|
|
33
22
|
# state callbacks
|
34
23
|
on_enter :none do |event| called << 'on_enter_none' end
|
@@ -41,33 +30,24 @@ describe FiniteMachine, 'callbacks' do
|
|
41
30
|
on_exit :green do |event| called << 'on_exit_green' end
|
42
31
|
|
43
32
|
# event callbacks
|
44
|
-
|
45
|
-
|
46
|
-
on_exit :init do |event| called << 'on_exit_init' end
|
33
|
+
on_before :init do |event| called << 'on_before_init' end
|
34
|
+
on_after :init do |event| called << 'on_after_init' end
|
47
35
|
}
|
48
36
|
end
|
49
37
|
|
50
38
|
expect(fsm.current).to eql(:none)
|
51
39
|
fsm.init
|
52
40
|
expect(called).to eql([
|
41
|
+
'on_before_init',
|
42
|
+
'on_before',
|
53
43
|
'on_exit_none',
|
54
44
|
'on_exit',
|
55
|
-
'on_exit_state',
|
56
|
-
'on_enter_init',
|
57
|
-
'on_enter',
|
58
|
-
'on_enter_event',
|
59
45
|
'on_transition_green',
|
60
46
|
'on_transition',
|
61
|
-
'on_transition_state',
|
62
|
-
'on_transition_init',
|
63
|
-
'on_transition',
|
64
|
-
'on_transition_event',
|
65
47
|
'on_enter_green',
|
66
48
|
'on_enter',
|
67
|
-
'
|
68
|
-
'
|
69
|
-
'on_exit',
|
70
|
-
'on_exit_event'
|
49
|
+
'on_after_init',
|
50
|
+
'on_after'
|
71
51
|
])
|
72
52
|
end
|
73
53
|
|
@@ -85,17 +65,12 @@ describe FiniteMachine, 'callbacks' do
|
|
85
65
|
|
86
66
|
callbacks {
|
87
67
|
# generic callbacks
|
88
|
-
on_enter
|
89
|
-
|
90
|
-
on_enter_event do |event| called << 'on_enter_event' end
|
91
|
-
|
92
|
-
on_transition do |event| called << 'on_transition' end
|
93
|
-
on_transition_state do |event| called << 'on_transition_state' end
|
94
|
-
on_transition_event do |event| called << 'on_transition_event' end
|
95
|
-
|
68
|
+
on_enter do |event| called << 'on_enter' end
|
69
|
+
on_transition do |event| called << 'on_transition' end
|
96
70
|
on_exit do |event| called << 'on_exit' end
|
97
|
-
|
98
|
-
|
71
|
+
|
72
|
+
on_before do |event| called << 'on_before' end
|
73
|
+
on_after do |event| called << 'on_after' end
|
99
74
|
|
100
75
|
# state callbacks
|
101
76
|
on_enter :green do |event| called << 'on_enter_green' end
|
@@ -111,113 +86,105 @@ describe FiniteMachine, 'callbacks' do
|
|
111
86
|
on_exit :red do |event| called << "on_exit_red" end
|
112
87
|
|
113
88
|
# event callbacks
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
on_exit :slow do |event| called << 'on_exit_slow' end
|
125
|
-
on_exit :stop do |event| called << "on_exit_stop" end
|
126
|
-
on_exit :ready do |event| called << "on_exit_ready" end
|
127
|
-
on_exit :go do |event| called << "on_exit_go" end
|
89
|
+
on_before :slow do |event| called << 'on_before_slow' end
|
90
|
+
on_before :stop do |event| called << "on_before_stop" end
|
91
|
+
on_before :ready do |event| called << "on_before_ready" end
|
92
|
+
on_before :go do |event| called << "on_before_go" end
|
93
|
+
|
94
|
+
on_after :slow do |event| called << 'on_after_slow' end
|
95
|
+
on_after :stop do |event| called << "on_after_stop" end
|
96
|
+
on_after :ready do |event| called << "on_after_ready" end
|
97
|
+
on_after :go do |event| called << "on_after_go" end
|
128
98
|
}
|
129
99
|
end
|
130
100
|
|
131
101
|
called = []
|
132
102
|
fsm.slow
|
133
103
|
expect(called).to eql([
|
104
|
+
'on_before_slow',
|
105
|
+
'on_before',
|
134
106
|
'on_exit_green',
|
135
107
|
'on_exit',
|
136
|
-
'on_exit_state',
|
137
|
-
'on_enter_slow',
|
138
|
-
'on_enter',
|
139
|
-
'on_enter_event',
|
140
108
|
'on_transition_yellow',
|
141
109
|
'on_transition',
|
142
|
-
'on_transition_state',
|
143
|
-
'on_transition_slow',
|
144
|
-
'on_transition',
|
145
|
-
'on_transition_event',
|
146
110
|
'on_enter_yellow',
|
147
111
|
'on_enter',
|
148
|
-
'
|
149
|
-
'
|
150
|
-
'on_exit',
|
151
|
-
'on_exit_event'
|
112
|
+
'on_after_slow',
|
113
|
+
'on_after'
|
152
114
|
])
|
153
115
|
|
154
116
|
called = []
|
155
117
|
fsm.stop
|
156
118
|
expect(called).to eql([
|
119
|
+
'on_before_stop',
|
120
|
+
'on_before',
|
157
121
|
'on_exit_yellow',
|
158
122
|
'on_exit',
|
159
|
-
'on_exit_state',
|
160
|
-
'on_enter_stop',
|
161
|
-
'on_enter',
|
162
|
-
'on_enter_event',
|
163
123
|
'on_transition_red',
|
164
124
|
'on_transition',
|
165
|
-
'on_transition_state',
|
166
|
-
'on_transition_stop',
|
167
|
-
'on_transition',
|
168
|
-
'on_transition_event',
|
169
125
|
'on_enter_red',
|
170
126
|
'on_enter',
|
171
|
-
'
|
172
|
-
'
|
173
|
-
'on_exit',
|
174
|
-
'on_exit_event'
|
127
|
+
'on_after_stop',
|
128
|
+
'on_after'
|
175
129
|
])
|
176
130
|
|
177
131
|
called = []
|
178
132
|
fsm.ready
|
179
133
|
expect(called).to eql([
|
134
|
+
'on_before_ready',
|
135
|
+
'on_before',
|
180
136
|
'on_exit_red',
|
181
137
|
'on_exit',
|
182
|
-
'on_exit_state',
|
183
|
-
'on_enter_ready',
|
184
|
-
'on_enter',
|
185
|
-
'on_enter_event',
|
186
138
|
'on_transition_yellow',
|
187
139
|
'on_transition',
|
188
|
-
'on_transition_state',
|
189
|
-
'on_transition_ready',
|
190
|
-
'on_transition',
|
191
|
-
'on_transition_event',
|
192
140
|
'on_enter_yellow',
|
193
141
|
'on_enter',
|
194
|
-
'
|
195
|
-
'
|
196
|
-
'on_exit',
|
197
|
-
'on_exit_event'
|
142
|
+
'on_after_ready',
|
143
|
+
'on_after'
|
198
144
|
])
|
199
145
|
|
200
146
|
called = []
|
201
147
|
fsm.go
|
202
148
|
expect(called).to eql([
|
149
|
+
'on_before_go',
|
150
|
+
'on_before',
|
203
151
|
'on_exit_yellow',
|
204
152
|
'on_exit',
|
205
|
-
'on_exit_state',
|
206
|
-
'on_enter_go',
|
207
|
-
'on_enter',
|
208
|
-
'on_enter_event',
|
209
153
|
'on_transition_green',
|
210
154
|
'on_transition',
|
211
|
-
'on_transition_state',
|
212
|
-
'on_transition_go',
|
213
|
-
'on_transition',
|
214
|
-
'on_transition_event',
|
215
155
|
'on_enter_green',
|
216
156
|
'on_enter',
|
217
|
-
'
|
218
|
-
'
|
219
|
-
|
220
|
-
|
157
|
+
'on_after_go',
|
158
|
+
'on_after'
|
159
|
+
])
|
160
|
+
end
|
161
|
+
|
162
|
+
it "maintains transition execution sequence from UML statechart" do
|
163
|
+
called = []
|
164
|
+
fsm = FiniteMachine.define do
|
165
|
+
initial :previous
|
166
|
+
|
167
|
+
events {
|
168
|
+
event :go, :previous => :next, if: -> { called << 'guard'; true}
|
169
|
+
}
|
170
|
+
|
171
|
+
callbacks {
|
172
|
+
on_exit { |event| called << "exit_#{event.from}" }
|
173
|
+
on_before { |event| called << "before_#{event.name}" }
|
174
|
+
on_transition { |event| called << "transition_#{event.from}_#{event.to}"}
|
175
|
+
on_enter { |event| called << "enter_#{event.to}"}
|
176
|
+
on_after { |event| called << "after_#{event.name}" }
|
177
|
+
}
|
178
|
+
end
|
179
|
+
expect(fsm.current).to eq(:previous)
|
180
|
+
fsm.go
|
181
|
+
expect(called).to eq([
|
182
|
+
'before_go',
|
183
|
+
'guard',
|
184
|
+
'exit_previous',
|
185
|
+
'transition_previous_next',
|
186
|
+
'enter_next',
|
187
|
+
'after_go'
|
221
188
|
])
|
222
189
|
end
|
223
190
|
|
@@ -234,26 +201,28 @@ describe FiniteMachine, 'callbacks' do
|
|
234
201
|
}
|
235
202
|
|
236
203
|
callbacks {
|
237
|
-
# generic callbacks
|
204
|
+
# generic state callbacks
|
238
205
|
on_enter do |event| called << 'on_enter' end
|
239
206
|
on_transition do |event| called << 'on_transition' end
|
240
207
|
on_exit do |event| called << 'on_exit' end
|
241
208
|
|
209
|
+
# generic event callbacks
|
210
|
+
on_before do |event| called << 'on_before' end
|
211
|
+
on_after do |event| called << 'on_after' end
|
212
|
+
|
242
213
|
# state callbacks
|
243
|
-
on_exit
|
244
|
-
on_exit
|
245
|
-
on_enter
|
246
|
-
on_enter
|
214
|
+
on_exit :green do |event| called << 'on_exit_green_1' end
|
215
|
+
on_exit :green do |event| called << 'on_exit_green_2' end
|
216
|
+
on_enter :yellow do |event| called << 'on_enter_yellow_1' end
|
217
|
+
on_enter :yellow do |event| called << 'on_enter_yellow_2' end
|
247
218
|
on_transition :yellow do |event| called << 'on_transition_yellow_1' end
|
248
219
|
on_transition :yellow do |event| called << 'on_transition_yellow_2' end
|
249
220
|
|
250
221
|
# event callbacks
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
on_exit :slow do |event| called << 'on_exit_slow_1' end
|
256
|
-
on_exit :slow do |event| called << 'on_exit_slow_2' end
|
222
|
+
on_before :slow do |event| called << 'on_before_slow_1' end
|
223
|
+
on_before :slow do |event| called << 'on_before_slow_2' end
|
224
|
+
on_after :slow do |event| called << 'on_after_slow_1' end
|
225
|
+
on_after :slow do |event| called << 'on_after_slow_2' end
|
257
226
|
}
|
258
227
|
end
|
259
228
|
|
@@ -261,24 +230,21 @@ describe FiniteMachine, 'callbacks' do
|
|
261
230
|
fsm.slow
|
262
231
|
expect(fsm.current).to eql(:yellow)
|
263
232
|
expect(called).to eql([
|
233
|
+
'on_before_slow_1',
|
234
|
+
'on_before_slow_2',
|
235
|
+
'on_before',
|
264
236
|
'on_exit_green_1',
|
265
237
|
'on_exit_green_2',
|
266
238
|
'on_exit',
|
267
|
-
'on_enter_slow_1',
|
268
|
-
'on_enter_slow_2',
|
269
|
-
'on_enter',
|
270
239
|
'on_transition_yellow_1',
|
271
240
|
'on_transition_yellow_2',
|
272
241
|
'on_transition',
|
273
|
-
'on_transition_slow_1',
|
274
|
-
'on_transition_slow_2',
|
275
|
-
'on_transition',
|
276
242
|
'on_enter_yellow_1',
|
277
243
|
'on_enter_yellow_2',
|
278
244
|
'on_enter',
|
279
|
-
'
|
280
|
-
'
|
281
|
-
'
|
245
|
+
'on_after_slow_1',
|
246
|
+
'on_after_slow_2',
|
247
|
+
'on_after'
|
282
248
|
])
|
283
249
|
end
|
284
250
|
|
@@ -301,9 +267,8 @@ describe FiniteMachine, 'callbacks' do
|
|
301
267
|
on_transition_yellow do |event| called << 'on_transition_yellow' end
|
302
268
|
|
303
269
|
# event callbacks
|
304
|
-
|
305
|
-
|
306
|
-
on_exit_slow do |event| called << 'on_exit_slow' end
|
270
|
+
on_before_slow do |event| called << 'on_before_slow' end
|
271
|
+
on_after_slow do |event| called << 'on_after_slow' end
|
307
272
|
}
|
308
273
|
end
|
309
274
|
|
@@ -311,18 +276,16 @@ describe FiniteMachine, 'callbacks' do
|
|
311
276
|
fsm.slow
|
312
277
|
expect(fsm.current).to eql(:yellow)
|
313
278
|
expect(called).to eql([
|
279
|
+
'on_before_slow',
|
314
280
|
'on_exit_green',
|
315
|
-
'on_enter_slow',
|
316
281
|
'on_transition_yellow',
|
317
|
-
'on_transition_slow',
|
318
282
|
'on_enter_yellow',
|
319
|
-
'
|
283
|
+
'on_after_slow'
|
320
284
|
])
|
321
285
|
end
|
322
286
|
|
323
287
|
it "passes event object to callback" do
|
324
288
|
evt = nil
|
325
|
-
|
326
289
|
fsm = FiniteMachine.define do
|
327
290
|
initial :green
|
328
291
|
|
@@ -346,7 +309,6 @@ describe FiniteMachine, 'callbacks' do
|
|
346
309
|
|
347
310
|
it "identifies the from state for callback event parameter" do
|
348
311
|
evt = nil
|
349
|
-
|
350
312
|
fsm = FiniteMachine.define do
|
351
313
|
initial :green
|
352
314
|
|
@@ -395,11 +357,15 @@ describe FiniteMachine, 'callbacks' do
|
|
395
357
|
}
|
396
358
|
|
397
359
|
callbacks {
|
398
|
-
# generic callbacks
|
360
|
+
# generic state callbacks
|
399
361
|
on_enter(&callback)
|
400
362
|
on_transition(&callback)
|
401
363
|
on_exit(&callback)
|
402
364
|
|
365
|
+
# generic event callbacks
|
366
|
+
on_before(&callback)
|
367
|
+
on_after(&callback)
|
368
|
+
|
403
369
|
# state callbacks
|
404
370
|
on_enter :green, &callback
|
405
371
|
on_enter :yellow, &callback
|
@@ -414,20 +380,15 @@ describe FiniteMachine, 'callbacks' do
|
|
414
380
|
on_exit :red , &callback
|
415
381
|
|
416
382
|
# event callbacks
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
on_exit :slow , &callback
|
428
|
-
on_exit :stop , &callback
|
429
|
-
on_exit :ready, &callback
|
430
|
-
on_exit :go , &callback
|
383
|
+
on_before :slow , &callback
|
384
|
+
on_before :stop , &callback
|
385
|
+
on_before :ready, &callback
|
386
|
+
on_before :go , &callback
|
387
|
+
|
388
|
+
on_after :slow , &callback
|
389
|
+
on_after :stop , &callback
|
390
|
+
on_after :ready, &callback
|
391
|
+
on_after :go , &callback
|
431
392
|
}
|
432
393
|
end
|
433
394
|
|
@@ -457,7 +418,27 @@ describe FiniteMachine, 'callbacks' do
|
|
457
418
|
on_enter(:magic) { |event| called << 'on_enter'}
|
458
419
|
}
|
459
420
|
end
|
460
|
-
}.to raise_error(FiniteMachine::InvalidCallbackNameError,
|
421
|
+
}.to raise_error(FiniteMachine::InvalidCallbackNameError, /\"magic\" is not a valid callback name/)
|
422
|
+
end
|
423
|
+
|
424
|
+
it "doesn't allow to mix state callback with event name" do
|
425
|
+
expect {
|
426
|
+
FiniteMachine.define do
|
427
|
+
events { event :slow, :green => :yellow }
|
428
|
+
|
429
|
+
callbacks { on_enter_slow do |event| end }
|
430
|
+
end
|
431
|
+
}.to raise_error(FiniteMachine::InvalidCallbackNameError, "\"on_enter\" callback is a state listener and cannot be used with \"slow\" event name. Please use on_before or on_after instead.")
|
432
|
+
end
|
433
|
+
|
434
|
+
it "doesn't allow to mix event callback with state name" do
|
435
|
+
expect {
|
436
|
+
FiniteMachine.define do
|
437
|
+
events { event :slow, :green => :yellow }
|
438
|
+
|
439
|
+
callbacks { on_before_green do |event| end }
|
440
|
+
end
|
441
|
+
}.to raise_error(FiniteMachine::InvalidCallbackNameError, '"on_before" callback is an event listener and cannot be used with "green" state name. Please use on_enter, on_transition or on_exit instead.')
|
461
442
|
end
|
462
443
|
|
463
444
|
it "propagates exceptions raised inside callback" do
|
@@ -484,8 +465,8 @@ describe FiniteMachine, 'callbacks' do
|
|
484
465
|
}
|
485
466
|
|
486
467
|
callbacks {
|
487
|
-
|
488
|
-
called << '
|
468
|
+
on_before_stop do |event|
|
469
|
+
called << 'on_before_stop'
|
489
470
|
end
|
490
471
|
}
|
491
472
|
end
|
@@ -495,8 +476,8 @@ describe FiniteMachine, 'callbacks' do
|
|
495
476
|
fsm.stop
|
496
477
|
expect(fsm.current).to eql(:red)
|
497
478
|
expect(called).to eql([
|
498
|
-
'
|
499
|
-
'
|
479
|
+
'on_before_stop',
|
480
|
+
'on_before_stop'
|
500
481
|
])
|
501
482
|
end
|
502
483
|
|
@@ -552,6 +533,7 @@ describe FiniteMachine, 'callbacks' do
|
|
552
533
|
}
|
553
534
|
|
554
535
|
callbacks {
|
536
|
+
# state callbacks
|
555
537
|
once_on_enter_green do |event| called << 'once_on_enter_green' end
|
556
538
|
once_on_enter_yellow do |event| called << 'once_on_enter_yellow' end
|
557
539
|
|
@@ -560,6 +542,13 @@ describe FiniteMachine, 'callbacks' do
|
|
560
542
|
|
561
543
|
once_on_exit_green do |event| called << 'once_on_exit_green' end
|
562
544
|
once_on_exit_yellow do |event| called << 'once_on_exit_yellow' end
|
545
|
+
|
546
|
+
# event callbacks
|
547
|
+
once_on_before_slow do |event| called << 'once_on_before_slow' end
|
548
|
+
once_on_before_go do |event| called << 'once_on_before_go' end
|
549
|
+
|
550
|
+
once_on_after_slow do |event| called << 'once_on_after_slow' end
|
551
|
+
once_on_after_go do |event| called << 'once_on_after_go' end
|
563
552
|
}
|
564
553
|
end
|
565
554
|
expect(fsm.current).to eql(:green)
|
@@ -570,12 +559,16 @@ describe FiniteMachine, 'callbacks' do
|
|
570
559
|
fsm.slow
|
571
560
|
expect(fsm.current).to eql(:yellow)
|
572
561
|
expect(called).to eql([
|
562
|
+
'once_on_before_slow',
|
573
563
|
'once_on_exit_green',
|
574
564
|
'once_on_transition_yellow',
|
575
565
|
'once_on_enter_yellow',
|
566
|
+
'once_on_after_slow',
|
567
|
+
'once_on_before_go',
|
576
568
|
'once_on_exit_yellow',
|
577
569
|
'once_on_transition_green',
|
578
|
-
'once_on_enter_green'
|
570
|
+
'once_on_enter_green',
|
571
|
+
'once_on_after_go'
|
579
572
|
])
|
580
573
|
end
|
581
574
|
|
@@ -633,35 +626,53 @@ describe FiniteMachine, 'callbacks' do
|
|
633
626
|
}
|
634
627
|
|
635
628
|
callbacks {
|
636
|
-
|
637
|
-
callbacks << "
|
629
|
+
on_enter do |event|
|
630
|
+
callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
|
631
|
+
end
|
632
|
+
on_exit do |event|
|
633
|
+
callbacks << "exit_#{event.name}_#{event.from}_#{event.to}"
|
634
|
+
end
|
635
|
+
on_before do |event|
|
636
|
+
callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
|
638
637
|
end
|
639
|
-
|
640
|
-
callbacks << "
|
638
|
+
on_after do |event|
|
639
|
+
callbacks << "after_#{event.name}_#{event.from}_#{event.to}"
|
641
640
|
end
|
642
641
|
}
|
643
642
|
end
|
644
643
|
expect(fsm.current).to eq(:initial)
|
645
644
|
fsm.bump
|
646
645
|
expect(callbacks).to eq([
|
647
|
-
'
|
648
|
-
'
|
646
|
+
'before_bump_initial_low',
|
647
|
+
'exit_bump_initial_low',
|
648
|
+
'enter_bump_initial_low',
|
649
|
+
'after_bump_initial_low'
|
649
650
|
])
|
650
651
|
fsm.bump
|
651
652
|
expect(callbacks).to eq([
|
652
|
-
'
|
653
|
-
'
|
654
|
-
'
|
655
|
-
'
|
653
|
+
'before_bump_initial_low',
|
654
|
+
'exit_bump_initial_low',
|
655
|
+
'enter_bump_initial_low',
|
656
|
+
'after_bump_initial_low',
|
657
|
+
'before_bump_low_medium',
|
658
|
+
'exit_bump_low_medium',
|
659
|
+
'enter_bump_low_medium',
|
660
|
+
'after_bump_low_medium'
|
656
661
|
])
|
657
662
|
fsm.bump
|
658
663
|
expect(callbacks).to eq([
|
659
|
-
'
|
660
|
-
'
|
661
|
-
'
|
662
|
-
'
|
663
|
-
'
|
664
|
-
'
|
664
|
+
'before_bump_initial_low',
|
665
|
+
'exit_bump_initial_low',
|
666
|
+
'enter_bump_initial_low',
|
667
|
+
'after_bump_initial_low',
|
668
|
+
'before_bump_low_medium',
|
669
|
+
'exit_bump_low_medium',
|
670
|
+
'enter_bump_low_medium',
|
671
|
+
'after_bump_low_medium',
|
672
|
+
'before_bump_medium_high',
|
673
|
+
'exit_bump_medium_high',
|
674
|
+
'enter_bump_medium_high',
|
675
|
+
'after_bump_medium_high'
|
665
676
|
])
|
666
677
|
end
|
667
678
|
|
@@ -677,35 +688,35 @@ describe FiniteMachine, 'callbacks' do
|
|
677
688
|
}
|
678
689
|
|
679
690
|
callbacks {
|
680
|
-
|
681
|
-
callbacks << "
|
691
|
+
on_enter do |event|
|
692
|
+
callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
|
682
693
|
end
|
683
|
-
|
684
|
-
callbacks << "
|
694
|
+
on_before do |event|
|
695
|
+
callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
|
685
696
|
end
|
686
697
|
}
|
687
698
|
end
|
688
699
|
expect(fsm.current).to eq(:initial)
|
689
700
|
fsm.bump
|
690
701
|
expect(callbacks).to eq([
|
691
|
-
'
|
692
|
-
'
|
702
|
+
'before_bump_initial_low',
|
703
|
+
'enter_bump_initial_low'
|
693
704
|
])
|
694
705
|
fsm.bump
|
695
706
|
expect(callbacks).to eq([
|
696
|
-
'
|
697
|
-
'
|
698
|
-
'
|
699
|
-
'
|
707
|
+
'before_bump_initial_low',
|
708
|
+
'enter_bump_initial_low',
|
709
|
+
'before_bump_low_medium',
|
710
|
+
'enter_bump_low_medium'
|
700
711
|
])
|
701
712
|
fsm.bump
|
702
713
|
expect(callbacks).to eq([
|
703
|
-
'
|
704
|
-
'
|
705
|
-
'
|
706
|
-
'
|
707
|
-
'
|
708
|
-
'
|
714
|
+
'before_bump_initial_low',
|
715
|
+
'enter_bump_initial_low',
|
716
|
+
'before_bump_low_medium',
|
717
|
+
'enter_bump_low_medium',
|
718
|
+
'before_bump_medium_high',
|
719
|
+
'enter_bump_medium_high'
|
709
720
|
])
|
710
721
|
end
|
711
722
|
end
|