state_machine 0.6.3 → 0.7.0
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.
- data/CHANGELOG.rdoc +31 -1
- data/README.rdoc +33 -21
- data/Rakefile +2 -2
- data/examples/merb-rest/controller.rb +51 -0
- data/examples/merb-rest/model.rb +28 -0
- data/examples/merb-rest/view_edit.html.erb +24 -0
- data/examples/merb-rest/view_index.html.erb +23 -0
- data/examples/merb-rest/view_new.html.erb +13 -0
- data/examples/merb-rest/view_show.html.erb +17 -0
- data/examples/rails-rest/controller.rb +43 -0
- data/examples/rails-rest/migration.rb +11 -0
- data/examples/rails-rest/model.rb +23 -0
- data/examples/rails-rest/view_edit.html.erb +25 -0
- data/examples/rails-rest/view_index.html.erb +23 -0
- data/examples/rails-rest/view_new.html.erb +14 -0
- data/examples/rails-rest/view_show.html.erb +17 -0
- data/lib/state_machine/assertions.rb +2 -2
- data/lib/state_machine/callback.rb +14 -8
- data/lib/state_machine/condition_proxy.rb +3 -3
- data/lib/state_machine/event.rb +19 -21
- data/lib/state_machine/event_collection.rb +114 -0
- data/lib/state_machine/extensions.rb +127 -11
- data/lib/state_machine/guard.rb +1 -1
- data/lib/state_machine/integrations/active_record/locale.rb +2 -1
- data/lib/state_machine/integrations/active_record.rb +117 -39
- data/lib/state_machine/integrations/data_mapper/observer.rb +20 -64
- data/lib/state_machine/integrations/data_mapper.rb +71 -26
- data/lib/state_machine/integrations/sequel.rb +69 -21
- data/lib/state_machine/machine.rb +267 -139
- data/lib/state_machine/machine_collection.rb +145 -0
- data/lib/state_machine/matcher.rb +2 -2
- data/lib/state_machine/node_collection.rb +9 -4
- data/lib/state_machine/state.rb +22 -32
- data/lib/state_machine/state_collection.rb +66 -17
- data/lib/state_machine/transition.rb +259 -28
- data/lib/state_machine.rb +121 -56
- data/tasks/state_machine.rake +1 -0
- data/tasks/state_machine.rb +26 -0
- data/test/active_record.log +116877 -0
- data/test/functional/state_machine_test.rb +118 -12
- data/test/sequel.log +28542 -0
- data/test/unit/callback_test.rb +46 -1
- data/test/unit/condition_proxy_test.rb +55 -28
- data/test/unit/event_collection_test.rb +228 -0
- data/test/unit/event_test.rb +51 -46
- data/test/unit/integrations/active_record_test.rb +128 -70
- data/test/unit/integrations/data_mapper_test.rb +150 -58
- data/test/unit/integrations/sequel_test.rb +63 -6
- data/test/unit/invalid_event_test.rb +7 -0
- data/test/unit/machine_collection_test.rb +678 -0
- data/test/unit/machine_test.rb +198 -91
- data/test/unit/node_collection_test.rb +33 -30
- data/test/unit/state_collection_test.rb +112 -5
- data/test/unit/state_test.rb +23 -3
- data/test/unit/transition_test.rb +750 -89
- metadata +28 -3
@@ -64,6 +64,10 @@ begin
|
|
64
64
|
def test_should_use_save_as_action
|
65
65
|
assert_equal :save, @machine.action
|
66
66
|
end
|
67
|
+
|
68
|
+
def test_should_not_use_transactions
|
69
|
+
assert_equal false, @machine.use_transactions
|
70
|
+
end
|
67
71
|
end
|
68
72
|
|
69
73
|
class MachineTest < BaseTestCase
|
@@ -125,13 +129,13 @@ begin
|
|
125
129
|
assert_equal [idling], @resource.without_state(:parked).with_state(:idling)
|
126
130
|
end
|
127
131
|
|
128
|
-
def
|
132
|
+
def test_should_not_rollback_transaction_if_false
|
129
133
|
@machine.within_transaction(@resource.new) do
|
130
134
|
@resource.create
|
131
135
|
false
|
132
136
|
end
|
133
137
|
|
134
|
-
assert_equal
|
138
|
+
assert_equal 1, @resource.all.size
|
135
139
|
end
|
136
140
|
|
137
141
|
def test_should_not_rollback_transaction_if_true
|
@@ -143,24 +147,6 @@ begin
|
|
143
147
|
assert_equal 1, @resource.all.size
|
144
148
|
end
|
145
149
|
|
146
|
-
def test_should_invalidate_using_errors
|
147
|
-
record = @resource.new
|
148
|
-
record.state = 'parked'
|
149
|
-
|
150
|
-
@machine.invalidate(record, StateMachine::Event.new(@machine, :park))
|
151
|
-
|
152
|
-
assert_equal ['cannot be transitioned via :park from :parked'], record.errors.on(:state)
|
153
|
-
end
|
154
|
-
|
155
|
-
def test_should_clear_errors_on_reset
|
156
|
-
record = @resource.new
|
157
|
-
record.state = 'parked'
|
158
|
-
record.errors.add(:state, 'is invalid')
|
159
|
-
|
160
|
-
@machine.reset(record)
|
161
|
-
assert_nil record.errors.on(:id)
|
162
|
-
end
|
163
|
-
|
164
150
|
def test_should_not_override_the_column_reader
|
165
151
|
record = @resource.new
|
166
152
|
record.attribute_set(:state, 'parked')
|
@@ -208,16 +194,10 @@ begin
|
|
208
194
|
@record = @resource.new
|
209
195
|
end
|
210
196
|
|
211
|
-
def
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
def test_should_not_define_a_writer_attribute_for_the_attribute
|
216
|
-
assert !@record.respond_to?(:status=)
|
217
|
-
end
|
218
|
-
|
219
|
-
def test_should_define_an_attribute_predicate
|
220
|
-
assert @record.respond_to?(:status?)
|
197
|
+
def test_should_define_a_new_property_for_the_attribute
|
198
|
+
assert_not_nil @resource.properties[:status]
|
199
|
+
assert @record.respond_to?(:status)
|
200
|
+
assert @record.respond_to?(:status=)
|
221
201
|
end
|
222
202
|
end
|
223
203
|
|
@@ -256,6 +236,7 @@ begin
|
|
256
236
|
@resource = new_resource
|
257
237
|
@machine = StateMachine::Machine.new(@resource)
|
258
238
|
@machine.state :parked, :idling
|
239
|
+
@machine.event :ignite
|
259
240
|
@record = @resource.new(:state => 'parked')
|
260
241
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
261
242
|
end
|
@@ -268,7 +249,7 @@ begin
|
|
268
249
|
assert called
|
269
250
|
end
|
270
251
|
|
271
|
-
def
|
252
|
+
def test_should_pass_transition_to_before_callbacks_with_one_argument
|
272
253
|
transition = nil
|
273
254
|
@machine.before_transition(lambda {|arg| transition = arg})
|
274
255
|
|
@@ -276,7 +257,7 @@ begin
|
|
276
257
|
assert_equal @transition, transition
|
277
258
|
end
|
278
259
|
|
279
|
-
def
|
260
|
+
def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
|
280
261
|
callback_args = nil
|
281
262
|
@machine.before_transition(lambda {|*args| callback_args = args})
|
282
263
|
|
@@ -300,12 +281,12 @@ begin
|
|
300
281
|
assert called
|
301
282
|
end
|
302
283
|
|
303
|
-
def
|
284
|
+
def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
|
304
285
|
callback_args = nil
|
305
286
|
@machine.after_transition(lambda {|*args| callback_args = args})
|
306
287
|
|
307
288
|
@transition.perform
|
308
|
-
assert_equal [@transition
|
289
|
+
assert_equal [@transition], callback_args
|
309
290
|
end
|
310
291
|
|
311
292
|
def test_should_run_after_callbacks_with_the_context_of_the_record
|
@@ -351,6 +332,7 @@ begin
|
|
351
332
|
@resource = new_resource
|
352
333
|
@machine = StateMachine::Machine.new(@resource)
|
353
334
|
@machine.state :parked, :idling
|
335
|
+
@machine.event :ignite
|
354
336
|
@record = @resource.new(:state => 'parked')
|
355
337
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
356
338
|
end
|
@@ -391,28 +373,6 @@ begin
|
|
391
373
|
assert !called
|
392
374
|
end
|
393
375
|
|
394
|
-
def test_should_allow_targeting_specific_machine
|
395
|
-
@second_machine = StateMachine::Machine.new(@resource, :status)
|
396
|
-
|
397
|
-
called_state = false
|
398
|
-
called_status = false
|
399
|
-
|
400
|
-
observer = new_observer(@resource) do
|
401
|
-
before_transition :state, :from => :parked do
|
402
|
-
called_state = true
|
403
|
-
end
|
404
|
-
|
405
|
-
before_transition :status, :from => :parked do
|
406
|
-
called_status = true
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
|
-
@transition.perform
|
411
|
-
|
412
|
-
assert called_state
|
413
|
-
assert !called_status
|
414
|
-
end
|
415
|
-
|
416
376
|
def test_should_pass_transition_to_before_callbacks
|
417
377
|
callback_args = nil
|
418
378
|
|
@@ -452,7 +412,7 @@ begin
|
|
452
412
|
assert !called
|
453
413
|
end
|
454
414
|
|
455
|
-
def
|
415
|
+
def test_should_pass_transition_to_after_callbacks
|
456
416
|
callback_args = nil
|
457
417
|
|
458
418
|
observer = new_observer(@resource) do
|
@@ -462,7 +422,61 @@ begin
|
|
462
422
|
end
|
463
423
|
|
464
424
|
@transition.perform
|
465
|
-
assert_equal [@transition
|
425
|
+
assert_equal [@transition], callback_args
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_should_raise_exception_if_targeting_invalid_machine
|
429
|
+
assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
|
430
|
+
new_observer(@resource) do
|
431
|
+
before_transition :invalid, :from => :parked do
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_should_allow_targeting_specific_machine
|
438
|
+
@second_machine = StateMachine::Machine.new(@resource, :status)
|
439
|
+
@resource.auto_migrate!
|
440
|
+
|
441
|
+
called_state = false
|
442
|
+
called_status = false
|
443
|
+
|
444
|
+
observer = new_observer(@resource) do
|
445
|
+
before_transition :state, :from => :parked do
|
446
|
+
called_state = true
|
447
|
+
end
|
448
|
+
|
449
|
+
before_transition :status, :from => :parked do
|
450
|
+
called_status = true
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
@transition.perform
|
455
|
+
|
456
|
+
assert called_state
|
457
|
+
assert !called_status
|
458
|
+
end
|
459
|
+
|
460
|
+
def test_should_allow_targeting_multiple_specific_machines
|
461
|
+
@second_machine = StateMachine::Machine.new(@resource, :status)
|
462
|
+
@second_machine.state :parked, :idling
|
463
|
+
@second_machine.event :ignite
|
464
|
+
@resource.auto_migrate!
|
465
|
+
|
466
|
+
called_attribute = nil
|
467
|
+
|
468
|
+
attributes = []
|
469
|
+
observer = new_observer(@resource) do
|
470
|
+
before_transition :state, :status, :from => :parked do |transition|
|
471
|
+
called_attribute = transition.attribute
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
@transition.perform
|
476
|
+
assert_equal :state, called_attribute
|
477
|
+
|
478
|
+
StateMachine::Transition.new(@record, @second_machine, :ignite, :parked, :idling).perform
|
479
|
+
assert_equal :status, called_attribute
|
466
480
|
end
|
467
481
|
end
|
468
482
|
|
@@ -471,6 +485,7 @@ begin
|
|
471
485
|
@resource = new_resource
|
472
486
|
@machine = StateMachine::Machine.new(@resource)
|
473
487
|
@machine.state :parked, :idling
|
488
|
+
@machine.event :ignite
|
474
489
|
@record = @resource.new(:state => 'parked')
|
475
490
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
476
491
|
|
@@ -512,6 +527,32 @@ begin
|
|
512
527
|
gem 'dm-validations', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.0'
|
513
528
|
require 'dm-validations'
|
514
529
|
|
530
|
+
class MachineWithValidationsTest < BaseTestCase
|
531
|
+
def setup
|
532
|
+
@resource = new_resource
|
533
|
+
@machine = StateMachine::Machine.new(@resource)
|
534
|
+
@machine.state :parked
|
535
|
+
end
|
536
|
+
|
537
|
+
def test_should_invalidate_using_errors
|
538
|
+
record = @resource.new
|
539
|
+
record.state = 'parked'
|
540
|
+
|
541
|
+
@machine.invalidate(record, :state, :invalid_transition, [[:event, :park]])
|
542
|
+
|
543
|
+
assert_equal ['cannot transition via "park"'], record.errors.on(:state)
|
544
|
+
end
|
545
|
+
|
546
|
+
def test_should_clear_errors_on_reset
|
547
|
+
record = @resource.new
|
548
|
+
record.state = 'parked'
|
549
|
+
record.errors.add(:state, 'is invalid')
|
550
|
+
|
551
|
+
@machine.reset(record)
|
552
|
+
assert_nil record.errors.on(:id)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
515
556
|
class MachineWithStateDrivenValidationsTest < BaseTestCase
|
516
557
|
def setup
|
517
558
|
@resource = new_resource do
|
@@ -540,6 +581,57 @@ begin
|
|
540
581
|
assert record.valid?
|
541
582
|
end
|
542
583
|
end
|
584
|
+
|
585
|
+
class MachineWithEventAttributesOnValidationTest < BaseTestCase
|
586
|
+
def setup
|
587
|
+
@resource = new_resource
|
588
|
+
@machine = StateMachine::Machine.new(@resource)
|
589
|
+
@machine.event :ignite do
|
590
|
+
transition :parked => :idling
|
591
|
+
end
|
592
|
+
|
593
|
+
@record = @resource.new
|
594
|
+
@record.state = 'parked'
|
595
|
+
@record.state_event = 'ignite'
|
596
|
+
end
|
597
|
+
|
598
|
+
def test_should_fail_if_event_is_invalid
|
599
|
+
@record.state_event = 'invalid'
|
600
|
+
assert !@record.valid?
|
601
|
+
assert_equal ['is invalid'], @record.errors.full_messages
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_should_fail_if_event_has_no_transition
|
605
|
+
@record.state = 'idling'
|
606
|
+
assert !@record.valid?
|
607
|
+
assert_equal ['cannot transition when idling'], @record.errors.full_messages
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_should_be_successful_if_event_has_transition
|
611
|
+
assert @record.valid?
|
612
|
+
end
|
613
|
+
|
614
|
+
def test_should_run_before_callbacks
|
615
|
+
ran_callback = false
|
616
|
+
@machine.before_transition { ran_callback = true }
|
617
|
+
|
618
|
+
@record.valid?
|
619
|
+
assert ran_callback
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_should_persist_new_state
|
623
|
+
@record.valid?
|
624
|
+
assert_equal 'idling', @record.state
|
625
|
+
end
|
626
|
+
|
627
|
+
def test_should_not_run_after_callbacks
|
628
|
+
ran_callback = false
|
629
|
+
@machine.after_transition { ran_callback = true }
|
630
|
+
|
631
|
+
@record.valid?
|
632
|
+
assert !ran_callback
|
633
|
+
end
|
634
|
+
end
|
543
635
|
rescue LoadError
|
544
636
|
$stderr.puts "Skipping DataMapper Validation tests. `gem install dm-validations#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}` and try again."
|
545
637
|
end
|
@@ -25,6 +25,7 @@ begin
|
|
25
25
|
end if auto_migrate
|
26
26
|
model = Class.new(Sequel::Model(:foo)) do
|
27
27
|
self.raise_on_save_failure = false
|
28
|
+
plugin :validation_class_methods if respond_to?(:plugin)
|
28
29
|
|
29
30
|
def self.name; 'SequelTest::Foo'; end
|
30
31
|
end
|
@@ -52,6 +53,10 @@ begin
|
|
52
53
|
def test_should_use_save_as_action
|
53
54
|
assert_equal :save, @machine.action
|
54
55
|
end
|
56
|
+
|
57
|
+
def test_should_use_transactions
|
58
|
+
assert_equal true, @machine.use_transactions
|
59
|
+
end
|
55
60
|
end
|
56
61
|
|
57
62
|
class MachineTest < BaseTestCase
|
@@ -135,9 +140,9 @@ begin
|
|
135
140
|
record = @model.new
|
136
141
|
record.state = 'parked'
|
137
142
|
|
138
|
-
@machine.invalidate(record,
|
143
|
+
@machine.invalidate(record, :state, :invalid_transition, [[:event, :park]])
|
139
144
|
|
140
|
-
assert_equal ['cannot
|
145
|
+
assert_equal ['cannot transition via "park"'], record.errors.on(:state)
|
141
146
|
end
|
142
147
|
|
143
148
|
def test_should_clear_errors_on_reset
|
@@ -244,6 +249,7 @@ begin
|
|
244
249
|
@model = new_model
|
245
250
|
@machine = StateMachine::Machine.new(@model)
|
246
251
|
@machine.state :parked, :idling
|
252
|
+
@machine.event :ignite
|
247
253
|
@record = @model.new(:state => 'parked')
|
248
254
|
@transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
|
249
255
|
end
|
@@ -256,7 +262,7 @@ begin
|
|
256
262
|
assert called
|
257
263
|
end
|
258
264
|
|
259
|
-
def
|
265
|
+
def test_should_pass_transition_to_before_callbacks_with_one_argument
|
260
266
|
transition = nil
|
261
267
|
@machine.before_transition(lambda {|arg| transition = arg})
|
262
268
|
|
@@ -264,7 +270,7 @@ begin
|
|
264
270
|
assert_equal @transition, transition
|
265
271
|
end
|
266
272
|
|
267
|
-
def
|
273
|
+
def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
|
268
274
|
callback_args = nil
|
269
275
|
@machine.before_transition(lambda {|*args| callback_args = args})
|
270
276
|
|
@@ -288,12 +294,12 @@ begin
|
|
288
294
|
assert called
|
289
295
|
end
|
290
296
|
|
291
|
-
def
|
297
|
+
def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
|
292
298
|
callback_args = nil
|
293
299
|
@machine.after_transition(lambda {|*args| callback_args = args})
|
294
300
|
|
295
301
|
@transition.perform
|
296
|
-
assert_equal [@transition
|
302
|
+
assert_equal [@transition], callback_args
|
297
303
|
end
|
298
304
|
|
299
305
|
def test_should_run_after_callbacks_with_the_context_of_the_record
|
@@ -358,6 +364,57 @@ begin
|
|
358
364
|
assert record.valid?
|
359
365
|
end
|
360
366
|
end
|
367
|
+
|
368
|
+
class MachineWithEventAttributesOnValidationTest < BaseTestCase
|
369
|
+
def setup
|
370
|
+
@model = new_model
|
371
|
+
@machine = StateMachine::Machine.new(@model)
|
372
|
+
@machine.event :ignite do
|
373
|
+
transition :parked => :idling
|
374
|
+
end
|
375
|
+
|
376
|
+
@record = @model.new
|
377
|
+
@record.state = 'parked'
|
378
|
+
@record.state_event = 'ignite'
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_should_fail_if_event_is_invalid
|
382
|
+
@record.state_event = 'invalid'
|
383
|
+
assert !@record.valid?
|
384
|
+
assert_equal ['state_event is invalid'], @record.errors.full_messages
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_should_fail_if_event_has_no_transition
|
388
|
+
@record.state = 'idling'
|
389
|
+
assert !@record.valid?
|
390
|
+
assert_equal ['state_event cannot transition when idling'], @record.errors.full_messages
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_should_be_successful_if_event_has_transition
|
394
|
+
assert @record.valid?
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_should_run_before_callbacks
|
398
|
+
ran_callback = false
|
399
|
+
@machine.before_transition { ran_callback = true }
|
400
|
+
|
401
|
+
@record.valid?
|
402
|
+
assert ran_callback
|
403
|
+
end
|
404
|
+
|
405
|
+
def test_should_persist_new_state
|
406
|
+
@record.valid?
|
407
|
+
assert_equal 'idling', @record.state
|
408
|
+
end
|
409
|
+
|
410
|
+
def test_should_not_run_after_callbacks
|
411
|
+
ran_callback = false
|
412
|
+
@machine.after_transition { ran_callback = true }
|
413
|
+
|
414
|
+
@record.valid?
|
415
|
+
assert !ran_callback
|
416
|
+
end
|
417
|
+
end
|
361
418
|
end
|
362
419
|
rescue LoadError
|
363
420
|
$stderr.puts "Skipping Sequel tests. `gem install sequel#{" -v #{ENV['SEQUEL_VERSION']}" if ENV['SEQUEL_VERSION']}` and try again."
|