finite_machine 0.12.1 → 0.13.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/README.md +1 -1
  4. data/lib/finite_machine.rb +3 -1
  5. data/lib/finite_machine/choice_merger.rb +2 -2
  6. data/lib/finite_machine/dsl.rb +4 -4
  7. data/lib/finite_machine/message_queue.rb +0 -1
  8. data/lib/finite_machine/state_machine.rb +3 -3
  9. data/lib/finite_machine/two_phase_lock.rb +6 -6
  10. data/lib/finite_machine/version.rb +1 -1
  11. metadata +20 -146
  12. data/Rakefile +0 -12
  13. data/benchmarks/memory_profile.rb +0 -11
  14. data/benchmarks/memory_usage.rb +0 -28
  15. data/examples/atm.rb +0 -45
  16. data/examples/bug_system.rb +0 -145
  17. data/finite_machine.gemspec +0 -30
  18. data/spec/integration/system_spec.rb +0 -93
  19. data/spec/performance/benchmark_spec.rb +0 -54
  20. data/spec/spec_helper.rb +0 -34
  21. data/spec/unit/alias_target_spec.rb +0 -89
  22. data/spec/unit/async_callbacks_spec.rb +0 -28
  23. data/spec/unit/auto_methods_spec.rb +0 -44
  24. data/spec/unit/callable/call_spec.rb +0 -111
  25. data/spec/unit/callbacks_spec.rb +0 -851
  26. data/spec/unit/can_spec.rb +0 -88
  27. data/spec/unit/cancel_callbacks_spec.rb +0 -46
  28. data/spec/unit/choice_spec.rb +0 -295
  29. data/spec/unit/define_spec.rb +0 -55
  30. data/spec/unit/definition_spec.rb +0 -98
  31. data/spec/unit/event_names_spec.rb +0 -15
  32. data/spec/unit/events_map/add_spec.rb +0 -23
  33. data/spec/unit/events_map/choice_transition_spec.rb +0 -25
  34. data/spec/unit/events_map/clear_spec.rb +0 -13
  35. data/spec/unit/events_map/events_spec.rb +0 -16
  36. data/spec/unit/events_map/inspect_spec.rb +0 -22
  37. data/spec/unit/events_map/match_transition_spec.rb +0 -35
  38. data/spec/unit/events_map/move_to_spec.rb +0 -45
  39. data/spec/unit/events_map/states_for_spec.rb +0 -17
  40. data/spec/unit/events_spec.rb +0 -390
  41. data/spec/unit/handlers_spec.rb +0 -120
  42. data/spec/unit/hook_event/any_state_or_event_spec.rb +0 -13
  43. data/spec/unit/hook_event/build_spec.rb +0 -13
  44. data/spec/unit/hook_event/eql_spec.rb +0 -34
  45. data/spec/unit/hook_event/initialize_spec.rb +0 -23
  46. data/spec/unit/hook_event/notify_spec.rb +0 -12
  47. data/spec/unit/hooks/clear_spec.rb +0 -16
  48. data/spec/unit/hooks/find_spec.rb +0 -19
  49. data/spec/unit/hooks/inspect_spec.rb +0 -25
  50. data/spec/unit/hooks/register_spec.rb +0 -17
  51. data/spec/unit/if_unless_spec.rb +0 -314
  52. data/spec/unit/initial_spec.rb +0 -190
  53. data/spec/unit/inspect_spec.rb +0 -22
  54. data/spec/unit/is_spec.rb +0 -49
  55. data/spec/unit/log_transitions_spec.rb +0 -24
  56. data/spec/unit/logger_spec.rb +0 -36
  57. data/spec/unit/message_queue_spec.rb +0 -62
  58. data/spec/unit/new_spec.rb +0 -50
  59. data/spec/unit/respond_to_spec.rb +0 -34
  60. data/spec/unit/state_parser/parse_spec.rb +0 -56
  61. data/spec/unit/states_spec.rb +0 -28
  62. data/spec/unit/subscribers_spec.rb +0 -40
  63. data/spec/unit/target_spec.rb +0 -225
  64. data/spec/unit/terminated_spec.rb +0 -85
  65. data/spec/unit/transition/check_conditions_spec.rb +0 -55
  66. data/spec/unit/transition/inspect_spec.rb +0 -25
  67. data/spec/unit/transition/matches_spec.rb +0 -21
  68. data/spec/unit/transition/states_spec.rb +0 -29
  69. data/spec/unit/transition/to_state_spec.rb +0 -19
  70. data/spec/unit/trigger_spec.rb +0 -18
  71. data/spec/unit/undefined_transition/eql_spec.rb +0 -15
  72. data/tasks/console.rake +0 -11
  73. data/tasks/coverage.rake +0 -11
  74. data/tasks/spec.rake +0 -34
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, 'async callbacks' do
4
- it "permits async callback" do
5
- called = []
6
- fsm = FiniteMachine.new do
7
- initial :green, silent: false
8
-
9
- event :slow, :green => :yellow
10
- event :go, :yellow => :green
11
-
12
- on_enter :green, :async do |event| called << 'on_enter_green' end
13
- on_before :slow, :async do |event| called << 'on_before_slow' end
14
- on_exit :yellow, :async do |event| called << 'on_exit_yellow' end
15
- on_after :go, :async do |event| called << 'on_after_go' end
16
- end
17
- fsm.slow
18
- fsm.go
19
- sleep 0.1
20
- expect(called).to match_array([
21
- 'on_enter_green',
22
- 'on_before_slow',
23
- 'on_exit_yellow',
24
- 'on_enter_green',
25
- 'on_after_go'
26
- ])
27
- end
28
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, ':auto_methods' do
4
- it "allows turning off automatic methods generation" do
5
- fsm = FiniteMachine.new(auto_methods: false) do
6
- initial :green
7
-
8
- event :slow, :green => :yellow
9
- event :stop, :yellow => :red
10
- event :ready, :red => :yellow
11
- event :go, :yellow => :green
12
-
13
- # allows for fluid callback names
14
- once_on_enter_yellow do |event| 'once_on_enter_yellow' end
15
- end
16
-
17
- expect(fsm.respond_to?(:slow)).to eq(false)
18
- expect { fsm.slow }.to raise_error(NoMethodError)
19
- expect(fsm.current).to eq(:green)
20
-
21
- fsm.trigger(:slow)
22
- expect(fsm.current).to eq(:yellow)
23
- end
24
-
25
- it "allows to use any method name without auto method generation" do
26
- fsm = FiniteMachine.new(auto_methods: false) do
27
- initial :green
28
-
29
- event :fail, :green => :red
30
- end
31
-
32
- fsm.trigger(:fail)
33
- expect(fsm.current).to eq(:red)
34
- end
35
-
36
- it "detects dangerous event names" do
37
- expect {
38
- FiniteMachine.new do
39
- event :trigger, :a => :b
40
- end
41
- }.to raise_error(FiniteMachine::AlreadyDefinedError)
42
- end
43
- end
44
-
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine::Callable, '#call' do
4
-
5
- before(:each) {
6
- stub_const("Car", Class.new do
7
- attr_reader :result
8
-
9
- def initialize
10
- @engine_on = false
11
- end
12
-
13
- def turn_engine_on
14
- @result = 'turn_engine_on'
15
- @engine_on = true
16
- end
17
-
18
- def set_engine(value = :on)
19
- @result = "set_engine(#{value})"
20
- @engine = value.to_sym == :on
21
- end
22
-
23
- def turn_engine_off
24
- @result = 'turn_engine_off'
25
- @engine_on = false
26
- end
27
-
28
- def engine_on?
29
- @result = 'engine_on'
30
- !!@engine_on
31
- end
32
- end)
33
- }
34
-
35
- let(:called) { [] }
36
-
37
- let(:target) { Car.new }
38
-
39
- let(:instance) { described_class.new(object) }
40
-
41
- context 'when string' do
42
- let(:object) { 'engine_on?' }
43
-
44
- it 'executes method on target' do
45
- instance.call(target)
46
- expect(target.result).to eql('engine_on')
47
- end
48
- end
49
-
50
- context 'when string' do
51
- let(:object) { 'set_engine(:on)' }
52
-
53
- it 'executes method with arguments' do
54
- instance.call(target)
55
- expect(target.result).to eql('set_engine(on)')
56
- end
57
- end
58
-
59
- context 'when string with arguments' do
60
- let(:object) { 'set_engine' }
61
-
62
- it 'executes method with arguments' do
63
- instance.call(target, :off)
64
- expect(target.result).to eql('set_engine(off)')
65
- end
66
- end
67
-
68
- context 'when symbol' do
69
- let(:object) { :set_engine }
70
-
71
- it 'executes method on target' do
72
- instance.call(target)
73
- expect(target.result).to eql('set_engine(on)')
74
- end
75
- end
76
-
77
- context 'when symbol with arguments' do
78
- let(:object) { :set_engine }
79
-
80
- it 'executes method on target' do
81
- instance.call(target, :off)
82
- expect(target.result).to eql('set_engine(off)')
83
- end
84
- end
85
-
86
- context 'when proc without args' do
87
- let(:object) { proc { |a| called << "block_with(#{a})" } }
88
-
89
- it 'passes arguments' do
90
- instance.call(target)
91
- expect(called).to eql(["block_with(#{target})"])
92
- end
93
- end
94
-
95
- context 'when proc with args' do
96
- let(:object) { proc { |a,b| called << "block_with(#{a},#{b})" } }
97
-
98
- it 'passes arguments' do
99
- instance.call(target, :red)
100
- expect(called).to eql(["block_with(#{target},red)"])
101
- end
102
- end
103
-
104
- context 'when unknown' do
105
- let(:object) { Object.new }
106
-
107
- it 'raises error' do
108
- expect { instance.call(target) }.to raise_error(ArgumentError)
109
- end
110
- end
111
- end
@@ -1,851 +0,0 @@
1
- # frozen_string_literal
2
-
3
- RSpec.describe FiniteMachine, 'callbacks' do
4
- it "triggers default init event" do
5
- called = []
6
- fsm = FiniteMachine.new do
7
- initial :green, defer: true, silent: false
8
-
9
- # generic state callbacks
10
- on_enter do |event| called << 'on_enter' end
11
- on_transition do |event| called << 'on_transition' end
12
- on_exit do |event| called << 'on_exit' end
13
-
14
- # generic event callbacks
15
- on_before any_event do |event| called << 'on_before' end
16
- on_after do |event| called << 'on_after' end
17
-
18
- # state callbacks
19
- on_enter :none do |event| called << 'on_enter_none' end
20
- on_enter :green do |event| called << 'on_enter_green' end
21
-
22
- on_transition :none do |event| called << 'on_transition_none' end
23
- on_transition :green do |event| called << 'on_transition_green' end
24
-
25
- on_exit :none do |event| called << 'on_exit_none' end
26
- on_exit :green do |event| called << 'on_exit_green' end
27
-
28
- # event callbacks
29
- on_before :init do |event| called << 'on_before_init' end
30
- on_after :init do |event| called << 'on_after_init' end
31
- end
32
-
33
- expect(fsm.current).to eql(:none)
34
- fsm.init
35
- expect(called).to eql([
36
- 'on_before',
37
- 'on_before_init',
38
- 'on_exit',
39
- 'on_exit_none',
40
- 'on_transition',
41
- 'on_transition_green',
42
- 'on_enter',
43
- 'on_enter_green',
44
- 'on_after',
45
- 'on_after_init'
46
- ])
47
- end
48
-
49
- it "executes callbacks in order" do
50
- called = []
51
- fsm = FiniteMachine.new do
52
- initial :green, silent: false
53
-
54
- event :slow, :green => :yellow
55
- event :stop, :yellow => :red
56
- event :ready, :red => :yellow
57
- event :go, :yellow => :green
58
-
59
- # generic callbacks
60
- on_enter do |event| called << 'on_enter' end
61
- on_transition do |event| called << 'on_transition' end
62
- on_exit do |event| called << 'on_exit' end
63
-
64
- on_before do |event| called << 'on_before' end
65
- on_after do |event| called << 'on_after' end
66
-
67
- # state callbacks
68
- on_enter :green do |event| called << 'on_enter_green' end
69
- on_enter :yellow do |event| called << "on_enter_yellow" end
70
- on_enter :red do |event| called << "on_enter_red" end
71
-
72
- on_transition :green do |event| called << 'on_transition_green' end
73
- on_transition :yellow do |event| called << "on_transition_yellow" end
74
- on_transition :red do |event| called << "on_transition_red" end
75
-
76
- on_exit :green do |event| called << 'on_exit_green' end
77
- on_exit :yellow do |event| called << "on_exit_yellow" end
78
- on_exit :red do |event| called << "on_exit_red" end
79
-
80
- # event callbacks
81
- on_before :slow do |event| called << 'on_before_slow' end
82
- on_before :stop do |event| called << "on_before_stop" end
83
- on_before :ready do |event| called << "on_before_ready" end
84
- on_before :go do |event| called << "on_before_go" end
85
-
86
- on_after :slow do |event| called << 'on_after_slow' end
87
- on_after :stop do |event| called << "on_after_stop" end
88
- on_after :ready do |event| called << "on_after_ready" end
89
- on_after :go do |event| called << "on_after_go" end
90
- end
91
-
92
- expect(fsm.current).to eq(:green)
93
- expect(called).to eq([
94
- 'on_before',
95
- 'on_exit',
96
- 'on_transition',
97
- 'on_transition_green',
98
- 'on_enter',
99
- 'on_enter_green',
100
- 'on_after'
101
- ])
102
-
103
- called = []
104
- fsm.slow
105
- expect(called).to eql([
106
- 'on_before',
107
- 'on_before_slow',
108
- 'on_exit',
109
- 'on_exit_green',
110
- 'on_transition',
111
- 'on_transition_yellow',
112
- 'on_enter',
113
- 'on_enter_yellow',
114
- 'on_after',
115
- 'on_after_slow'
116
- ])
117
-
118
- called = []
119
- fsm.stop
120
- expect(called).to eql([
121
- 'on_before',
122
- 'on_before_stop',
123
- 'on_exit',
124
- 'on_exit_yellow',
125
- 'on_transition',
126
- 'on_transition_red',
127
- 'on_enter',
128
- 'on_enter_red',
129
- 'on_after',
130
- 'on_after_stop'
131
- ])
132
-
133
- called = []
134
- fsm.ready
135
- expect(called).to eql([
136
- 'on_before',
137
- 'on_before_ready',
138
- 'on_exit',
139
- 'on_exit_red',
140
- 'on_transition',
141
- 'on_transition_yellow',
142
- 'on_enter',
143
- 'on_enter_yellow',
144
- 'on_after',
145
- 'on_after_ready'
146
- ])
147
-
148
- called = []
149
- fsm.go
150
- expect(called).to eql([
151
- 'on_before',
152
- 'on_before_go',
153
- 'on_exit',
154
- 'on_exit_yellow',
155
- 'on_transition',
156
- 'on_transition_green',
157
- 'on_enter',
158
- 'on_enter_green',
159
- 'on_after',
160
- 'on_after_go'
161
- ])
162
- end
163
-
164
- it "maintains transition execution sequence from UML statechart" do
165
- called = []
166
- fsm = FiniteMachine.new do
167
- initial :previous, silent: false
168
-
169
- event :go, :previous => :next, if: -> { called << 'guard'; true}
170
-
171
- on_exit { |event| called << "exit_#{event.from}" }
172
- on_before { |event| called << "before_#{event.name}" }
173
- on_transition { |event| called << "transition_#{event.from}_#{event.to}"}
174
- on_enter { |event| called << "enter_#{event.to}"}
175
- on_after { |event| called << "after_#{event.name}" }
176
- end
177
-
178
- expect(fsm.current).to eq(:previous)
179
- fsm.go
180
- expect(called).to eq([
181
- 'before_init',
182
- 'exit_none',
183
- 'transition_none_previous',
184
- 'enter_previous',
185
- 'after_init',
186
- 'before_go',
187
- 'guard',
188
- 'exit_previous',
189
- 'transition_previous_next',
190
- 'enter_next',
191
- 'after_go'
192
- ])
193
- end
194
-
195
- it "allows multiple callbacks for the same state" do
196
- called = []
197
- fsm = FiniteMachine.new do
198
- initial :green, silent: false
199
-
200
- event :slow, :green => :yellow
201
- event :stop, :yellow => :red
202
- event :ready, :red => :yellow
203
- event :go, :yellow => :green
204
-
205
- # generic state callbacks
206
- on_enter do |event| called << 'on_enter' end
207
- on_transition do |event| called << 'on_transition' end
208
- on_exit do |event| called << 'on_exit' end
209
-
210
- # generic event callbacks
211
- on_before do |event| called << 'on_before' end
212
- on_after do |event| called << 'on_after' end
213
-
214
- # state callbacks
215
- on_exit :green do |event| called << 'on_exit_green_1' end
216
- on_exit :green do |event| called << 'on_exit_green_2' end
217
- on_enter :yellow do |event| called << 'on_enter_yellow_1' end
218
- on_enter :yellow do |event| called << 'on_enter_yellow_2' end
219
- on_transition :yellow do |event| called << 'on_transition_yellow_1' end
220
- on_transition :yellow do |event| called << 'on_transition_yellow_2' end
221
-
222
- # event callbacks
223
- on_before :slow do |event| called << 'on_before_slow_1' end
224
- on_before :slow do |event| called << 'on_before_slow_2' end
225
- on_after :slow do |event| called << 'on_after_slow_1' end
226
- on_after :slow do |event| called << 'on_after_slow_2' end
227
- end
228
-
229
- expect(fsm.current).to eql(:green)
230
- expect(called).to eql([
231
- 'on_before',
232
- 'on_exit',
233
- 'on_transition',
234
- 'on_enter',
235
- 'on_after'
236
- ])
237
- called = []
238
- fsm.slow
239
- expect(fsm.current).to eql(:yellow)
240
- expect(called).to eql([
241
- 'on_before',
242
- 'on_before_slow_1',
243
- 'on_before_slow_2',
244
- 'on_exit',
245
- 'on_exit_green_1',
246
- 'on_exit_green_2',
247
- 'on_transition',
248
- 'on_transition_yellow_1',
249
- 'on_transition_yellow_2',
250
- 'on_enter',
251
- 'on_enter_yellow_1',
252
- 'on_enter_yellow_2',
253
- 'on_after',
254
- 'on_after_slow_1',
255
- 'on_after_slow_2'
256
- ])
257
- end
258
-
259
- it "allows for fluid callback definition" do
260
- called = []
261
- fsm = FiniteMachine.new do
262
- initial :green
263
-
264
- event :slow, :green => :yellow
265
- event :stop, :yellow => :red
266
- event :ready, :red => :yellow
267
- event :go, :yellow => :green
268
-
269
- # state callbacks
270
- on_exit_green do |event| called << 'on_exit_green' end
271
- on_enter_yellow do |event| called << 'on_enter_yellow' end
272
- on_transition_yellow do |event| called << 'on_transition_yellow' end
273
-
274
- # event callbacks
275
- on_before_slow do |event| called << 'on_before_slow' end
276
- on_after_slow do |event| called << 'on_after_slow' end
277
- end
278
-
279
- called = []
280
- fsm.slow
281
- expect(fsm.current).to eql(:yellow)
282
- expect(called).to eql([
283
- 'on_before_slow',
284
- 'on_exit_green',
285
- 'on_transition_yellow',
286
- 'on_enter_yellow',
287
- 'on_after_slow'
288
- ])
289
- end
290
-
291
- it "passes event object to callback" do
292
- evt = nil
293
- fsm = FiniteMachine.new do
294
- initial :green
295
-
296
- event :slow, :green => :yellow
297
-
298
- on_enter(:yellow) { |e| evt = e }
299
- end
300
-
301
- expect(fsm.current).to eql(:green)
302
- fsm.slow
303
- expect(fsm.current).to eql(:yellow)
304
-
305
- expect(evt.from).to eql(:green)
306
- expect(evt.to).to eql(:yellow)
307
- expect(evt.name).to eql(:slow)
308
- end
309
-
310
- it "identifies the from state for callback event parameter" do
311
- evt = nil
312
- fsm = FiniteMachine.new do
313
- initial :green
314
-
315
- event :slow, [:red, :blue, :green] => :yellow
316
- event :fast, :red => :purple
317
-
318
- on_enter(:yellow) { |e| evt = e }
319
- end
320
-
321
- expect(fsm.current).to eql(:green)
322
- fsm.slow
323
- expect(fsm.current).to eql(:yellow)
324
-
325
- expect(evt.from).to eql(:green)
326
- expect(evt.to).to eql(:yellow)
327
- expect(evt.name).to eql(:slow)
328
- end
329
-
330
- it "passes extra parameters to callbacks" do
331
- expected = {name: :init, from: :none, to: :green, a: nil, b: nil, c: nil }
332
-
333
- callback = Proc.new { |event, a, b, c|
334
- target.expect(event.from).to target.eql(expected[:from])
335
- target.expect(event.to).to target.eql(expected[:to])
336
- target.expect(event.name).to target.eql(expected[:name])
337
- target.expect(a).to target.eql(expected[:a])
338
- target.expect(b).to target.eql(expected[:b])
339
- target.expect(c).to target.eql(expected[:c])
340
- }
341
-
342
- fsm = FiniteMachine.new(self) do
343
- initial :green
344
-
345
- event :slow, :green => :yellow
346
- event :stop, :yellow => :red
347
- event :ready, :red => :yellow
348
- event :go, :yellow => :green
349
-
350
- # generic state callbacks
351
- on_enter(&callback)
352
- on_transition(&callback)
353
- on_exit(&callback)
354
-
355
- # generic event callbacks
356
- on_before(&callback)
357
- on_after(&callback)
358
-
359
- # state callbacks
360
- on_enter :green, &callback
361
- on_enter :yellow, &callback
362
- on_enter :red, &callback
363
-
364
- on_transition :green , &callback
365
- on_transition :yellow, &callback
366
- on_transition :red , &callback
367
-
368
- on_exit :green , &callback
369
- on_exit :yellow, &callback
370
- on_exit :red , &callback
371
-
372
- # event callbacks
373
- on_before :slow , &callback
374
- on_before :stop , &callback
375
- on_before :ready, &callback
376
- on_before :go , &callback
377
-
378
- on_after :slow , &callback
379
- on_after :stop , &callback
380
- on_after :ready, &callback
381
- on_after :go , &callback
382
- end
383
-
384
- expected = {name: :slow, from: :green, to: :yellow, a: 1, b: 2, c: 3}
385
- fsm.slow(1, 2, 3)
386
-
387
- expected = {name: :stop, from: :yellow, to: :red, a: 'foo', b: 'bar'}
388
- fsm.stop('foo', 'bar')
389
-
390
- expected = {name: :ready, from: :red, to: :yellow, a: :foo, b: :bar}
391
- fsm.ready(:foo, :bar)
392
-
393
- expected = {name: :go, from: :yellow, to: :green, a: nil, b: nil}
394
- fsm.go(nil, nil)
395
- end
396
-
397
- it "sets callback parameters correctly for transition from :any state" do
398
- expected = {name: :init, from: :none, to: :green, a: nil, b: nil, c: nil }
399
-
400
- callback = Proc.new { |event, a, b, c|
401
- target.expect(event.from).to target.eql(expected[:from])
402
- target.expect(event.to).to target.eql(expected[:to])
403
- target.expect(event.name).to target.eql(expected[:name])
404
- target.expect(a).to target.eql(expected[:a])
405
- target.expect(b).to target.eql(expected[:b])
406
- target.expect(c).to target.eql(expected[:c])
407
- }
408
-
409
- fsm = FiniteMachine.new(self) do
410
- initial :red
411
-
412
- event :power_on, :off => :red
413
- event :power_off, any_state => :off
414
- event :go, :red => :green
415
- event :slow, :green => :yellow
416
- event :stop, :yellow => :red
417
-
418
- # generic state callbacks
419
- on_enter(&callback)
420
- on_transition(&callback)
421
- on_exit(&callback)
422
-
423
- # generic event callbacks
424
- on_before(&callback)
425
- on_after(&callback)
426
-
427
- # state callbacks
428
- on_enter :green, &callback
429
- on_enter :yellow, &callback
430
- on_enter :red, &callback
431
- on_enter :off, &callback
432
- on_enter :off, &callback
433
-
434
- on_transition :green, &callback
435
- on_transition :yellow, &callback
436
- on_transition :red, &callback
437
- on_transition :off, &callback
438
- on_transition :off, &callback
439
-
440
- on_exit :green, &callback
441
- on_exit :yellow, &callback
442
- on_exit :red, &callback
443
- on_exit :off, &callback
444
- on_exit :off, &callback
445
-
446
- # event callbacks
447
- on_before :power_on, &callback
448
- on_before :power_off, &callback
449
- on_before :go, &callback
450
- on_before :slow, &callback
451
- on_before :stop, &callback
452
-
453
- on_after :power_on, &callback
454
- on_after :power_off, &callback
455
- on_after :go, &callback
456
- on_after :slow, &callback
457
- on_after :stop, &callback
458
- end
459
-
460
- expect(fsm.current).to eq(:red)
461
-
462
- expected = {name: :go, from: :red, to: :green, a: 1, b: 2, c: 3 }
463
- fsm.go(1, 2, 3)
464
-
465
- expected = {name: :slow, from: :green, to: :yellow, a: 4, b: 5, c: 6}
466
- fsm.slow(4, 5, 6)
467
-
468
- expected = {name: :stop, from: :yellow, to: :red, a: 7, b: 8, c: 9}
469
- fsm.stop(7, 8, 9)
470
-
471
- expected = {name: :power_off, from: :red, to: :off, a: 10, b: 11, c: 12}
472
- fsm.power_off(10, 11, 12)
473
- end
474
-
475
- it "raises an error with invalid callback name" do
476
- expect {
477
- FiniteMachine.new do
478
- initial :green
479
-
480
- event :slow, :green => :yellow
481
-
482
- on_enter(:magic) { |event| called << 'on_enter'}
483
- end
484
- }.to raise_error(FiniteMachine::InvalidCallbackNameError, /\"magic\" is not a valid callback name/)
485
- end
486
-
487
- it "doesn't allow to mix state callback with event name" do
488
- expect {
489
- FiniteMachine.new do
490
- event :slow, :green => :yellow
491
-
492
- on_enter_slow do |event| end
493
- end
494
- }.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.")
495
- end
496
-
497
- it "doesn't allow to mix event callback with state name" do
498
- expect {
499
- FiniteMachine.new do
500
- event :slow, :green => :yellow
501
-
502
- on_before_green do |event| end
503
- end
504
- }.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.')
505
- end
506
-
507
- it "propagates exceptions raised inside callback" do
508
- fsm = FiniteMachine.new do
509
- initial :green
510
-
511
- event :slow, :green => :yellow
512
-
513
- on_enter(:yellow) { raise RuntimeError }
514
- end
515
-
516
- expect(fsm.current).to eql(:green)
517
- expect { fsm.slow }.to raise_error(RuntimeError)
518
- end
519
-
520
- it "executes callbacks with multiple 'from' transitions" do
521
- called = []
522
- fsm = FiniteMachine.new do
523
- initial :green
524
-
525
- event :stop, :green => :yellow
526
- event :stop, :yellow => :red
527
-
528
- on_before_stop do |event|
529
- called << 'on_before_stop'
530
- end
531
- end
532
- expect(fsm.current).to eql(:green)
533
- fsm.stop
534
- expect(fsm.current).to eql(:yellow)
535
- fsm.stop
536
- expect(fsm.current).to eql(:red)
537
- expect(called).to eql([
538
- 'on_before_stop',
539
- 'on_before_stop'
540
- ])
541
- end
542
-
543
- it "allows to define callbacks on machine instance" do
544
- called = []
545
- fsm = FiniteMachine.new do
546
- initial :green
547
-
548
- event :slow, :green => :yellow
549
- event :stop, :yellow => :red
550
- event :ready, :red => :yellow
551
- event :go, :yellow => :green
552
- end
553
-
554
- fsm.on_enter_yellow do |event|
555
- called << 'on_enter_yellow'
556
- end
557
-
558
- expect(fsm.current).to eql(:green)
559
- fsm.slow
560
- expect(called).to eql([
561
- 'on_enter_yellow'
562
- ])
563
- end
564
-
565
- it "raises error for unknown callback" do
566
- expect {
567
- FiniteMachine.new do
568
- initial :green
569
-
570
- event :slow, :green => :yellow
571
- event :stop, :yellow => :red
572
- event :ready, :red => :yellow
573
- event :go, :yellow => :green
574
-
575
- on_enter_unknown do |event| end
576
- end
577
- }.to raise_error(NameError, /`on_enter_unknown'/)
578
- end
579
-
580
- it "triggers callbacks only once" do
581
- called = []
582
- fsm = FiniteMachine.new do
583
- initial :green, silent: false
584
-
585
- event :slow, :green => :yellow
586
- event :go, :yellow => :green
587
-
588
- # state callbacks
589
- once_on_enter_green do |event| called << 'once_on_enter_green' end
590
- once_on_enter_yellow do |event| called << 'once_on_enter_yellow' end
591
-
592
- once_on_transition_green do |event| called << 'once_on_transition_green' end
593
- once_on_transition_yellow do |event| called << 'once_on_transition_yellow' end
594
- once_on_exit_none do |event| called << 'once_on_exit_none' end
595
- once_on_exit_green do |event| called << 'once_on_exit_green' end
596
- once_on_exit_yellow do |event| called << 'once_on_exit_yellow' end
597
-
598
- # event callbacks
599
- once_on_before_init do |event| called << 'once_on_before_init' end
600
- once_on_before_slow do |event| called << 'once_on_before_slow' end
601
- once_on_before_go do |event| called << 'once_on_before_go' end
602
-
603
- once_on_after_init do |event| called << 'once_on_after_init' end
604
- once_on_after_slow do |event| called << 'once_on_after_slow' end
605
- once_on_after_go do |event| called << 'once_on_after_go' end
606
- end
607
- expect(fsm.current).to eql(:green)
608
- fsm.slow
609
- expect(fsm.current).to eql(:yellow)
610
- fsm.go
611
- expect(fsm.current).to eql(:green)
612
- fsm.slow
613
- expect(fsm.current).to eql(:yellow)
614
- expect(called).to eql([
615
- 'once_on_before_init',
616
- 'once_on_exit_none',
617
- 'once_on_transition_green',
618
- 'once_on_enter_green',
619
- 'once_on_after_init',
620
- 'once_on_before_slow',
621
- 'once_on_exit_green',
622
- 'once_on_transition_yellow',
623
- 'once_on_enter_yellow',
624
- 'once_on_after_slow',
625
- 'once_on_before_go',
626
- 'once_on_exit_yellow',
627
- 'once_on_after_go'
628
- ])
629
- end
630
-
631
- xit "groups callbacks"
632
-
633
- it "groups states from separate events with the same name" do
634
- callbacks = []
635
- fsm = FiniteMachine.new do
636
- initial :initial, silent: false
637
-
638
- event :bump, :initial => :low
639
- event :bump, :low => :medium
640
- event :bump, :medium => :high
641
-
642
- on_enter do |event|
643
- callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
644
- end
645
- on_exit do |event|
646
- callbacks << "exit_#{event.name}_#{event.from}_#{event.to}"
647
- end
648
- on_before do |event|
649
- callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
650
- end
651
- on_after do |event|
652
- callbacks << "after_#{event.name}_#{event.from}_#{event.to}"
653
- end
654
- end
655
-
656
- expect(fsm.current).to eq(:initial)
657
- fsm.bump
658
- expect(callbacks).to eq([
659
- 'before_init_none_initial',
660
- 'exit_init_none_initial',
661
- 'enter_init_none_initial',
662
- 'after_init_none_initial',
663
- 'before_bump_initial_low',
664
- 'exit_bump_initial_low',
665
- 'enter_bump_initial_low',
666
- 'after_bump_initial_low'
667
- ])
668
- fsm.bump
669
- expect(callbacks).to eq([
670
- 'before_init_none_initial',
671
- 'exit_init_none_initial',
672
- 'enter_init_none_initial',
673
- 'after_init_none_initial',
674
- 'before_bump_initial_low',
675
- 'exit_bump_initial_low',
676
- 'enter_bump_initial_low',
677
- 'after_bump_initial_low',
678
- 'before_bump_low_medium',
679
- 'exit_bump_low_medium',
680
- 'enter_bump_low_medium',
681
- 'after_bump_low_medium'
682
- ])
683
- fsm.bump
684
- expect(callbacks).to eq([
685
- 'before_init_none_initial',
686
- 'exit_init_none_initial',
687
- 'enter_init_none_initial',
688
- 'after_init_none_initial',
689
- 'before_bump_initial_low',
690
- 'exit_bump_initial_low',
691
- 'enter_bump_initial_low',
692
- 'after_bump_initial_low',
693
- 'before_bump_low_medium',
694
- 'exit_bump_low_medium',
695
- 'enter_bump_low_medium',
696
- 'after_bump_low_medium',
697
- 'before_bump_medium_high',
698
- 'exit_bump_medium_high',
699
- 'enter_bump_medium_high',
700
- 'after_bump_medium_high'
701
- ])
702
- end
703
-
704
- it "groups states under event name" do
705
- callbacks = []
706
- fsm = FiniteMachine.new do
707
- initial :initial, silent: false
708
-
709
- event :bump, :initial => :low,
710
- :low => :medium,
711
- :medium => :high
712
-
713
- on_enter do |event|
714
- callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
715
- end
716
- on_before do |event|
717
- callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
718
- end
719
- end
720
-
721
- expect(fsm.current).to eq(:initial)
722
- fsm.bump
723
- expect(callbacks).to eq([
724
- 'before_init_none_initial',
725
- 'enter_init_none_initial',
726
- 'before_bump_initial_low',
727
- 'enter_bump_initial_low'
728
- ])
729
- fsm.bump
730
- expect(callbacks).to eq([
731
- 'before_init_none_initial',
732
- 'enter_init_none_initial',
733
- 'before_bump_initial_low',
734
- 'enter_bump_initial_low',
735
- 'before_bump_low_medium',
736
- 'enter_bump_low_medium'
737
- ])
738
- fsm.bump
739
- expect(callbacks).to eq([
740
- 'before_init_none_initial',
741
- 'enter_init_none_initial',
742
- 'before_bump_initial_low',
743
- 'enter_bump_initial_low',
744
- 'before_bump_low_medium',
745
- 'enter_bump_low_medium',
746
- 'before_bump_medium_high',
747
- 'enter_bump_medium_high'
748
- ])
749
- end
750
-
751
- it "permits state and event with the same name" do
752
- called = []
753
- fsm = FiniteMachine.new do
754
- initial :on_hook, silent: false
755
-
756
- event :off_hook, :on_hook => :off_hook
757
- event :on_hook, :off_hook => :on_hook
758
-
759
- on_before(:on_hook) { |event| called << "on_before_#{event.name}"}
760
- on_enter(:on_hook) { |event| called << "on_enter_#{event.to}"}
761
- end
762
- expect(fsm.current).to eq(:on_hook)
763
- expect(called).to eq([
764
- 'on_enter_on_hook'
765
- ])
766
- fsm.off_hook
767
- expect(fsm.current).to eq(:off_hook)
768
- fsm.on_hook
769
- expect(called).to eq([
770
- 'on_enter_on_hook',
771
- 'on_before_on_hook',
772
- 'on_enter_on_hook'
773
- ]);
774
- end
775
-
776
- it "allows to selectively silence events" do
777
- called = []
778
- fsm = FiniteMachine.new do
779
- initial :yellow
780
-
781
- event :go, :yellow => :green, silent: true
782
- event :stop, :green => :red
783
-
784
- on_enter :green do |event| called << 'on_enter_yellow' end
785
- on_enter :red do |event| called << 'on_enter_red' end
786
- end
787
- expect(fsm.current).to eq(:yellow)
788
- fsm.go
789
- fsm.stop
790
- expect(called).to eq(['on_enter_red'])
791
- end
792
-
793
- it "executes event-based callbacks even when state does not change" do
794
- called = []
795
- fsm = FiniteMachine.new do
796
- initial :active
797
-
798
- event :advance, :active => :inactive, if: -> { false }
799
- event :advance, :inactive => :active, if: -> { false }
800
-
801
- on_before do |event|
802
- called << "before_#{event.name}_#{event.from}_#{event.to}"
803
- end
804
- on_after do |event|
805
- called << "after_#{event.name}_#{event.from}_#{event.to}"
806
- end
807
- end
808
- expect(fsm.current).to eq(:active)
809
- fsm.advance
810
- expect(fsm.current).to eq(:active)
811
- expect(called).to eq([
812
- 'before_advance_active_inactive',
813
- 'after_advance_active_inactive'
814
- ])
815
- end
816
-
817
- it "doesn't transition if error raised in callback" do
818
- fsm = FiniteMachine.new do
819
- initial :green
820
-
821
- event :slow, :green => :yellow
822
-
823
- on_enter { raise RuntimeError }
824
- end
825
-
826
- expect {
827
- fsm.slow
828
- }.to raise_error(RuntimeError)
829
- expect(fsm.current).to eq(:green)
830
- end
831
-
832
- xit "narrows down on_transition callback to state transition" do
833
- called = []
834
- fsm = FiniteMachine.new do
835
- initial :red
836
-
837
- event :ready, :red => :yellow
838
- event :go, :yellow => :green
839
- event :stop, :green => :red
840
-
841
- on_transition :yellow => :green do
842
- called << 'on_transition_yellow_green'
843
- end
844
- end
845
-
846
- fsm.ready
847
- fsm.go
848
-
849
- expect(called).to eq(['on_transition_yellow_green'])
850
- end
851
- end