finite_machine 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|