state_machine 0.8.1 → 0.9.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.
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