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
@@ -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
+