end_state 0.12.0 → 1.0.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.
@@ -6,185 +6,13 @@ module EndState
6
6
  subject(:machine) { StateMachine.new(object) }
7
7
  let(:object) { OpenStruct.new(state: nil) }
8
8
  before do
9
- StateMachine.instance_variable_set '@transitions'.to_sym, nil
9
+ StateMachine.instance_variable_set '@transition_configurations'.to_sym, nil
10
10
  StateMachine.instance_variable_set '@events'.to_sym, nil
11
11
  StateMachine.instance_variable_set '@store_states_as_strings'.to_sym, nil
12
12
  StateMachine.instance_variable_set '@initial_state'.to_sym, :__nil__
13
13
  StateMachine.instance_variable_set '@mode'.to_sym, :soft
14
14
  end
15
15
 
16
- describe '.transition' do
17
- let(:options) { { a: :b } }
18
-
19
- before do
20
- @transitions = []
21
- StateMachine.transition(options) { |transition| @transitions << transition }
22
- end
23
-
24
- it 'does not require a block' do
25
- expect { StateMachine.transition(options) }.not_to raise_error
26
- end
27
-
28
- context 'single transition' do
29
- it 'yields a transition for the supplied end state' do
30
- expect(@transitions.count).to eq 1
31
- expect(@transitions[0].state).to eq :b
32
- end
33
-
34
- it 'adds the transition to the state machine' do
35
- expect(StateMachine.transitions[a: :b]).to eq @transitions[0]
36
- end
37
-
38
- context 'with as' do
39
- let(:options) { { a: :b, as: :go } }
40
-
41
- it 'creates an alias' do
42
- expect(StateMachine.events[:go]).to eq [{ a: :b }]
43
- end
44
-
45
- context 'another single transition with as' do
46
- before { StateMachine.transition({c: :d, as: :go}) }
47
-
48
- it 'appends to the event' do
49
- expect(StateMachine.events[:go]).to eq [{ a: :b }, { c: :d }]
50
- end
51
- end
52
-
53
- context 'another single transition with as that conflicts' do
54
- it 'raises an error' do
55
- expect{ StateMachine.transition({a: :c, as: :go}) }.to raise_error EventConflict,
56
- 'Attempting to define :go as transitioning from :a => :c when :a => :b already exists. ' \
57
- 'You cannot define multiple transitions from a single state with the same event name.'
58
- end
59
- end
60
-
61
- context 'another single transition with as that conflicts' do
62
- it 'raises an error' do
63
- expect{ StateMachine.transition({any_state: :c, as: :go}) }.to raise_error EventConflict,
64
- 'Attempting to define :go as transitioning from :any_state => :c when :a => :b already exists. ' \
65
- 'You cannot define multiple transitions from a single state with the same event name.'
66
- end
67
- end
68
- end
69
- end
70
-
71
- context 'multiple start states' do
72
- let(:options) { { [:a, :b] => :c } }
73
-
74
- it 'yields each transition for the supplied end state' do
75
- expect(@transitions.count).to eq 1
76
- expect(@transitions[0].state).to eq :c
77
- end
78
-
79
- it 'adds the transitions to the state machine' do
80
- expect(StateMachine.transitions[a: :c]).to eq @transitions[0]
81
- expect(StateMachine.transitions[b: :c]).to eq @transitions[0]
82
- end
83
-
84
- context 'with as' do
85
- let(:options) { { [:a, :b] => :c, as: :go } }
86
-
87
- it 'creates an alias' do
88
- expect(StateMachine.events[:go]).to eq [{ a: :c }, { b: :c }]
89
- end
90
- end
91
- end
92
-
93
- context 'multiple transitions' do
94
- let(:options) { { a: :b, c: :d } }
95
-
96
- it 'yields each transition for the supplied end state' do
97
- expect(@transitions.count).to eq 2
98
- expect(@transitions[0].state).to eq :b
99
- expect(@transitions[1].state).to eq :d
100
- end
101
-
102
- it 'adds the transitions to the state machine' do
103
- expect(StateMachine.transitions[a: :b]).to eq @transitions[0]
104
- expect(StateMachine.transitions[c: :d]).to eq @transitions[1]
105
- end
106
-
107
- context 'with as' do
108
- let(:options) { { a: :b, c: :d, as: :go } }
109
-
110
- it 'creates an alias' do
111
- expect(StateMachine.events[:go]).to eq [{ a: :b }, { c: :d }]
112
- end
113
- end
114
- end
115
- end
116
-
117
- describe '.state_attribute' do
118
- context 'when set to :foobar' do
119
- let(:object) { OpenStruct.new(foobar: :a) }
120
- before { StateMachine.state_attribute :foobar }
121
-
122
- it 'answers state with foobar' do
123
- expect(machine.state).to eq object.foobar
124
- end
125
-
126
- it 'answers state= with foobar=' do
127
- machine.state = :b
128
- expect(object.foobar).to eq :b
129
- end
130
-
131
- after do
132
- StateMachine.send(:remove_method, :state)
133
- StateMachine.send(:remove_method, :state=)
134
- end
135
- end
136
- end
137
-
138
- describe '.states' do
139
- before do
140
- StateMachine.transition(a: :b)
141
- StateMachine.transition(b: :c)
142
- end
143
-
144
- specify { expect(StateMachine.states).to eq [:a, :b, :c] }
145
- end
146
-
147
- describe '.start_states' do
148
- before do
149
- StateMachine.transition(a: :b)
150
- StateMachine.transition(b: :c)
151
- end
152
-
153
- specify { expect(StateMachine.start_states).to eq [:a, :b] }
154
- end
155
-
156
- describe '.end_states' do
157
- before do
158
- StateMachine.transition(a: :b)
159
- StateMachine.transition(b: :c)
160
- end
161
-
162
- specify { expect(StateMachine.end_states).to eq [:b, :c] }
163
- end
164
-
165
- describe '.store_states_as_strings!' do
166
- it 'sets the flag' do
167
- StateMachine.store_states_as_strings!
168
- expect(StateMachine.store_states_as_strings).to be true
169
- end
170
- end
171
-
172
- describe '#store_states_as_strings' do
173
- it 'is false by default' do
174
- expect(StateMachine.store_states_as_strings).to be false
175
- end
176
- end
177
-
178
- describe '.initial_state' do
179
- context 'when set to :first' do
180
- before { StateMachine.set_initial_state :first }
181
-
182
- it 'has that initial state' do
183
- expect(machine.state).to eq :first
184
- end
185
- end
186
- end
187
-
188
16
  describe '#state' do
189
17
  context 'when there is no state set' do
190
18
  specify { expect(machine.state).to eq :__nil__ }
@@ -251,9 +79,7 @@ module EndState
251
79
 
252
80
  context 'single transition' do
253
81
  before do
254
- StateMachine.transition a: :b, as: :go do |t|
255
- t.blocked 'Invalid event!'
256
- end
82
+ StateMachine.transition a: :b, as: :go
257
83
  end
258
84
 
259
85
  it 'transitions the state' do
@@ -281,11 +107,6 @@ module EndState
281
107
  expect(machine.state).to eq :c
282
108
  end
283
109
 
284
- it 'adds a failure message specified by blocked' do
285
- machine.go
286
- expect(machine.failure_messages).to eq ['Invalid event!']
287
- end
288
-
289
110
  context 'and all transitions are forced to run in :hard mode' do
290
111
  before { machine.class.treat_all_transitions_as_hard! }
291
112
 
@@ -309,9 +130,7 @@ module EndState
309
130
 
310
131
  context 'multiple start states' do
311
132
  before do
312
- StateMachine.transition [:a, :b] => :c, as: :go do |t|
313
- t.blocked 'Invalid event!'
314
- end
133
+ StateMachine.transition [:a, :b] => :c, as: :go
315
134
  end
316
135
 
317
136
  context 'initial state is :a' do
@@ -344,9 +163,7 @@ module EndState
344
163
 
345
164
  context 'multiple transitions' do
346
165
  before do
347
- StateMachine.transition a: :b, c: :d, as: :go do |t|
348
- t.blocked 'Invalid event!'
349
- end
166
+ StateMachine.transition a: :b, c: :d, as: :go
350
167
  end
351
168
 
352
169
  context 'initial state is :a' do
@@ -372,9 +189,7 @@ module EndState
372
189
  describe '#{event}!' do
373
190
  let(:object) { OpenStruct.new(state: :a) }
374
191
  before do
375
- StateMachine.transition a: :b, as: :go do |t|
376
- t.blocked 'Invalid event!'
377
- end
192
+ StateMachine.transition a: :b, as: :go
378
193
  end
379
194
 
380
195
  it 'transitions the state' do
@@ -612,8 +427,9 @@ module EndState
612
427
  let(:guard) { double :guard, new: guard_instance }
613
428
  let(:guard_instance) { double :guard_instance, allowed?: nil }
614
429
  before do
615
- StateMachine.transition a: :b
616
- StateMachine.transitions[{ a: :b }].guards << guard
430
+ StateMachine.transition a: :b do |t|
431
+ t.guard guard
432
+ end
617
433
  end
618
434
 
619
435
  context 'and the object satisfies the guard' do
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module EndState
5
+ describe TransitionConfigurationSet do
6
+ subject(:set) { TransitionConfigurationSet.new }
7
+ let(:config1) { double :config }
8
+ let(:config2) { double :config }
9
+ let(:config3) { double :config }
10
+ let(:config4) { double :config }
11
+
12
+ describe 'without any configurations added' do
13
+ context '#get_configuration' do
14
+ it 'returns nil' do
15
+ expect(set.get_configuration(:a, :b)).to be_nil
16
+ end
17
+ end
18
+
19
+ context '#get_end_state' do
20
+ it 'returns nil' do
21
+ expect(set.get_end_state(:a, :advance)).to be_nil
22
+ end
23
+ end
24
+
25
+ context '#each' do
26
+ it 'iterates over []' do
27
+ expect{ |b| set.each(&b) }.to_not yield_control
28
+ end
29
+ end
30
+
31
+ context '#start_states' do
32
+ it 'returns []' do
33
+ expect(set.start_states).to eql []
34
+ end
35
+ end
36
+
37
+ context '#end_states' do
38
+ it 'returns []' do
39
+ expect(set.end_states).to eql []
40
+ end
41
+ end
42
+
43
+ context '#events' do
44
+ it 'returns []' do
45
+ expect(set.events).to eql []
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'with direct transitions set' do
51
+ before do
52
+ set.add(:a, :b, config1)
53
+ set.add(:b, :c, config2, :advance)
54
+ set.add(:c, :a, config3, :reset)
55
+ end
56
+
57
+ context '#get_configuration' do
58
+ it 'returns nil if the configuration does not exist' do
59
+ expect(set.get_configuration(:b, :a)).to be_nil
60
+ expect(set.get_configuration(:c, :b)).to be_nil
61
+ end
62
+
63
+ it 'returns the configuration if it exists' do
64
+ expect(set.get_configuration(:a, :b)).to eql config1
65
+ expect(set.get_configuration(:b, :c)).to eql config2
66
+ expect(set.get_configuration(:c, :a)).to eql config3
67
+ end
68
+ end
69
+
70
+ context '#get_end_state' do
71
+ it 'returns nil if the configuration does not exist' do
72
+ expect(set.get_end_state(:b, :reset)).to be_nil
73
+ expect(set.get_end_state(:c, :advance)).to be_nil
74
+ end
75
+
76
+ it 'returns the configuration if it exists' do
77
+ expect(set.get_end_state(:b, :advance)).to eql :c
78
+ expect(set.get_end_state(:c, :reset)).to eql :a
79
+ end
80
+ end
81
+
82
+ context '#each' do
83
+ it 'iterates over all transitions' do
84
+ expect{ |b| set.each(&b) }.to yield_control.exactly(3)
85
+ expect(set.each).to match_array [
86
+ [:a, :b, config1, nil], [:b, :c, config2, :advance], [:c, :a, config3, :reset]
87
+ ]
88
+ end
89
+ end
90
+
91
+ context '#start_states' do
92
+ it 'returns all the start_states' do
93
+ expect(set.start_states).to match_array [:a, :b, :c]
94
+ end
95
+ end
96
+
97
+ context '#end_states' do
98
+ it 'returns all the end_states' do
99
+ expect(set.end_states).to match_array [:a, :b, :c]
100
+ end
101
+ end
102
+
103
+ context '#events' do
104
+ it 'returns all the events' do
105
+ expect(set.events).to match_array [:advance, :reset]
106
+ end
107
+ end
108
+
109
+ context "#event_conflicts?" do
110
+ it 'returns false if the event would not conflict with an existing event' do
111
+ expect(set.event_conflicts?(:a, :advance)).to eql false
112
+ expect(set.event_conflicts?(:b, :reset)).to eql false
113
+ expect(set.event_conflicts?(:c, :other)).to eql false
114
+ expect(set.event_conflicts?(:any_state, :other)).to eql false
115
+ end
116
+
117
+ it 'returns true if the event would conflict with an existing event' do
118
+ expect(set.event_conflicts?(:b, :advance)).to eql true
119
+ expect(set.event_conflicts?(:c, :reset)).to eql true
120
+ expect(set.event_conflicts?(:any_state, :advance)).to eql true
121
+ expect(set.event_conflicts?(:any_state, :reset)).to eql true
122
+ end
123
+ end
124
+ end
125
+
126
+ describe 'with direct and :any_state transitions set' do
127
+ before do
128
+ set.add(:a, :b, config1)
129
+ set.add(:b, :c, config2)
130
+ set.add(:any_state, :d, config3, :done)
131
+ set.add(:any_state, :e, config4)
132
+ end
133
+
134
+ context '#get_configuration' do
135
+ it 'returns nil if the configuration does not exist' do
136
+ expect(set.get_configuration(:d, :a)).to be_nil
137
+ expect(set.get_configuration(:d, :b)).to be_nil
138
+ end
139
+
140
+ it 'returns the configuration if it exists' do
141
+ expect(set.get_configuration(:a, :d)).to eql config3
142
+ expect(set.get_configuration(:b, :d)).to eql config3
143
+ expect(set.get_configuration(:c, :d)).to eql config3
144
+ expect(set.get_configuration(:d, :d)).to eql config3
145
+ expect(set.get_configuration(:e, :d)).to eql config3
146
+
147
+ expect(set.get_configuration(:a, :e)).to eql config4
148
+ expect(set.get_configuration(:b, :e)).to eql config4
149
+ expect(set.get_configuration(:c, :e)).to eql config4
150
+ expect(set.get_configuration(:d, :e)).to eql config4
151
+ expect(set.get_configuration(:e, :e)).to eql config4
152
+ end
153
+ end
154
+
155
+ context '#get_end_state' do
156
+ it 'returns nil if the end_state does not exist' do
157
+ expect(set.get_end_state(:a, :invalid)).to be_nil
158
+ expect(set.get_end_state(:e, :go)).to be_nil
159
+ end
160
+
161
+ it 'returns the end state if it exists' do
162
+ expect(set.get_end_state(:a, :done)).to eql :d
163
+ expect(set.get_end_state(:b, :done)).to eql :d
164
+ expect(set.get_end_state(:c, :done)).to eql :d
165
+ expect(set.get_end_state(:d, :done)).to eql :d
166
+ expect(set.get_end_state(:e, :done)).to eql :d
167
+ end
168
+ end
169
+
170
+ context '#each' do
171
+ it 'iterates over all transitions' do
172
+ expect{ |b| set.each(&b) }.to yield_control.exactly(12)
173
+ expect(set.each).to match_array [
174
+ [:a, :b, config1, nil], [:b, :c, config2, nil],
175
+ [:a, :d, config3, :done], [:b, :d, config3, :done], [:c, :d, config3, :done], [:d, :d, config3, :done], [:e, :d, config3, :done],
176
+ [:a, :e, config4, nil], [:b, :e, config4, nil], [:c, :e, config4, nil], [:d, :e, config4, nil], [:e, :e, config4, nil]
177
+ ]
178
+ end
179
+ end
180
+
181
+ context '#start_states' do
182
+ it 'returns all the start_states' do
183
+ expect(set.start_states).to match_array [:a, :b, :c, :d, :e]
184
+ end
185
+ end
186
+
187
+ context '#end_states' do
188
+ it 'returns all the end_states' do
189
+ expect(set.end_states).to match_array [:b, :c, :d, :e]
190
+ end
191
+ end
192
+
193
+ context '#events' do
194
+ it 'returns all the events' do
195
+ expect(set.events).to match_array [:done]
196
+ end
197
+ end
198
+
199
+ context "#event_conflicts?" do
200
+ it 'returns false if the event would not conflict with an existing event' do
201
+ expect(set.event_conflicts?(:a, :other)).to eql false
202
+ expect(set.event_conflicts?(:b, :other)).to eql false
203
+ expect(set.event_conflicts?(:c, :other)).to eql false
204
+ expect(set.event_conflicts?(:any_state, :other)).to eql false
205
+ end
206
+
207
+ it 'returns true if the event would conflict with an existing event' do
208
+ expect(set.event_conflicts?(:a, :done)).to eql true
209
+ expect(set.event_conflicts?(:b, :done)).to eql true
210
+ expect(set.event_conflicts?(:c, :done)).to eql true
211
+ expect(set.event_conflicts?(:d, :done)).to eql true
212
+ expect(set.event_conflicts?(:e, :done)).to eql true
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module EndState
5
+ describe TransitionConfiguration do
6
+ subject(:config) { TransitionConfiguration.new }
7
+
8
+ describe '#custom_action' do
9
+ let(:custom) { double :custom }
10
+
11
+ it 'sets the action' do
12
+ config.custom_action custom
13
+ expect(config.action).to eq custom
14
+ end
15
+ end
16
+
17
+ describe '#guard' do
18
+ let(:guard) { double :guard }
19
+ let(:another_guard) { double :another_guard }
20
+
21
+ it 'adds a guard' do
22
+ expect { config.guard guard }.to change(config.guards, :count).by(1)
23
+ end
24
+
25
+ it 'adds multiple guards' do
26
+ expect { config.guard guard, another_guard }.to change(config.guards, :count).by(2)
27
+ end
28
+ end
29
+
30
+ describe '#concluder' do
31
+ let(:concluder) { double :concluder }
32
+ let(:another_concluder) { double :another_concluder }
33
+
34
+ it 'adds a concluder' do
35
+ expect { config.concluder concluder }.to change(config.concluders, :count).by(1)
36
+ end
37
+
38
+ it 'adds multiple concluders' do
39
+ expect { config.concluder concluder, another_concluder }.to change(config.concluders, :count).by(2)
40
+ end
41
+ end
42
+
43
+ describe '#persistence_on' do
44
+ it 'adds a Persistence concluder' do
45
+ expect { config.persistence_on }.to change(config.concluders, :count).by(1)
46
+ end
47
+ end
48
+
49
+ describe '#allow_params' do
50
+ it 'adds supplied keys to the allowed_params array' do
51
+ expect { config.allow_params :foo, :bar }.to change(config.allowed_params, :count).by(2)
52
+ end
53
+ end
54
+
55
+ describe '#require_params' do
56
+ it 'adds supplied keys to the required_params array' do
57
+ expect { config.require_params :foo, :bar }.to change(config.required_params, :count).by(2)
58
+ end
59
+
60
+ it 'adds supplied keys to the allowed_params array' do
61
+ expect { config.allow_params :foo, :bar }.to change(config.allowed_params, :count).by(2)
62
+ end
63
+ end
64
+ end
65
+ end