state_machine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +162 -23
  4. data/Rakefile +3 -18
  5. data/lib/state_machine.rb +3 -4
  6. data/lib/state_machine/callback.rb +65 -13
  7. data/lib/state_machine/eval_helpers.rb +20 -4
  8. data/lib/state_machine/initializers.rb +4 -0
  9. data/lib/state_machine/initializers/merb.rb +1 -0
  10. data/lib/state_machine/initializers/rails.rb +7 -0
  11. data/lib/state_machine/integrations.rb +21 -6
  12. data/lib/state_machine/integrations/active_model.rb +414 -0
  13. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  14. data/lib/state_machine/integrations/{active_record → active_model}/observer.rb +7 -7
  15. data/lib/state_machine/integrations/active_record.rb +65 -129
  16. data/lib/state_machine/integrations/active_record/locale.rb +4 -11
  17. data/lib/state_machine/integrations/data_mapper.rb +24 -6
  18. data/lib/state_machine/integrations/data_mapper/observer.rb +36 -0
  19. data/lib/state_machine/integrations/mongo_mapper.rb +295 -0
  20. data/lib/state_machine/integrations/sequel.rb +33 -7
  21. data/lib/state_machine/machine.rb +121 -23
  22. data/lib/state_machine/machine_collection.rb +12 -103
  23. data/lib/state_machine/transition.rb +125 -164
  24. data/lib/state_machine/transition_collection.rb +244 -0
  25. data/lib/tasks/state_machine.rb +12 -15
  26. data/test/functional/state_machine_test.rb +11 -1
  27. data/test/unit/callback_test.rb +305 -32
  28. data/test/unit/eval_helpers_test.rb +103 -1
  29. data/test/unit/event_test.rb +2 -1
  30. data/test/unit/guard_test.rb +2 -1
  31. data/test/unit/integrations/active_model_test.rb +909 -0
  32. data/test/unit/integrations/active_record_test.rb +1542 -1292
  33. data/test/unit/integrations/data_mapper_test.rb +1369 -1041
  34. data/test/unit/integrations/mongo_mapper_test.rb +1349 -0
  35. data/test/unit/integrations/sequel_test.rb +1214 -985
  36. data/test/unit/integrations_test.rb +8 -0
  37. data/test/unit/machine_collection_test.rb +140 -513
  38. data/test/unit/machine_test.rb +212 -10
  39. data/test/unit/state_test.rb +2 -1
  40. data/test/unit/transition_collection_test.rb +2098 -0
  41. data/test/unit/transition_test.rb +704 -552
  42. metadata +16 -3
@@ -1,9 +1,18 @@
1
1
  namespace :state_machine do
2
2
  desc 'Draws a set of state machines using GraphViz. Target files to load with FILE=x,y,z; Machine class with CLASS=x,y,z; Font name with FONT=x; Image format with FORMAT=x; Orientation with ORIENTATION=x'
3
3
  task :draw do
4
- # Load the library
5
- $:.unshift(File.dirname(__FILE__) + '/..')
6
- require 'state_machine'
4
+ if defined?(Rails)
5
+ Rake::Task['environment'].invoke
6
+ elsif defined?(Merb)
7
+ Rake::Task['merb_env'].invoke
8
+
9
+ # Fix ruby-graphviz being incompatible with Merb's process title
10
+ $0 = 'rake'
11
+ else
12
+ # Load the library
13
+ $:.unshift(File.dirname(__FILE__) + '/..')
14
+ require 'state_machine'
15
+ end
7
16
 
8
17
  # Build drawing options
9
18
  options = {}
@@ -15,16 +24,4 @@ namespace :state_machine do
15
24
 
16
25
  StateMachine::Machine.draw(ENV['CLASS'], options)
17
26
  end
18
-
19
- namespace :draw do
20
- desc 'Draws a set of state machines using GraphViz for a Ruby on Rails application. Target class with CLASS=x,y,z; Font name with FONT=x; Image format with FORMAT=x; Orientation with ORIENTATION=x'
21
- task :rails => [:environment, 'state_machine:draw']
22
-
23
- desc 'Draws a set of state machines using GraphViz for a Merb application. Target class with CLASS=x,y,z; Font name with FONT=x; Image format with FORMAT=x; Orientation with ORIENTATION=x'
24
- task :merb => [:merb_env] do
25
- # Fix ruby-graphviz being incompatible with Merb's process title
26
- $0 = 'rake'
27
- Rake::Task['state_machine:draw'].invoke
28
- end
29
- end
30
27
  end
@@ -40,7 +40,7 @@ class ModelBase
40
40
  end
41
41
 
42
42
  class Vehicle < ModelBase
43
- attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved
43
+ attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved, :time_elapsed
44
44
 
45
45
  def initialize(attributes = {})
46
46
  attributes = {
@@ -68,6 +68,12 @@ class Vehicle < ModelBase
68
68
  after_transition any => :parked, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_parked'}
69
69
  before_transition any => :idling, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_idling'}
70
70
 
71
+ around_transition do |vehicle, transition, block|
72
+ time = Time.now
73
+ block.call
74
+ vehicle.time_elapsed = Time.now - time
75
+ end
76
+
71
77
  event :park do
72
78
  transition [:idling, :first_gear] => :parked
73
79
  end
@@ -447,6 +453,10 @@ class VehicleIdlingTest < Test::Unit::TestCase
447
453
  assert @vehicle.seatbelt_on
448
454
  end
449
455
 
456
+ def test_should_track_time_elapsed
457
+ assert_not_nil @vehicle.time_elapsed
458
+ end
459
+
450
460
  def test_should_allow_park
451
461
  assert @vehicle.park
452
462
  end
@@ -1,25 +1,42 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
3
  class CallbackTest < Test::Unit::TestCase
4
+ def test_should_raise_exception_if_invalid_type_specified
5
+ exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:invalid) {} }
6
+ assert_equal 'Type must be :before, :after, or :around', exception.message
7
+ end
8
+
9
+ def test_should_not_raise_exception_if_using_before_type
10
+ assert_nothing_raised { StateMachine::Callback.new(:before) {} }
11
+ end
12
+
13
+ def test_should_not_raise_exception_if_using_after_type
14
+ assert_nothing_raised { StateMachine::Callback.new(:after) {} }
15
+ end
16
+
17
+ def test_should_not_raise_exception_if_using_around_type
18
+ assert_nothing_raised { StateMachine::Callback.new(:around) {} }
19
+ end
20
+
4
21
  def test_should_raise_exception_if_no_methods_specified
5
- exception = assert_raise(ArgumentError) { StateMachine::Callback.new }
22
+ exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:before) }
6
23
  assert_equal 'Method(s) for callback must be specified', exception.message
7
24
  end
8
25
 
9
26
  def test_should_not_raise_exception_if_method_specified_in_do_option
10
- assert_nothing_raised { StateMachine::Callback.new(:do => :run) }
27
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run) }
11
28
  end
12
29
 
13
30
  def test_should_not_raise_exception_if_method_specified_as_argument
14
- assert_nothing_raised { StateMachine::Callback.new(:run) }
31
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) }
15
32
  end
16
33
 
17
34
  def test_should_not_raise_exception_if_method_specified_as_block
18
- assert_nothing_raised { StateMachine::Callback.new(:run) {} }
35
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) {} }
19
36
  end
20
37
 
21
38
  def test_should_not_raise_exception_if_implicit_option_specified
22
- assert_nothing_raised { StateMachine::Callback.new(:do => :run, :invalid => :valid) }
39
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run, :invalid => :valid) }
23
40
  end
24
41
 
25
42
  def test_should_not_bind_to_objects
@@ -33,7 +50,11 @@ end
33
50
 
34
51
  class CallbackByDefaultTest < Test::Unit::TestCase
35
52
  def setup
36
- @callback = StateMachine::Callback.new(:do => lambda {})
53
+ @callback = StateMachine::Callback.new(:before) {}
54
+ end
55
+
56
+ def test_should_have_type
57
+ assert_equal :before, @callback.type
37
58
  end
38
59
 
39
60
  def test_should_not_have_a_terminator
@@ -53,7 +74,7 @@ end
53
74
 
54
75
  class CallbackWithMethodArgumentTest < Test::Unit::TestCase
55
76
  def setup
56
- @callback = StateMachine::Callback.new(lambda {|*args| @args = args})
77
+ @callback = StateMachine::Callback.new(:before, lambda {|*args| @args = args})
57
78
 
58
79
  @object = Object.new
59
80
  @result = @callback.call(@object)
@@ -70,7 +91,7 @@ end
70
91
 
71
92
  class CallbackWithMultipleMethodArgumentsTest < Test::Unit::TestCase
72
93
  def setup
73
- @callback = StateMachine::Callback.new(:run_1, :run_2)
94
+ @callback = StateMachine::Callback.new(:before, :run_1, :run_2)
74
95
 
75
96
  class << @object = Object.new
76
97
  attr_accessor :callbacks
@@ -98,7 +119,7 @@ end
98
119
 
99
120
  class CallbackWithDoMethodTest < Test::Unit::TestCase
100
121
  def setup
101
- @callback = StateMachine::Callback.new(:do => lambda {|*args| @args = args})
122
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
102
123
 
103
124
  @object = Object.new
104
125
  @result = @callback.call(@object)
@@ -115,7 +136,7 @@ end
115
136
 
116
137
  class CallbackWithMultipleDoMethodsTest < Test::Unit::TestCase
117
138
  def setup
118
- @callback = StateMachine::Callback.new(:do => [:run_1, :run_2])
139
+ @callback = StateMachine::Callback.new(:before, :do => [:run_1, :run_2])
119
140
 
120
141
  class << @object = Object.new
121
142
  attr_accessor :callbacks
@@ -143,7 +164,7 @@ end
143
164
 
144
165
  class CallbackWithBlockTest < Test::Unit::TestCase
145
166
  def setup
146
- @callback = StateMachine::Callback.new do |*args|
167
+ @callback = StateMachine::Callback.new(:before) do |*args|
147
168
  @args = args
148
169
  end
149
170
 
@@ -162,7 +183,7 @@ end
162
183
 
163
184
  class CallbackWithMixedMethodsTest < Test::Unit::TestCase
164
185
  def setup
165
- @callback = StateMachine::Callback.new(:run_argument, :do => :run_do) do |object|
186
+ @callback = StateMachine::Callback.new(:before, :run_argument, :do => :run_do) do |object|
166
187
  object.callbacks << :block
167
188
  end
168
189
 
@@ -193,7 +214,7 @@ end
193
214
  class CallbackWithExplicitRequirementsTest < Test::Unit::TestCase
194
215
  def setup
195
216
  @object = Object.new
196
- @callback = StateMachine::Callback.new(:from => :parked, :to => :idling, :on => :ignite, :do => lambda {})
217
+ @callback = StateMachine::Callback.new(:before, :from => :parked, :to => :idling, :on => :ignite, :do => lambda {})
197
218
  end
198
219
 
199
220
  def test_should_call_with_empty_context
@@ -224,7 +245,7 @@ end
224
245
  class CallbackWithImplicitRequirementsTest < Test::Unit::TestCase
225
246
  def setup
226
247
  @object = Object.new
227
- @callback = StateMachine::Callback.new(:parked => :idling, :on => :ignite, :do => lambda {})
248
+ @callback = StateMachine::Callback.new(:before, :parked => :idling, :on => :ignite, :do => lambda {})
228
249
  end
229
250
 
230
251
  def test_should_call_with_empty_context
@@ -258,12 +279,12 @@ class CallbackWithIfConditionTest < Test::Unit::TestCase
258
279
  end
259
280
 
260
281
  def test_should_call_if_true
261
- callback = StateMachine::Callback.new(:if => lambda {true}, :do => lambda {})
282
+ callback = StateMachine::Callback.new(:before, :if => lambda {true}, :do => lambda {})
262
283
  assert callback.call(@object)
263
284
  end
264
285
 
265
286
  def test_should_not_call_if_false
266
- callback = StateMachine::Callback.new(:if => lambda {false}, :do => lambda {})
287
+ callback = StateMachine::Callback.new(:before, :if => lambda {false}, :do => lambda {})
267
288
  assert !callback.call(@object)
268
289
  end
269
290
  end
@@ -274,12 +295,12 @@ class CallbackWithUnlessConditionTest < Test::Unit::TestCase
274
295
  end
275
296
 
276
297
  def test_should_call_if_false
277
- callback = StateMachine::Callback.new(:unless => lambda {false}, :do => lambda {})
298
+ callback = StateMachine::Callback.new(:before, :unless => lambda {false}, :do => lambda {})
278
299
  assert callback.call(@object)
279
300
  end
280
301
 
281
302
  def test_should_not_call_if_true
282
- callback = StateMachine::Callback.new(:unless => lambda {true}, :do => lambda {})
303
+ callback = StateMachine::Callback.new(:before, :unless => lambda {true}, :do => lambda {})
283
304
  assert !callback.call(@object)
284
305
  end
285
306
  end
@@ -290,7 +311,7 @@ class CallbackWithoutTerminatorTest < Test::Unit::TestCase
290
311
  end
291
312
 
292
313
  def test_should_not_halt_if_result_is_false
293
- callback = StateMachine::Callback.new(:do => lambda {false}, :terminator => nil)
314
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => nil)
294
315
  assert_nothing_thrown { callback.call(@object) }
295
316
  end
296
317
  end
@@ -301,24 +322,24 @@ class CallbackWithTerminatorTest < Test::Unit::TestCase
301
322
  end
302
323
 
303
324
  def test_should_not_halt_if_terminator_does_not_match
304
- callback = StateMachine::Callback.new(:do => lambda {false}, :terminator => lambda {|result| result == true})
325
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == true})
305
326
  assert_nothing_thrown { callback.call(@object) }
306
327
  end
307
328
 
308
329
  def test_should_halt_if_terminator_matches
309
- callback = StateMachine::Callback.new(:do => lambda {false}, :terminator => lambda {|result| result == false})
330
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == false})
310
331
  assert_throws(:halt) { callback.call(@object) }
311
332
  end
312
333
 
313
334
  def test_should_halt_if_terminator_matches_any_method
314
- callback = StateMachine::Callback.new(:do => [lambda {true}, lambda {false}], :terminator => lambda {|result| result == false})
335
+ callback = StateMachine::Callback.new(:before, :do => [lambda {true}, lambda {false}], :terminator => lambda {|result| result == false})
315
336
  assert_throws(:halt) { callback.call(@object) }
316
337
  end
317
338
  end
318
339
 
319
340
  class CallbackWithoutArgumentsTest < Test::Unit::TestCase
320
341
  def setup
321
- @callback = StateMachine::Callback.new(:do => lambda {|object| @arg = object})
342
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|object| @arg = object})
322
343
 
323
344
  @object = Object.new
324
345
  @callback.call(@object, {}, 1, 2, 3)
@@ -331,7 +352,7 @@ end
331
352
 
332
353
  class CallbackWithArgumentsTest < Test::Unit::TestCase
333
354
  def setup
334
- @callback = StateMachine::Callback.new(:do => lambda {|*args| @args = args})
355
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
335
356
 
336
357
  @object = Object.new
337
358
  @callback.call(@object, {}, 1, 2, 3)
@@ -344,7 +365,7 @@ end
344
365
 
345
366
  class CallbackWithUnboundMethodTest < Test::Unit::TestCase
346
367
  def setup
347
- @callback = StateMachine::Callback.new(:do => lambda {|*args| @context = args.unshift(self)})
368
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @context = args.unshift(self)})
348
369
 
349
370
  @object = Object.new
350
371
  @callback.call(@object, {}, 1, 2, 3)
@@ -362,7 +383,7 @@ class CallbackWithBoundMethodTest < Test::Unit::TestCase
362
383
 
363
384
  def test_should_call_method_within_the_context_of_the_object_for_block_methods
364
385
  context = nil
365
- callback = StateMachine::Callback.new(:do => lambda {|*args| context = [self] + args}, :bind_to_object => true)
386
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = [self] + args}, :bind_to_object => true)
366
387
  callback.call(@object, {}, 1, 2, 3)
367
388
 
368
389
  assert_equal [@object, 1, 2, 3], context
@@ -377,14 +398,14 @@ class CallbackWithBoundMethodTest < Test::Unit::TestCase
377
398
  end
378
399
  end
379
400
 
380
- callback = StateMachine::Callback.new(:do => :after_ignite, :bind_to_object => true)
401
+ callback = StateMachine::Callback.new(:before, :do => :after_ignite, :bind_to_object => true)
381
402
  callback.call(@object)
382
403
 
383
404
  assert_equal [], @object.context
384
405
  end
385
406
 
386
407
  def test_should_ignore_option_for_string_methods
387
- callback = StateMachine::Callback.new(:do => '[1, 2, 3]', :bind_to_object => true)
408
+ callback = StateMachine::Callback.new(:before, :do => '[1, 2, 3]', :bind_to_object => true)
388
409
  assert callback.call(@object)
389
410
  end
390
411
  end
@@ -396,7 +417,7 @@ class CallbackWithMultipleBoundMethodsTest < Test::Unit::TestCase
396
417
  first_context = nil
397
418
  second_context = nil
398
419
 
399
- @callback = StateMachine::Callback.new(:do => [lambda {first_context = self}, lambda {second_context = self}], :bind_to_object => true)
420
+ @callback = StateMachine::Callback.new(:before, :do => [lambda {first_context = self}, lambda {second_context = self}], :bind_to_object => true)
400
421
  @callback.call(@object)
401
422
 
402
423
  @first_context = first_context
@@ -415,7 +436,7 @@ class CallbackWithApplicationBoundObjectTest < Test::Unit::TestCase
415
436
  StateMachine::Callback.bind_to_object = true
416
437
 
417
438
  context = nil
418
- @callback = StateMachine::Callback.new(:do => lambda {|*args| context = self})
439
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = self})
419
440
 
420
441
  @object = Object.new
421
442
  @callback.call(@object)
@@ -431,6 +452,33 @@ class CallbackWithApplicationBoundObjectTest < Test::Unit::TestCase
431
452
  end
432
453
  end
433
454
 
455
+ class CallbackWithBoundMethodAndArgumentsTest < Test::Unit::TestCase
456
+ def setup
457
+ @object = Object.new
458
+ end
459
+
460
+ def test_should_include_single_argument_if_specified
461
+ context = nil
462
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1| context = [arg1]}, :bind_to_object => true)
463
+ callback.call(@object, {}, 1)
464
+ assert_equal [1], context
465
+ end
466
+
467
+ def test_should_include_multiple_arguments_if_specified
468
+ context = nil
469
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1, arg2, arg3| context = [arg1, arg2, arg3]}, :bind_to_object => true)
470
+ callback.call(@object, {}, 1, 2, 3)
471
+ assert_equal [1, 2, 3], context
472
+ end
473
+
474
+ def test_should_include_arguments_if_splat_used
475
+ context = nil
476
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = args}, :bind_to_object => true)
477
+ callback.call(@object, {}, 1, 2, 3)
478
+ assert_equal [1, 2, 3], context
479
+ end
480
+ end
481
+
434
482
  class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
435
483
  def setup
436
484
  @original_terminator = StateMachine::Callback.bind_to_object
@@ -440,12 +488,12 @@ class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
440
488
  end
441
489
 
442
490
  def test_should_not_halt_if_terminator_does_not_match
443
- callback = StateMachine::Callback.new(:do => lambda {true})
491
+ callback = StateMachine::Callback.new(:before, :do => lambda {true})
444
492
  assert_nothing_thrown { callback.call(@object) }
445
493
  end
446
494
 
447
495
  def test_should_halt_if_terminator_matches
448
- callback = StateMachine::Callback.new(:do => lambda {false})
496
+ callback = StateMachine::Callback.new(:before, :do => lambda {false})
449
497
  assert_throws(:halt) { callback.call(@object) }
450
498
  end
451
499
 
@@ -453,3 +501,228 @@ class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
453
501
  StateMachine::Callback.bind_to_object = @original_bind_to_object
454
502
  end
455
503
  end
504
+
505
+ class CallbackWithAroundTypeAndBlockTest < Test::Unit::TestCase
506
+ def setup
507
+ @object = Object.new
508
+ @callbacks = []
509
+ end
510
+
511
+ def test_should_evaluate_before_without_after
512
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
513
+ assert callback.call(@object)
514
+ assert_equal [@object], @args
515
+ end
516
+
517
+ def test_should_evaluate_after_without_before
518
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; block.call; @args = args})
519
+ assert callback.call(@object)
520
+ assert_equal [@object], @args
521
+ end
522
+
523
+ def test_should_halt_if_not_yielded
524
+ callback = StateMachine::Callback.new(:around, lambda {|block|})
525
+ assert_throws(:halt) { callback.call(@object) }
526
+ end
527
+
528
+ def test_should_call_block_after_before
529
+ callback = StateMachine::Callback.new(:around, lambda {|block| @callbacks << :before; block.call})
530
+ assert callback.call(@object) { @callbacks << :block }
531
+ assert_equal [:before, :block], @callbacks
532
+ end
533
+
534
+ def test_should_call_block_before_after
535
+ @callbacks = []
536
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
537
+ assert callback.call(@object) { @callbacks << :block }
538
+ assert_equal [:block, :after], @callbacks
539
+ end
540
+
541
+ def test_should_halt_if_block_halts
542
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
543
+ assert_throws(:halt) { callback.call(@object) { throw :halt } }
544
+ assert_equal [], @callbacks
545
+ end
546
+ end
547
+
548
+ class CallbackWithAroundTypeAndMultipleMethodsTest < Test::Unit::TestCase
549
+ def setup
550
+ @callback = StateMachine::Callback.new(:around, :run_1, :run_2)
551
+
552
+ class << @object = Object.new
553
+ attr_accessor :before_callbacks
554
+ attr_accessor :after_callbacks
555
+
556
+ def run_1
557
+ (@before_callbacks ||= []) << :run_1
558
+ yield
559
+ (@after_callbacks ||= []) << :run_1
560
+ end
561
+
562
+ def run_2
563
+ (@before_callbacks ||= []) << :run_2
564
+ yield
565
+ (@after_callbacks ||= []) << :run_2
566
+ end
567
+ end
568
+ end
569
+
570
+ def test_should_succeed
571
+ assert @callback.call(@object)
572
+ end
573
+
574
+ def test_should_evaluate_before_callbacks_in_order
575
+ @callback.call(@object)
576
+ assert_equal [:run_1, :run_2], @object.before_callbacks
577
+ end
578
+
579
+ def test_should_evaluate_after_callbacks_in_reverse_order
580
+ @callback.call(@object)
581
+ assert_equal [:run_2, :run_1], @object.after_callbacks
582
+ end
583
+
584
+ def test_should_call_block_after_before_callbacks
585
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
586
+ assert_equal [:run_1, :run_2, :block], @object.before_callbacks
587
+ end
588
+
589
+ def test_should_call_block_before_after_callbacks
590
+ @callback.call(@object) { (@object.after_callbacks ||= []) << :block }
591
+ assert_equal [:block, :run_2, :run_1], @object.after_callbacks
592
+ end
593
+
594
+ def test_should_halt_if_first_doesnt_yield
595
+ class << @object
596
+ def run_1
597
+ (@before_callbacks ||= []) << :run_1
598
+ end
599
+ end
600
+
601
+ catch(:halt) do
602
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
603
+ end
604
+
605
+ assert_equal [:run_1], @object.before_callbacks
606
+ assert_nil @object.after_callbacks
607
+ end
608
+
609
+ def test_should_halt_if_last_doesnt_yield
610
+ class << @object
611
+ def run_2
612
+ (@before_callbacks ||= []) << :run_2
613
+ end
614
+ end
615
+
616
+ catch(:halt) { @callback.call(@object) }
617
+ assert_equal [:run_1, :run_2], @object.before_callbacks
618
+ assert_nil @object.after_callbacks
619
+ end
620
+
621
+ def test_should_not_evaluate_further_methods_if_after_halts
622
+ class << @object
623
+ def run_2
624
+ (@before_callbacks ||= []) << :run_2
625
+ yield
626
+ (@after_callbacks ||= []) << :run_2
627
+ throw :halt
628
+ end
629
+ end
630
+
631
+ catch(:halt) { @callback.call(@object) }
632
+ assert_equal [:run_1, :run_2], @object.before_callbacks
633
+ assert_equal [:run_2], @object.after_callbacks
634
+ end
635
+ end
636
+
637
+ class CallbackWithAroundTypeAndArgumentsTest < Test::Unit::TestCase
638
+ def setup
639
+ @object = Object.new
640
+ end
641
+
642
+ def test_should_include_object_if_specified
643
+ callback = StateMachine::Callback.new(:around, lambda {|object, block| @args = [object]; block.call})
644
+ callback.call(@object)
645
+ assert_equal [@object], @args
646
+ end
647
+
648
+ def test_should_include_arguments_if_specified
649
+ callback = StateMachine::Callback.new(:around, lambda {|object, arg1, arg2, arg3, block| @args = [object, arg1, arg2, arg3]; block.call})
650
+ callback.call(@object, {}, 1, 2, 3)
651
+ assert_equal [@object, 1, 2, 3], @args
652
+ end
653
+
654
+ def test_should_include_arguments_if_splat_used
655
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
656
+ callback.call(@object, {}, 1, 2, 3)
657
+ assert_equal [@object, 1, 2, 3], @args
658
+ end
659
+ end
660
+
661
+ class CallbackWithAroundTypeAndTerminatorTest < Test::Unit::TestCase
662
+ def setup
663
+ @object = Object.new
664
+ end
665
+
666
+ def test_should_not_halt_if_terminator_does_not_match
667
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == true})
668
+ assert_nothing_thrown { callback.call(@object) }
669
+ end
670
+
671
+ def test_should_not_halt_if_terminator_matches
672
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == false})
673
+ assert_nothing_thrown { callback.call(@object) }
674
+ end
675
+ end
676
+
677
+ class CallbackWithAroundTypeAndBoundMethodTest < Test::Unit::TestCase
678
+ def setup
679
+ @object = Object.new
680
+ end
681
+
682
+ def test_should_call_method_within_the_context_of_the_object
683
+ context = nil
684
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| context = self; block.call}, :bind_to_object => true)
685
+ callback.call(@object, {}, 1, 2, 3)
686
+
687
+ assert_equal @object, context
688
+ end
689
+
690
+ def test_should_include_arguments_if_specified
691
+ context = nil
692
+ callback = StateMachine::Callback.new(:around, :do => lambda {|*args| block = args.pop; context = args; block.call}, :bind_to_object => true)
693
+ callback.call(@object, {}, 1, 2, 3)
694
+
695
+ assert_equal [1, 2, 3], context
696
+ end
697
+ end
698
+
699
+ class CallbackSuccessMatcherTest < Test::Unit::TestCase
700
+ def setup
701
+ @object = Object.new
702
+ end
703
+
704
+ def test_should_match_if_not_specified
705
+ callback = StateMachine::Callback.new(:before) {}
706
+ assert callback.matches_success?(true)
707
+ end
708
+
709
+ def test_should_match_if_true_and_not_including_failures
710
+ callback = StateMachine::Callback.new(:before, :include_failures => false) {}
711
+ assert callback.matches_success?(true)
712
+ end
713
+
714
+ def test_should_match_if_true_and_including_failures
715
+ callback = StateMachine::Callback.new(:before, :include_failures => true) {}
716
+ assert callback.matches_success?(true)
717
+ end
718
+
719
+ def test_should_not_match_if_false_and_not_including_failures
720
+ callback = StateMachine::Callback.new(:before, :include_failures => false) {}
721
+ assert !callback.matches_success?(false)
722
+ end
723
+
724
+ def test_Should_match_if_false_and_including_failures
725
+ callback = StateMachine::Callback.new(:before, :include_failures => true) {}
726
+ assert callback.matches_success?(false)
727
+ end
728
+ end