finite_machine 0.11.3 → 0.12.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 +5 -5
- data/CHANGELOG.md +34 -0
- data/README.md +564 -569
- data/Rakefile +5 -1
- data/benchmarks/memory_profile.rb +11 -0
- data/benchmarks/memory_usage.rb +16 -9
- data/finite_machine.gemspec +10 -3
- data/lib/finite_machine.rb +34 -46
- data/lib/finite_machine/async_call.rb +5 -21
- data/lib/finite_machine/callable.rb +4 -4
- data/lib/finite_machine/catchable.rb +4 -2
- data/lib/finite_machine/choice_merger.rb +19 -19
- data/lib/finite_machine/const.rb +16 -0
- data/lib/finite_machine/definition.rb +2 -2
- data/lib/finite_machine/dsl.rb +66 -149
- data/lib/finite_machine/env.rb +4 -2
- data/lib/finite_machine/event_definition.rb +7 -15
- data/lib/finite_machine/{events_chain.rb → events_map.rb} +39 -51
- data/lib/finite_machine/hook_event.rb +60 -61
- data/lib/finite_machine/hooks.rb +44 -36
- data/lib/finite_machine/listener.rb +2 -2
- data/lib/finite_machine/logger.rb +5 -4
- data/lib/finite_machine/message_queue.rb +39 -30
- data/lib/finite_machine/observer.rb +55 -37
- data/lib/finite_machine/safety.rb +12 -10
- data/lib/finite_machine/state_definition.rb +3 -5
- data/lib/finite_machine/state_machine.rb +83 -64
- data/lib/finite_machine/state_parser.rb +51 -79
- data/lib/finite_machine/subscribers.rb +1 -1
- data/lib/finite_machine/threadable.rb +3 -1
- data/lib/finite_machine/transition.rb +30 -31
- data/lib/finite_machine/transition_builder.rb +23 -32
- data/lib/finite_machine/transition_event.rb +12 -11
- data/lib/finite_machine/two_phase_lock.rb +3 -1
- data/lib/finite_machine/undefined_transition.rb +5 -6
- data/lib/finite_machine/version.rb +2 -2
- data/spec/integration/system_spec.rb +36 -38
- data/spec/performance/benchmark_spec.rb +13 -21
- data/spec/unit/alias_target_spec.rb +22 -41
- data/spec/unit/async_callbacks_spec.rb +8 -13
- data/spec/unit/auto_methods_spec.rb +44 -0
- data/spec/unit/callable/call_spec.rb +1 -3
- data/spec/unit/callbacks_spec.rb +372 -463
- data/spec/unit/can_spec.rb +13 -23
- data/spec/unit/cancel_callbacks_spec.rb +46 -0
- data/spec/unit/choice_spec.rb +105 -141
- data/spec/unit/define_spec.rb +31 -31
- data/spec/unit/definition_spec.rb +24 -41
- data/spec/unit/event_names_spec.rb +6 -10
- data/spec/unit/events_map/add_spec.rb +23 -0
- data/spec/unit/events_map/choice_transition_spec.rb +25 -0
- data/spec/unit/events_map/clear_spec.rb +13 -0
- data/spec/unit/events_map/events_spec.rb +16 -0
- data/spec/unit/events_map/inspect_spec.rb +22 -0
- data/spec/unit/{events_chain → events_map}/match_transition_spec.rb +12 -14
- data/spec/unit/{events_chain → events_map}/move_to_spec.rb +14 -17
- data/spec/unit/events_map/states_for_spec.rb +17 -0
- data/spec/unit/events_spec.rb +91 -160
- data/spec/unit/handlers_spec.rb +34 -66
- data/spec/unit/hook_event/any_state_or_event_spec.rb +13 -0
- data/spec/unit/hook_event/build_spec.rb +1 -3
- data/spec/unit/hook_event/eql_spec.rb +1 -3
- data/spec/unit/hook_event/initialize_spec.rb +2 -4
- data/spec/unit/hook_event/notify_spec.rb +2 -4
- data/spec/unit/hooks/clear_spec.rb +1 -1
- data/spec/unit/hooks/{call_spec.rb → find_spec.rb} +4 -9
- data/spec/unit/hooks/inspect_spec.rb +16 -8
- data/spec/unit/hooks/register_spec.rb +4 -9
- data/spec/unit/if_unless_spec.rb +76 -115
- data/spec/unit/initial_spec.rb +50 -82
- data/spec/unit/inspect_spec.rb +14 -9
- data/spec/unit/is_spec.rb +12 -18
- data/spec/unit/log_transitions_spec.rb +4 -10
- data/spec/unit/logger_spec.rb +1 -3
- data/spec/unit/{event_queue_spec.rb → message_queue_spec.rb} +15 -8
- data/spec/unit/new_spec.rb +50 -0
- data/spec/unit/respond_to_spec.rb +2 -6
- data/spec/unit/state_parser/parse_spec.rb +9 -12
- data/spec/unit/states_spec.rb +12 -18
- data/spec/unit/subscribers_spec.rb +1 -3
- data/spec/unit/target_spec.rb +60 -93
- data/spec/unit/terminated_spec.rb +15 -25
- data/spec/unit/transition/check_conditions_spec.rb +16 -15
- data/spec/unit/transition/inspect_spec.rb +6 -6
- data/spec/unit/transition/matches_spec.rb +5 -7
- data/spec/unit/transition/states_spec.rb +5 -7
- data/spec/unit/transition/to_state_spec.rb +5 -13
- data/spec/unit/trigger_spec.rb +5 -9
- data/spec/unit/undefined_transition/eql_spec.rb +1 -3
- metadata +86 -49
- data/.gitignore +0 -18
- data/.rspec +0 -5
- data/.travis.yml +0 -27
- data/Gemfile +0 -16
- data/assets/finite_machine_logo.png +0 -0
- data/lib/finite_machine/async_proxy.rb +0 -55
- data/spec/unit/async_events_spec.rb +0 -107
- data/spec/unit/events_chain/add_spec.rb +0 -25
- data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
- data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
- data/spec/unit/events_chain/clear_spec.rb +0 -15
- data/spec/unit/events_chain/events_spec.rb +0 -18
- data/spec/unit/events_chain/inspect_spec.rb +0 -24
- data/spec/unit/events_chain/states_for_spec.rb +0 -17
- data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
- data/spec/unit/state_parser/inspect_spec.rb +0 -25
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require 'spec_helper'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
RSpec.describe FiniteMachine::Definition, '#alias_target' do
|
6
4
|
|
@@ -22,67 +20,51 @@ RSpec.describe FiniteMachine::Definition, '#alias_target' do
|
|
22
20
|
|
23
21
|
it "aliases target" do
|
24
22
|
car = Car.new
|
25
|
-
fsm = FiniteMachine.new
|
26
|
-
fsm.target(car)
|
23
|
+
fsm = FiniteMachine.new(car, alias_target: :delorean)
|
27
24
|
|
28
25
|
expect(fsm.target).to eq(car)
|
29
26
|
expect { fsm.car }.to raise_error(NoMethodError)
|
30
|
-
|
31
|
-
fsm.alias_target(:delorean)
|
32
27
|
expect(fsm.delorean).to eq(car)
|
33
28
|
end
|
34
29
|
|
35
30
|
it "scopes the target alias to a state machine instance" do
|
36
31
|
delorean = Car.new
|
37
32
|
batmobile = Car.new
|
38
|
-
fsm_a = FiniteMachine.new
|
39
|
-
|
40
|
-
fsm_b = FiniteMachine.new
|
41
|
-
fsm_b.target(batmobile)
|
42
|
-
|
43
|
-
fsm_a.alias_target(:delorean)
|
44
|
-
fsm_b.alias_target(:batmobile)
|
33
|
+
fsm_a = FiniteMachine.new(delorean, alias_target: :delorean)
|
34
|
+
fsm_b = FiniteMachine.new(batmobile, alias_target: :batmobile)
|
45
35
|
|
46
36
|
expect(fsm_a.delorean).to eq(delorean)
|
47
|
-
expect { fsm_a.batmobile }.to raise_error(
|
37
|
+
expect { fsm_a.batmobile }.to raise_error(NameError)
|
48
38
|
|
49
39
|
expect(fsm_b.batmobile).to eq(batmobile)
|
50
|
-
expect { fsm_b.delorean }.to raise_error(
|
40
|
+
expect { fsm_b.delorean }.to raise_error(NameError)
|
51
41
|
end
|
52
42
|
|
53
43
|
context 'when inside definition' do
|
54
44
|
before do
|
55
|
-
|
45
|
+
stub_const("Engine", Class.new(FiniteMachine::Definition) do
|
56
46
|
initial :neutral
|
57
47
|
|
58
|
-
|
48
|
+
event :forward, [:reverse, :neutral] => :one
|
49
|
+
event :shift, :one => :two
|
50
|
+
event :shift, :two => :one
|
51
|
+
event :back, [:neutral, :one] => :reverse
|
59
52
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
event :shift, :two => :one
|
64
|
-
event :back, [:neutral, :one] => :reverse
|
65
|
-
}
|
53
|
+
on_enter :reverse do |event|
|
54
|
+
car.turn_reverse_lights_on
|
55
|
+
end
|
66
56
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
57
|
+
on_exit :reverse do |event|
|
58
|
+
car.turn_reverse_lights_off
|
59
|
+
end
|
71
60
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
}
|
76
|
-
|
77
|
-
handlers {
|
78
|
-
handle FiniteMachine::InvalidStateError do |exception| end
|
79
|
-
}
|
80
|
-
end
|
61
|
+
handle FiniteMachine::InvalidStateError do |exception| end
|
62
|
+
end)
|
81
63
|
end
|
82
64
|
|
83
65
|
it "creates unique instances" do
|
84
|
-
engine_a = Engine.new
|
85
|
-
engine_b = Engine.new
|
66
|
+
engine_a = Engine.new(alias_target: :car)
|
67
|
+
engine_b = Engine.new(alias_target: :car)
|
86
68
|
expect(engine_a).not_to be(engine_b)
|
87
69
|
|
88
70
|
engine_a.forward
|
@@ -92,8 +74,7 @@ RSpec.describe FiniteMachine::Definition, '#alias_target' do
|
|
92
74
|
|
93
75
|
it "allows to create standalone machine" do
|
94
76
|
car = Car.new
|
95
|
-
engine = Engine.new
|
96
|
-
engine.target car
|
77
|
+
engine = Engine.new(car, alias_target: :car)
|
97
78
|
expect(engine.current).to eq(:neutral)
|
98
79
|
|
99
80
|
engine.forward
|
@@ -1,23 +1,18 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FiniteMachine, 'async callbacks' do
|
4
|
-
|
5
4
|
it "permits async callback" do
|
6
5
|
called = []
|
7
|
-
fsm = FiniteMachine.
|
6
|
+
fsm = FiniteMachine.new do
|
8
7
|
initial :green, silent: false
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
event :go, :yellow => :green
|
13
|
-
}
|
9
|
+
event :slow, :green => :yellow
|
10
|
+
event :go, :yellow => :green
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
on_after :go, :async do |event| called << 'on_after_go' end
|
20
|
-
}
|
12
|
+
on_enter :green, :async do |event| called << 'on_enter_green' end
|
13
|
+
on_before :slow, :async do |event| called << 'on_before_slow' end
|
14
|
+
on_exit :yellow, :async do |event| called << 'on_exit_yellow' end
|
15
|
+
on_after :go, :async do |event| called << 'on_after_go' end
|
21
16
|
end
|
22
17
|
fsm.slow
|
23
18
|
fsm.go
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe FiniteMachine, ':auto_methods' do
|
4
|
+
it "allows turning off automatic methods generation" do
|
5
|
+
fsm = FiniteMachine.new(auto_methods: false) do
|
6
|
+
initial :green
|
7
|
+
|
8
|
+
event :slow, :green => :yellow
|
9
|
+
event :stop, :yellow => :red
|
10
|
+
event :ready, :red => :yellow
|
11
|
+
event :go, :yellow => :green
|
12
|
+
|
13
|
+
# allows for fluid callback names
|
14
|
+
once_on_enter_yellow do |event| 'once_on_enter_yellow' end
|
15
|
+
end
|
16
|
+
|
17
|
+
expect(fsm.respond_to?(:slow)).to eq(false)
|
18
|
+
expect { fsm.slow }.to raise_error(NoMethodError)
|
19
|
+
expect(fsm.current).to eq(:green)
|
20
|
+
|
21
|
+
fsm.trigger(:slow)
|
22
|
+
expect(fsm.current).to eq(:yellow)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "allows to use any method name without auto method generation" do
|
26
|
+
fsm = FiniteMachine.new(auto_methods: false) do
|
27
|
+
initial :green
|
28
|
+
|
29
|
+
event :fail, :green => :red
|
30
|
+
end
|
31
|
+
|
32
|
+
fsm.trigger(:fail)
|
33
|
+
expect(fsm.current).to eq(:red)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "detects dangerous event names" do
|
37
|
+
expect {
|
38
|
+
FiniteMachine.new do
|
39
|
+
event :trigger, :a => :b
|
40
|
+
end
|
41
|
+
}.to raise_error(FiniteMachine::AlreadyDefinedError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -1,192 +1,180 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require 'spec_helper'
|
1
|
+
# frozen_string_literal
|
4
2
|
|
5
3
|
RSpec.describe FiniteMachine, 'callbacks' do
|
6
|
-
|
7
4
|
it "triggers default init event" do
|
8
5
|
called = []
|
9
|
-
fsm = FiniteMachine.
|
6
|
+
fsm = FiniteMachine.new do
|
10
7
|
initial :green, defer: true, silent: false
|
11
8
|
|
12
|
-
callbacks
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
on_exit do |event| called << 'on_exit' end
|
9
|
+
# generic state callbacks
|
10
|
+
on_enter do |event| called << 'on_enter' end
|
11
|
+
on_transition do |event| called << 'on_transition' end
|
12
|
+
on_exit do |event| called << 'on_exit' end
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
# generic event callbacks
|
15
|
+
on_before any_event do |event| called << 'on_before' end
|
16
|
+
on_after do |event| called << 'on_after' end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
# state callbacks
|
19
|
+
on_enter :none do |event| called << 'on_enter_none' end
|
20
|
+
on_enter :green do |event| called << 'on_enter_green' end
|
25
21
|
|
26
|
-
|
27
|
-
|
22
|
+
on_transition :none do |event| called << 'on_transition_none' end
|
23
|
+
on_transition :green do |event| called << 'on_transition_green' end
|
28
24
|
|
29
|
-
|
30
|
-
|
25
|
+
on_exit :none do |event| called << 'on_exit_none' end
|
26
|
+
on_exit :green do |event| called << 'on_exit_green' end
|
31
27
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
}
|
28
|
+
# event callbacks
|
29
|
+
on_before :init do |event| called << 'on_before_init' end
|
30
|
+
on_after :init do |event| called << 'on_after_init' end
|
36
31
|
end
|
37
32
|
|
38
33
|
expect(fsm.current).to eql(:none)
|
39
34
|
fsm.init
|
40
35
|
expect(called).to eql([
|
41
|
-
'on_before_init',
|
42
36
|
'on_before',
|
43
|
-
'
|
37
|
+
'on_before_init',
|
44
38
|
'on_exit',
|
45
|
-
'
|
39
|
+
'on_exit_none',
|
46
40
|
'on_transition',
|
47
|
-
'
|
41
|
+
'on_transition_green',
|
48
42
|
'on_enter',
|
49
|
-
'
|
50
|
-
'on_after'
|
43
|
+
'on_enter_green',
|
44
|
+
'on_after',
|
45
|
+
'on_after_init'
|
51
46
|
])
|
52
47
|
end
|
53
48
|
|
54
49
|
it "executes callbacks in order" do
|
55
50
|
called = []
|
56
|
-
fsm = FiniteMachine.
|
51
|
+
fsm = FiniteMachine.new do
|
57
52
|
initial :green, silent: false
|
58
53
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
on_after :stop do |event| called << "on_after_stop" end
|
96
|
-
on_after :ready do |event| called << "on_after_ready" end
|
97
|
-
on_after :go do |event| called << "on_after_go" end
|
98
|
-
}
|
54
|
+
event :slow, :green => :yellow
|
55
|
+
event :stop, :yellow => :red
|
56
|
+
event :ready, :red => :yellow
|
57
|
+
event :go, :yellow => :green
|
58
|
+
|
59
|
+
# generic callbacks
|
60
|
+
on_enter do |event| called << 'on_enter' end
|
61
|
+
on_transition do |event| called << 'on_transition' end
|
62
|
+
on_exit do |event| called << 'on_exit' end
|
63
|
+
|
64
|
+
on_before do |event| called << 'on_before' end
|
65
|
+
on_after do |event| called << 'on_after' end
|
66
|
+
|
67
|
+
# state callbacks
|
68
|
+
on_enter :green do |event| called << 'on_enter_green' end
|
69
|
+
on_enter :yellow do |event| called << "on_enter_yellow" end
|
70
|
+
on_enter :red do |event| called << "on_enter_red" end
|
71
|
+
|
72
|
+
on_transition :green do |event| called << 'on_transition_green' end
|
73
|
+
on_transition :yellow do |event| called << "on_transition_yellow" end
|
74
|
+
on_transition :red do |event| called << "on_transition_red" end
|
75
|
+
|
76
|
+
on_exit :green do |event| called << 'on_exit_green' end
|
77
|
+
on_exit :yellow do |event| called << "on_exit_yellow" end
|
78
|
+
on_exit :red do |event| called << "on_exit_red" end
|
79
|
+
|
80
|
+
# event callbacks
|
81
|
+
on_before :slow do |event| called << 'on_before_slow' end
|
82
|
+
on_before :stop do |event| called << "on_before_stop" end
|
83
|
+
on_before :ready do |event| called << "on_before_ready" end
|
84
|
+
on_before :go do |event| called << "on_before_go" end
|
85
|
+
|
86
|
+
on_after :slow do |event| called << 'on_after_slow' end
|
87
|
+
on_after :stop do |event| called << "on_after_stop" end
|
88
|
+
on_after :ready do |event| called << "on_after_ready" end
|
89
|
+
on_after :go do |event| called << "on_after_go" end
|
99
90
|
end
|
100
91
|
|
101
92
|
expect(fsm.current).to eq(:green)
|
102
93
|
expect(called).to eq([
|
103
94
|
'on_before',
|
104
95
|
'on_exit',
|
105
|
-
'on_transition_green',
|
106
96
|
'on_transition',
|
107
|
-
'
|
97
|
+
'on_transition_green',
|
108
98
|
'on_enter',
|
99
|
+
'on_enter_green',
|
109
100
|
'on_after'
|
110
101
|
])
|
111
102
|
|
112
103
|
called = []
|
113
104
|
fsm.slow
|
114
105
|
expect(called).to eql([
|
115
|
-
'on_before_slow',
|
116
106
|
'on_before',
|
117
|
-
'
|
107
|
+
'on_before_slow',
|
118
108
|
'on_exit',
|
119
|
-
'
|
109
|
+
'on_exit_green',
|
120
110
|
'on_transition',
|
121
|
-
'
|
111
|
+
'on_transition_yellow',
|
122
112
|
'on_enter',
|
123
|
-
'
|
124
|
-
'on_after'
|
113
|
+
'on_enter_yellow',
|
114
|
+
'on_after',
|
115
|
+
'on_after_slow'
|
125
116
|
])
|
126
117
|
|
127
118
|
called = []
|
128
119
|
fsm.stop
|
129
120
|
expect(called).to eql([
|
130
|
-
'on_before_stop',
|
131
121
|
'on_before',
|
132
|
-
'
|
122
|
+
'on_before_stop',
|
133
123
|
'on_exit',
|
134
|
-
'
|
124
|
+
'on_exit_yellow',
|
135
125
|
'on_transition',
|
136
|
-
'
|
126
|
+
'on_transition_red',
|
137
127
|
'on_enter',
|
138
|
-
'
|
139
|
-
'on_after'
|
128
|
+
'on_enter_red',
|
129
|
+
'on_after',
|
130
|
+
'on_after_stop'
|
140
131
|
])
|
141
132
|
|
142
133
|
called = []
|
143
134
|
fsm.ready
|
144
135
|
expect(called).to eql([
|
145
|
-
'on_before_ready',
|
146
136
|
'on_before',
|
147
|
-
'
|
137
|
+
'on_before_ready',
|
148
138
|
'on_exit',
|
149
|
-
'
|
139
|
+
'on_exit_red',
|
150
140
|
'on_transition',
|
151
|
-
'
|
141
|
+
'on_transition_yellow',
|
152
142
|
'on_enter',
|
153
|
-
'
|
154
|
-
'on_after'
|
143
|
+
'on_enter_yellow',
|
144
|
+
'on_after',
|
145
|
+
'on_after_ready'
|
155
146
|
])
|
156
147
|
|
157
148
|
called = []
|
158
149
|
fsm.go
|
159
150
|
expect(called).to eql([
|
160
|
-
'on_before_go',
|
161
151
|
'on_before',
|
162
|
-
'
|
152
|
+
'on_before_go',
|
163
153
|
'on_exit',
|
164
|
-
'
|
154
|
+
'on_exit_yellow',
|
165
155
|
'on_transition',
|
166
|
-
'
|
156
|
+
'on_transition_green',
|
167
157
|
'on_enter',
|
168
|
-
'
|
169
|
-
'on_after'
|
158
|
+
'on_enter_green',
|
159
|
+
'on_after',
|
160
|
+
'on_after_go'
|
170
161
|
])
|
171
162
|
end
|
172
163
|
|
173
164
|
it "maintains transition execution sequence from UML statechart" do
|
174
165
|
called = []
|
175
|
-
fsm = FiniteMachine.
|
166
|
+
fsm = FiniteMachine.new do
|
176
167
|
initial :previous, silent: false
|
177
168
|
|
178
|
-
|
179
|
-
|
180
|
-
}
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
on_transition { |event| called << "transition_#{event.from}_#{event.to}"}
|
186
|
-
on_enter { |event| called << "enter_#{event.to}"}
|
187
|
-
on_after { |event| called << "after_#{event.name}" }
|
188
|
-
}
|
169
|
+
event :go, :previous => :next, if: -> { called << 'guard'; true}
|
170
|
+
|
171
|
+
on_exit { |event| called << "exit_#{event.from}" }
|
172
|
+
on_before { |event| called << "before_#{event.name}" }
|
173
|
+
on_transition { |event| called << "transition_#{event.from}_#{event.to}"}
|
174
|
+
on_enter { |event| called << "enter_#{event.to}"}
|
175
|
+
on_after { |event| called << "after_#{event.name}" }
|
189
176
|
end
|
177
|
+
|
190
178
|
expect(fsm.current).to eq(:previous)
|
191
179
|
fsm.go
|
192
180
|
expect(called).to eq([
|
@@ -206,40 +194,36 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
206
194
|
|
207
195
|
it "allows multiple callbacks for the same state" do
|
208
196
|
called = []
|
209
|
-
fsm = FiniteMachine.
|
197
|
+
fsm = FiniteMachine.new do
|
210
198
|
initial :green, silent: false
|
211
199
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
on_before :slow do |event| called << 'on_before_slow_2' end
|
240
|
-
on_after :slow do |event| called << 'on_after_slow_1' end
|
241
|
-
on_after :slow do |event| called << 'on_after_slow_2' end
|
242
|
-
}
|
200
|
+
event :slow, :green => :yellow
|
201
|
+
event :stop, :yellow => :red
|
202
|
+
event :ready, :red => :yellow
|
203
|
+
event :go, :yellow => :green
|
204
|
+
|
205
|
+
# generic state callbacks
|
206
|
+
on_enter do |event| called << 'on_enter' end
|
207
|
+
on_transition do |event| called << 'on_transition' end
|
208
|
+
on_exit do |event| called << 'on_exit' end
|
209
|
+
|
210
|
+
# generic event callbacks
|
211
|
+
on_before do |event| called << 'on_before' end
|
212
|
+
on_after do |event| called << 'on_after' end
|
213
|
+
|
214
|
+
# state callbacks
|
215
|
+
on_exit :green do |event| called << 'on_exit_green_1' end
|
216
|
+
on_exit :green do |event| called << 'on_exit_green_2' end
|
217
|
+
on_enter :yellow do |event| called << 'on_enter_yellow_1' end
|
218
|
+
on_enter :yellow do |event| called << 'on_enter_yellow_2' end
|
219
|
+
on_transition :yellow do |event| called << 'on_transition_yellow_1' end
|
220
|
+
on_transition :yellow do |event| called << 'on_transition_yellow_2' end
|
221
|
+
|
222
|
+
# event callbacks
|
223
|
+
on_before :slow do |event| called << 'on_before_slow_1' end
|
224
|
+
on_before :slow do |event| called << 'on_before_slow_2' end
|
225
|
+
on_after :slow do |event| called << 'on_after_slow_1' end
|
226
|
+
on_after :slow do |event| called << 'on_after_slow_2' end
|
243
227
|
end
|
244
228
|
|
245
229
|
expect(fsm.current).to eql(:green)
|
@@ -254,46 +238,42 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
254
238
|
fsm.slow
|
255
239
|
expect(fsm.current).to eql(:yellow)
|
256
240
|
expect(called).to eql([
|
241
|
+
'on_before',
|
257
242
|
'on_before_slow_1',
|
258
243
|
'on_before_slow_2',
|
259
|
-
'
|
244
|
+
'on_exit',
|
260
245
|
'on_exit_green_1',
|
261
246
|
'on_exit_green_2',
|
262
|
-
'
|
247
|
+
'on_transition',
|
263
248
|
'on_transition_yellow_1',
|
264
249
|
'on_transition_yellow_2',
|
265
|
-
'
|
250
|
+
'on_enter',
|
266
251
|
'on_enter_yellow_1',
|
267
252
|
'on_enter_yellow_2',
|
268
|
-
'
|
253
|
+
'on_after',
|
269
254
|
'on_after_slow_1',
|
270
|
-
'on_after_slow_2'
|
271
|
-
'on_after'
|
255
|
+
'on_after_slow_2'
|
272
256
|
])
|
273
257
|
end
|
274
258
|
|
275
259
|
it "allows for fluid callback definition" do
|
276
260
|
called = []
|
277
|
-
fsm = FiniteMachine.
|
261
|
+
fsm = FiniteMachine.new do
|
278
262
|
initial :green
|
279
263
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
# event callbacks
|
294
|
-
on_before_slow do |event| called << 'on_before_slow' end
|
295
|
-
on_after_slow do |event| called << 'on_after_slow' end
|
296
|
-
}
|
264
|
+
event :slow, :green => :yellow
|
265
|
+
event :stop, :yellow => :red
|
266
|
+
event :ready, :red => :yellow
|
267
|
+
event :go, :yellow => :green
|
268
|
+
|
269
|
+
# state callbacks
|
270
|
+
on_exit_green do |event| called << 'on_exit_green' end
|
271
|
+
on_enter_yellow do |event| called << 'on_enter_yellow' end
|
272
|
+
on_transition_yellow do |event| called << 'on_transition_yellow' end
|
273
|
+
|
274
|
+
# event callbacks
|
275
|
+
on_before_slow do |event| called << 'on_before_slow' end
|
276
|
+
on_after_slow do |event| called << 'on_after_slow' end
|
297
277
|
end
|
298
278
|
|
299
279
|
called = []
|
@@ -310,16 +290,12 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
310
290
|
|
311
291
|
it "passes event object to callback" do
|
312
292
|
evt = nil
|
313
|
-
fsm = FiniteMachine.
|
293
|
+
fsm = FiniteMachine.new do
|
314
294
|
initial :green
|
315
295
|
|
316
|
-
|
317
|
-
event :slow, :green => :yellow
|
318
|
-
}
|
296
|
+
event :slow, :green => :yellow
|
319
297
|
|
320
|
-
|
321
|
-
on_enter(:yellow) { |e| evt = e }
|
322
|
-
}
|
298
|
+
on_enter(:yellow) { |e| evt = e }
|
323
299
|
end
|
324
300
|
|
325
301
|
expect(fsm.current).to eql(:green)
|
@@ -333,17 +309,13 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
333
309
|
|
334
310
|
it "identifies the from state for callback event parameter" do
|
335
311
|
evt = nil
|
336
|
-
fsm = FiniteMachine.
|
312
|
+
fsm = FiniteMachine.new do
|
337
313
|
initial :green
|
338
314
|
|
339
|
-
|
340
|
-
|
341
|
-
event :fast, :red => :purple
|
342
|
-
}
|
315
|
+
event :slow, [:red, :blue, :green] => :yellow
|
316
|
+
event :fast, :red => :purple
|
343
317
|
|
344
|
-
|
345
|
-
on_enter(:yellow) { |e| evt = e }
|
346
|
-
}
|
318
|
+
on_enter(:yellow) { |e| evt = e }
|
347
319
|
end
|
348
320
|
|
349
321
|
expect(fsm.current).to eql(:green)
|
@@ -366,54 +338,47 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
366
338
|
target.expect(b).to target.eql(expected[:b])
|
367
339
|
target.expect(c).to target.eql(expected[:c])
|
368
340
|
}
|
369
|
-
context = self
|
370
341
|
|
371
|
-
fsm = FiniteMachine.
|
342
|
+
fsm = FiniteMachine.new(self) do
|
372
343
|
initial :green
|
373
344
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
on_after :slow , &callback
|
413
|
-
on_after :stop , &callback
|
414
|
-
on_after :ready, &callback
|
415
|
-
on_after :go , &callback
|
416
|
-
}
|
345
|
+
event :slow, :green => :yellow
|
346
|
+
event :stop, :yellow => :red
|
347
|
+
event :ready, :red => :yellow
|
348
|
+
event :go, :yellow => :green
|
349
|
+
|
350
|
+
# generic state callbacks
|
351
|
+
on_enter(&callback)
|
352
|
+
on_transition(&callback)
|
353
|
+
on_exit(&callback)
|
354
|
+
|
355
|
+
# generic event callbacks
|
356
|
+
on_before(&callback)
|
357
|
+
on_after(&callback)
|
358
|
+
|
359
|
+
# state callbacks
|
360
|
+
on_enter :green, &callback
|
361
|
+
on_enter :yellow, &callback
|
362
|
+
on_enter :red, &callback
|
363
|
+
|
364
|
+
on_transition :green , &callback
|
365
|
+
on_transition :yellow, &callback
|
366
|
+
on_transition :red , &callback
|
367
|
+
|
368
|
+
on_exit :green , &callback
|
369
|
+
on_exit :yellow, &callback
|
370
|
+
on_exit :red , &callback
|
371
|
+
|
372
|
+
# event callbacks
|
373
|
+
on_before :slow , &callback
|
374
|
+
on_before :stop , &callback
|
375
|
+
on_before :ready, &callback
|
376
|
+
on_before :go , &callback
|
377
|
+
|
378
|
+
on_after :slow , &callback
|
379
|
+
on_after :stop , &callback
|
380
|
+
on_after :ready, &callback
|
381
|
+
on_after :go , &callback
|
417
382
|
end
|
418
383
|
|
419
384
|
expected = {name: :slow, from: :green, to: :yellow, a: 1, b: 2, c: 3}
|
@@ -441,63 +406,55 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
441
406
|
target.expect(c).to target.eql(expected[:c])
|
442
407
|
}
|
443
408
|
|
444
|
-
|
445
|
-
|
446
|
-
fsm = FiniteMachine.define do
|
409
|
+
fsm = FiniteMachine.new(self) do
|
447
410
|
initial :red
|
448
411
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
on_after :power_on, &callback
|
496
|
-
on_after :power_off, &callback
|
497
|
-
on_after :go, &callback
|
498
|
-
on_after :slow, &callback
|
499
|
-
on_after :stop, &callback
|
500
|
-
}
|
412
|
+
event :power_on, :off => :red
|
413
|
+
event :power_off, any_state => :off
|
414
|
+
event :go, :red => :green
|
415
|
+
event :slow, :green => :yellow
|
416
|
+
event :stop, :yellow => :red
|
417
|
+
|
418
|
+
# generic state callbacks
|
419
|
+
on_enter(&callback)
|
420
|
+
on_transition(&callback)
|
421
|
+
on_exit(&callback)
|
422
|
+
|
423
|
+
# generic event callbacks
|
424
|
+
on_before(&callback)
|
425
|
+
on_after(&callback)
|
426
|
+
|
427
|
+
# state callbacks
|
428
|
+
on_enter :green, &callback
|
429
|
+
on_enter :yellow, &callback
|
430
|
+
on_enter :red, &callback
|
431
|
+
on_enter :off, &callback
|
432
|
+
on_enter :off, &callback
|
433
|
+
|
434
|
+
on_transition :green, &callback
|
435
|
+
on_transition :yellow, &callback
|
436
|
+
on_transition :red, &callback
|
437
|
+
on_transition :off, &callback
|
438
|
+
on_transition :off, &callback
|
439
|
+
|
440
|
+
on_exit :green, &callback
|
441
|
+
on_exit :yellow, &callback
|
442
|
+
on_exit :red, &callback
|
443
|
+
on_exit :off, &callback
|
444
|
+
on_exit :off, &callback
|
445
|
+
|
446
|
+
# event callbacks
|
447
|
+
on_before :power_on, &callback
|
448
|
+
on_before :power_off, &callback
|
449
|
+
on_before :go, &callback
|
450
|
+
on_before :slow, &callback
|
451
|
+
on_before :stop, &callback
|
452
|
+
|
453
|
+
on_after :power_on, &callback
|
454
|
+
on_after :power_off, &callback
|
455
|
+
on_after :go, &callback
|
456
|
+
on_after :slow, &callback
|
457
|
+
on_after :stop, &callback
|
501
458
|
end
|
502
459
|
|
503
460
|
expect(fsm.current).to eq(:red)
|
@@ -517,47 +474,43 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
517
474
|
|
518
475
|
it "raises an error with invalid callback name" do
|
519
476
|
expect {
|
520
|
-
FiniteMachine.
|
477
|
+
FiniteMachine.new do
|
521
478
|
initial :green
|
522
479
|
|
523
|
-
|
524
|
-
event :slow, :green => :yellow
|
525
|
-
}
|
480
|
+
event :slow, :green => :yellow
|
526
481
|
|
527
|
-
|
528
|
-
on_enter(:magic) { |event| called << 'on_enter'}
|
529
|
-
}
|
482
|
+
on_enter(:magic) { |event| called << 'on_enter'}
|
530
483
|
end
|
531
484
|
}.to raise_error(FiniteMachine::InvalidCallbackNameError, /\"magic\" is not a valid callback name/)
|
532
485
|
end
|
533
486
|
|
534
487
|
it "doesn't allow to mix state callback with event name" do
|
535
488
|
expect {
|
536
|
-
FiniteMachine.
|
537
|
-
|
489
|
+
FiniteMachine.new do
|
490
|
+
event :slow, :green => :yellow
|
538
491
|
|
539
|
-
|
492
|
+
on_enter_slow do |event| end
|
540
493
|
end
|
541
494
|
}.to raise_error(FiniteMachine::InvalidCallbackNameError, "\"on_enter\" callback is a state listener and cannot be used with \"slow\" event name. Please use on_before or on_after instead.")
|
542
495
|
end
|
543
496
|
|
544
497
|
it "doesn't allow to mix event callback with state name" do
|
545
498
|
expect {
|
546
|
-
FiniteMachine.
|
547
|
-
|
499
|
+
FiniteMachine.new do
|
500
|
+
event :slow, :green => :yellow
|
548
501
|
|
549
|
-
|
502
|
+
on_before_green do |event| end
|
550
503
|
end
|
551
504
|
}.to raise_error(FiniteMachine::InvalidCallbackNameError, '"on_before" callback is an event listener and cannot be used with "green" state name. Please use on_enter, on_transition or on_exit instead.')
|
552
505
|
end
|
553
506
|
|
554
507
|
it "propagates exceptions raised inside callback" do
|
555
|
-
fsm = FiniteMachine.
|
508
|
+
fsm = FiniteMachine.new do
|
556
509
|
initial :green
|
557
510
|
|
558
|
-
|
511
|
+
event :slow, :green => :yellow
|
559
512
|
|
560
|
-
|
513
|
+
on_enter(:yellow) { raise RuntimeError }
|
561
514
|
end
|
562
515
|
|
563
516
|
expect(fsm.current).to eql(:green)
|
@@ -566,19 +519,15 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
566
519
|
|
567
520
|
it "executes callbacks with multiple 'from' transitions" do
|
568
521
|
called = []
|
569
|
-
fsm = FiniteMachine.
|
522
|
+
fsm = FiniteMachine.new do
|
570
523
|
initial :green
|
571
524
|
|
572
|
-
|
573
|
-
|
574
|
-
event :stop, :yellow => :red
|
575
|
-
}
|
525
|
+
event :stop, :green => :yellow
|
526
|
+
event :stop, :yellow => :red
|
576
527
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
end
|
581
|
-
}
|
528
|
+
on_before_stop do |event|
|
529
|
+
called << 'on_before_stop'
|
530
|
+
end
|
582
531
|
end
|
583
532
|
expect(fsm.current).to eql(:green)
|
584
533
|
fsm.stop
|
@@ -593,15 +542,13 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
593
542
|
|
594
543
|
it "allows to define callbacks on machine instance" do
|
595
544
|
called = []
|
596
|
-
fsm = FiniteMachine.
|
545
|
+
fsm = FiniteMachine.new do
|
597
546
|
initial :green
|
598
547
|
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
event :go, :yellow => :green
|
604
|
-
}
|
548
|
+
event :slow, :green => :yellow
|
549
|
+
event :stop, :yellow => :red
|
550
|
+
event :ready, :red => :yellow
|
551
|
+
event :go, :yellow => :green
|
605
552
|
end
|
606
553
|
|
607
554
|
fsm.on_enter_yellow do |event|
|
@@ -616,52 +563,46 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
616
563
|
end
|
617
564
|
|
618
565
|
it "raises error for unknown callback" do
|
619
|
-
expect {
|
620
|
-
|
566
|
+
expect {
|
567
|
+
FiniteMachine.new do
|
568
|
+
initial :green
|
621
569
|
|
622
|
-
events {
|
623
570
|
event :slow, :green => :yellow
|
624
571
|
event :stop, :yellow => :red
|
625
572
|
event :ready, :red => :yellow
|
626
573
|
event :go, :yellow => :green
|
627
|
-
}
|
628
574
|
|
629
|
-
callbacks {
|
630
575
|
on_enter_unknown do |event| end
|
631
|
-
|
632
|
-
|
576
|
+
end
|
577
|
+
}.to raise_error(NameError, /`on_enter_unknown'/)
|
633
578
|
end
|
634
579
|
|
635
580
|
it "triggers callbacks only once" do
|
636
581
|
called = []
|
637
|
-
fsm = FiniteMachine.
|
582
|
+
fsm = FiniteMachine.new do
|
638
583
|
initial :green, silent: false
|
639
584
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
once_on_after_init do |event| called << 'once_on_after_init' end
|
662
|
-
once_on_after_slow do |event| called << 'once_on_after_slow' end
|
663
|
-
once_on_after_go do |event| called << 'once_on_after_go' end
|
664
|
-
}
|
585
|
+
event :slow, :green => :yellow
|
586
|
+
event :go, :yellow => :green
|
587
|
+
|
588
|
+
# state callbacks
|
589
|
+
once_on_enter_green do |event| called << 'once_on_enter_green' end
|
590
|
+
once_on_enter_yellow do |event| called << 'once_on_enter_yellow' end
|
591
|
+
|
592
|
+
once_on_transition_green do |event| called << 'once_on_transition_green' end
|
593
|
+
once_on_transition_yellow do |event| called << 'once_on_transition_yellow' end
|
594
|
+
once_on_exit_none do |event| called << 'once_on_exit_none' end
|
595
|
+
once_on_exit_green do |event| called << 'once_on_exit_green' end
|
596
|
+
once_on_exit_yellow do |event| called << 'once_on_exit_yellow' end
|
597
|
+
|
598
|
+
# event callbacks
|
599
|
+
once_on_before_init do |event| called << 'once_on_before_init' end
|
600
|
+
once_on_before_slow do |event| called << 'once_on_before_slow' end
|
601
|
+
once_on_before_go do |event| called << 'once_on_before_go' end
|
602
|
+
|
603
|
+
once_on_after_init do |event| called << 'once_on_after_init' end
|
604
|
+
once_on_after_slow do |event| called << 'once_on_after_slow' end
|
605
|
+
once_on_after_go do |event| called << 'once_on_after_go' end
|
665
606
|
end
|
666
607
|
expect(fsm.current).to eql(:green)
|
667
608
|
fsm.slow
|
@@ -687,83 +628,31 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
687
628
|
])
|
688
629
|
end
|
689
630
|
|
690
|
-
it "cancels transition on event 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|
|
701
|
-
FiniteMachine::CANCELLED
|
702
|
-
end
|
703
|
-
}
|
704
|
-
end
|
705
|
-
|
706
|
-
expect(fsm.current).to eql(:green)
|
707
|
-
fsm.slow
|
708
|
-
expect(fsm.current).to eql(:green)
|
709
|
-
end
|
710
|
-
|
711
|
-
it "stops executing callbacks when cancelled" do
|
712
|
-
called = []
|
713
|
-
|
714
|
-
fsm = FiniteMachine.define do
|
715
|
-
initial :initial
|
716
|
-
|
717
|
-
events { event :bump, initial: :low }
|
718
|
-
|
719
|
-
callbacks {
|
720
|
-
on_before do |event|
|
721
|
-
called << "enter_#{event.name}_#{event.from}_#{event.to}"
|
722
|
-
|
723
|
-
FiniteMachine::CANCELLED
|
724
|
-
end
|
725
|
-
|
726
|
-
on_exit :initial do |event| called << "exit_initial" end
|
727
|
-
on_exit do |event| called << "exit_any" end
|
728
|
-
on_enter :low do |event| called << "enter_low" end
|
729
|
-
on_after :bump do |event| called << "after_#{event.name}" end
|
730
|
-
on_after do |event| called << "after_any" end
|
731
|
-
}
|
732
|
-
end
|
733
|
-
|
734
|
-
fsm.bump
|
735
|
-
|
736
|
-
expect(called).to eq(['enter_bump_initial_low'])
|
737
|
-
end
|
738
|
-
|
739
631
|
xit "groups callbacks"
|
740
632
|
|
741
633
|
it "groups states from separate events with the same name" do
|
742
634
|
callbacks = []
|
743
|
-
fsm = FiniteMachine.
|
635
|
+
fsm = FiniteMachine.new do
|
744
636
|
initial :initial, silent: false
|
745
637
|
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
on_after do |event|
|
763
|
-
callbacks << "after_#{event.name}_#{event.from}_#{event.to}"
|
764
|
-
end
|
765
|
-
}
|
638
|
+
event :bump, :initial => :low
|
639
|
+
event :bump, :low => :medium
|
640
|
+
event :bump, :medium => :high
|
641
|
+
|
642
|
+
on_enter do |event|
|
643
|
+
callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
|
644
|
+
end
|
645
|
+
on_exit do |event|
|
646
|
+
callbacks << "exit_#{event.name}_#{event.from}_#{event.to}"
|
647
|
+
end
|
648
|
+
on_before do |event|
|
649
|
+
callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
|
650
|
+
end
|
651
|
+
on_after do |event|
|
652
|
+
callbacks << "after_#{event.name}_#{event.from}_#{event.to}"
|
653
|
+
end
|
766
654
|
end
|
655
|
+
|
767
656
|
expect(fsm.current).to eq(:initial)
|
768
657
|
fsm.bump
|
769
658
|
expect(callbacks).to eq([
|
@@ -814,24 +703,21 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
814
703
|
|
815
704
|
it "groups states under event name" do
|
816
705
|
callbacks = []
|
817
|
-
fsm = FiniteMachine.
|
706
|
+
fsm = FiniteMachine.new do
|
818
707
|
initial :initial, silent: false
|
819
708
|
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
on_before do |event|
|
831
|
-
callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
|
832
|
-
end
|
833
|
-
}
|
709
|
+
event :bump, :initial => :low,
|
710
|
+
:low => :medium,
|
711
|
+
:medium => :high
|
712
|
+
|
713
|
+
on_enter do |event|
|
714
|
+
callbacks << "enter_#{event.name}_#{event.from}_#{event.to}"
|
715
|
+
end
|
716
|
+
on_before do |event|
|
717
|
+
callbacks << "before_#{event.name}_#{event.from}_#{event.to}"
|
718
|
+
end
|
834
719
|
end
|
720
|
+
|
835
721
|
expect(fsm.current).to eq(:initial)
|
836
722
|
fsm.bump
|
837
723
|
expect(callbacks).to eq([
|
@@ -864,18 +750,14 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
864
750
|
|
865
751
|
it "permits state and event with the same name" do
|
866
752
|
called = []
|
867
|
-
fsm = FiniteMachine.
|
753
|
+
fsm = FiniteMachine.new do
|
868
754
|
initial :on_hook, silent: false
|
869
755
|
|
870
|
-
|
871
|
-
|
872
|
-
event :on_hook, :off_hook => :on_hook
|
873
|
-
}
|
756
|
+
event :off_hook, :on_hook => :off_hook
|
757
|
+
event :on_hook, :off_hook => :on_hook
|
874
758
|
|
875
|
-
|
876
|
-
|
877
|
-
on_enter(:on_hook) { |event| called << "on_enter_#{event.to}"}
|
878
|
-
}
|
759
|
+
on_before(:on_hook) { |event| called << "on_before_#{event.name}"}
|
760
|
+
on_enter(:on_hook) { |event| called << "on_enter_#{event.to}"}
|
879
761
|
end
|
880
762
|
expect(fsm.current).to eq(:on_hook)
|
881
763
|
expect(called).to eq([
|
@@ -893,18 +775,14 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
893
775
|
|
894
776
|
it "allows to selectively silence events" do
|
895
777
|
called = []
|
896
|
-
fsm = FiniteMachine.
|
778
|
+
fsm = FiniteMachine.new do
|
897
779
|
initial :yellow
|
898
780
|
|
899
|
-
|
900
|
-
|
901
|
-
event :stop, :green => :red
|
902
|
-
}
|
781
|
+
event :go, :yellow => :green, silent: true
|
782
|
+
event :stop, :green => :red
|
903
783
|
|
904
|
-
|
905
|
-
|
906
|
-
on_enter :red do |event| called << 'on_enter_red' end
|
907
|
-
}
|
784
|
+
on_enter :green do |event| called << 'on_enter_yellow' end
|
785
|
+
on_enter :red do |event| called << 'on_enter_red' end
|
908
786
|
end
|
909
787
|
expect(fsm.current).to eq(:yellow)
|
910
788
|
fsm.go
|
@@ -914,22 +792,18 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
914
792
|
|
915
793
|
it "executes event-based callbacks even when state does not change" do
|
916
794
|
called = []
|
917
|
-
fsm = FiniteMachine.
|
795
|
+
fsm = FiniteMachine.new do
|
918
796
|
initial :active
|
919
797
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
on_after do |event|
|
930
|
-
called << "after_#{event.name}_#{event.from}_#{event.to}"
|
931
|
-
end
|
932
|
-
}
|
798
|
+
event :advance, :active => :inactive, if: -> { false }
|
799
|
+
event :advance, :inactive => :active, if: -> { false }
|
800
|
+
|
801
|
+
on_before do |event|
|
802
|
+
called << "before_#{event.name}_#{event.from}_#{event.to}"
|
803
|
+
end
|
804
|
+
on_after do |event|
|
805
|
+
called << "after_#{event.name}_#{event.from}_#{event.to}"
|
806
|
+
end
|
933
807
|
end
|
934
808
|
expect(fsm.current).to eq(:active)
|
935
809
|
fsm.advance
|
@@ -939,4 +813,39 @@ RSpec.describe FiniteMachine, 'callbacks' do
|
|
939
813
|
'after_advance_active_inactive'
|
940
814
|
])
|
941
815
|
end
|
816
|
+
|
817
|
+
it "doesn't transition if error raised in callback" do
|
818
|
+
fsm = FiniteMachine.new do
|
819
|
+
initial :green
|
820
|
+
|
821
|
+
event :slow, :green => :yellow
|
822
|
+
|
823
|
+
on_enter { raise RuntimeError }
|
824
|
+
end
|
825
|
+
|
826
|
+
expect {
|
827
|
+
fsm.slow
|
828
|
+
}.to raise_error(RuntimeError)
|
829
|
+
expect(fsm.current).to eq(:green)
|
830
|
+
end
|
831
|
+
|
832
|
+
xit "narrows down on_transition callback to state transition" do
|
833
|
+
called = []
|
834
|
+
fsm = FiniteMachine.new do
|
835
|
+
initial :red
|
836
|
+
|
837
|
+
event :ready, :red => :yellow
|
838
|
+
event :go, :yellow => :green
|
839
|
+
event :stop, :green => :red
|
840
|
+
|
841
|
+
on_transition :yellow => :green do
|
842
|
+
called << 'on_transition_yellow_green'
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
fsm.ready
|
847
|
+
fsm.go
|
848
|
+
|
849
|
+
expect(called).to eq(['on_transition_yellow_green'])
|
850
|
+
end
|
942
851
|
end
|