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,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