finite_machine 0.11.2 → 0.14.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.
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