state_machines 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.idea/.name +1 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/cssxfire.xml +9 -0
  6. data/.idea/encodings.xml +5 -0
  7. data/.idea/misc.xml +5 -0
  8. data/.idea/modules.xml +12 -0
  9. data/.idea/scopes/scope_settings.xml +5 -0
  10. data/.idea/state_machine2.iml +34 -0
  11. data/.idea/vcs.xml +9 -0
  12. data/.idea/workspace.xml +1156 -0
  13. data/.rspec +3 -0
  14. data/.travis.yml +8 -0
  15. data/Gemfile +4 -0
  16. data/LICENSE.txt +23 -0
  17. data/README.md +29 -0
  18. data/Rakefile +1 -0
  19. data/lib/state_machines/assertions.rb +40 -0
  20. data/lib/state_machines/branch.rb +187 -0
  21. data/lib/state_machines/callback.rb +220 -0
  22. data/lib/state_machines/core.rb +25 -0
  23. data/lib/state_machines/core_ext/class/state_machine.rb +5 -0
  24. data/lib/state_machines/core_ext.rb +2 -0
  25. data/lib/state_machines/error.rb +13 -0
  26. data/lib/state_machines/eval_helpers.rb +87 -0
  27. data/lib/state_machines/event.rb +246 -0
  28. data/lib/state_machines/event_collection.rb +141 -0
  29. data/lib/state_machines/extensions.rb +148 -0
  30. data/lib/state_machines/helper_module.rb +17 -0
  31. data/lib/state_machines/integrations/base.rb +100 -0
  32. data/lib/state_machines/integrations.rb +113 -0
  33. data/lib/state_machines/machine.rb +2234 -0
  34. data/lib/state_machines/machine_collection.rb +84 -0
  35. data/lib/state_machines/macro_methods.rb +520 -0
  36. data/lib/state_machines/matcher.rb +123 -0
  37. data/lib/state_machines/matcher_helpers.rb +54 -0
  38. data/lib/state_machines/node_collection.rb +221 -0
  39. data/lib/state_machines/path.rb +120 -0
  40. data/lib/state_machines/path_collection.rb +90 -0
  41. data/lib/state_machines/state.rb +276 -0
  42. data/lib/state_machines/state_collection.rb +112 -0
  43. data/lib/state_machines/state_context.rb +138 -0
  44. data/lib/state_machines/transition.rb +470 -0
  45. data/lib/state_machines/transition_collection.rb +245 -0
  46. data/lib/state_machines/version.rb +3 -0
  47. data/lib/state_machines/yard.rb +8 -0
  48. data/lib/state_machines.rb +3 -0
  49. data/spec/errors/default_spec.rb +14 -0
  50. data/spec/errors/with_message_spec.rb +39 -0
  51. data/spec/helpers/helper_spec.rb +14 -0
  52. data/spec/internal/app/models/auto_shop.rb +31 -0
  53. data/spec/internal/app/models/car.rb +19 -0
  54. data/spec/internal/app/models/model_base.rb +6 -0
  55. data/spec/internal/app/models/motorcycle.rb +9 -0
  56. data/spec/internal/app/models/traffic_light.rb +47 -0
  57. data/spec/internal/app/models/vehicle.rb +123 -0
  58. data/spec/machine_spec.rb +3167 -0
  59. data/spec/matcher_helpers_spec.rb +39 -0
  60. data/spec/matcher_spec.rb +157 -0
  61. data/spec/models/auto_shop_spec.rb +41 -0
  62. data/spec/models/car_spec.rb +90 -0
  63. data/spec/models/motorcycle_spec.rb +44 -0
  64. data/spec/models/traffic_light_spec.rb +56 -0
  65. data/spec/models/vehicle_spec.rb +580 -0
  66. data/spec/node_collection_spec.rb +371 -0
  67. data/spec/path_collection_spec.rb +271 -0
  68. data/spec/path_spec.rb +488 -0
  69. data/spec/spec_helper.rb +6 -0
  70. data/spec/state_collection_spec.rb +352 -0
  71. data/spec/state_context_spec.rb +442 -0
  72. data/spec/state_machine_spec.rb +29 -0
  73. data/spec/state_spec.rb +970 -0
  74. data/spec/support/migration_helpers.rb +50 -0
  75. data/spec/support/models.rb +6 -0
  76. data/spec/transition_collection_spec.rb +2199 -0
  77. data/spec/transition_spec.rb +1558 -0
  78. data/state_machines.gemspec +23 -0
  79. metadata +194 -0
data/spec/path_spec.rb ADDED
@@ -0,0 +1,488 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachines::Path do
4
+ context 'ByDefault' do
5
+ before(:each) do
6
+ @klass = Class.new
7
+ @machine = StateMachines::Machine.new(@klass)
8
+ @object = @klass.new
9
+
10
+ @path = StateMachines::Path.new(@object, @machine)
11
+ end
12
+
13
+ it 'should_have_an_object' do
14
+ assert_equal @object, @path.object
15
+ end
16
+
17
+ it 'should_have_a_machine' do
18
+ assert_equal @machine, @path.machine
19
+ end
20
+
21
+ it 'should_not_have_walked_anywhere' do
22
+ assert_equal [], @path
23
+ end
24
+
25
+ it 'should_not_have_a_from_name' do
26
+ assert_nil @path.from_name
27
+ end
28
+
29
+ it 'should_have_no_from_states' do
30
+ assert_equal [], @path.from_states
31
+ end
32
+
33
+ it 'should_not_have_a_to_name' do
34
+ assert_nil @path.to_name
35
+ end
36
+
37
+ it 'should_have_no_to_states' do
38
+ assert_equal [], @path.to_states
39
+ end
40
+
41
+ it 'should_have_no_events' do
42
+ assert_equal [], @path.events
43
+ end
44
+
45
+ it 'should_not_be_able_to_walk_anywhere' do
46
+ walked = false
47
+ @path.walk { walked = true }
48
+ assert_equal false, walked
49
+ end
50
+
51
+ it 'should_not_be_complete' do
52
+ assert_equal false, @path.complete?
53
+ end
54
+ end
55
+
56
+ context '' do
57
+ before(:each) do
58
+ @klass = Class.new
59
+ @machine = StateMachines::Machine.new(@klass)
60
+ @object = @klass.new
61
+ end
62
+
63
+ it 'should_raise_exception_if_invalid_option_specified' do
64
+ assert_raise(ArgumentError) { StateMachines::Path.new(@object, @machine, :invalid => true) }
65
+ # FIXME
66
+ #assert_equal 'Invalid key(s): invalid', exception.message
67
+ end
68
+ end
69
+
70
+ context 'WithoutTransitions' do
71
+ before(:each) do
72
+ @klass = Class.new
73
+ @machine = StateMachines::Machine.new(@klass)
74
+ @machine.state :parked, :idling
75
+ @machine.event :ignite
76
+
77
+ @object = @klass.new
78
+
79
+ @path = StateMachines::Path.new(@object, @machine)
80
+ @path.concat([
81
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
82
+ ])
83
+ end
84
+
85
+ it 'should_not_be_able_to_walk_anywhere' do
86
+ walked = false
87
+ @path.walk { walked = true }
88
+ assert_equal false, walked
89
+ end
90
+ end
91
+
92
+ context 'WithTransitions' do
93
+ before(:each) do
94
+ @klass = Class.new
95
+ @machine = StateMachines::Machine.new(@klass)
96
+ @machine.state :parked, :idling, :first_gear
97
+ @machine.event :ignite, :shift_up
98
+
99
+ @object = @klass.new
100
+ @object.state = 'parked'
101
+
102
+ @path = StateMachines::Path.new(@object, @machine)
103
+ @path.concat([
104
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
105
+ @shift_up_transition = StateMachines::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)
106
+ ])
107
+ end
108
+
109
+ it 'should_enumerate_transitions' do
110
+ assert_equal [@ignite_transition, @shift_up_transition], @path
111
+ end
112
+
113
+ it 'should_have_a_from_name' do
114
+ assert_equal :parked, @path.from_name
115
+ end
116
+
117
+ it 'should_have_from_states' do
118
+ assert_equal [:parked, :idling], @path.from_states
119
+ end
120
+
121
+ it 'should_have_a_to_name' do
122
+ assert_equal :first_gear, @path.to_name
123
+ end
124
+
125
+ it 'should_have_to_states' do
126
+ assert_equal [:idling, :first_gear], @path.to_states
127
+ end
128
+
129
+ it 'should_have_events' do
130
+ assert_equal [:ignite, :shift_up], @path.events
131
+ end
132
+
133
+ it 'should_not_be_able_to_walk_anywhere' do
134
+ walked = false
135
+ @path.walk { walked = true }
136
+ assert_equal false, walked
137
+ end
138
+
139
+ it 'should_be_complete' do
140
+ assert_equal true, @path.complete?
141
+ end
142
+ end
143
+
144
+ context 'WithDuplicates' do
145
+ before(:each) do
146
+ @klass = Class.new
147
+ @machine = StateMachines::Machine.new(@klass)
148
+ @machine.state :parked, :idling
149
+ @machine.event :park, :ignite
150
+
151
+ @object = @klass.new
152
+ @object.state = 'parked'
153
+
154
+ @path = StateMachines::Path.new(@object, @machine)
155
+ @path.concat([
156
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
157
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked),
158
+ @ignite_again_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
159
+ ])
160
+ end
161
+
162
+ it 'should_not_include_duplicates_in_from_states' do
163
+ assert_equal [:parked, :idling], @path.from_states
164
+ end
165
+
166
+ it 'should_not_include_duplicates_in_to_states' do
167
+ assert_equal [:idling, :parked], @path.to_states
168
+ end
169
+
170
+ it 'should_not_include_duplicates_in_events' do
171
+ assert_equal [:ignite, :park], @path.events
172
+ end
173
+ end
174
+
175
+ context 'WithAvailableTransitions' do
176
+ before(:each) do
177
+ @klass = Class.new
178
+ @machine = StateMachines::Machine.new(@klass)
179
+ @machine.state :parked, :idling, :first_gear
180
+ @machine.event :ignite
181
+ @machine.event :shift_up do
182
+ transition :idling => :first_gear
183
+ end
184
+ @machine.event :park do
185
+ transition :idling => :parked
186
+ end
187
+
188
+ @object = @klass.new
189
+ @object.state = 'parked'
190
+
191
+ @path = StateMachines::Path.new(@object, @machine)
192
+ @path.concat([
193
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
194
+ ])
195
+ end
196
+
197
+ it 'should_not_be_complete' do
198
+ assert !@path.complete?
199
+ end
200
+
201
+ it 'should_walk_each_available_transition' do
202
+ paths = []
203
+ @path.walk { |path| paths << path }
204
+
205
+ assert_equal [
206
+ [@ignite_transition, StateMachines::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)],
207
+ [@ignite_transition, StateMachines::Transition.new(@object, @machine, :park, :idling, :parked)]
208
+ ], paths
209
+ end
210
+
211
+ it 'should_yield_path_instances_when_walking' do
212
+ @path.walk do |path|
213
+ assert_instance_of StateMachines::Path, path
214
+ end
215
+ end
216
+
217
+ it 'should_not_modify_current_path_after_walking' do
218
+ @path.walk {}
219
+ assert_equal [@ignite_transition], @path
220
+ end
221
+
222
+ it 'should_not_modify_object_after_walking' do
223
+ @path.walk {}
224
+ assert_equal 'parked', @object.state
225
+ end
226
+ end
227
+
228
+ context 'WithGuardedTransitions' do
229
+ before(:each) do
230
+ @klass = Class.new
231
+ @machine = StateMachines::Machine.new(@klass)
232
+ @machine.state :parked, :idling
233
+ @machine.event :ignite
234
+ @machine.event :shift_up do
235
+ transition :idling => :first_gear, :if => lambda { false }
236
+ end
237
+
238
+ @object = @klass.new
239
+ @object.state = 'parked'
240
+ end
241
+
242
+ it 'should_not_walk_transitions_if_guard_enabled' do
243
+ path = StateMachines::Path.new(@object, @machine)
244
+ path.concat([
245
+ StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
246
+ ])
247
+
248
+ paths = []
249
+ path.walk { |next_path| paths << next_path }
250
+
251
+ assert_equal [], paths
252
+ end
253
+
254
+ it 'should_not_walk_transitions_if_guard_disabled' do
255
+ path = StateMachines::Path.new(@object, @machine, :guard => false)
256
+ path.concat([
257
+ ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
258
+ ])
259
+
260
+ paths = []
261
+ path.walk { |next_path| paths << next_path }
262
+
263
+ assert_equal [
264
+ [ignite_transition, StateMachines::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)]
265
+ ], paths
266
+ end
267
+ end
268
+
269
+ context 'WithEncounteredTransitions' do
270
+ before(:each) do
271
+ @klass = Class.new
272
+ @machine = StateMachines::Machine.new(@klass)
273
+ @machine.state :parked, :idling, :first_gear
274
+ @machine.event :ignite do
275
+ transition :parked => :idling
276
+ end
277
+ @machine.event :park do
278
+ transition :idling => :parked
279
+ end
280
+
281
+ @object = @klass.new
282
+ @object.state = 'parked'
283
+
284
+ @path = StateMachines::Path.new(@object, @machine)
285
+ @path.concat([
286
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
287
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked)
288
+ ])
289
+ end
290
+
291
+ it 'should_be_complete' do
292
+ assert_equal true, @path.complete?
293
+ end
294
+
295
+ it 'should_not_be_able_to_walk' do
296
+ walked = false
297
+ @path.walk { walked = true }
298
+ assert_equal false, walked
299
+ end
300
+ end
301
+
302
+ context 'WithUnreachedTarget' do
303
+ before(:each) do
304
+ @klass = Class.new
305
+ @machine = StateMachines::Machine.new(@klass)
306
+ @machine.state :parked, :idling
307
+ @machine.event :ignite do
308
+ transition :parked => :idling
309
+ end
310
+
311
+ @object = @klass.new
312
+ @object.state = 'parked'
313
+
314
+ @path = StateMachines::Path.new(@object, @machine, :target => :parked)
315
+ @path.concat([
316
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling)
317
+ ])
318
+ end
319
+
320
+ it 'should_not_be_complete' do
321
+ assert_equal false, @path.complete?
322
+ end
323
+
324
+ it 'should_not_be_able_to_walk' do
325
+ walked = false
326
+ @path.walk { walked = true }
327
+ assert_equal false, walked
328
+ end
329
+ end
330
+
331
+ context 'WithReachedTarget' do
332
+ before(:each) do
333
+ @klass = Class.new
334
+ @machine = StateMachines::Machine.new(@klass)
335
+ @machine.state :parked, :idling
336
+ @machine.event :ignite do
337
+ transition :parked => :idling
338
+ end
339
+ @machine.event :park do
340
+ transition :idling => :parked
341
+ end
342
+
343
+ @object = @klass.new
344
+ @object.state = 'parked'
345
+
346
+ @path = StateMachines::Path.new(@object, @machine, :target => :parked)
347
+ @path.concat([
348
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
349
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked)
350
+ ])
351
+ end
352
+
353
+ it 'should_be_complete' do
354
+ assert_equal true, @path.complete?
355
+ end
356
+
357
+ it 'should_not_be_able_to_walk' do
358
+ walked = false
359
+ @path.walk { walked = true }
360
+ assert_equal false, walked
361
+ end
362
+ end
363
+
364
+ context 'WithAvailableTransitionsAfterReachingTarget' do
365
+ before(:each) do
366
+ @klass = Class.new
367
+ @machine = StateMachines::Machine.new(@klass)
368
+ @machine.state :parked, :idling
369
+ @machine.event :ignite do
370
+ transition :parked => :idling
371
+ end
372
+ @machine.event :shift_up do
373
+ transition :parked => :first_gear
374
+ end
375
+ @machine.event :park do
376
+ transition [:idling, :first_gear] => :parked
377
+ end
378
+
379
+ @object = @klass.new
380
+ @object.state = 'parked'
381
+
382
+ @path = StateMachines::Path.new(@object, @machine, :target => :parked)
383
+ @path.concat([
384
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
385
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked)
386
+ ])
387
+ end
388
+
389
+ it 'should_be_complete' do
390
+ assert_equal true, @path.complete?
391
+ end
392
+
393
+ it 'should_be_able_to_walk' do
394
+ paths = []
395
+ @path.walk { |path| paths << path }
396
+ assert_equal [
397
+ [@ignite_transition, @park_transition, StateMachines::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)]
398
+ ], paths
399
+ end
400
+ end
401
+
402
+ context 'WithDeepTarget' do
403
+ before(:each) do
404
+ @klass = Class.new
405
+ @machine = StateMachines::Machine.new(@klass)
406
+ @machine.state :parked, :idling
407
+ @machine.event :ignite do
408
+ transition :parked => :idling
409
+ end
410
+ @machine.event :shift_up do
411
+ transition :parked => :first_gear
412
+ end
413
+ @machine.event :park do
414
+ transition [:idling, :first_gear] => :parked
415
+ end
416
+
417
+ @object = @klass.new
418
+ @object.state = 'parked'
419
+
420
+ @path = StateMachines::Path.new(@object, @machine, :target => :parked)
421
+ @path.concat([
422
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
423
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked),
424
+ @shift_up_transition = StateMachines::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)
425
+ ])
426
+ end
427
+
428
+ it 'should_not_be_complete' do
429
+ assert_equal false, @path.complete?
430
+ end
431
+
432
+ it 'should_be_able_to_walk' do
433
+ paths = []
434
+ @path.walk { |path| paths << path }
435
+ assert_equal [
436
+ [@ignite_transition, @park_transition, @shift_up_transition, StateMachines::Transition.new(@object, @machine, :park, :first_gear, :parked)]
437
+ ], paths
438
+ end
439
+ end
440
+
441
+ context 'WithDeepTargetReached' do
442
+ before(:each) do
443
+ @klass = Class.new
444
+ @machine = StateMachines::Machine.new(@klass)
445
+ @machine.state :parked, :idling
446
+ @machine.event :ignite do
447
+ transition :parked => :idling
448
+ end
449
+ @machine.event :shift_up do
450
+ transition :parked => :first_gear
451
+ end
452
+ @machine.event :park do
453
+ transition [:idling, :first_gear] => :parked
454
+ end
455
+
456
+ @object = @klass.new
457
+ @object.state = 'parked'
458
+
459
+ @path = StateMachines::Path.new(@object, @machine, :target => :parked)
460
+ @path.concat([
461
+ @ignite_transition = StateMachines::Transition.new(@object, @machine, :ignite, :parked, :idling),
462
+ @park_transition = StateMachines::Transition.new(@object, @machine, :park, :idling, :parked),
463
+ @shift_up_transition = StateMachines::Transition.new(@object, @machine, :shift_up, :parked, :first_gear),
464
+ @park_transition_2 = StateMachines::Transition.new(@object, @machine, :park, :first_gear, :parked)
465
+ ])
466
+ end
467
+
468
+ it 'should_be_complete' do
469
+ assert_equal true, @path.complete?
470
+ end
471
+
472
+ it 'should_not_be_able_to_walk' do
473
+ walked = false
474
+ @path.walk { walked = true }
475
+ assert_equal false, walked
476
+ end
477
+
478
+ it 'should_not_be_able_to_walk_with_available_transitions' do
479
+ @machine.event :park do
480
+ transition :parked => same
481
+ end
482
+
483
+ walked = false
484
+ @path.walk { walked = true }
485
+ assert_equal false, walked
486
+ end
487
+ end
488
+ end
@@ -0,0 +1,6 @@
1
+ require 'state_machines'
2
+ require 'stringio'
3
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
4
+ RSpec.configure do |config|
5
+ config.raise_errors_for_deprecations!
6
+ end