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,222 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, 'initial' do
6
-
7
- before(:each) {
8
- stub_const("DummyLogger", Class.new do
9
- attr_accessor :level
10
-
11
- def initialize
12
- @level = :pending
13
- end
14
- end)
15
- }
16
-
17
- it "defaults initial state to :none" do
18
- fsm = FiniteMachine.define do
19
- events {
20
- event :slow, :green => :yellow
21
- event :stop, :yellow => :red
22
- }
23
- end
24
-
25
- expect(fsm.current).to eql(:none)
26
- end
27
-
28
- it "requires initial state transition from :none" do
29
- fsm = FiniteMachine.define do
30
- events {
31
- event :init, :none => :green
32
- event :slow, :green => :yellow
33
- event :stop, :yellow => :red
34
- }
35
- end
36
-
37
- expect(fsm.current).to eql(:none)
38
- fsm.init
39
- expect(fsm.current).to eql(:green)
40
- end
41
-
42
- it "allows to specify inital state" do
43
- called = []
44
- fsm = FiniteMachine.define do
45
- initial :green
46
-
47
- events {
48
- event :slow, :green => :yellow
49
- event :stop, :yellow => :red
50
- }
51
- callbacks {
52
- on_exit :none do |event| called << 'on_exit_none' end
53
- on_enter :green do |event| called << 'on_enter_green' end
54
- }
55
- end
56
- expect(fsm.current).to eql(:green)
57
- expect(called).to be_empty
58
- end
59
-
60
- it "allows to specify initial state through parameter" do
61
- fsm = FiniteMachine.define initial: :green do
62
- events {
63
- event :slow, :green => :yellow
64
- event :stop, :yellow => :red
65
- }
66
- end
67
- expect(fsm.current).to eql(:green)
68
- end
69
-
70
- it "allows to specify deferred inital state" do
71
- fsm = FiniteMachine.define do
72
- initial :green, defer: true
73
-
74
- events {
75
- event :slow, :green => :yellow
76
- event :stop, :yellow => :red
77
- }
78
- end
79
-
80
- expect(fsm.current).to eql(:none)
81
- fsm.init
82
- expect(fsm.current).to eql(:green)
83
- end
84
-
85
- it "raises error when specyfying initial without state name" do
86
- expect {
87
- FiniteMachine.define do
88
- initial defer: true
89
-
90
- events {
91
- event :slow, :green => :yellow
92
- event :stop, :yellow => :red
93
- }
94
- end
95
- }.to raise_error(FiniteMachine::MissingInitialStateError)
96
- end
97
-
98
- it "allows to specify inital start event" do
99
- fsm = FiniteMachine.define do
100
- initial :green, event: :start
101
-
102
- events {
103
- event :slow, :green => :none
104
- event :stop, :yellow => :red
105
- }
106
- end
107
-
108
- expect(fsm.current).to eql(:green)
109
- fsm.slow
110
- expect(fsm.current).to eql(:none)
111
- fsm.start
112
- expect(fsm.current).to eql(:green)
113
- end
114
-
115
- it "allows to specify deferred inital start event" do
116
- fsm = FiniteMachine.define do
117
- initial :green, event: :start, defer: true
118
-
119
- events {
120
- event :slow, :green => :yellow
121
- event :stop, :yellow => :red
122
- }
123
- end
124
-
125
- expect(fsm.current).to eql(:none)
126
- fsm.start
127
- expect(fsm.current).to eql(:green)
128
- end
129
-
130
- it "evaluates initial state" do
131
- logger = DummyLogger.new
132
- fsm = FiniteMachine.define do
133
- initial logger.level
134
-
135
- events {
136
- event :slow, :green => :none
137
- event :stop, :yellow => :red
138
- }
139
- end
140
- expect(fsm.current).to eql(:pending)
141
- end
142
-
143
- it "doesn't care about state type" do
144
- fsm = FiniteMachine.define do
145
- initial 1
146
- events {
147
- event :a, 1 => 2
148
- event :b, 2 => 3
149
- }
150
- end
151
- expect(fsm.current).to eql(1)
152
- fsm.a
153
- expect(fsm.current).to eql(2)
154
- fsm.b
155
- expect(fsm.current).to eql(3)
156
- end
157
-
158
- it "allows to retrieve initial state" do
159
- fsm = FiniteMachine.define do
160
- initial :green
161
-
162
- events {
163
- event :slow, :green => :yellow
164
- event :stop, :yellow => :red
165
- }
166
- end
167
- expect(fsm.current).to eq(:green)
168
- expect(fsm.initial_state).to eq(:green)
169
- fsm.slow
170
- expect(fsm.current).to eq(:yellow)
171
- expect(fsm.initial_state).to eq(:green)
172
- end
173
-
174
- it "allows to retrieve initial state for deferred" do
175
- fsm = FiniteMachine.define do
176
- initial :green, defer: true
177
-
178
- events {
179
- event :slow, :green => :yellow
180
- event :stop, :yellow => :red
181
- }
182
- end
183
- expect(fsm.current).to eq(:none)
184
- expect(fsm.initial_state).to eq(:none)
185
- fsm.init
186
- expect(fsm.current).to eq(:green)
187
- expect(fsm.initial_state).to eq(:green)
188
- end
189
-
190
- it "allows to trigger callbacks on initial with :silent option" do
191
- called = []
192
- fsm = FiniteMachine.define do
193
- initial :green, silent: false
194
-
195
- events {
196
- event :slow, :green => :yellow
197
- }
198
- callbacks {
199
- on_enter :green do |event| called << 'on_enter_green' end
200
- }
201
- end
202
- expect(fsm.current).to eq(:green)
203
- expect(called).to eq(['on_enter_green'])
204
- end
205
-
206
- it "allows to trigger callbacks on deferred initial state" do
207
- called = []
208
- fsm = FiniteMachine.define do
209
- initial :green, silent: false, defer: true
210
-
211
- events {
212
- event :slow, :green => :yellow
213
- }
214
- callbacks {
215
- on_enter :green do |event| called << 'on_enter_green' end
216
- }
217
- end
218
- expect(fsm.current).to eq(:none)
219
- fsm.init
220
- expect(called).to eq(['on_enter_green'])
221
- end
222
- end
@@ -1,17 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, '#inspect' do
6
- it "print useful information about state machine" do
7
- fsm = FiniteMachine.define do
8
- initial :green
9
-
10
- events {
11
- event :slow, :green => :yellow
12
- event :stop, :yellow => :red
13
- }
14
- end
15
- expect(fsm.inspect).to match(/^<#FiniteMachine::StateMachine:0x#{fsm.object_id.to_s(16)} @states=\[:none, :green, :yellow, :red\], @events=\[:init, :slow, :stop\], @transitions=\[{:none=>:green}, {:green=>:yellow}, {:yellow=>:red}\]>$/)
16
- end
17
- end
@@ -1,55 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, 'is?' do
6
-
7
- it "allows to check if state is reachable" do
8
- fsm = FiniteMachine.define do
9
- initial :green
10
-
11
- events {
12
- event :slow, :green => :yellow
13
- event :stop, :yellow => :red
14
- event :ready, :red => :yellow
15
- event :go, :yellow => :green
16
- }
17
- end
18
-
19
- expect(fsm.current).to eql(:green)
20
-
21
- expect(fsm.is?(:green)).to be true
22
- expect(fsm.is?(:yellow)).to be false
23
- expect(fsm.is?([:green, :red])).to be true
24
- expect(fsm.is?([:yellow, :red])).to be false
25
-
26
- fsm.slow
27
-
28
- expect(fsm.is?(:green)).to be false
29
- expect(fsm.is?(:yellow)).to be true
30
- expect(fsm.is?([:green, :red])).to be false
31
- expect(fsm.is?([:yellow, :red])).to be true
32
- end
33
-
34
- it "defines helper methods to check current state" do
35
- fsm = FiniteMachine.define do
36
- initial :green
37
-
38
- events {
39
- event :slow, :green => :yellow
40
- event :stop, :yellow => :red
41
- event :ready, :red => :yellow
42
- event :go, :yellow => :green
43
- }
44
- end
45
- expect(fsm.current).to eql(:green)
46
-
47
- expect(fsm.green?).to be true
48
- expect(fsm.yellow?).to be false
49
-
50
- fsm.slow
51
-
52
- expect(fsm.green?).to be false
53
- expect(fsm.yellow?).to be true
54
- end
55
- end
@@ -1,30 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, 'log_transitions' do
6
- let(:output) { StringIO.new('', 'w+')}
7
-
8
- before { FiniteMachine.logger = ::Logger.new(output) }
9
-
10
- after { FiniteMachine.logger = ::Logger.new($stderr) }
11
-
12
- it "logs transitions" do
13
- fsm = FiniteMachine.define log_transitions: true do
14
- initial :green
15
-
16
- events {
17
- event :slow, :green => :yellow
18
- event :stop, :yellow => :red
19
- }
20
- end
21
-
22
- fsm.slow
23
- output.rewind
24
- expect(output.read).to match(/Transition: @event=slow green -> yellow/)
25
-
26
- fsm.stop(1, 2)
27
- output.rewind
28
- expect(output.read).to match(/Transition: @event=stop @with=\[1,2\] yellow -> red/)
29
- end
30
- end
@@ -1,38 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::Logger do
6
- let(:message) { 'error' }
7
- let(:log) { spy }
8
-
9
- subject(:logger) { described_class }
10
-
11
- before { allow(FiniteMachine).to receive(:logger) { log } }
12
-
13
- it "debugs message call" do
14
- expect(log).to receive(:debug).with(message)
15
- logger.debug(message)
16
- end
17
-
18
- it "informs message call" do
19
- expect(log).to receive(:info).with(message)
20
- logger.info(message)
21
- end
22
-
23
- it "warns message call" do
24
- expect(log).to receive(:warn).with(message)
25
- logger.warn(message)
26
- end
27
-
28
- it "errors message call" do
29
- expect(log).to receive(:error).with(message)
30
- logger.error(message)
31
- end
32
-
33
- it "reports transition" do
34
- logger.report_transition(:go, :red, :green)
35
-
36
- expect(log).to have_received(:info).with("Transition: @event=go red -> green")
37
- end
38
- end
@@ -1,38 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine, '#respond_to' do
6
-
7
- subject(:fsm) {
8
- stub_const("Car", Class.new do
9
- def engine_on?
10
- true
11
- end
12
- end)
13
-
14
- FiniteMachine.new target: Car.new do
15
- initial :green
16
-
17
- events {
18
- event :slow, :green => :yellow
19
- }
20
- end
21
- }
22
-
23
- it "knows about event name" do
24
- expect(fsm).to respond_to(:slow)
25
- end
26
-
27
- it "doesn't know about not implemented call" do
28
- expect(fsm).not_to respond_to(:not_implemented)
29
- end
30
-
31
- it "knows about event callback" do
32
- expect(fsm).to respond_to(:on_enter_slow)
33
- end
34
-
35
- it "doesn't know about target class methods" do
36
- expect(fsm).not_to respond_to(:engine_on?)
37
- end
38
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::StateParser, "#inspect" do
6
- let(:object) { described_class }
7
-
8
- subject(:parser) { object.new(attrs) }
9
-
10
- describe '#inspect' do
11
- let(:attrs) { { green: :yellow } }
12
-
13
- it "inspects parser" do
14
- expect(parser.inspect).to eq("<#FiniteMachine::StateParser @attrs=green:yellow>")
15
- end
16
- end
17
-
18
- describe '#to_s' do
19
- let(:attrs) { { green: :yellow } }
20
-
21
- it "prints parser attributes" do
22
- expect(parser.to_s).to eq(attrs.to_s)
23
- end
24
- end
25
- end
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::StateParser, '#parse' do
6
- let(:object) { described_class }
7
-
8
- subject(:parser) { object.new(attrs) }
9
-
10
- context 'when no attributes' do
11
- let(:attrs) { { } }
12
-
13
- it "raises error for no transitions" do
14
- expect {
15
- parser.parse
16
- }.to raise_error(FiniteMachine::NotEnoughTransitionsError)
17
- end
18
- end
19
-
20
- context 'when :from and :to keys' do
21
- let(:attrs) { { from: :green, to: :yellow }}
22
-
23
- it "removes :from and :to keys" do
24
- expect(parser.parse).to eq({green: :yellow})
25
- end
26
- end
27
-
28
- context 'when only :from key' do
29
- let(:attrs) { { from: :green }}
30
-
31
- it "adds to state as copy of from" do
32
- expect(parser.parse).to eq({green: :green})
33
- end
34
- end
35
-
36
- context 'when only :to key' do
37
- let(:attrs) { { to: :green }}
38
-
39
- it "inserts :any from state" do
40
- expect(parser.parse).to eq({any: :green})
41
- end
42
- end
43
-
44
- context 'when attribuets as hash' do
45
- let(:attrs) { { green: :yellow } }
46
-
47
- it "copies attributes over" do
48
- expect(parser.parse).to eq({green: :yellow})
49
- end
50
- end
51
-
52
- context 'when array of from states' do
53
- let(:attrs) { { [:green, :red] => :yellow } }
54
-
55
- it "extracts states" do
56
- expect(parser.parse).to include({red: :yellow, green: :yellow})
57
- end
58
- end
59
- end