finite_machine 0.10.2 → 0.11.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 +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile +1 -1
- data/README.md +73 -35
- data/assets/finite_machine_logo.png +0 -0
- data/lib/finite_machine.rb +0 -7
- data/lib/finite_machine/async_proxy.rb +1 -2
- data/lib/finite_machine/dsl.rb +13 -14
- data/lib/finite_machine/event_definition.rb +32 -35
- data/lib/finite_machine/events_chain.rb +183 -37
- data/lib/finite_machine/hook_event.rb +47 -42
- data/lib/finite_machine/logger.rb +3 -4
- data/lib/finite_machine/observer.rb +27 -11
- data/lib/finite_machine/state_definition.rb +66 -0
- data/lib/finite_machine/state_machine.rb +177 -99
- data/lib/finite_machine/subscribers.rb +17 -6
- data/lib/finite_machine/thread_context.rb +1 -1
- data/lib/finite_machine/transition.rb +45 -173
- data/lib/finite_machine/transition_builder.rb +24 -6
- data/lib/finite_machine/transition_event.rb +5 -4
- data/lib/finite_machine/undefined_transition.rb +32 -0
- data/lib/finite_machine/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/async_events_spec.rb +24 -18
- data/spec/unit/callbacks_spec.rb +0 -19
- data/spec/unit/event_names_spec.rb +19 -0
- data/spec/unit/events_chain/add_spec.rb +25 -0
- data/spec/unit/events_chain/cancel_transitions_spec.rb +22 -0
- data/spec/unit/events_chain/choice_transition_spec.rb +28 -0
- data/spec/unit/events_chain/clear_spec.rb +7 -18
- data/spec/unit/events_chain/events_spec.rb +18 -0
- data/spec/unit/events_chain/inspect_spec.rb +14 -17
- data/spec/unit/events_chain/match_transition_spec.rb +37 -0
- data/spec/unit/events_chain/move_to_spec.rb +48 -0
- data/spec/unit/events_chain/states_for_spec.rb +17 -0
- data/spec/unit/events_spec.rb +119 -27
- data/spec/unit/hook_event/build_spec.rb +15 -0
- data/spec/unit/hook_event/eql_spec.rb +3 -4
- data/spec/unit/hook_event/initialize_spec.rb +14 -11
- data/spec/unit/hook_event/notify_spec.rb +14 -0
- data/spec/unit/{initialize_spec.rb → initial_spec.rb} +1 -1
- data/spec/unit/inspect_spec.rb +1 -1
- data/spec/unit/logger_spec.rb +4 -5
- data/spec/unit/subscribers_spec.rb +20 -9
- data/spec/unit/transition/check_conditions_spec.rb +54 -0
- data/spec/unit/transition/inspect_spec.rb +2 -2
- data/spec/unit/transition/matches_spec.rb +23 -0
- data/spec/unit/transition/states_spec.rb +31 -0
- data/spec/unit/transition/to_state_spec.rb +27 -0
- data/spec/unit/trigger_spec.rb +22 -0
- data/spec/unit/undefined_transition/eql_spec.rb +17 -0
- data/tasks/console.rake +1 -0
- metadata +39 -23
- data/lib/finite_machine/event.rb +0 -146
- data/spec/unit/event/add_spec.rb +0 -16
- data/spec/unit/event/eql_spec.rb +0 -37
- data/spec/unit/event/initialize_spec.rb +0 -38
- data/spec/unit/event/inspect_spec.rb +0 -21
- data/spec/unit/event/next_transition_spec.rb +0 -35
- data/spec/unit/events_chain/check_choice_conditions_spec.rb +0 -20
- data/spec/unit/events_chain/insert_spec.rb +0 -26
- data/spec/unit/events_chain/select_transition_spec.rb +0 -23
- data/spec/unit/transition/parse_states_spec.rb +0 -42
data/spec/spec_helper.rb
CHANGED
@@ -72,26 +72,32 @@ RSpec.describe FiniteMachine, 'async_events' do
|
|
72
72
|
|
73
73
|
it "ensure queue per thread" do
|
74
74
|
called = []
|
75
|
-
fsmFoo =
|
76
|
-
|
77
|
-
|
75
|
+
fsmFoo = nil
|
76
|
+
fsmBar = nil
|
77
|
+
foo_thread = Thread.new {
|
78
|
+
fsmFoo = FiniteMachine.define do
|
79
|
+
initial :green
|
80
|
+
events { event :slow, :green => :yellow }
|
78
81
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
callbacks {
|
83
|
+
on_enter :yellow do |event, a| called << "(foo)on_enter_yellow_#{a}" end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
fsmFoo.async.slow(:foo)
|
87
|
+
}
|
88
|
+
bar_thread = Thread.new {
|
89
|
+
fsmBar = FiniteMachine.define do
|
90
|
+
initial :green
|
91
|
+
events { event :slow, :green => :yellow }
|
86
92
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
callbacks {
|
94
|
+
on_enter :yellow do |event, a| called << "(bar)on_enter_yellow_#{a}" end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
fsmBar.async.slow(:bar)
|
98
|
+
}
|
99
|
+
ThreadsWait.all_waits(foo_thread, bar_thread)
|
100
|
+
sleep 0.01
|
95
101
|
expect(called).to match_array([
|
96
102
|
'(foo)on_enter_yellow_foo',
|
97
103
|
'(bar)on_enter_yellow_bar'
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -687,25 +687,6 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
687
687
|
])
|
688
688
|
end
|
689
689
|
|
690
|
-
it "cancels transition on state callback" do
|
691
|
-
fsm = FiniteMachine.define do
|
692
|
-
initial :green
|
693
|
-
|
694
|
-
events {
|
695
|
-
event :slow, :green => :yellow
|
696
|
-
event :go, :yellow => :green
|
697
|
-
}
|
698
|
-
|
699
|
-
callbacks {
|
700
|
-
on_exit :green do |event| FiniteMachine::CANCELLED end
|
701
|
-
}
|
702
|
-
end
|
703
|
-
|
704
|
-
expect(fsm.current).to eql(:green)
|
705
|
-
fsm.slow
|
706
|
-
expect(fsm.current).to eql(:green)
|
707
|
-
end
|
708
|
-
|
709
690
|
it "cancels transition on event callback" do
|
710
691
|
fsm = FiniteMachine.define do
|
711
692
|
initial :green
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine, '.event_names' do
|
6
|
+
it "retrieves all event names" do
|
7
|
+
fsm = FiniteMachine.define do
|
8
|
+
initial :green
|
9
|
+
|
10
|
+
events {
|
11
|
+
event :start, :red => :green
|
12
|
+
event :stop, :green => :red
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
expect(fsm.current).to eql(:green)
|
17
|
+
expect(fsm.event_names).to eql([:init, :start, :stop])
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.add' do
|
6
|
+
it "adds transitions" do
|
7
|
+
transition = double(:transition)
|
8
|
+
events_chain = described_class.new
|
9
|
+
|
10
|
+
events_chain.add(:validated, transition)
|
11
|
+
expect(events_chain[:validated]).to eq([transition])
|
12
|
+
|
13
|
+
events_chain.add(:validated, transition)
|
14
|
+
expect(events_chain[:validated]).to eq([transition, transition])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows to chain add operations" do
|
18
|
+
events_chain = described_class.new
|
19
|
+
transition = double(:transition)
|
20
|
+
|
21
|
+
events_chain.add(:go, transition).add(:start, transition)
|
22
|
+
|
23
|
+
expect(events_chain.size).to eq(2)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.cancel_transitions' do
|
6
|
+
it "sets cancel status for chosen transitions" do
|
7
|
+
events_chain = described_class.new
|
8
|
+
transition_a = spy(:transition_a, cancelled: false)
|
9
|
+
transition_b = spy(:transition_b, cancelled: false)
|
10
|
+
transition_c = spy(:transition_c, cancelled: false)
|
11
|
+
|
12
|
+
events_chain.add(:start, transition_a)
|
13
|
+
events_chain.add(:start, transition_b)
|
14
|
+
events_chain.add(:finish, transition_c)
|
15
|
+
|
16
|
+
events_chain.cancel_transitions(:start, true)
|
17
|
+
|
18
|
+
expect(transition_a).to have_received(:cancelled=).with(true)
|
19
|
+
expect(transition_b).to have_received(:cancelled=).with(true)
|
20
|
+
expect(transition_c).not_to have_received(:cancelled=)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.choice_transition?' do
|
6
|
+
|
7
|
+
it "checks if transition has many branches" do
|
8
|
+
transition_a = double(:transition_a, matches?: true)
|
9
|
+
transition_b = double(:transition_b, matches?: true)
|
10
|
+
|
11
|
+
events_chain = described_class.new
|
12
|
+
events_chain.add(:go, transition_a)
|
13
|
+
events_chain.add(:go, transition_b)
|
14
|
+
|
15
|
+
expect(events_chain.choice_transition?(:go, :green)).to eq(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "checks that transition has no branches" do
|
19
|
+
transition_a = double(:transition_a, matches?: false)
|
20
|
+
transition_b = double(:transition_b, matches?: true)
|
21
|
+
|
22
|
+
events_chain = described_class.new
|
23
|
+
events_chain.add(:go, transition_a)
|
24
|
+
events_chain.add(:go, transition_b)
|
25
|
+
|
26
|
+
expect(events_chain.choice_transition?(:go, :green)).to eq(false)
|
27
|
+
end
|
28
|
+
end
|
@@ -2,25 +2,14 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe FiniteMachine::EventsChain, '#
|
6
|
-
|
7
|
-
|
8
|
-
let(:machine) { double(:machine) }
|
9
|
-
|
10
|
-
let(:transition) { double(:transition) }
|
11
|
-
|
12
|
-
subject(:chain) { object.new(machine) }
|
13
|
-
|
14
|
-
it "inserts transition" do
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '#clear' do
|
6
|
+
it "clears chain events" do
|
15
7
|
event = double(:event)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
expect(event).to receive(:<<).with(transition)
|
20
|
-
chain.insert(:validated, transition)
|
21
|
-
end
|
8
|
+
events_chain = described_class.new
|
9
|
+
events_chain.add(:validated, event)
|
10
|
+
expect(events_chain.empty?).to be(false)
|
22
11
|
|
23
|
-
|
24
|
-
expect(
|
12
|
+
events_chain.clear
|
13
|
+
expect(events_chain.empty?).to be(true)
|
25
14
|
end
|
26
15
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.events' do
|
6
|
+
it "has no event names" do
|
7
|
+
events_chain = described_class.new
|
8
|
+
expect(events_chain.events).to eq([])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns all event names" do
|
12
|
+
events_chain = described_class.new
|
13
|
+
transition = double(:transition)
|
14
|
+
events_chain.add(:ready, transition)
|
15
|
+
events_chain.add(:go, transition)
|
16
|
+
expect(events_chain.events).to match_array([:ready, :go])
|
17
|
+
end
|
18
|
+
end
|
@@ -2,26 +2,23 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe FiniteMachine::EventsChain, '#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
subject(:chain) { object.new(machine) }
|
11
|
-
|
12
|
-
it "inspects empty chain" do
|
13
|
-
expect(chain.inspect).to eq("<#FiniteMachine::EventsChain @chain={}>")
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '#inspect' do
|
6
|
+
it "inspects empty events chain" do
|
7
|
+
events_chain = described_class.new
|
8
|
+
expect(events_chain.inspect).to eq("<#FiniteMachine::EventsChain @chain={}>")
|
14
9
|
end
|
15
10
|
|
16
|
-
it "inspect chain" do
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
it "inspect events chain" do
|
12
|
+
transition = double(:transition)
|
13
|
+
events_chain = described_class.new
|
14
|
+
events_chain.add(:validated, transition)
|
15
|
+
expect(events_chain.inspect).to eq("<#FiniteMachine::EventsChain @chain=#{{validated: [transition]}}>")
|
20
16
|
end
|
21
17
|
|
22
|
-
it "prints chain" do
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
it "prints events chain" do
|
19
|
+
transition = double(:transition)
|
20
|
+
events_chain = described_class.new
|
21
|
+
events_chain.add(:validated, transition)
|
22
|
+
expect(events_chain.to_s).to eq("#{{validated: [transition]}}")
|
26
23
|
end
|
27
24
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.match_transition' do
|
6
|
+
it "matches transition without conditions" do
|
7
|
+
transition_a = double(:transition_a, matches?: false)
|
8
|
+
transition_b = double(:transition_b, matches?: true)
|
9
|
+
events_chain = described_class.new
|
10
|
+
|
11
|
+
events_chain.add(:a, transition_a)
|
12
|
+
events_chain.add(:a, transition_b)
|
13
|
+
|
14
|
+
expect(events_chain.match_transition(:a, :green)).to eq(transition_b)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "fails to match any transition" do
|
18
|
+
events_chain = described_class.new
|
19
|
+
|
20
|
+
expect(events_chain.match_transition(:a, :green)).to eq(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "matches transition with conditions" do
|
24
|
+
transition_a = double(:transition_a, matches?: true)
|
25
|
+
transition_b = double(:transition_b, matches?: true)
|
26
|
+
events_chain = described_class.new
|
27
|
+
|
28
|
+
events_chain.add(:a, transition_a)
|
29
|
+
events_chain.add(:a, transition_b)
|
30
|
+
|
31
|
+
allow(transition_a).to receive(:check_conditions).and_return(false)
|
32
|
+
allow(transition_b).to receive(:check_conditions).and_return(true)
|
33
|
+
|
34
|
+
expect(events_chain.match_transition_with(:a, :green, 'Piotr')).to eq(transition_b)
|
35
|
+
expect(transition_a).to have_received(:check_conditions).with('Piotr')
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe FiniteMachine::EventsChain, '.move_to' do
|
6
|
+
|
7
|
+
it "moves to state by matching individual transition" do
|
8
|
+
transition_a = double(:transition_a, matches?: false)
|
9
|
+
transition_b = double(:transition_b, matches?: true)
|
10
|
+
|
11
|
+
events_chain = described_class.new
|
12
|
+
events_chain.add(:go, transition_a)
|
13
|
+
events_chain.add(:go, transition_b)
|
14
|
+
|
15
|
+
allow(transition_b).to receive(:to_state).with(:yellow).and_return(:red)
|
16
|
+
|
17
|
+
expect(events_chain.move_to(:go, :yellow)).to eq(:red)
|
18
|
+
expect(transition_b).to have_received(:to_state).with(:yellow)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "moves to state by matching choice transition" do
|
22
|
+
transition_a = double(:transition_a, matches?: true)
|
23
|
+
transition_b = double(:transition_b, matches?: true)
|
24
|
+
|
25
|
+
events_chain = described_class.new
|
26
|
+
events_chain.add(:go, transition_a)
|
27
|
+
events_chain.add(:go, transition_b)
|
28
|
+
|
29
|
+
allow(transition_a).to receive(:check_conditions).and_return(false)
|
30
|
+
allow(transition_b).to receive(:check_conditions).and_return(true)
|
31
|
+
|
32
|
+
allow(transition_b).to receive(:to_state).with(:green).and_return(:red)
|
33
|
+
|
34
|
+
expect(events_chain.move_to(:go, :green)).to eq(:red)
|
35
|
+
expect(transition_b).to have_received(:to_state).with(:green)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "moves to from state if no transition available" do
|
39
|
+
transition_a = double(:transition_a, matches?: false)
|
40
|
+
transition_b = double(:transition_b, matches?: false)
|
41
|
+
|
42
|
+
events_chain = described_class.new
|
43
|
+
events_chain.add(:go, transition_a)
|
44
|
+
events_chain.add(:go, transition_b)
|
45
|
+
|
46
|
+
expect(events_chain.move_to(:go, :green)).to eq(:green)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe FiniteMachine::EventsChain do
|
4
|
+
it "finds current states for event name" do
|
5
|
+
transition = spy(:transition, states: {:red => :yellow, :yellow => :green})
|
6
|
+
events_chain = described_class.new
|
7
|
+
events_chain.add(:start, transition)
|
8
|
+
|
9
|
+
expect(events_chain.states_for(:start)).to eq([:red, :yellow])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "fails to find any states for event name" do
|
13
|
+
events_chain = described_class.new
|
14
|
+
|
15
|
+
expect(events_chain.states_for(:start)).to eq([])
|
16
|
+
end
|
17
|
+
end
|
data/spec/unit/events_spec.rb
CHANGED
@@ -169,37 +169,109 @@ RSpec.describe FiniteMachine, 'events' do
|
|
169
169
|
expect(fsm.current).to eql(:green)
|
170
170
|
end
|
171
171
|
|
172
|
-
it "
|
172
|
+
it "doesn't raise error on invalid transition for non-dangerous version" do
|
173
|
+
called = []
|
173
174
|
fsm = FiniteMachine.define do
|
174
175
|
initial :green
|
175
176
|
|
176
177
|
events {
|
177
|
-
event :
|
178
|
-
|
178
|
+
event :stop, from: :yellow, to: :red
|
179
|
+
}
|
180
|
+
callbacks {
|
181
|
+
on_before :stop do |event| called << 'on_before_stop' end
|
182
|
+
on_after :stop do |event| called << 'on_before_stop' end
|
179
183
|
}
|
180
184
|
end
|
181
185
|
|
182
|
-
expect(fsm.current).to
|
186
|
+
expect(fsm.current).to eq(:green)
|
187
|
+
expect(fsm.stop).to eq(false)
|
188
|
+
expect(fsm.current).to eq(:green)
|
189
|
+
expect(called).to match_array(['on_before_stop'])
|
190
|
+
end
|
183
191
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
192
|
+
context 'for non-dangerous version' do
|
193
|
+
it "doesn't raise error on invalid transition and fires callbacks" do
|
194
|
+
called = []
|
195
|
+
fsm = FiniteMachine.define do
|
196
|
+
initial :green
|
197
|
+
|
198
|
+
events {
|
199
|
+
event :stop, from: :yellow, to: :red
|
200
|
+
}
|
201
|
+
callbacks {
|
202
|
+
on_before :stop do |event| called << 'on_before_stop' end
|
203
|
+
on_after :stop do |event| called << 'on_before_stop' end
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
expect(fsm.current).to eq(:green)
|
208
|
+
expect(fsm.stop).to eq(false)
|
209
|
+
expect(fsm.current).to eq(:green)
|
210
|
+
expect(called).to match_array(['on_before_stop'])
|
211
|
+
end
|
212
|
+
|
213
|
+
it "raises error on invalid transition for dangerous version" do
|
214
|
+
called = []
|
215
|
+
fsm = FiniteMachine.define do
|
216
|
+
initial :green
|
217
|
+
|
218
|
+
events {
|
219
|
+
event :slow, from: :green, to: :yellow
|
220
|
+
event :stop, from: :yellow, to: :red, silent: true
|
221
|
+
}
|
222
|
+
callbacks {
|
223
|
+
on_before :stop do |event| called << 'on_before_stop' end
|
224
|
+
on_after :stop do |event| called << 'on_before_stop' end
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
expect(fsm.current).to eql(:green)
|
229
|
+
expect(fsm.stop).to eq(false)
|
230
|
+
expect(called).to match_array([])
|
231
|
+
end
|
188
232
|
end
|
189
233
|
|
190
|
-
|
191
|
-
|
192
|
-
|
234
|
+
context 'for dangerous version' do
|
235
|
+
it "raises error on invalid transition without callbacks" do
|
236
|
+
called = []
|
237
|
+
fsm = FiniteMachine.define do
|
238
|
+
initial :green
|
193
239
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
240
|
+
events {
|
241
|
+
event :start, :red => :yellow, silent: true
|
242
|
+
}
|
243
|
+
callbacks {
|
244
|
+
on_before :start do |event| called << 'on_before_start' end
|
245
|
+
on_after :start do |event| called << 'on_after_start' end
|
246
|
+
}
|
247
|
+
end
|
248
|
+
|
249
|
+
expect(fsm.current).to eq(:green)
|
250
|
+
expect { fsm.start! }.to raise_error(FiniteMachine::InvalidStateError)
|
251
|
+
expect(called).to eq([])
|
252
|
+
expect(fsm.current).to eq(:green)
|
253
|
+
end
|
254
|
+
|
255
|
+
it "raises error on invalid transition with callbacks fired" do
|
256
|
+
called = []
|
257
|
+
fsm = FiniteMachine.define do
|
258
|
+
initial :green
|
259
|
+
|
260
|
+
events {
|
261
|
+
event :start, :red => :yellow
|
262
|
+
}
|
263
|
+
callbacks {
|
264
|
+
on_before :start do |event| called << 'on_before_start' end
|
265
|
+
on_after :start do |event| called << 'on_after_start' end
|
266
|
+
}
|
267
|
+
end
|
268
|
+
|
269
|
+
expect(fsm.current).to eq(:green)
|
270
|
+
expect { fsm.start! }.to raise_error(FiniteMachine::InvalidStateError,
|
271
|
+
/inappropriate current state 'green'/)
|
272
|
+
expect(called).to eq(['on_before_start'])
|
273
|
+
expect(fsm.current).to eq(:green)
|
198
274
|
end
|
199
|
-
expect(fsm.current).to eql(:green)
|
200
|
-
expect(fsm.can?(:stop)).to be false
|
201
|
-
fsm.stop!
|
202
|
-
expect(fsm.current).to eql(:red)
|
203
275
|
end
|
204
276
|
|
205
277
|
context 'when multiple from states' do
|
@@ -314,16 +386,16 @@ RSpec.describe FiniteMachine, 'events' do
|
|
314
386
|
}
|
315
387
|
|
316
388
|
callbacks {
|
317
|
-
on_before(:drive) { }
|
389
|
+
on_before(:drive) { FiniteMachine::CANCELLED }
|
318
390
|
on_after(:stop) { }
|
319
391
|
}
|
320
392
|
end
|
321
393
|
|
322
394
|
expect(fsm.current).to eql(:neutral)
|
323
|
-
expect(fsm.start).to eql(
|
324
|
-
expect(fsm.drive).to eql(
|
325
|
-
expect(fsm.stop).to eql(
|
326
|
-
expect(fsm.stop).to eql(
|
395
|
+
expect(fsm.start).to eql(true)
|
396
|
+
expect(fsm.drive).to eql(false)
|
397
|
+
expect(fsm.stop).to eql(true)
|
398
|
+
expect(fsm.stop).to eql(true)
|
327
399
|
end
|
328
400
|
|
329
401
|
it "allows for self transition events" do
|
@@ -358,10 +430,30 @@ RSpec.describe FiniteMachine, 'events' do
|
|
358
430
|
end
|
359
431
|
|
360
432
|
it "detects dangerous event names" do
|
361
|
-
expect {
|
433
|
+
expect {
|
434
|
+
FiniteMachine.define do
|
435
|
+
events {
|
436
|
+
event :trigger, :a => :b
|
437
|
+
}
|
438
|
+
end
|
439
|
+
}.to raise_error(FiniteMachine::AlreadyDefinedError)
|
440
|
+
end
|
441
|
+
|
442
|
+
it "executes event block" do
|
443
|
+
fsm = FiniteMachine.define do
|
444
|
+
initial :red
|
445
|
+
|
362
446
|
events {
|
363
|
-
event :
|
447
|
+
event :start, :red => :green
|
448
|
+
event :stop, :green => :red
|
364
449
|
}
|
365
|
-
end
|
450
|
+
end
|
451
|
+
|
452
|
+
expect(fsm.current).to eq(:red)
|
453
|
+
called = []
|
454
|
+
fsm.start do |from, to|
|
455
|
+
called << "execute_start_#{from}_#{to}"
|
456
|
+
end
|
457
|
+
expect(called).to eq(['execute_start_red_green'])
|
366
458
|
end
|
367
459
|
end
|