finite_machine 0.8.1 → 0.9.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +1 -1
  4. data/README.md +150 -35
  5. data/lib/finite_machine.rb +1 -0
  6. data/lib/finite_machine/catchable.rb +1 -1
  7. data/lib/finite_machine/definition.rb +61 -0
  8. data/lib/finite_machine/dsl.rb +45 -10
  9. data/lib/finite_machine/event.rb +17 -1
  10. data/lib/finite_machine/hook_event.rb +66 -7
  11. data/lib/finite_machine/observer.rb +3 -3
  12. data/lib/finite_machine/state_machine.rb +36 -28
  13. data/lib/finite_machine/version.rb +1 -1
  14. data/spec/spec_helper.rb +2 -2
  15. data/spec/unit/async_events_spec.rb +1 -1
  16. data/spec/unit/callbacks_spec.rb +23 -23
  17. data/spec/unit/can_spec.rb +22 -22
  18. data/spec/unit/event/eql_spec.rb +37 -0
  19. data/spec/unit/event/initialize_spec.rb +38 -0
  20. data/spec/unit/event/inspect_spec.rb +1 -1
  21. data/spec/unit/event_queue_spec.rb +2 -2
  22. data/spec/unit/events_chain/check_choice_conditions_spec.rb +2 -2
  23. data/spec/unit/events_chain/clear_spec.rb +1 -1
  24. data/spec/unit/events_chain/insert_spec.rb +1 -1
  25. data/spec/unit/events_spec.rb +17 -20
  26. data/spec/unit/hook_event/eql_spec.rb +37 -0
  27. data/spec/unit/hook_event/initialize_spec.rb +22 -0
  28. data/spec/unit/if_unless_spec.rb +6 -6
  29. data/spec/unit/initialize_spec.rb +6 -6
  30. data/spec/unit/is_spec.rb +12 -12
  31. data/spec/unit/logger_spec.rb +1 -1
  32. data/spec/unit/respond_to_spec.rb +2 -2
  33. data/spec/unit/standalone_spec.rb +72 -0
  34. data/spec/unit/subscribers_spec.rb +2 -2
  35. data/spec/unit/target_spec.rb +59 -10
  36. data/spec/unit/{finished_spec.rb → terminated_spec.rb} +38 -8
  37. metadata +15 -4
data/spec/unit/is_spec.rb CHANGED
@@ -18,17 +18,17 @@ describe FiniteMachine, 'is?' do
18
18
 
19
19
  expect(fsm.current).to eql(:green)
20
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
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
25
 
26
26
  fsm.slow
27
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
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
32
  end
33
33
 
34
34
  it "defines helper methods to check current state" do
@@ -44,12 +44,12 @@ describe FiniteMachine, 'is?' do
44
44
  end
45
45
  expect(fsm.current).to eql(:green)
46
46
 
47
- expect(fsm.green?).to be_true
48
- expect(fsm.yellow?).to be_false
47
+ expect(fsm.green?).to be true
48
+ expect(fsm.yellow?).to be false
49
49
 
50
50
  fsm.slow
51
51
 
52
- expect(fsm.green?).to be_false
53
- expect(fsm.yellow?).to be_true
52
+ expect(fsm.green?).to be false
53
+ expect(fsm.yellow?).to be true
54
54
  end
55
55
  end
@@ -9,7 +9,7 @@ describe FiniteMachine::Logger do
9
9
 
10
10
  subject(:logger) { described_class }
11
11
 
12
- before { FiniteMachine.stub(:logger) { log } }
12
+ before { allow(FiniteMachine).to receive(:logger) { log } }
13
13
 
14
14
  it "debugs message call" do
15
15
  expect(log).to receive(:debug).with(message)
@@ -31,7 +31,7 @@ describe FiniteMachine, '#respond_to' do
31
31
  expect(fsm).to respond_to(:on_enter_slow)
32
32
  end
33
33
 
34
- it "knows about target class methods" do
35
- expect(fsm).to respond_to(:engine_on?)
34
+ it "doesn't know about target class methods" do
35
+ expect(fsm).not_to respond_to(:engine_on?)
36
36
  end
37
37
  end
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine::Definition, 'definition' do
6
+
7
+ before do
8
+ class Engine < FiniteMachine::Definition
9
+ initial :neutral
10
+
11
+ events {
12
+ event :forward, [:reverse, :neutral] => :one
13
+ event :shift, :one => :two
14
+ event :shift, :two => :one
15
+ event :back, [:neutral, :one] => :reverse
16
+ }
17
+
18
+ callbacks {
19
+ on_enter :reverse do |event|
20
+ target.turn_reverse_lights_on
21
+ end
22
+
23
+ on_exit :reverse do |event|
24
+ target.turn_reverse_lights_off
25
+ end
26
+ }
27
+
28
+ handlers {
29
+ handle FiniteMachine::InvalidStateError do |exception| end
30
+ }
31
+ end
32
+ end
33
+
34
+ it "creates unique instances" do
35
+ engine_a = Engine.new
36
+ engine_b = Engine.new
37
+ expect(engine_a).not_to be(engine_b)
38
+
39
+ engine_a.forward
40
+ expect(engine_a.current).to eq(:one)
41
+ expect(engine_b.current).to eq(:neutral)
42
+ end
43
+
44
+ it "allows to create standalone machine" do
45
+ Car = Class.new do
46
+ def turn_reverse_lights_off
47
+ @reverse_lights = false
48
+ end
49
+
50
+ def turn_reverse_lights_on
51
+ @reverse_lights = true
52
+ end
53
+
54
+ def reverse_lights?
55
+ @reverse_lights ||= false
56
+ end
57
+ end
58
+
59
+ car = Car.new
60
+ engine = Engine.new
61
+ engine.target car
62
+ expect(engine.current).to eq(:neutral)
63
+
64
+ engine.forward
65
+ expect(engine.current).to eq(:one)
66
+ expect(car.reverse_lights?).to be false
67
+
68
+ engine.back
69
+ expect(engine.current).to eq(:reverse)
70
+ expect(car.reverse_lights?).to be true
71
+ end
72
+ end
@@ -12,7 +12,7 @@ describe FiniteMachine::Subscribers do
12
12
  before { subscribers.subscribe(listener) }
13
13
 
14
14
  it "checks if any subscribers exist" do
15
- expect(subscribers.empty?).to be_false
15
+ expect(subscribers.empty?).to be(false)
16
16
  end
17
17
 
18
18
  it "returns index for the subscriber" do
@@ -26,6 +26,6 @@ describe FiniteMachine::Subscribers do
26
26
 
27
27
  it "resets the subscribers" do
28
28
  subscribers.reset
29
- expect(subscribers.empty?).to be_true
29
+ expect(subscribers.empty?).to be(true)
30
30
  end
31
31
  end
@@ -16,6 +16,10 @@ describe FiniteMachine, '#target' do
16
16
  @reverse_lights = true
17
17
  end
18
18
 
19
+ def reverse_lights?
20
+ @reverse_lights ||= false
21
+ end
22
+
19
23
  def engine
20
24
  context = self
21
25
  @engine ||= FiniteMachine.define do
@@ -32,25 +36,25 @@ describe FiniteMachine, '#target' do
32
36
 
33
37
  callbacks {
34
38
  on_enter :reverse do |event|
35
- turn_reverse_lights_on
39
+ target.turn_reverse_lights_on
36
40
  end
37
41
 
38
42
  on_exit :reverse do |event|
39
- turn_reverse_lights_off
43
+ target.turn_reverse_lights_off
40
44
  end
41
45
  }
42
46
  end
43
47
  end
44
48
  end
45
49
  car = Car.new
46
- expect(car.reverse_lights).to be_false
50
+ expect(car.reverse_lights?).to be(false)
47
51
  expect(car.engine.current).to eql(:neutral)
48
52
  car.engine.back
49
53
  expect(car.engine.current).to eql(:reverse)
50
- expect(car.reverse_lights).to be_true
54
+ expect(car.reverse_lights?).to be(true)
51
55
  car.engine.forward
52
56
  expect(car.engine.current).to eql(:one)
53
- expect(car.reverse_lights).to be_false
57
+ expect(car.reverse_lights?).to be(false)
54
58
  end
55
59
 
56
60
  it "propagates method call" do
@@ -112,6 +116,10 @@ describe FiniteMachine, '#target' do
112
116
  @reverse_lights = true
113
117
  end
114
118
 
119
+ def reverse_lights?
120
+ @reverse_lights ||= false
121
+ end
122
+
115
123
  def engine
116
124
  self.called ||= []
117
125
  context ||= self
@@ -129,12 +137,12 @@ describe FiniteMachine, '#target' do
129
137
 
130
138
  callbacks {
131
139
  on_enter :reverse do |event|
132
- called << 'on_enter_reverse'
133
- turn_reverse_lights_on
140
+ target.called << 'on_enter_reverse'
141
+ target.turn_reverse_lights_on
134
142
  forward('Piotr!')
135
143
  end
136
144
  on_before :forward do |event, name|
137
- called << "on_enter_forward with #{name}"
145
+ target.called << "on_enter_forward with #{name}"
138
146
  end
139
147
  }
140
148
  end
@@ -142,7 +150,7 @@ describe FiniteMachine, '#target' do
142
150
  end
143
151
 
144
152
  car = Car.new
145
- expect(car.reverse_lights).to be_false
153
+ expect(car.reverse_lights?).to be(false)
146
154
  expect(car.engine.current).to eql(:neutral)
147
155
  car.engine.back
148
156
  expect(car.engine.current).to eql(:one)
@@ -158,7 +166,7 @@ describe FiniteMachine, '#target' do
158
166
  fsm = FiniteMachine.define do
159
167
  initial :green
160
168
 
161
- target context
169
+ target context
162
170
 
163
171
  events {
164
172
  event :slow, :green => :yellow
@@ -174,4 +182,45 @@ describe FiniteMachine, '#target' do
174
182
  fsm.slow
175
183
  expect(called).to eq(context)
176
184
  end
185
+
186
+ it "allows to differentiate between same named methods" do
187
+ called = []
188
+ Car = Class.new do
189
+ def initialize(called)
190
+ @called = called
191
+ end
192
+ def save
193
+ @called << 'car save called'
194
+ end
195
+ end
196
+
197
+ car = Car.new(called)
198
+ fsm = FiniteMachine.define do
199
+ initial :unsaved
200
+
201
+ target car
202
+
203
+ events {
204
+ event :validate, :unsaved => :valid
205
+ event :save, :valid => :saved
206
+ }
207
+
208
+ callbacks {
209
+ on_enter :valid do |event|
210
+ target.save
211
+ save
212
+ end
213
+ on_after :save do |event|
214
+ called << 'event save called'
215
+ end
216
+ }
217
+ end
218
+ expect(fsm.current).to eql(:unsaved)
219
+ fsm.validate
220
+ expect(fsm.current).to eql(:saved)
221
+ expect(called).to eq([
222
+ 'car save called',
223
+ 'event save called'
224
+ ])
225
+ end
177
226
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'finished?' do
5
+ describe FiniteMachine, 'terminated?' do
6
6
 
7
7
  it "allows to specify terminal state" do
8
8
  fsm = FiniteMachine.define do
@@ -16,15 +16,15 @@ describe FiniteMachine, 'finished?' do
16
16
  end
17
17
 
18
18
  expect(fsm.current).to eql(:green)
19
- expect(fsm.finished?).to be_false
19
+ expect(fsm.terminated?).to be(false)
20
20
 
21
21
  fsm.slow
22
22
  expect(fsm.current).to eql(:yellow)
23
- expect(fsm.finished?).to be_false
23
+ expect(fsm.terminated?).to be(false)
24
24
 
25
25
  fsm.stop
26
26
  expect(fsm.current).to eql(:red)
27
- expect(fsm.finished?).to be_true
27
+ expect(fsm.terminated?).to be(true)
28
28
  end
29
29
 
30
30
  it "allows to specify terminal state as parameter" do
@@ -38,7 +38,7 @@ describe FiniteMachine, 'finished?' do
38
38
  end
39
39
  fsm.slow
40
40
  fsm.stop
41
- expect(fsm.finished?).to be_true
41
+ expect(fsm.terminated?).to be(true)
42
42
  end
43
43
 
44
44
  it "checks without terminal state" do
@@ -52,14 +52,44 @@ describe FiniteMachine, 'finished?' do
52
52
  end
53
53
 
54
54
  expect(fsm.current).to eql(:green)
55
- expect(fsm.finished?).to be_false
55
+ expect(fsm.terminated?).to be(false)
56
56
 
57
57
  fsm.slow
58
58
  expect(fsm.current).to eql(:yellow)
59
- expect(fsm.finished?).to be_false
59
+ expect(fsm.terminated?).to be(false)
60
60
 
61
61
  fsm.stop
62
62
  expect(fsm.current).to eql(:red)
63
- expect(fsm.finished?).to be_false
63
+ expect(fsm.terminated?).to be(false)
64
+ end
65
+
66
+ it "allows for multiple terminal states" do
67
+ fsm = FiniteMachine.define do
68
+ initial :open
69
+
70
+ terminal :close, :canceled, :faulty
71
+
72
+ events {
73
+ event :resolve, :open => :close
74
+ event :decline, :open => :canceled
75
+ event :error, :open => :faulty
76
+ }
77
+ end
78
+ expect(fsm.current).to eql(:open)
79
+ expect(fsm.terminated?).to be(false)
80
+
81
+ fsm.resolve
82
+ expect(fsm.current).to eql(:close)
83
+ expect(fsm.terminated?).to be(true)
84
+
85
+ fsm.restore!(:open)
86
+ fsm.decline
87
+ expect(fsm.current).to eql(:canceled)
88
+ expect(fsm.terminated?).to be(true)
89
+
90
+ fsm.restore!(:open)
91
+ fsm.error
92
+ expect(fsm.current).to eql(:faulty)
93
+ expect(fsm.terminated?).to be(true)
64
94
  end
65
95
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finite_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-05 00:00:00.000000000 Z
11
+ date: 2014-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,7 @@ files:
52
52
  - lib/finite_machine/callable.rb
53
53
  - lib/finite_machine/catchable.rb
54
54
  - lib/finite_machine/choice_merger.rb
55
+ - lib/finite_machine/definition.rb
55
56
  - lib/finite_machine/dsl.rb
56
57
  - lib/finite_machine/event.rb
57
58
  - lib/finite_machine/event_builder.rb
@@ -79,6 +80,8 @@ files:
79
80
  - spec/unit/choice_spec.rb
80
81
  - spec/unit/define_spec.rb
81
82
  - spec/unit/event/add_spec.rb
83
+ - spec/unit/event/eql_spec.rb
84
+ - spec/unit/event/initialize_spec.rb
82
85
  - spec/unit/event/inspect_spec.rb
83
86
  - spec/unit/event/next_transition_spec.rb
84
87
  - spec/unit/event_queue_spec.rb
@@ -88,8 +91,9 @@ files:
88
91
  - spec/unit/events_chain/inspect_spec.rb
89
92
  - spec/unit/events_chain/select_transition_spec.rb
90
93
  - spec/unit/events_spec.rb
91
- - spec/unit/finished_spec.rb
92
94
  - spec/unit/handlers_spec.rb
95
+ - spec/unit/hook_event/eql_spec.rb
96
+ - spec/unit/hook_event/initialize_spec.rb
93
97
  - spec/unit/hooks/call_spec.rb
94
98
  - spec/unit/hooks/inspect_spec.rb
95
99
  - spec/unit/hooks/register_spec.rb
@@ -99,11 +103,13 @@ files:
99
103
  - spec/unit/is_spec.rb
100
104
  - spec/unit/logger_spec.rb
101
105
  - spec/unit/respond_to_spec.rb
106
+ - spec/unit/standalone_spec.rb
102
107
  - spec/unit/state_parser/inspect_spec.rb
103
108
  - spec/unit/state_parser/parse_states_spec.rb
104
109
  - spec/unit/states_spec.rb
105
110
  - spec/unit/subscribers_spec.rb
106
111
  - spec/unit/target_spec.rb
112
+ - spec/unit/terminated_spec.rb
107
113
  - spec/unit/transition/inspect_spec.rb
108
114
  - spec/unit/transition/parse_states_spec.rb
109
115
  - tasks/console.rake
@@ -142,6 +148,8 @@ test_files:
142
148
  - spec/unit/choice_spec.rb
143
149
  - spec/unit/define_spec.rb
144
150
  - spec/unit/event/add_spec.rb
151
+ - spec/unit/event/eql_spec.rb
152
+ - spec/unit/event/initialize_spec.rb
145
153
  - spec/unit/event/inspect_spec.rb
146
154
  - spec/unit/event/next_transition_spec.rb
147
155
  - spec/unit/event_queue_spec.rb
@@ -151,8 +159,9 @@ test_files:
151
159
  - spec/unit/events_chain/inspect_spec.rb
152
160
  - spec/unit/events_chain/select_transition_spec.rb
153
161
  - spec/unit/events_spec.rb
154
- - spec/unit/finished_spec.rb
155
162
  - spec/unit/handlers_spec.rb
163
+ - spec/unit/hook_event/eql_spec.rb
164
+ - spec/unit/hook_event/initialize_spec.rb
156
165
  - spec/unit/hooks/call_spec.rb
157
166
  - spec/unit/hooks/inspect_spec.rb
158
167
  - spec/unit/hooks/register_spec.rb
@@ -162,11 +171,13 @@ test_files:
162
171
  - spec/unit/is_spec.rb
163
172
  - spec/unit/logger_spec.rb
164
173
  - spec/unit/respond_to_spec.rb
174
+ - spec/unit/standalone_spec.rb
165
175
  - spec/unit/state_parser/inspect_spec.rb
166
176
  - spec/unit/state_parser/parse_states_spec.rb
167
177
  - spec/unit/states_spec.rb
168
178
  - spec/unit/subscribers_spec.rb
169
179
  - spec/unit/target_spec.rb
180
+ - spec/unit/terminated_spec.rb
170
181
  - spec/unit/transition/inspect_spec.rb
171
182
  - spec/unit/transition/parse_states_spec.rb
172
183
  has_rdoc: