state_machine 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/LICENSE +1 -1
- data/README.rdoc +4 -4
- data/Rakefile +1 -1
- data/lib/state_machine/event.rb +5 -3
- data/lib/state_machine/extensions.rb +2 -1
- data/lib/state_machine/guard.rb +24 -17
- data/lib/state_machine/integrations/active_record.rb +23 -1
- data/lib/state_machine/machine.rb +68 -27
- data/lib/state_machine.rb +1 -3
- data/test/active_record.log +17542 -0
- data/test/data_mapper.log +4814 -0
- data/test/sequel.log +2697 -0
- data/test/unit/event_test.rb +33 -0
- data/test/unit/guard_test.rb +64 -1
- data/test/unit/integrations/active_record_test.rb +58 -2
- data/test/unit/machine_test.rb +82 -11
- metadata +2 -2
data/test/unit/event_test.rb
CHANGED
@@ -301,6 +301,39 @@ class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
|
|
301
301
|
end
|
302
302
|
end
|
303
303
|
|
304
|
+
class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
|
305
|
+
def setup
|
306
|
+
@klass = Class.new
|
307
|
+
@machine = StateMachine::Machine.new(@klass)
|
308
|
+
@event = StateMachine::Event.new(@machine, 'turn_off')
|
309
|
+
@event.transition(:from => 'off', :to => nil)
|
310
|
+
|
311
|
+
@object = @klass.new
|
312
|
+
@object.state = 'off'
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_should_be_able_to_fire
|
316
|
+
assert @event.can_fire?(@object)
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_should_have_a_next_transition
|
320
|
+
transition = @event.next_transition(@object)
|
321
|
+
assert_not_nil transition
|
322
|
+
assert_equal 'off', transition.from
|
323
|
+
assert_equal nil, transition.to
|
324
|
+
assert_equal 'turn_off', transition.event
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_should_fire
|
328
|
+
assert @event.fire(@object)
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_should_not_change_the_current_state
|
332
|
+
@event.fire(@object)
|
333
|
+
assert_equal nil, @object.state
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
304
337
|
class EventWithTransitionWithDynamicToStateTest < Test::Unit::TestCase
|
305
338
|
def setup
|
306
339
|
@klass = Class.new
|
data/test/unit/guard_test.rb
CHANGED
@@ -10,7 +10,7 @@ class GuardTest < Test::Unit::TestCase
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_should_have_requirements
|
13
|
-
expected = {:to =>
|
13
|
+
expected = {:to => %w(on), :from => %w(off)}
|
14
14
|
assert_equal expected, @guard.requirements
|
15
15
|
end
|
16
16
|
end
|
@@ -40,6 +40,10 @@ class GuardWithToRequirementTest < Test::Unit::TestCase
|
|
40
40
|
@guard = StateMachine::Guard.new(:to => 'on')
|
41
41
|
end
|
42
42
|
|
43
|
+
def test_should_match_if_not_specified
|
44
|
+
assert @guard.matches?(@object, :from => 'off')
|
45
|
+
end
|
46
|
+
|
43
47
|
def test_should_match_if_included
|
44
48
|
assert @guard.matches?(@object, :to => 'on')
|
45
49
|
end
|
@@ -48,6 +52,10 @@ class GuardWithToRequirementTest < Test::Unit::TestCase
|
|
48
52
|
assert !@guard.matches?(@object, :to => 'off')
|
49
53
|
end
|
50
54
|
|
55
|
+
def test_should_not_match_if_nil
|
56
|
+
assert !@guard.matches?(@object, :to => nil)
|
57
|
+
end
|
58
|
+
|
51
59
|
def test_should_ignore_from
|
52
60
|
assert @guard.matches?(@object, :to => 'on', :from => 'off')
|
53
61
|
end
|
@@ -86,6 +94,10 @@ class GuardWithFromRequirementTest < Test::Unit::TestCase
|
|
86
94
|
@guard = StateMachine::Guard.new(:from => 'on')
|
87
95
|
end
|
88
96
|
|
97
|
+
def test_should_match_if_not_specified
|
98
|
+
assert @guard.matches?(@object, :to => 'off')
|
99
|
+
end
|
100
|
+
|
89
101
|
def test_should_match_if_included
|
90
102
|
assert @guard.matches?(@object, :from => 'on')
|
91
103
|
end
|
@@ -94,6 +106,10 @@ class GuardWithFromRequirementTest < Test::Unit::TestCase
|
|
94
106
|
assert !@guard.matches?(@object, :from => 'off')
|
95
107
|
end
|
96
108
|
|
109
|
+
def test_should_not_match_if_nil
|
110
|
+
assert !@guard.matches?(@object, :from => nil)
|
111
|
+
end
|
112
|
+
|
97
113
|
def test_should_ignore_to
|
98
114
|
assert @guard.matches?(@object, :from => 'on', :to => 'off')
|
99
115
|
end
|
@@ -132,6 +148,10 @@ class GuardWithOnRequirementTest < Test::Unit::TestCase
|
|
132
148
|
@guard = StateMachine::Guard.new(:on => 'turn_on')
|
133
149
|
end
|
134
150
|
|
151
|
+
def test_should_match_if_not_specified
|
152
|
+
assert @guard.matches?(@object, :from => 'off')
|
153
|
+
end
|
154
|
+
|
135
155
|
def test_should_match_if_included
|
136
156
|
assert @guard.matches?(@object, :on => 'turn_on')
|
137
157
|
end
|
@@ -140,6 +160,10 @@ class GuardWithOnRequirementTest < Test::Unit::TestCase
|
|
140
160
|
assert !@guard.matches?(@object, :on => 'turn_off')
|
141
161
|
end
|
142
162
|
|
163
|
+
def test_should_not_match_if_nil
|
164
|
+
assert !@guard.matches?(@object, :on => nil)
|
165
|
+
end
|
166
|
+
|
143
167
|
def test_should_ignore_to
|
144
168
|
assert @guard.matches?(@object, :on => 'turn_on', :to => 'off')
|
145
169
|
end
|
@@ -182,6 +206,10 @@ class GuardWithExceptToRequirementTest < Test::Unit::TestCase
|
|
182
206
|
assert !@guard.matches?(@object, :to => 'off')
|
183
207
|
end
|
184
208
|
|
209
|
+
def test_should_match_if_nil
|
210
|
+
assert @guard.matches?(@object, :to => nil)
|
211
|
+
end
|
212
|
+
|
185
213
|
def test_should_ignore_from
|
186
214
|
assert @guard.matches?(@object, :except_to => 'off', :from => 'off')
|
187
215
|
end
|
@@ -228,6 +256,10 @@ class GuardWithExceptFromRequirementTest < Test::Unit::TestCase
|
|
228
256
|
assert !@guard.matches?(@object, :from => 'off')
|
229
257
|
end
|
230
258
|
|
259
|
+
def test_should_match_if_nil
|
260
|
+
assert @guard.matches?(@object, :from => nil)
|
261
|
+
end
|
262
|
+
|
231
263
|
def test_should_ignore_to
|
232
264
|
assert @guard.matches?(@object, :from => 'on', :to => 'off')
|
233
265
|
end
|
@@ -274,6 +306,10 @@ class GuardWithExceptOnRequirementTest < Test::Unit::TestCase
|
|
274
306
|
assert !@guard.matches?(@object, :on => 'turn_off')
|
275
307
|
end
|
276
308
|
|
309
|
+
def test_should_match_if_nil
|
310
|
+
assert @guard.matches?(@object, :on => nil)
|
311
|
+
end
|
312
|
+
|
277
313
|
def test_should_ignore_to
|
278
314
|
assert @guard.matches?(@object, :on => 'turn_on', :to => 'off')
|
279
315
|
end
|
@@ -371,6 +407,33 @@ class GuardWithDifferentRequirementsTest < Test::Unit::TestCase
|
|
371
407
|
end
|
372
408
|
end
|
373
409
|
|
410
|
+
class GuardWithNilRequirementsTest < Test::Unit::TestCase
|
411
|
+
def setup
|
412
|
+
@object = Object.new
|
413
|
+
@guard = StateMachine::Guard.new(:from => nil, :to => nil)
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_should_match_empty_query
|
417
|
+
assert @guard.matches?(@object)
|
418
|
+
end
|
419
|
+
|
420
|
+
def test_should_match_if_all_requirements_match
|
421
|
+
assert @guard.matches?(@object, :from => nil, :to => nil)
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_should_not_match_if_from_not_included
|
425
|
+
assert !@guard.matches?(@object, :from => 'off')
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_should_not_match_if_to_not_included
|
429
|
+
assert !@guard.matches?(@object, :to => 'on')
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_should_include_all_known_states
|
433
|
+
assert_equal [nil], @guard.known_states
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
374
437
|
class GuardWithIfConditionalTest < Test::Unit::TestCase
|
375
438
|
def setup
|
376
439
|
@object = Object.new
|
@@ -190,10 +190,43 @@ begin
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
|
193
|
+
class MachineWithColumnStateAttributeTest < ActiveRecord::TestCase
|
194
|
+
def setup
|
195
|
+
@model = new_model
|
196
|
+
@machine = StateMachine::Machine.new(@model, :initial => 'off')
|
197
|
+
@machine.other_states('on')
|
198
|
+
@record = @model.new
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_should_have_an_attribute_predicate
|
202
|
+
assert @record.respond_to?(:state?)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_should_test_for_existence_on_predicate_without_parameters
|
206
|
+
assert @record.state?
|
207
|
+
|
208
|
+
@record.state = nil
|
209
|
+
assert !@record.state?
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
213
|
+
assert !@record.state?('on')
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_should_return_true_for_predicate_if_matches_current_value
|
217
|
+
assert @record.state?('off')
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_should_raise_exception_for_predicate_if_invalid_state_specified
|
221
|
+
assert_raise(ArgumentError) { @record.state?('invalid') }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
193
225
|
class MachineWithNonColumnStateAttributeTest < ActiveRecord::TestCase
|
194
226
|
def setup
|
195
227
|
@model = new_model
|
196
228
|
@machine = StateMachine::Machine.new(@model, :status, :initial => 'off')
|
229
|
+
@machine.other_states('on')
|
197
230
|
@record = @model.new
|
198
231
|
end
|
199
232
|
|
@@ -205,6 +238,29 @@ begin
|
|
205
238
|
assert @record.respond_to?(:status=)
|
206
239
|
end
|
207
240
|
|
241
|
+
def test_should_define_an_attribute_predicate
|
242
|
+
assert @record.respond_to?(:status?)
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_should_raise_exception_on_predicate_without_parameters
|
246
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
247
|
+
assert_raise(ArgumentError) { @record.status? }
|
248
|
+
ensure
|
249
|
+
$VERBOSE = old_verbose
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_should_return_false_for_predicate_if_does_not_match_current_value
|
253
|
+
assert !@record.status?('on')
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_should_return_true_for_predicate_if_matches_current_value
|
257
|
+
assert @record.status?('off')
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_should_raise_exception_for_predicate_if_invalid_state_specified
|
261
|
+
assert_raise(ArgumentError) { @record.status?('invalid') }
|
262
|
+
end
|
263
|
+
|
208
264
|
def test_should_set_initial_state_on_created_object
|
209
265
|
assert_equal 'off', @record.status
|
210
266
|
end
|
@@ -213,7 +269,7 @@ begin
|
|
213
269
|
class MachineWithCallbacksTest < ActiveRecord::TestCase
|
214
270
|
def setup
|
215
271
|
@model = new_model
|
216
|
-
@machine = StateMachine::Machine.new(@model)
|
272
|
+
@machine = StateMachine::Machine.new(@model, :initial => 'off')
|
217
273
|
@record = @model.new(:state => 'off')
|
218
274
|
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
219
275
|
end
|
@@ -285,7 +341,7 @@ begin
|
|
285
341
|
def test_should_include_transition_states_in_known_states
|
286
342
|
@machine.before_transition :to => 'error', :do => lambda {}
|
287
343
|
|
288
|
-
assert_equal %w(error), @machine.states.sort
|
344
|
+
assert_equal %w(error off), @machine.states.sort
|
289
345
|
end
|
290
346
|
end
|
291
347
|
|
data/test/unit/machine_test.rb
CHANGED
@@ -35,8 +35,8 @@ class MachineByDefaultTest < Test::Unit::TestCase
|
|
35
35
|
assert_nil @machine.action
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
|
38
|
+
def test_should_have_a_nil_state
|
39
|
+
assert_equal [nil], @machine.states
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_should_not_be_extended_by_the_active_record_integration
|
@@ -158,7 +158,8 @@ class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
|
|
158
158
|
@klass = Class.new do
|
159
159
|
attr_accessor :initial_state
|
160
160
|
end
|
161
|
-
@
|
161
|
+
@initial_state = lambda {|object| object.initial_state || 'default'}
|
162
|
+
@machine = StateMachine::Machine.new(@klass, :initial => @initial_state)
|
162
163
|
@object = @klass.new
|
163
164
|
end
|
164
165
|
|
@@ -174,8 +175,8 @@ class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
|
|
174
175
|
assert_equal 'default', @object.state
|
175
176
|
end
|
176
177
|
|
177
|
-
def
|
178
|
-
assert_equal [], @machine.states
|
178
|
+
def test_should_be_included_in_known_states
|
179
|
+
assert_equal [@initial_state], @machine.states
|
179
180
|
end
|
180
181
|
end
|
181
182
|
|
@@ -228,6 +229,15 @@ class MachineTest < Test::Unit::TestCase
|
|
228
229
|
def test_should_raise_exception_if_invalid_option_specified
|
229
230
|
assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)}
|
230
231
|
end
|
232
|
+
|
233
|
+
def test_should_evaluate_a_block_during_initialization
|
234
|
+
called = true
|
235
|
+
StateMachine::Machine.new(Class.new) do
|
236
|
+
called = respond_to?(:event)
|
237
|
+
end
|
238
|
+
|
239
|
+
assert called
|
240
|
+
end
|
231
241
|
end
|
232
242
|
|
233
243
|
class MachineWithoutIntegrationTest < Test::Unit::TestCase
|
@@ -822,7 +832,7 @@ end
|
|
822
832
|
class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
|
823
833
|
def setup
|
824
834
|
@klass = Class.new
|
825
|
-
@machine = StateMachine::Machine.new(@klass)
|
835
|
+
@machine = StateMachine::Machine.new(@klass, :initial => 'off')
|
826
836
|
@machine.event(:turn_on) do
|
827
837
|
transition :to => 'on', :from => 'off'
|
828
838
|
transition :to => 'error', :from => 'unknown'
|
@@ -893,19 +903,34 @@ class MachineWithNumericStatesTest < Test::Unit::TestCase
|
|
893
903
|
end
|
894
904
|
end
|
895
905
|
|
906
|
+
class MachineWithNilStatesTest < Test::Unit::TestCase
|
907
|
+
def setup
|
908
|
+
@klass = Class.new
|
909
|
+
@machine = StateMachine::Machine.new(@klass)
|
910
|
+
@machine.event(:turn_on) do
|
911
|
+
transition :to => 'on', :from => nil
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
def test_should_not_redefine_nil_predicate
|
916
|
+
object = @klass.new
|
917
|
+
assert !object.nil?
|
918
|
+
assert !object.respond_to?('?')
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
896
922
|
class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
|
897
923
|
def setup
|
898
924
|
@klass = Class.new do
|
899
925
|
attr_accessor :callbacks
|
900
926
|
end
|
901
927
|
|
902
|
-
@machine = StateMachine::Machine.new(@klass)
|
928
|
+
@machine = StateMachine::Machine.new(@klass, :initial => 'off')
|
903
929
|
@event = @machine.event :turn_on do
|
904
930
|
transition :to => 'on', :from => 'off'
|
905
931
|
end
|
906
932
|
|
907
933
|
@object = @klass.new
|
908
|
-
@object.state = 'off'
|
909
934
|
@object.callbacks = []
|
910
935
|
end
|
911
936
|
|
@@ -1052,6 +1077,15 @@ class MachineFinderWithoutExistingMachineTest < Test::Unit::TestCase
|
|
1052
1077
|
@machine = StateMachine::Machine.find_or_create(@klass)
|
1053
1078
|
end
|
1054
1079
|
|
1080
|
+
def test_should_accept_a_block
|
1081
|
+
called = false
|
1082
|
+
StateMachine::Machine.find_or_create(Class.new) do
|
1083
|
+
called = respond_to?(:event)
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
assert called
|
1087
|
+
end
|
1088
|
+
|
1055
1089
|
def test_should_create_a_new_machine
|
1056
1090
|
assert_not_nil @machine
|
1057
1091
|
end
|
@@ -1068,6 +1102,15 @@ class MachineFinderWithExistingOnSameClassTest < Test::Unit::TestCase
|
|
1068
1102
|
@machine = StateMachine::Machine.find_or_create(@klass)
|
1069
1103
|
end
|
1070
1104
|
|
1105
|
+
def test_should_accept_a_block
|
1106
|
+
called = false
|
1107
|
+
StateMachine::Machine.find_or_create(@klass) do
|
1108
|
+
called = respond_to?(:event)
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
assert called
|
1112
|
+
end
|
1113
|
+
|
1071
1114
|
def test_should_not_create_a_new_machine
|
1072
1115
|
assert_same @machine, @existing_machine
|
1073
1116
|
end
|
@@ -1092,6 +1135,15 @@ class MachineFinderWithExistingMachineOnSuperclassTest < Test::Unit::TestCase
|
|
1092
1135
|
@machine = StateMachine::Machine.find_or_create(@klass, 'status')
|
1093
1136
|
end
|
1094
1137
|
|
1138
|
+
def test_should_accept_a_block
|
1139
|
+
called = false
|
1140
|
+
StateMachine::Machine.find_or_create(Class.new(@base_class)) do
|
1141
|
+
called = respond_to?(:event)
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
assert called
|
1145
|
+
end
|
1146
|
+
|
1095
1147
|
def test_should_create_a_new_machine
|
1096
1148
|
assert_not_nil @machine
|
1097
1149
|
assert_not_same @machine, @base_machine
|
@@ -1211,14 +1263,33 @@ begin
|
|
1211
1263
|
end
|
1212
1264
|
end
|
1213
1265
|
|
1214
|
-
class
|
1266
|
+
class MachineDrawingWithNilStatesTest < Test::Unit::TestCase
|
1267
|
+
def setup
|
1268
|
+
@klass = Class.new do
|
1269
|
+
def self.name; 'Vehicle'; end
|
1270
|
+
end
|
1271
|
+
@machine = StateMachine::Machine.new(@klass, :activated_at, :initial => 'inactive')
|
1272
|
+
@machine.event :activate do
|
1273
|
+
transition :from => nil, :to => 'active'
|
1274
|
+
end
|
1275
|
+
@machine.draw
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
def test_should_draw_machine
|
1279
|
+
assert File.exist?('./Vehicle_activated_at.png')
|
1280
|
+
ensure
|
1281
|
+
FileUtils.rm('./Vehicle_activated_at.png')
|
1282
|
+
end
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
class MachineDrawingWithDynamicStatesTest < Test::Unit::TestCase
|
1215
1286
|
def setup
|
1216
1287
|
@klass = Class.new do
|
1217
1288
|
def self.name; 'Vehicle'; end
|
1218
1289
|
end
|
1219
|
-
@machine = StateMachine::Machine.new(@klass, :activated_at)
|
1290
|
+
@machine = StateMachine::Machine.new(@klass, :activated_at, :initial => 'inactive')
|
1220
1291
|
@machine.event :activate do
|
1221
|
-
transition :from =>
|
1292
|
+
transition :from => 'inactive', :to => lambda {Time.now}
|
1222
1293
|
end
|
1223
1294
|
@machine.draw
|
1224
1295
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-16 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|