state_machines 0.0.1

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 (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