finite_machine 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, 'can?' do
4
- before(:each) {
5
- stub_const("Bug", Class.new do
6
- def pending?
7
- false
8
- end
9
- end)
10
- }
11
-
12
- it "allows to check if event can be fired" do
13
- fsm = FiniteMachine.new do
14
- initial :green
15
-
16
- event :slow, :green => :yellow
17
- event :stop, :yellow => :red
18
- event :ready, :red => :yellow
19
- event :go, :yellow => :green
20
- end
21
-
22
- expect(fsm.current).to eql(:green)
23
-
24
- expect(fsm.can?(:slow)).to be(true)
25
- expect(fsm.cannot?(:stop)).to be(true)
26
- expect(fsm.can?(:ready)).to be(false)
27
- expect(fsm.can?(:go)).to be(false)
28
-
29
- fsm.slow
30
- expect(fsm.current).to eql(:yellow)
31
-
32
- expect(fsm.can?(:slow)).to be(false)
33
- expect(fsm.can?(:stop)).to be(true)
34
- expect(fsm.can?(:ready)).to be(false)
35
- expect(fsm.can?(:go)).to be(true)
36
-
37
- fsm.stop
38
- expect(fsm.current).to eql(:red)
39
-
40
- expect(fsm.can?(:slow)).to be(false)
41
- expect(fsm.can?(:stop)).to be(false)
42
- expect(fsm.can?(:ready)).to be(true)
43
- expect(fsm.can?(:go)).to be(false)
44
-
45
- fsm.ready
46
- expect(fsm.current).to eql(:yellow)
47
-
48
- expect(fsm.can?(:slow)).to be(false)
49
- expect(fsm.can?(:stop)).to be(true)
50
- expect(fsm.can?(:ready)).to be(false)
51
- expect(fsm.can?(:go)).to be(true)
52
- end
53
-
54
- context 'with conditionl transition' do
55
- it "evalutes condition with parameters" do
56
- fsm = FiniteMachine.new do
57
- initial :green
58
-
59
- event :slow, :green => :yellow
60
- event :stop, :yellow => :red, if: proc { |_, state| state }
61
- end
62
- expect(fsm.current).to eq(:green)
63
- expect(fsm.can?(:slow)).to be(true)
64
- expect(fsm.can?(:stop)).to be(false)
65
-
66
- fsm.slow
67
- expect(fsm.current).to eq(:yellow)
68
- expect(fsm.can?(:stop, false)).to be(false)
69
- expect(fsm.can?(:stop, true)).to be(true)
70
- end
71
-
72
- it "checks against target and grouped events" do
73
- bug = Bug.new
74
- fsm = FiniteMachine.new(bug) do
75
- initial :initial
76
-
77
- event :bump, :initial => :low
78
- event :bump, :low => :medium, if: :pending?
79
- event :bump, :medium => :high
80
- end
81
- expect(fsm.current).to eq(:initial)
82
-
83
- expect(fsm.can?(:bump)).to be(true)
84
- fsm.bump
85
- expect(fsm.can?(:bump)).to be(false)
86
- end
87
- end
88
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, '#cancel_event' do
4
- it "cancels transition on event callback" do
5
- fsm = FiniteMachine.new do
6
- initial :green
7
-
8
- event :slow, :green => :yellow
9
- event :go, :yellow => :green
10
-
11
- on_exit :green do |event|
12
- cancel_event(event)
13
- end
14
- end
15
-
16
- expect(fsm.current).to eql(:green)
17
- fsm.slow
18
- expect(fsm.current).to eql(:green)
19
- end
20
-
21
- it "stops executing callbacks when cancelled" do
22
- called = []
23
-
24
- fsm = FiniteMachine.new do
25
- initial :initial
26
-
27
- event :bump, initial: :low
28
-
29
- on_before do |event|
30
- called << "enter_#{event.name}_#{event.from}_#{event.to}"
31
-
32
- cancel_event(event)
33
- end
34
-
35
- on_exit :initial do |event| called << "exit_initial" end
36
- on_exit do |event| called << "exit_any" end
37
- on_enter :low do |event| called << "enter_low" end
38
- on_after :bump do |event| called << "after_#{event.name}" end
39
- on_after do |event| called << "after_any" end
40
- end
41
-
42
- fsm.bump
43
-
44
- expect(called).to eq(['enter_bump_initial_low'])
45
- end
46
- end
@@ -1,295 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, '#choice' do
4
- before(:each) {
5
- stub_const("User", Class.new do
6
- def promo?(token = false)
7
- token == :yes
8
- end
9
- end)
10
- }
11
-
12
- it "allows for static choice based on conditional branching" do
13
- called = []
14
- fsm = FiniteMachine.new do
15
- initial :company_form
16
-
17
- event :next, from: :company_form do
18
- choice :agreement_form, if: -> { false }
19
- choice :promo_form, if: -> { false }
20
- choice :official_form, if: -> { true }
21
- end
22
-
23
- on_exit do |event| called << "on_exit_#{event.from}" end
24
- on_enter do |event| called << "on_enter_#{event.to}" end
25
- end
26
- expect(fsm.current).to eq(:company_form)
27
- fsm.next
28
- expect(fsm.current).to eq(:official_form)
29
- expect(called).to eq([
30
- 'on_exit_company_form',
31
- 'on_enter_official_form'
32
- ])
33
- end
34
-
35
- it "allows for dynamic choice based on conditional branching" do
36
- fsm = FiniteMachine.new do
37
- initial :company_form
38
-
39
- event :next, from: :company_form do
40
- choice :agreement_form, if: proc { |_, a| a < 1 }
41
- choice :promo_form, if: proc { |_, a| a == 1 }
42
- choice :official_form, if: proc { |_, a| a > 1 }
43
- end
44
- end
45
- expect(fsm.current).to eq(:company_form)
46
- fsm.next(0)
47
- expect(fsm.current).to eq(:agreement_form)
48
-
49
- fsm.restore!(:company_form)
50
- fsm.next(1)
51
- expect(fsm.current).to eq(:promo_form)
52
-
53
- fsm.restore!(:company_form)
54
- fsm.next(2)
55
- expect(fsm.current).to eq(:official_form)
56
- end
57
-
58
- it "allows for dynamic choice based on conditional branching and target" do
59
- user = User.new
60
- fsm = FiniteMachine.new(user) do
61
- initial :company_form
62
-
63
- event :next, from: :company_form do
64
- choice :agreement_form, if: proc { |_user, token| _user.promo?(token) }
65
- choice :promo_form, unless: proc { |_user, token| _user.promo?(token) }
66
- end
67
- end
68
- expect(fsm.current).to eq(:company_form)
69
- fsm.next(:no)
70
- expect(fsm.current).to eq(:promo_form)
71
- fsm.restore!(:company_form)
72
- fsm.next(:yes)
73
- expect(fsm.current).to eq(:agreement_form)
74
- end
75
-
76
- it "chooses state when skipped if/unless" do
77
- fsm = FiniteMachine.new do
78
- initial :company_form
79
-
80
- event :next, from: :company_form do
81
- choice :agreement_form, if: -> { false }
82
- choice :promo_form
83
- choice :official_form, if: -> { true }
84
- end
85
- end
86
- expect(fsm.current).to eq(:company_form)
87
- fsm.next
88
- expect(fsm.current).to eq(:promo_form)
89
- end
90
-
91
- it "chooses default state when branching conditions don't match" do
92
- fsm = FiniteMachine.new do
93
- initial :company_form
94
-
95
- event :next, from: :company_form do
96
- choice :agreement_form, if: -> { false }
97
- choice :promo_form, if: -> { false }
98
- default :official_form
99
- end
100
- end
101
- expect(fsm.current).to eq(:company_form)
102
- fsm.next
103
- expect(fsm.current).to eq(:official_form)
104
- end
105
-
106
- it "fails to transition when no condition matches without default state" do
107
- fsm = FiniteMachine.new do
108
- initial :company_form
109
-
110
- event :next, from: :company_form do
111
- choice :agreement_form, if: -> { false }
112
- choice :promo_form, if: -> { false }
113
- end
114
- end
115
- expect(fsm.current).to eq(:company_form)
116
- fsm.next
117
- expect(fsm.current).to eq(:company_form)
118
- end
119
-
120
- it "allows to transition from multiple states to choice pseudostate" do
121
- fsm = FiniteMachine.new do
122
- initial :red
123
-
124
- event :go, from: [:yellow, :red] do
125
- choice :pink, if: -> { false }
126
- choice :green
127
- end
128
- end
129
- expect(fsm.current).to eq(:red)
130
- fsm.go
131
- expect(fsm.current).to eq(:green)
132
- fsm.restore!(:yellow)
133
- expect(fsm.current).to eq(:yellow)
134
- fsm.go
135
- expect(fsm.current).to eq(:green)
136
- end
137
-
138
- it "allows to transition from any state to choice pseudo state" do
139
- fsm = FiniteMachine.new do
140
- initial :red
141
-
142
- event :go, from: any_state do
143
- choice :pink, if: -> { false }
144
- choice :green
145
- end
146
- end
147
- expect(fsm.current).to eq(:red)
148
- fsm.go
149
- expect(fsm.current).to eq(:green)
150
- end
151
-
152
- it "groups correctly events under the same name" do
153
- fsm = FiniteMachine.new do
154
- initial :red
155
-
156
- event :next, from: :yellow, to: :green
157
-
158
- event :next, from: :red do
159
- choice :pink, if: -> { false }
160
- choice :yellow
161
- end
162
- end
163
- expect(fsm.current).to eq(:red)
164
- fsm.next
165
- expect(fsm.current).to eq(:yellow)
166
- fsm.next
167
- expect(fsm.current).to eq(:green)
168
- end
169
-
170
- it "performs matching transitions for multiple event definitions with the same name" do
171
- ticket = double(:ticket, :pending? => true, :finished? => true)
172
- fsm = FiniteMachine.new(ticket) do
173
- initial :inactive
174
-
175
- event :advance, from: [:inactive, :paused, :fulfilled] do
176
- choice :active, if: proc { |_ticket| !_ticket.pending? }
177
- end
178
-
179
- event :advance, from: [:inactive, :active, :fulfilled] do
180
- choice :paused, if: proc { |_ticket| _ticket.pending? }
181
- end
182
-
183
- event :advance, from: [:inactive, :active, :paused] do
184
- choice :fulfilled, if: proc { |_ticket| _ticket.finished? }
185
- end
186
- end
187
- expect(fsm.current).to eq(:inactive)
188
- fsm.advance
189
- expect(fsm.current).to eq(:paused)
190
- fsm.advance
191
- expect(fsm.current).to eq(:fulfilled)
192
- end
193
-
194
- it "does not transition when no matching choice for multiple event definitions" do
195
- ticket = double(:ticket, :pending? => true, :finished? => false)
196
- called = []
197
- fsm = FiniteMachine.new(ticket) do
198
- initial :inactive
199
-
200
- event :advance, from: [:inactive, :paused, :fulfilled] do
201
- choice :active, if: proc { |_ticket| !_ticket.pending? }
202
- end
203
-
204
- event :advance, from: [:inactive, :active, :fulfilled] do
205
- choice :paused, if: proc { |_ticket| _ticket.pending? }
206
- end
207
-
208
- event :advance, from: [:inactive, :active, :paused] do
209
- choice :fulfilled, if: proc { |_ticket| _ticket.finished? }
210
- end
211
-
212
- on_before(:advance) { called << 'on_before_advance' }
213
- on_after(:advance) { called << 'on_after_advance' }
214
- end
215
- expect(fsm.current).to eq(:inactive)
216
- fsm.advance
217
- expect(fsm.current).to eq(:paused)
218
- fsm.advance
219
- expect(fsm.current).to eq(:paused)
220
- expect(called).to eq([
221
- 'on_before_advance',
222
- 'on_after_advance',
223
- 'on_before_advance',
224
- 'on_after_advance'
225
- ])
226
- end
227
-
228
- it "sets callback properties correctly" do
229
- expected = {name: :init, from: :none, to: :red, a: nil, b: nil, c: nil }
230
-
231
- callback = Proc.new { |event, a, b, c|
232
- target.expect(event.from).to target.eql(expected[:from])
233
- target.expect(event.to).to target.eql(expected[:to])
234
- target.expect(event.name).to target.eql(expected[:name])
235
- target.expect(a).to target.eql(expected[:a])
236
- target.expect(b).to target.eql(expected[:b])
237
- target.expect(c).to target.eql(expected[:c])
238
- }
239
-
240
- fsm = FiniteMachine.new(self) do
241
- initial :red
242
-
243
- event :next, from: :red do
244
- choice :green, if: -> { false }
245
- choice :yellow
246
- end
247
-
248
- event :next, from: :yellow do
249
- choice :green, if: -> { true }
250
- choice :yellow
251
- end
252
-
253
- event :finish, from: any_state do
254
- choice :green, if: -> { false }
255
- choice :red
256
- end
257
-
258
- # generic state callbacks
259
- on_enter(&callback)
260
- on_transition(&callback)
261
- on_exit(&callback)
262
-
263
- # generic event callbacks
264
- on_before(&callback)
265
- on_after(&callback)
266
-
267
- # state callbacks
268
- on_enter :green, &callback
269
- on_enter :yellow, &callback
270
- on_enter :red, &callback
271
-
272
- on_transition :green, &callback
273
- on_transition :yellow, &callback
274
- on_transition :red, &callback
275
-
276
- on_exit :green, &callback
277
- on_exit :yellow, &callback
278
- on_exit :red, &callback
279
-
280
- # event callbacks
281
- on_before :next, &callback
282
- on_after :next, &callback
283
- end
284
- expect(fsm.current).to eq(:red)
285
-
286
- expected = {name: :next, from: :red, to: :yellow, a: 1, b: 2, c: 3}
287
- fsm.next(1, 2, 3)
288
-
289
- expected = {name: :next, from: :yellow, to: :green, a: 4, b: 5, c: 6}
290
- fsm.next(4, 5, 6)
291
-
292
- expected = {name: :finish, from: :green, to: :red, a: 7, b: 8, c: 9}
293
- fsm.finish(7, 8, 9)
294
- end
295
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe FiniteMachine, '.define' do
4
- context 'with block' do
5
- it "creates system state machine" do
6
- stub_const("TrafficLights", FiniteMachine.define do
7
- initial :green
8
-
9
- event :slow, :green => :yellow
10
- event :stop, :yellow => :red
11
- event :ready, :red => :yellow
12
- event :go, :yellow => :green
13
- end)
14
-
15
- lights_fsm_a = TrafficLights.new
16
- lights_fsm_b = TrafficLights.new
17
-
18
- expect(lights_fsm_a.current).to eql(:green)
19
- expect(lights_fsm_b.current).to eql(:green)
20
-
21
- lights_fsm_a.slow
22
- expect(lights_fsm_a.current).to eql(:yellow)
23
- expect(lights_fsm_b.current).to eql(:green)
24
-
25
- lights_fsm_a.stop
26
- expect(lights_fsm_a.current).to eql(:red)
27
- expect(lights_fsm_b.current).to eql(:green)
28
- end
29
- end
30
-
31
- context 'without block' do
32
- it "creates state machine" do
33
- called = []
34
- stub_const("TrafficLights", FiniteMachine.define)
35
- TrafficLights.initial(:green)
36
- TrafficLights.event(:slow, :green => :yellow)
37
- TrafficLights.event(:stop, :yellow => :red)
38
- TrafficLights.event(:ready,:red => :yellow)
39
- TrafficLights.event(:go, :yellow => :green)
40
- TrafficLights.on_enter(:yellow) { |event| called << 'on_enter_yellow' }
41
- TrafficLights.handle(FiniteMachine::InvalidStateError) { |exception|
42
- called << 'error_handler'
43
- }
44
-
45
- fsm = TrafficLights.new
46
-
47
- expect(fsm.current).to eql(:green)
48
- fsm.slow
49
- expect(fsm.current).to eql(:yellow)
50
- fsm.ready
51
- expect(fsm.current).to eql(:yellow)
52
- expect(called).to match_array(['on_enter_yellow', 'error_handler'])
53
- end
54
- end
55
- end