finite_machine 0.11.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +80 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +679 -624
  5. data/lib/finite_machine.rb +35 -45
  6. data/lib/finite_machine/async_call.rb +5 -21
  7. data/lib/finite_machine/callable.rb +4 -4
  8. data/lib/finite_machine/catchable.rb +24 -14
  9. data/lib/finite_machine/choice_merger.rb +20 -20
  10. data/lib/finite_machine/const.rb +16 -0
  11. data/lib/finite_machine/definition.rb +3 -3
  12. data/lib/finite_machine/dsl.rb +98 -151
  13. data/lib/finite_machine/env.rb +4 -2
  14. data/lib/finite_machine/event_definition.rb +7 -15
  15. data/lib/finite_machine/{events_chain.rb → events_map.rb} +40 -53
  16. data/lib/finite_machine/hook_event.rb +60 -61
  17. data/lib/finite_machine/hooks.rb +44 -36
  18. data/lib/finite_machine/listener.rb +2 -2
  19. data/lib/finite_machine/logger.rb +5 -4
  20. data/lib/finite_machine/{event_queue.rb → message_queue.rb} +76 -32
  21. data/lib/finite_machine/observer.rb +71 -34
  22. data/lib/finite_machine/safety.rb +16 -14
  23. data/lib/finite_machine/state_definition.rb +3 -5
  24. data/lib/finite_machine/state_machine.rb +93 -76
  25. data/lib/finite_machine/state_parser.rb +55 -83
  26. data/lib/finite_machine/subscribers.rb +2 -2
  27. data/lib/finite_machine/threadable.rb +3 -1
  28. data/lib/finite_machine/transition.rb +34 -34
  29. data/lib/finite_machine/transition_builder.rb +23 -32
  30. data/lib/finite_machine/transition_event.rb +12 -11
  31. data/lib/finite_machine/two_phase_lock.rb +8 -6
  32. data/lib/finite_machine/undefined_transition.rb +5 -6
  33. data/lib/finite_machine/version.rb +2 -2
  34. metadata +58 -142
  35. data/.gitignore +0 -18
  36. data/.rspec +0 -5
  37. data/.ruby-gemset +0 -1
  38. data/.ruby-version +0 -1
  39. data/.travis.yml +0 -26
  40. data/Gemfile +0 -15
  41. data/Rakefile +0 -8
  42. data/assets/finite_machine_logo.png +0 -0
  43. data/examples/atm.rb +0 -45
  44. data/examples/bug_system.rb +0 -145
  45. data/finite_machine.gemspec +0 -23
  46. data/lib/finite_machine/async_proxy.rb +0 -30
  47. data/spec/integration/system_spec.rb +0 -95
  48. data/spec/spec_helper.rb +0 -33
  49. data/spec/unit/alias_target_spec.rb +0 -108
  50. data/spec/unit/async_events_spec.rb +0 -138
  51. data/spec/unit/callable/call_spec.rb +0 -113
  52. data/spec/unit/callbacks_spec.rb +0 -942
  53. data/spec/unit/can_spec.rb +0 -98
  54. data/spec/unit/choice_spec.rb +0 -331
  55. data/spec/unit/define_spec.rb +0 -55
  56. data/spec/unit/definition_spec.rb +0 -115
  57. data/spec/unit/event_names_spec.rb +0 -19
  58. data/spec/unit/event_queue_spec.rb +0 -52
  59. data/spec/unit/events_chain/add_spec.rb +0 -25
  60. data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
  61. data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
  62. data/spec/unit/events_chain/clear_spec.rb +0 -15
  63. data/spec/unit/events_chain/events_spec.rb +0 -18
  64. data/spec/unit/events_chain/inspect_spec.rb +0 -24
  65. data/spec/unit/events_chain/match_transition_spec.rb +0 -37
  66. data/spec/unit/events_chain/move_to_spec.rb +0 -48
  67. data/spec/unit/events_chain/states_for_spec.rb +0 -17
  68. data/spec/unit/events_spec.rb +0 -459
  69. data/spec/unit/handlers_spec.rb +0 -152
  70. data/spec/unit/hook_event/build_spec.rb +0 -15
  71. data/spec/unit/hook_event/eql_spec.rb +0 -36
  72. data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
  73. data/spec/unit/hook_event/initialize_spec.rb +0 -25
  74. data/spec/unit/hook_event/notify_spec.rb +0 -14
  75. data/spec/unit/hooks/call_spec.rb +0 -24
  76. data/spec/unit/hooks/clear_spec.rb +0 -16
  77. data/spec/unit/hooks/inspect_spec.rb +0 -17
  78. data/spec/unit/hooks/register_spec.rb +0 -22
  79. data/spec/unit/if_unless_spec.rb +0 -353
  80. data/spec/unit/initial_spec.rb +0 -222
  81. data/spec/unit/inspect_spec.rb +0 -17
  82. data/spec/unit/is_spec.rb +0 -55
  83. data/spec/unit/log_transitions_spec.rb +0 -30
  84. data/spec/unit/logger_spec.rb +0 -38
  85. data/spec/unit/respond_to_spec.rb +0 -38
  86. data/spec/unit/state_parser/inspect_spec.rb +0 -25
  87. data/spec/unit/state_parser/parse_spec.rb +0 -59
  88. data/spec/unit/states_spec.rb +0 -34
  89. data/spec/unit/subscribers_spec.rb +0 -42
  90. data/spec/unit/target_spec.rb +0 -225
  91. data/spec/unit/terminated_spec.rb +0 -95
  92. data/spec/unit/transition/check_conditions_spec.rb +0 -54
  93. data/spec/unit/transition/inspect_spec.rb +0 -25
  94. data/spec/unit/transition/matches_spec.rb +0 -23
  95. data/spec/unit/transition/states_spec.rb +0 -31
  96. data/spec/unit/transition/to_state_spec.rb +0 -27
  97. data/spec/unit/trigger_spec.rb +0 -22
  98. data/spec/unit/undefined_transition/eql_spec.rb +0 -17
  99. data/tasks/console.rake +0 -11
  100. data/tasks/coverage.rake +0 -11
  101. data/tasks/spec.rake +0 -29
@@ -1,152 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, 'handlers' do
6
-
7
- before(:each) {
8
- stub_const("DummyLogger", Class.new do
9
- attr_reader :result
10
-
11
- def log_error(exception)
12
- @result = "log_error(#{exception})"
13
- end
14
-
15
- def raise_error
16
- raise FiniteMachine::TransitionError
17
- end
18
- end)
19
- }
20
-
21
- it "allows to customise error handling" do
22
- called = []
23
- fsm = FiniteMachine.define do
24
- initial :green
25
-
26
- events {
27
- event :slow, :green => :yellow
28
- event :stop, :yellow => :red
29
- }
30
-
31
- handlers {
32
- handle FiniteMachine::InvalidStateError do |exception|
33
- called << 'invalidstate'
34
- end
35
- }
36
- end
37
-
38
- expect(fsm.current).to eql(:green)
39
- fsm.stop
40
- expect(fsm.current).to eql(:green)
41
- expect(called).to eql([
42
- 'invalidstate'
43
- ])
44
- end
45
-
46
- it 'allows for :with to be symbol' do
47
- logger = DummyLogger.new
48
- fsm = FiniteMachine.define do
49
- initial :green
50
-
51
- target logger
52
-
53
- events {
54
- event :slow, :green => :yellow
55
- event :stop, :yellow => :red
56
- }
57
-
58
- handlers {
59
- handle FiniteMachine::InvalidStateError, with: :log_error
60
- }
61
- end
62
-
63
- expect(fsm.current).to eql(:green)
64
- fsm.stop
65
- expect(fsm.current).to eql(:green)
66
- expect(logger.result).to eql('log_error(FiniteMachine::InvalidStateError)')
67
- end
68
-
69
- it 'allows for error type as string' do
70
- logger = DummyLogger.new
71
- called = []
72
- fsm = FiniteMachine.define do
73
- initial :green
74
-
75
- target logger
76
-
77
- events {
78
- event :slow, :green => :yellow
79
- event :stop, :yellow => :red
80
- }
81
-
82
- callbacks {
83
- on_enter_yellow do |event|
84
- raise_error
85
- end
86
- }
87
- handlers {
88
- handle 'InvalidStateError' do |exception|
89
- called << 'invalid_state_error'
90
- end
91
- }
92
- end
93
-
94
- expect(fsm.current).to eql(:green)
95
- fsm.stop
96
- expect(fsm.current).to eql(:green)
97
- expect(called).to eql(['invalid_state_error'])
98
- end
99
-
100
- it 'allows for empty block handler' do
101
- called = []
102
- fsm = FiniteMachine.define do
103
- initial :green
104
-
105
- events {
106
- event :slow, :green => :yellow
107
- event :stop, :yellow => :red
108
- }
109
-
110
- handlers {
111
- handle FiniteMachine::InvalidStateError do
112
- called << 'invalidstate'
113
- end
114
- }
115
- end
116
-
117
- expect(fsm.current).to eql(:green)
118
- fsm.stop
119
- expect(fsm.current).to eql(:green)
120
- expect(called).to eql([
121
- 'invalidstate'
122
- ])
123
- end
124
-
125
- it 'requires error handler' do
126
- expect { FiniteMachine.define do
127
- initial :green
128
-
129
- events {
130
- event :slow, :green => :yellow
131
- }
132
-
133
- handlers {
134
- handle 'UnknownErrorType'
135
- }
136
- end }.to raise_error(ArgumentError, /error handler/)
137
- end
138
-
139
- it 'checks handler class to be Exception' do
140
- expect { FiniteMachine.define do
141
- initial :green
142
-
143
- events {
144
- event :slow, :green => :yellow
145
- }
146
-
147
- handlers {
148
- handle Object do end
149
- }
150
- end }.to raise_error(ArgumentError, /Object isn't an Exception/)
151
- end
152
- end
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::HookEvent, '#build' do
6
- it "builds action event" do
7
- hook_event = FiniteMachine::HookEvent::Before.build(:green, :go, :red)
8
- expect(hook_event.name).to eq(:go)
9
- end
10
-
11
- it "builds state event" do
12
- hook_event = FiniteMachine::HookEvent::Enter.build(:green, :go, :red)
13
- expect(hook_event.name).to eq(:green)
14
- end
15
- end
@@ -1,36 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::HookEvent, 'eql?' do
6
- let(:name) { :green }
7
- let(:event_name) { :go }
8
- let(:object) { described_class }
9
-
10
- subject(:hook) { object.new(name, event_name, name) }
11
-
12
- context 'with the same object' do
13
- let(:other) { hook }
14
-
15
- it "equals" do
16
- expect(hook).to eql(other)
17
- end
18
- end
19
-
20
- context 'with an equivalent object' do
21
- let(:other) { hook.dup }
22
-
23
- it "equals" do
24
- expect(hook).to eql(other)
25
- end
26
- end
27
-
28
- context "with an object having different name" do
29
- let(:other_name) { :red }
30
- let(:other) { object.new(other_name, event_name, other_name) }
31
-
32
- it "doesn't equal" do
33
- expect(hook).not_to eql(other)
34
- end
35
- end
36
- end
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
-
3
- RSpec.describe FiniteMachine::HookEvent, '#infer_default_name' do
4
- it "infers default name for state" do
5
- hook_event = described_class::Enter
6
- expect(described_class.infer_default_name(hook_event)).to eq(:any)
7
- end
8
-
9
- it "infers default name for event" do
10
- hook_event = described_class::Before
11
- expect(described_class.infer_default_name(hook_event)).to eq(:any_event)
12
- end
13
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::HookEvent, '#new' do
6
- it "reads event name" do
7
- hook_event = described_class.new(:green, :go, :green)
8
- expect(hook_event.name).to eql(:green)
9
- end
10
-
11
- it "reads event type" do
12
- hook_event = described_class.new(:green, :go, :green)
13
- expect(hook_event.type).to eql(FiniteMachine::HookEvent)
14
- end
15
-
16
- it "reads the from state" do
17
- hook_event = described_class.new(:green, :go, :red)
18
- expect(hook_event.from).to eql(:red)
19
- end
20
-
21
- it "freezes object" do
22
- hook_event = described_class.new(:green, :go, :green)
23
- expect { hook_event.name = :red }.to raise_error(RuntimeError)
24
- end
25
- end
@@ -1,14 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::HookEvent, '.notify' do
6
- it "emits event on the subscriber" do
7
- subscriber = spy(:subscriber)
8
- hook_event = described_class.new(:green, :go, :red)
9
-
10
- hook_event.notify(subscriber, 1, 2)
11
-
12
- expect(subscriber).to have_received(:emit).with(hook_event, 1, 2)
13
- end
14
- end
@@ -1,24 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::Hooks, '#call' do
6
- let(:object) { described_class }
7
-
8
- subject(:hooks) { object.new }
9
-
10
- it "adds and removes a single hook" do
11
- expect(hooks).to be_empty
12
-
13
- yielded = []
14
- event_type = FiniteMachine::HookEvent::Before
15
- hook = -> { }
16
- hooks.register(event_type, :foo, hook)
17
-
18
- hooks.call(event_type, :foo) do |callback|
19
- yielded << callback
20
- end
21
-
22
- expect(yielded).to eq([hook])
23
- end
24
- end
@@ -1,16 +0,0 @@
1
- # encoding: utf-8
2
-
3
- RSpec.describe FiniteMachine::Hooks, '#clear' do
4
- it "clears all registered hooks" do
5
- hooks = described_class.new
6
-
7
- event_type = FiniteMachine::HookEvent::Before
8
- hook = -> { }
9
- hooks.register(event_type, :foo, hook)
10
- hooks.register(event_type, :bar, hook)
11
-
12
- expect(hooks.empty?).to eq(false)
13
- hooks.clear
14
- expect(hooks.empty?).to eq(true)
15
- end
16
- end
@@ -1,17 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::Hooks, '#inspect' do
6
- subject(:hooks) { described_class.new }
7
-
8
- it "displays name and transitions" do
9
- hook = -> { }
10
- event = FiniteMachine::HookEvent::Enter
11
- collection = {event => {yellow: [hook]}}
12
- hooks.register(event, :yellow, hook)
13
-
14
- expect(hooks.inspect).to eql("<#FiniteMachine::Hooks:0x#{hooks.object_id.to_s(16)} @collection=#{collection}>")
15
- expect(hooks.to_s).to eql(hooks.inspect)
16
- end
17
- end
@@ -1,22 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::Hooks, '#register' do
6
- let(:object) { described_class }
7
-
8
- subject(:hooks) { object.new }
9
-
10
- it "adds and removes a single hook" do
11
- expect(hooks).to be_empty
12
-
13
- event_type = FiniteMachine::HookEvent::Before
14
- hook = -> { }
15
-
16
- hooks.register(event_type, :foo, hook)
17
- expect(hooks.collection).to eq({event_type => {foo: [hook]}})
18
-
19
- hooks.unregister(event_type, :foo, hook)
20
- expect(hooks.collection).to eq({event_type => {foo: []}})
21
- end
22
- end
@@ -1,353 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, ':if, :unless' do
6
- before(:each) {
7
- stub_const("Car", Class.new do
8
- attr_accessor :engine_on
9
-
10
- def turn_engine_on
11
- @engine_on = true
12
- end
13
-
14
- def turn_engine_off
15
- @engine_on = false
16
- end
17
-
18
- def engine_on?
19
- !!@engine_on
20
- end
21
- end)
22
-
23
- stub_const("Bug", Class.new do
24
- def pending?
25
- false
26
- end
27
- end)
28
- }
29
-
30
- it "passes context to conditionals" do
31
- called = []
32
- fsm = FiniteMachine.define do
33
- initial :red
34
-
35
- events {
36
- event :go, :red => :green,
37
- if: proc { |context| called << "cond_red_green(#{context})"; true}
38
- event :stop, from: :any do
39
- choice :red,
40
- if: proc { |context| called << "cond_any_red(#{context})"; true }
41
- end
42
- }
43
- end
44
-
45
- expect(fsm.current).to eq(:red)
46
-
47
- fsm.go
48
- expect(fsm.current).to eq(:green)
49
- expect(called).to eq(["cond_red_green(#{fsm})"])
50
-
51
- fsm.stop
52
- expect(fsm.current).to eq(:red)
53
- expect(called).to match_array([
54
- "cond_red_green(#{fsm})",
55
- "cond_any_red(#{fsm})"
56
- ])
57
- end
58
-
59
- it "passes context & arguments to conditionals" do
60
- called = []
61
- fsm = FiniteMachine.define do
62
- initial :red
63
-
64
- events {
65
- event :go, :red => :green,
66
- if: proc { |_, a| called << "cond_red_green(#{a})"; true }
67
- event :stop, from: :any do
68
- choice :red,
69
- if: proc { |_, b| called << "cond_any_red(#{b})"; true }
70
- end
71
- }
72
- end
73
-
74
- expect(fsm.current).to eq(:red)
75
-
76
- fsm.go(:foo)
77
- expect(fsm.current).to eq(:green)
78
- expect(called).to eq(["cond_red_green(foo)"])
79
-
80
- fsm.stop(:bar)
81
- expect(fsm.current).to eq(:red)
82
- expect(called).to match_array([
83
- "cond_red_green(foo)",
84
- "cond_any_red(bar)"
85
- ])
86
- end
87
-
88
- it "allows to cancel event with :if option" do
89
- called = []
90
-
91
- fsm = FiniteMachine.define do
92
- initial :green
93
-
94
- events {
95
- event :slow, :green => :yellow, if: -> { return false }
96
- event :stop, :yellow => :red
97
- }
98
-
99
- callbacks {
100
- # generic callbacks
101
- on_enter do |event| called << 'on_enter' end
102
- on_transition do |event| called << 'on_transition' end
103
- on_exit do |event| called << 'on_exit' end
104
-
105
- # state callbacks
106
- on_enter :green do |event| called << 'on_enter_green' end
107
- on_enter :yellow do |event| called << "on_enter_yellow" end
108
-
109
- on_transition :green do |event| called << 'on_transition_green' end
110
- on_transition :yellow do |event| called << "on_transition_yellow" end
111
-
112
- on_exit :green do |event| called << 'on_exit_green' end
113
- on_exit :yellow do |event| called << "on_exit_yellow" end
114
- }
115
- end
116
-
117
- expect(fsm.current).to eql(:green)
118
- called = []
119
- fsm.slow
120
- expect(fsm.current).to eql(:green)
121
- expect(called).to eql([])
122
- end
123
-
124
- it "allows to cancel event with :unless option" do
125
- called = []
126
-
127
- fsm = FiniteMachine.define do
128
- initial :green
129
-
130
- events {
131
- event :slow, :green => :yellow, unless: -> { true }
132
- event :stop, :yellow => :red
133
- }
134
-
135
- callbacks {
136
- # generic callbacks
137
- on_enter do |event| called << 'on_enter' end
138
- on_transition do |event| called << 'on_transition' end
139
- on_exit do |event| called << 'on_exit' end
140
-
141
- # state callbacks
142
- on_enter :green do |event| called << 'on_enter_green' end
143
- on_enter :yellow do |event| called << "on_enter_yellow" end
144
-
145
- on_transition :green do |event| called << 'on_transition_green' end
146
- on_transition :yellow do |event| called << "on_transition_yellow" end
147
-
148
- on_exit :green do |event| called << 'on_exit_green' end
149
- on_exit :yellow do |event| called << "on_exit_yellow" end
150
- }
151
- end
152
-
153
- expect(fsm.current).to eql(:green)
154
- called = []
155
- fsm.slow
156
- expect(fsm.current).to eql(:green)
157
- expect(called).to eql([])
158
- end
159
-
160
- it "allows to combine conditionals" do
161
- conditions = []
162
-
163
- fsm = FiniteMachine.define do
164
- initial :green
165
-
166
- events {
167
- event :slow, :green => :yellow,
168
- if: [ -> { conditions << 'first_if'; return true },
169
- -> { conditions << 'second_if'; return true}],
170
- unless: -> { conditions << 'first_unless'; return true }
171
- event :stop, :yellow => :red
172
- }
173
- end
174
-
175
- expect(fsm.current).to eql(:green)
176
- fsm.slow
177
- expect(fsm.current).to eql(:green)
178
- expect(conditions).to eql([
179
- 'first_if',
180
- 'second_if',
181
- 'first_unless'
182
- ])
183
- end
184
-
185
- context 'when proc' do
186
- it "specifies :if and :unless" do
187
- car = Car.new
188
-
189
- fsm = FiniteMachine.define do
190
- initial :neutral
191
-
192
- target car
193
-
194
- events {
195
- event :start, :neutral => :one, if: proc {|_car| _car.engine_on? }
196
- event :shift, :one => :two
197
- }
198
- end
199
- car.turn_engine_off
200
- expect(car.engine_on?).to be false
201
- expect(fsm.current).to eql(:neutral)
202
- fsm.start
203
- expect(fsm.current).to eql(:neutral)
204
-
205
- car.turn_engine_on
206
- expect(car.engine_on?).to be true
207
- expect(fsm.current).to eql(:neutral)
208
- fsm.start
209
- expect(fsm.current).to eql(:one)
210
- end
211
-
212
- it "passes arguments to the scope" do
213
- car = Car.new
214
-
215
- fsm = FiniteMachine.define do
216
- initial :neutral
217
-
218
- target car
219
-
220
- events {
221
- event :start, :neutral => :one, if: proc { |_car, state|
222
- _car.engine_on = state
223
- _car.engine_on?
224
- }
225
- event :shift, :one => :two
226
- }
227
- end
228
- fsm.start(false)
229
- expect(fsm.current).to eql(:neutral)
230
- fsm.start(true)
231
- expect(fsm.current).to eql(:one)
232
- end
233
- end
234
-
235
- context 'when symbol' do
236
- it "specifies :if and :unless" do
237
- car = Car.new
238
-
239
- fsm = FiniteMachine.define do
240
- initial :neutral
241
-
242
- target car
243
-
244
- events {
245
- event :start, :neutral => :one, if: :engine_on?
246
- event :shift, :one => :two
247
- }
248
- end
249
- car.turn_engine_off
250
- expect(car.engine_on?).to be false
251
- expect(fsm.current).to eql(:neutral)
252
- fsm.start
253
- expect(fsm.current).to eql(:neutral)
254
-
255
- car.turn_engine_on
256
- expect(car.engine_on?).to be true
257
- expect(fsm.current).to eql(:neutral)
258
- fsm.start
259
- expect(fsm.current).to eql(:one)
260
- end
261
- end
262
-
263
- context 'when string' do
264
- it "specifies :if and :unless" do
265
- car = Car.new
266
-
267
- fsm = FiniteMachine.define do
268
- initial :neutral
269
-
270
- target car
271
-
272
- events {
273
- event :start, :neutral => :one, if: "engine_on?"
274
- event :shift, :one => :two
275
- }
276
- end
277
- car.turn_engine_off
278
- expect(car.engine_on?).to be false
279
- expect(fsm.current).to eql(:neutral)
280
- fsm.start
281
- expect(fsm.current).to eql(:neutral)
282
-
283
- car.turn_engine_on
284
- expect(car.engine_on?).to be true
285
- expect(fsm.current).to eql(:neutral)
286
- fsm.start
287
- expect(fsm.current).to eql(:one)
288
- end
289
- end
290
-
291
- context 'when same event name' do
292
- it "preservers conditions for the same named event" do
293
- bug = Bug.new
294
- fsm = FiniteMachine.define do
295
- initial :initial
296
-
297
- target bug
298
-
299
- events {
300
- event :bump, :initial => :low
301
- event :bump, :low => :medium, if: :pending?
302
- event :bump, :medium => :high
303
- }
304
- end
305
- expect(fsm.current).to eq(:initial)
306
- fsm.bump
307
- expect(fsm.current).to eq(:low)
308
- fsm.bump
309
- expect(fsm.current).to eq(:low)
310
- end
311
-
312
- it "allows for static choice based on branching condition" do
313
- fsm = FiniteMachine.define do
314
- initial :company_form
315
-
316
- events {
317
- event :next, :company_form => :agreement_form, if: -> { false }
318
- event :next, :company_form => :promo_form, if: -> { false }
319
- event :next, :company_form => :official_form, if: -> { true }
320
- }
321
- end
322
- expect(fsm.current).to eq(:company_form)
323
- fsm.next
324
- expect(fsm.current).to eq(:official_form)
325
- end
326
-
327
- it "allows for dynamic choice based on branching condition" do
328
- fsm = FiniteMachine.define do
329
- initial :company_form
330
-
331
- events {
332
- event :next, :company_form => :agreement_form, if: proc { |_, a| a < 1 }
333
- event :next, :company_form => :promo_form, if: proc { |_, a| a == 1 }
334
- event :next, :company_form => :official_form, if: proc { |_, a| a > 1 }
335
- }
336
- end
337
- expect(fsm.current).to eq(:company_form)
338
-
339
- fsm.next(0)
340
- expect(fsm.current).to eq(:agreement_form)
341
- fsm.restore!(:company_form)
342
- expect(fsm.current).to eq(:company_form)
343
-
344
- fsm.next(1)
345
- expect(fsm.current).to eq(:promo_form)
346
- fsm.restore!(:company_form)
347
- expect(fsm.current).to eq(:company_form)
348
-
349
- fsm.next(2)
350
- expect(fsm.current).to eq(:official_form)
351
- end
352
- end
353
- end