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
@@ -0,0 +1,580 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vehicle do
4
+ let(:vehicle) { Vehicle.new }
5
+ it 'should_not_allow_access_to_subclass_events' do
6
+ expect(vehicle).respond_to?(:reverse)
7
+ end
8
+
9
+ it 'should_have_human_state_names' do
10
+ expect(Vehicle.human_state_name(:parked)).to eq('parked')
11
+ end
12
+
13
+ it 'should_have_human_state_event_names' do
14
+ expect(Vehicle.human_state_event_name(:park)).to eq('park')
15
+ end
16
+
17
+ context 'unsaved' do
18
+ it 'should_be_in_parked_state' do
19
+ expect(vehicle.state).to eq('parked')
20
+ end
21
+ it 'should_raise_exception_if_checking_invalid_state' do
22
+ expect { vehicle.state?(:invalid) }.to raise_error(IndexError)
23
+ end
24
+
25
+ it 'should_raise_exception_if_getting_name_of_invalid_state' do
26
+ vehicle.state ='invalid'
27
+ expect { vehicle.state_name }.to raise_error(ArgumentError)
28
+ end
29
+
30
+ it 'should_be_parked' do
31
+ expect(vehicle.parked?).to be_truthy
32
+ expect(vehicle.state?(:parked)).to be_truthy
33
+ expect(vehicle.state_name).to eq(:parked)
34
+ expect(vehicle.human_state_name).to eq('parked')
35
+ end
36
+
37
+ it 'should_not_be_idling' do
38
+ expect(vehicle.idling?).to be_falsy
39
+ end
40
+
41
+ it 'should_not_be_first_gear' do
42
+ expect(vehicle.first_gear?).to be_falsy
43
+ end
44
+
45
+ it 'should_not_be_second_gear' do
46
+ expect(vehicle.second_gear?).to be_falsy
47
+ end
48
+
49
+ it 'should_not_be_stalled' do
50
+ expect(vehicle.stalled?).to be_falsy
51
+ end
52
+
53
+ it 'should_not_be_able_to_park' do
54
+ expect(vehicle.can_park?).to be_falsy
55
+ end
56
+
57
+
58
+ it 'should_not_have_a_transition_for_park' do
59
+ expect(vehicle.park_transition).to be_nil
60
+ end
61
+
62
+
63
+ it 'should_not_allow_park' do
64
+ expect(vehicle.park).to be_falsy
65
+ end
66
+
67
+ it 'should_be_able_to_ignite' do
68
+ expect(vehicle.can_ignite?).to be_truthy
69
+ end
70
+
71
+ it 'should_have_a_transition_for_ignite' do
72
+ transition = vehicle.ignite_transition
73
+ expect(transition).to_not be_nil
74
+ expect(transition.from).to eq('parked')
75
+ expect(transition.to).to eq('idling')
76
+ expect(transition.event).to eq(:ignite)
77
+ expect(transition.attribute).to eq(:state)
78
+ expect(transition.object).to eq(vehicle)
79
+
80
+ end
81
+
82
+ it 'should_have_a_list_of_possible_events' do
83
+ expect(vehicle.state_events).to eq([:ignite])
84
+ end
85
+
86
+ it 'should_have_a_list_of_possible_transitions' do
87
+ expect(vehicle.state_transitions.map { |transition| transition.attributes }).to eq([{:object => vehicle, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}])
88
+ end
89
+
90
+ it 'should_have_a_list_of_possible_paths' do
91
+ expect(vehicle.state_paths(:to => :first_gear)).to eq([[
92
+ StateMachines::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling),
93
+ StateMachines::Transition.new(vehicle, Vehicle.state_machine, :shift_up, :idling, :first_gear)
94
+ ]])
95
+ end
96
+
97
+ it 'should_allow_generic_event_to_fire' do
98
+ expect(vehicle.fire_state_event(:ignite)).to be_truthy
99
+ expect(vehicle.state).to eq('idling')
100
+ end
101
+
102
+ it 'should_pass_arguments_through_to_generic_event_runner' do
103
+ vehicle.fire_state_event(:ignite, 1, 2, 3)
104
+ expect(vehicle.last_transition_args).to eq([1, 2, 3])
105
+ end
106
+
107
+ it 'should_allow_skipping_action_through_generic_event_runner' do
108
+ vehicle.fire_state_event(:ignite, false)
109
+ expect(vehicle.saved).to be_falsy
110
+ end
111
+
112
+ it 'should_raise_error_with_invalid_event_through_generic_event_runner' do
113
+ expect { vehicle.fire_state_event(:invalid) }.to raise_error(IndexError)
114
+ end
115
+
116
+ it 'should_allow_ignite' do
117
+ vehicle.ignite
118
+ expect(vehicle.state).to eq('idling')
119
+ end
120
+
121
+ it 'should_allow_ignite_with_skipped_action' do
122
+ expect(vehicle.ignite(false)).to be_truthy
123
+ expect(vehicle.new_record?).to be_truthy
124
+ end
125
+
126
+ it 'should_allow_ignite_bang' do
127
+ expect(vehicle.ignite!).to be_truthy
128
+ end
129
+
130
+ it 'should_allow_ignite_bang_with_skipped_action' do
131
+ expect(vehicle.ignite!(false)).to be_truthy
132
+ expect(vehicle.new_record?).to be_truthy
133
+ end
134
+
135
+ it 'should_be_saved_after_successful_event' do
136
+ vehicle.ignite
137
+ expect(vehicle.new_record?).to be_falsy
138
+ end
139
+
140
+ it 'should_not_allow_idle' do
141
+ expect(vehicle.idle).to be_falsy
142
+ end
143
+
144
+ it 'should_not_allow_shift_down' do
145
+ expect(vehicle.shift_down).to be_falsy
146
+ end
147
+
148
+ it 'should_not_allow_crash' do
149
+ expect(vehicle.crash).to be_falsy
150
+ end
151
+
152
+ it 'should_not_allow_repair' do
153
+ expect(vehicle.repair).to be_falsy
154
+ end
155
+
156
+ it 'should_be_insurance_inactive' do
157
+ expect(vehicle.insurance_inactive?).to be_truthy
158
+ end
159
+
160
+ it 'should_be_able_to_buy' do
161
+ expect(vehicle.can_buy_insurance?).to be_truthy
162
+ end
163
+
164
+ it 'should_allow_buying_insurance' do
165
+ expect(vehicle.buy_insurance).to be_truthy
166
+ end
167
+
168
+ it 'should_allow_buying_insurance_bang' do
169
+ expect(vehicle.buy_insurance!).to be_truthy
170
+ end
171
+
172
+ it 'should_allow_ignite_buying_insurance_with_skipped_action' do
173
+ expect(vehicle.buy_insurance!(false)).to be_truthy
174
+ expect(vehicle.new_record?).to be_truthy
175
+ end
176
+
177
+ it 'should_not_be_insurance_active' do
178
+ expect(vehicle.insurance_active?).to be_falsy
179
+ end
180
+
181
+ it 'should_not_be_able_to_cancel' do
182
+ expect(vehicle.can_cancel_insurance?).to be_falsy
183
+ end
184
+
185
+ it 'should_not_allow_cancelling_insurance' do
186
+ expect(vehicle.cancel_insurance).to be_falsy
187
+ end
188
+ end
189
+
190
+ context 'Parked' do
191
+
192
+ it 'should_be_in_parked_state' do
193
+ expect(vehicle.state).to eq('parked')
194
+ end
195
+
196
+ it 'should_not_have_the_seatbelt_on' do
197
+ expect(vehicle.seatbelt_on).to be_falsy
198
+ end
199
+
200
+ it 'should_not_allow_park' do
201
+ expect(vehicle.park).to be_falsy
202
+ end
203
+
204
+ it 'should_allow_ignite' do
205
+ expect(vehicle.ignite).to be_truthy
206
+ expect(vehicle.state).to eq('idling')
207
+ end
208
+
209
+ it 'should_not_allow_idle' do
210
+ expect(vehicle.idle).to be_falsy
211
+ end
212
+
213
+ it 'should_not_allow_shift_up' do
214
+ expect(vehicle.shift_up).to be_falsy
215
+ end
216
+
217
+ it 'should_not_allow_shift_down' do
218
+ expect(vehicle.shift_down).to be_falsy
219
+ end
220
+
221
+ it 'should_not_allow_crash' do
222
+ expect(vehicle.crash).to be_falsy
223
+ end
224
+
225
+ it 'should_not_allow_repair' do
226
+ expect(vehicle.repair).to be_falsy
227
+ end
228
+ #
229
+ # it 'should_raise_exception_if_repair_not_allowed!' do
230
+ # exception = assert_raise(StateMachines::InvalidTransition) {vehicle.repair!}
231
+ # assert_equal vehicle, exception.object
232
+ # assert_equal Vehicle.state_machine(:state), exception.machine
233
+ # assert_equal :repair, exception.event
234
+ # assert_equal'parked', exception.from
235
+ # end
236
+ end
237
+
238
+ context 'Idling' do
239
+ before(:each) do
240
+ vehicle.ignite
241
+ end
242
+
243
+ it 'should_be_in_idling_state' do
244
+ assert_equal 'idling', vehicle.state
245
+ end
246
+
247
+ it 'should_be_idling' do
248
+ assert vehicle.idling?
249
+ end
250
+
251
+ it 'should_have_seatbelt_on' do
252
+ assert vehicle.seatbelt_on
253
+ end
254
+
255
+ it 'should_track_time_elapsed' do
256
+ assert_not_nil vehicle.time_elapsed
257
+ end
258
+
259
+ it 'should_allow_park' do
260
+ assert vehicle.park
261
+ end
262
+
263
+ it 'should_call_park_with_bang_action' do
264
+ class << vehicle
265
+ def park
266
+ super && 1
267
+ end
268
+ end
269
+
270
+ assert_equal 1, vehicle.park!
271
+ end
272
+
273
+ it 'should_not_allow_idle' do
274
+ assert !vehicle.idle
275
+ end
276
+
277
+ it 'should_allow_shift_up' do
278
+ assert vehicle.shift_up
279
+ end
280
+
281
+ it 'should_not_allow_shift_down' do
282
+ assert !vehicle.shift_down
283
+ end
284
+
285
+ it 'should_not_allow_crash' do
286
+ assert !vehicle.crash
287
+ end
288
+
289
+ it 'should_not_allow_repair' do
290
+ assert !vehicle.repair
291
+ end
292
+ end
293
+
294
+ context 'Locked' do
295
+ before(:each) do
296
+ vehicle.state ='locked'
297
+ end
298
+
299
+
300
+ it 'should_be_parked_after_park' do
301
+ vehicle.park
302
+ expect(vehicle.parked?).to be_truthy
303
+ end
304
+
305
+ it 'should_be_parked_after_ignite' do
306
+ vehicle.ignite
307
+ expect(vehicle.parked?).to be_truthy
308
+ end
309
+
310
+ it 'should_be_parked_after_shift_up' do
311
+ vehicle.shift_up
312
+ expect(vehicle.parked?).to be_truthy
313
+ end
314
+
315
+ it 'should_be_parked_after_shift_down' do
316
+ vehicle.shift_down
317
+ expect(vehicle.parked?).to be_truthy
318
+ end
319
+ end
320
+
321
+ context 'FirstGear' do
322
+ before(:each) do
323
+
324
+ vehicle.ignite
325
+ vehicle.shift_up
326
+ end
327
+
328
+ it 'should_be_in_first_gear_state' do
329
+ assert_equal 'first_gear', vehicle.state
330
+ end
331
+
332
+ it 'should_be_first_gear' do
333
+ assert vehicle.first_gear?
334
+ end
335
+
336
+ it 'should_allow_park' do
337
+ assert vehicle.park
338
+ end
339
+
340
+ it 'should_allow_idle' do
341
+ assert vehicle.idle
342
+ end
343
+
344
+ it 'should_allow_shift_up' do
345
+ assert vehicle.shift_up
346
+ end
347
+
348
+ it 'should_not_allow_shift_down' do
349
+ assert !vehicle.shift_down
350
+ end
351
+
352
+ it 'should_allow_crash' do
353
+ assert vehicle.crash
354
+ end
355
+
356
+ it 'should_not_allow_repair' do
357
+ assert !vehicle.repair
358
+ end
359
+ end
360
+
361
+
362
+ context 'SecondGear' do
363
+ before(:each) do
364
+ vehicle.ignite
365
+ 2.times { vehicle.shift_up }
366
+ end
367
+
368
+ it 'should_be_in_second_gear_state' do
369
+ assert_equal 'second_gear', vehicle.state
370
+ end
371
+
372
+ it 'should_be_second_gear' do
373
+ assert vehicle.second_gear?
374
+ end
375
+
376
+ it 'should_not_allow_park' do
377
+ assert !vehicle.park
378
+ end
379
+
380
+ it 'should_not_allow_idle' do
381
+ assert !vehicle.idle
382
+ end
383
+
384
+ it 'should_allow_shift_up' do
385
+ assert vehicle.shift_up
386
+ end
387
+
388
+ it 'should_allow_shift_down' do
389
+ assert vehicle.shift_down
390
+ end
391
+
392
+ it 'should_allow_crash' do
393
+ assert vehicle.crash
394
+ end
395
+
396
+ it 'should_not_allow_repair' do
397
+ assert !vehicle.repair
398
+ end
399
+ end
400
+
401
+ context 'ThirdGear' do
402
+ before(:each) do
403
+ vehicle.ignite
404
+ 3.times { vehicle.shift_up }
405
+ end
406
+
407
+ it 'should_be_in_third_gear_state' do
408
+ assert_equal 'third_gear', vehicle.state
409
+ end
410
+
411
+ it 'should_be_third_gear' do
412
+ assert vehicle.third_gear?
413
+ end
414
+
415
+ it 'should_not_allow_park' do
416
+ assert !vehicle.park
417
+ end
418
+
419
+ it 'should_not_allow_idle' do
420
+ assert !vehicle.idle
421
+ end
422
+
423
+ it 'should_not_allow_shift_up' do
424
+ assert !vehicle.shift_up
425
+ end
426
+
427
+ it 'should_allow_shift_down' do
428
+ assert vehicle.shift_down
429
+ end
430
+
431
+ it 'should_allow_crash' do
432
+ assert vehicle.crash
433
+ end
434
+
435
+ it 'should_not_allow_repair' do
436
+ assert !vehicle.repair
437
+ end
438
+ end
439
+
440
+ context 'Stalled' do
441
+ before(:each) do
442
+ vehicle.ignite
443
+ vehicle.shift_up
444
+ vehicle.crash
445
+ end
446
+
447
+ it 'should_be_in_stalled_state' do
448
+ assert_equal 'stalled', vehicle.state
449
+ end
450
+
451
+ it 'should_be_stalled' do
452
+ assert vehicle.stalled?
453
+ end
454
+
455
+ it 'should_be_towed' do
456
+ assert vehicle.auto_shop.busy?
457
+ assert_equal 1, vehicle.auto_shop.num_customers
458
+ end
459
+
460
+ it 'should_have_an_increased_insurance_premium' do
461
+ assert_equal 150, vehicle.insurance_premium
462
+ end
463
+
464
+ it 'should_not_allow_park' do
465
+ assert !vehicle.park
466
+ end
467
+
468
+ it 'should_allow_ignite' do
469
+ assert vehicle.ignite
470
+ end
471
+
472
+ it 'should_not_change_state_when_ignited' do
473
+ assert_equal 'stalled', vehicle.state
474
+ end
475
+
476
+ it 'should_not_allow_idle' do
477
+ assert !vehicle.idle
478
+ end
479
+
480
+ it 'should_now_allow_shift_up' do
481
+ assert !vehicle.shift_up
482
+ end
483
+
484
+ it 'should_not_allow_shift_down' do
485
+ assert !vehicle.shift_down
486
+ end
487
+
488
+ it 'should_not_allow_crash' do
489
+ assert !vehicle.crash
490
+ end
491
+
492
+ it 'should_allow_repair_if_auto_shop_is_busy' do
493
+ assert vehicle.repair
494
+ end
495
+
496
+ it 'should_not_allow_repair_if_auto_shop_is_available' do
497
+ vehicle.auto_shop.fix_vehicle
498
+ assert !vehicle.repair
499
+ end
500
+ end
501
+
502
+ context 'Repaired' do
503
+ before(:each) do
504
+
505
+ vehicle.ignite
506
+ vehicle.shift_up
507
+ vehicle.crash
508
+ vehicle.repair
509
+ end
510
+
511
+ it 'should_be_in_parked_state' do
512
+ assert_equal 'parked', vehicle.state
513
+ end
514
+
515
+ it 'should_not_have_a_busy_auto_shop' do
516
+ assert vehicle.auto_shop.available?
517
+ end
518
+ end
519
+
520
+ context 'Parallel events' do
521
+
522
+ it 'should_fail_if_any_event_cannot_transition' do
523
+ expect(vehicle.fire_events(:ignite, :cancel_insurance)).to be_falsy
524
+ end
525
+
526
+ it 'should_be_successful_if_all_events_transition' do
527
+ expect(vehicle.fire_events(:ignite, :buy_insurance)).to be_truthy
528
+ end
529
+
530
+ it 'should_not_save_if_skipping_action' do
531
+ expect(vehicle.fire_events(:ignite, :buy_insurance, false)).to be_truthy
532
+ expect(vehicle.saved).to be_falsy
533
+ end
534
+
535
+ it 'should_raise_exception_if_any_event_cannot_transition_on_bang' do
536
+ assert_raise(StateMachines::InvalidParallelTransition) { vehicle.fire_events!(:ignite, :cancel_insurance) }
537
+ # assert_equal vehicle, exception.object
538
+ # assert_equal [:ignite, :cancel_insurance], exception.events
539
+ end
540
+
541
+ it 'should_not_raise_exception_if_all_events_transition_on_bang' do
542
+ expect(vehicle.fire_events!(:ignite, :buy_insurance)).to be_truthy
543
+ end
544
+
545
+ it 'should_not_save_if_skipping_action_on_bang' do
546
+ expect(vehicle.fire_events!(:ignite, :buy_insurance, false)).to be_truthy
547
+ expect(vehicle.saved).to be_falsy
548
+ end
549
+ end
550
+
551
+ context 'Event attributes' do
552
+ before(:each) do
553
+ vehicle.state_event ='ignite'
554
+ end
555
+
556
+
557
+ it 'should_fail_if_event_is_invalid' do
558
+ vehicle.state_event ='invalid'
559
+ expect(vehicle.save).to be_falsy
560
+ expect(vehicle.state).to eq('parked')
561
+ end
562
+
563
+ it 'should_fail_if_event_has_no_transition' do
564
+ vehicle.state_event ='park'
565
+ expect(vehicle.save).to be_falsy
566
+ expect(vehicle.state).to eq('parked')
567
+ end
568
+
569
+ it 'should_return_original_action_value_on_success' do
570
+ expect(vehicle.save).to eq(vehicle)
571
+ end
572
+
573
+ it 'should_transition_state_on_success' do
574
+ vehicle.save
575
+ expect(vehicle.state).to eq('idling')
576
+ end
577
+ end
578
+
579
+ end
580
+