spree-state_machine 2.0.0.beta1

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +5 -0
  5. data/CHANGELOG.md +502 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +20 -0
  8. data/README.md +1246 -0
  9. data/Rakefile +20 -0
  10. data/examples/AutoShop_state.png +0 -0
  11. data/examples/Car_state.png +0 -0
  12. data/examples/Gemfile +5 -0
  13. data/examples/Gemfile.lock +14 -0
  14. data/examples/TrafficLight_state.png +0 -0
  15. data/examples/Vehicle_state.png +0 -0
  16. data/examples/auto_shop.rb +13 -0
  17. data/examples/car.rb +21 -0
  18. data/examples/doc/AutoShop.html +2856 -0
  19. data/examples/doc/AutoShop_state.png +0 -0
  20. data/examples/doc/Car.html +919 -0
  21. data/examples/doc/Car_state.png +0 -0
  22. data/examples/doc/TrafficLight.html +2230 -0
  23. data/examples/doc/TrafficLight_state.png +0 -0
  24. data/examples/doc/Vehicle.html +7921 -0
  25. data/examples/doc/Vehicle_state.png +0 -0
  26. data/examples/doc/_index.html +136 -0
  27. data/examples/doc/class_list.html +47 -0
  28. data/examples/doc/css/common.css +1 -0
  29. data/examples/doc/css/full_list.css +55 -0
  30. data/examples/doc/css/style.css +322 -0
  31. data/examples/doc/file_list.html +46 -0
  32. data/examples/doc/frames.html +13 -0
  33. data/examples/doc/index.html +136 -0
  34. data/examples/doc/js/app.js +205 -0
  35. data/examples/doc/js/full_list.js +173 -0
  36. data/examples/doc/js/jquery.js +16 -0
  37. data/examples/doc/method_list.html +734 -0
  38. data/examples/doc/top-level-namespace.html +105 -0
  39. data/examples/merb-rest/controller.rb +51 -0
  40. data/examples/merb-rest/model.rb +28 -0
  41. data/examples/merb-rest/view_edit.html.erb +24 -0
  42. data/examples/merb-rest/view_index.html.erb +23 -0
  43. data/examples/merb-rest/view_new.html.erb +13 -0
  44. data/examples/merb-rest/view_show.html.erb +17 -0
  45. data/examples/rails-rest/controller.rb +43 -0
  46. data/examples/rails-rest/migration.rb +7 -0
  47. data/examples/rails-rest/model.rb +23 -0
  48. data/examples/rails-rest/view__form.html.erb +34 -0
  49. data/examples/rails-rest/view_edit.html.erb +6 -0
  50. data/examples/rails-rest/view_index.html.erb +25 -0
  51. data/examples/rails-rest/view_new.html.erb +5 -0
  52. data/examples/rails-rest/view_show.html.erb +19 -0
  53. data/examples/traffic_light.rb +9 -0
  54. data/examples/vehicle.rb +33 -0
  55. data/lib/state_machine/assertions.rb +36 -0
  56. data/lib/state_machine/branch.rb +225 -0
  57. data/lib/state_machine/callback.rb +236 -0
  58. data/lib/state_machine/core.rb +7 -0
  59. data/lib/state_machine/core_ext/class/state_machine.rb +5 -0
  60. data/lib/state_machine/core_ext.rb +2 -0
  61. data/lib/state_machine/error.rb +13 -0
  62. data/lib/state_machine/eval_helpers.rb +87 -0
  63. data/lib/state_machine/event.rb +257 -0
  64. data/lib/state_machine/event_collection.rb +141 -0
  65. data/lib/state_machine/extensions.rb +149 -0
  66. data/lib/state_machine/graph.rb +92 -0
  67. data/lib/state_machine/helper_module.rb +17 -0
  68. data/lib/state_machine/initializers/rails.rb +25 -0
  69. data/lib/state_machine/initializers.rb +4 -0
  70. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  71. data/lib/state_machine/integrations/active_model/observer.rb +33 -0
  72. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  73. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  74. data/lib/state_machine/integrations/active_model.rb +585 -0
  75. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  76. data/lib/state_machine/integrations/active_record/versions.rb +123 -0
  77. data/lib/state_machine/integrations/active_record.rb +525 -0
  78. data/lib/state_machine/integrations/base.rb +100 -0
  79. data/lib/state_machine/integrations.rb +121 -0
  80. data/lib/state_machine/machine.rb +2287 -0
  81. data/lib/state_machine/machine_collection.rb +74 -0
  82. data/lib/state_machine/macro_methods.rb +522 -0
  83. data/lib/state_machine/matcher.rb +123 -0
  84. data/lib/state_machine/matcher_helpers.rb +54 -0
  85. data/lib/state_machine/node_collection.rb +222 -0
  86. data/lib/state_machine/path.rb +120 -0
  87. data/lib/state_machine/path_collection.rb +90 -0
  88. data/lib/state_machine/state.rb +297 -0
  89. data/lib/state_machine/state_collection.rb +112 -0
  90. data/lib/state_machine/state_context.rb +138 -0
  91. data/lib/state_machine/transition.rb +470 -0
  92. data/lib/state_machine/transition_collection.rb +245 -0
  93. data/lib/state_machine/version.rb +3 -0
  94. data/lib/state_machine/yard/handlers/base.rb +32 -0
  95. data/lib/state_machine/yard/handlers/event.rb +25 -0
  96. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  97. data/lib/state_machine/yard/handlers/state.rb +25 -0
  98. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  99. data/lib/state_machine/yard/handlers.rb +12 -0
  100. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  101. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  102. data/lib/state_machine/yard/templates.rb +3 -0
  103. data/lib/state_machine/yard.rb +8 -0
  104. data/lib/state_machine.rb +8 -0
  105. data/lib/yard-state_machine.rb +2 -0
  106. data/state_machine.gemspec +22 -0
  107. data/test/files/en.yml +17 -0
  108. data/test/files/switch.rb +15 -0
  109. data/test/functional/state_machine_test.rb +1066 -0
  110. data/test/test_helper.rb +7 -0
  111. data/test/unit/assertions_test.rb +40 -0
  112. data/test/unit/branch_test.rb +969 -0
  113. data/test/unit/callback_test.rb +704 -0
  114. data/test/unit/error_test.rb +43 -0
  115. data/test/unit/eval_helpers_test.rb +270 -0
  116. data/test/unit/event_collection_test.rb +398 -0
  117. data/test/unit/event_test.rb +1196 -0
  118. data/test/unit/graph_test.rb +98 -0
  119. data/test/unit/helper_module_test.rb +17 -0
  120. data/test/unit/integrations/active_model_test.rb +1245 -0
  121. data/test/unit/integrations/active_record_test.rb +2551 -0
  122. data/test/unit/integrations/base_test.rb +104 -0
  123. data/test/unit/integrations_test.rb +71 -0
  124. data/test/unit/invalid_event_test.rb +20 -0
  125. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  126. data/test/unit/invalid_transition_test.rb +115 -0
  127. data/test/unit/machine_collection_test.rb +603 -0
  128. data/test/unit/machine_test.rb +3395 -0
  129. data/test/unit/matcher_helpers_test.rb +37 -0
  130. data/test/unit/matcher_test.rb +155 -0
  131. data/test/unit/node_collection_test.rb +362 -0
  132. data/test/unit/path_collection_test.rb +266 -0
  133. data/test/unit/path_test.rb +485 -0
  134. data/test/unit/state_collection_test.rb +352 -0
  135. data/test/unit/state_context_test.rb +441 -0
  136. data/test/unit/state_machine_test.rb +31 -0
  137. data/test/unit/state_test.rb +1101 -0
  138. data/test/unit/transition_collection_test.rb +2168 -0
  139. data/test/unit/transition_test.rb +1558 -0
  140. metadata +264 -0
@@ -0,0 +1,704 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
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, :around, or :failure', 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
+
21
+ def test_should_not_raise_exception_if_using_failure_type
22
+ assert_nothing_raised { StateMachine::Callback.new(:failure) {} }
23
+ end
24
+
25
+ def test_should_raise_exception_if_no_methods_specified
26
+ exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:before) }
27
+ assert_equal 'Method(s) for callback must be specified', exception.message
28
+ end
29
+
30
+ def test_should_not_raise_exception_if_method_specified_in_do_option
31
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run) }
32
+ end
33
+
34
+ def test_should_not_raise_exception_if_method_specified_as_argument
35
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) }
36
+ end
37
+
38
+ def test_should_not_raise_exception_if_method_specified_as_block
39
+ assert_nothing_raised { StateMachine::Callback.new(:before, :run) {} }
40
+ end
41
+
42
+ def test_should_not_raise_exception_if_implicit_option_specified
43
+ assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run, :invalid => :valid) }
44
+ end
45
+
46
+ def test_should_not_bind_to_objects
47
+ assert !StateMachine::Callback.bind_to_object
48
+ end
49
+
50
+ def test_should_not_have_a_terminator
51
+ assert_nil StateMachine::Callback.terminator
52
+ end
53
+ end
54
+
55
+ class CallbackByDefaultTest < Test::Unit::TestCase
56
+ def setup
57
+ @callback = StateMachine::Callback.new(:before) {}
58
+ end
59
+
60
+ def test_should_have_type
61
+ assert_equal :before, @callback.type
62
+ end
63
+
64
+ def test_should_not_have_a_terminator
65
+ assert_nil @callback.terminator
66
+ end
67
+
68
+ def test_should_have_a_branch_with_all_matcher_requirements
69
+ assert_equal StateMachine::AllMatcher.instance, @callback.branch.event_requirement
70
+ assert_equal StateMachine::AllMatcher.instance, @callback.branch.state_requirements.first[:from]
71
+ assert_equal StateMachine::AllMatcher.instance, @callback.branch.state_requirements.first[:to]
72
+ end
73
+
74
+ def test_should_not_have_any_known_states
75
+ assert_equal [], @callback.known_states
76
+ end
77
+ end
78
+
79
+ class CallbackWithMethodArgumentTest < Test::Unit::TestCase
80
+ def setup
81
+ @callback = StateMachine::Callback.new(:before, lambda {|*args| @args = args})
82
+
83
+ @object = Object.new
84
+ @result = @callback.call(@object)
85
+ end
86
+
87
+ def test_should_be_successful
88
+ assert @result
89
+ end
90
+
91
+ def test_should_call_with_empty_context
92
+ assert_equal [@object], @args
93
+ end
94
+ end
95
+
96
+ class CallbackWithMultipleMethodArgumentsTest < Test::Unit::TestCase
97
+ def setup
98
+ @callback = StateMachine::Callback.new(:before, :run_1, :run_2)
99
+
100
+ class << @object = Object.new
101
+ attr_accessor :callbacks
102
+
103
+ def run_1
104
+ (@callbacks ||= []) << :run_1
105
+ end
106
+
107
+ def run_2
108
+ (@callbacks ||= []) << :run_2
109
+ end
110
+ end
111
+
112
+ @result = @callback.call(@object)
113
+ end
114
+
115
+ def test_should_be_successful
116
+ assert @result
117
+ end
118
+
119
+ def test_should_call_each_callback_in_order
120
+ assert_equal [:run_1, :run_2], @object.callbacks
121
+ end
122
+ end
123
+
124
+ class CallbackWithDoMethodTest < Test::Unit::TestCase
125
+ def setup
126
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
127
+
128
+ @object = Object.new
129
+ @result = @callback.call(@object)
130
+ end
131
+
132
+ def test_should_be_successful
133
+ assert @result
134
+ end
135
+
136
+ def test_should_call_with_empty_context
137
+ assert_equal [@object], @args
138
+ end
139
+ end
140
+
141
+ class CallbackWithMultipleDoMethodsTest < Test::Unit::TestCase
142
+ def setup
143
+ @callback = StateMachine::Callback.new(:before, :do => [:run_1, :run_2])
144
+
145
+ class << @object = Object.new
146
+ attr_accessor :callbacks
147
+
148
+ def run_1
149
+ (@callbacks ||= []) << :run_1
150
+ end
151
+
152
+ def run_2
153
+ (@callbacks ||= []) << :run_2
154
+ end
155
+ end
156
+
157
+ @result = @callback.call(@object)
158
+ end
159
+
160
+ def test_should_be_successful
161
+ assert @result
162
+ end
163
+
164
+ def test_should_call_each_callback_in_order
165
+ assert_equal [:run_1, :run_2], @object.callbacks
166
+ end
167
+ end
168
+
169
+ class CallbackWithBlockTest < Test::Unit::TestCase
170
+ def setup
171
+ @callback = StateMachine::Callback.new(:before) do |*args|
172
+ @args = args
173
+ end
174
+
175
+ @object = Object.new
176
+ @result = @callback.call(@object)
177
+ end
178
+
179
+ def test_should_be_successful
180
+ assert @result
181
+ end
182
+
183
+ def test_should_call_with_empty_context
184
+ assert_equal [@object], @args
185
+ end
186
+ end
187
+
188
+ class CallbackWithMixedMethodsTest < Test::Unit::TestCase
189
+ def setup
190
+ @callback = StateMachine::Callback.new(:before, :run_argument, :do => :run_do) do |object|
191
+ object.callbacks << :block
192
+ end
193
+
194
+ class << @object = Object.new
195
+ attr_accessor :callbacks
196
+
197
+ def run_argument
198
+ (@callbacks ||= []) << :argument
199
+ end
200
+
201
+ def run_do
202
+ (@callbacks ||= []) << :do
203
+ end
204
+ end
205
+
206
+ @result = @callback.call(@object)
207
+ end
208
+
209
+ def test_should_be_successful
210
+ assert @result
211
+ end
212
+
213
+ def test_should_call_each_callback_in_order
214
+ assert_equal [:argument, :do, :block], @object.callbacks
215
+ end
216
+ end
217
+
218
+ class CallbackWithExplicitRequirementsTest < Test::Unit::TestCase
219
+ def setup
220
+ @object = Object.new
221
+ @callback = StateMachine::Callback.new(:before, :from => :parked, :to => :idling, :on => :ignite, :do => lambda {})
222
+ end
223
+
224
+ def test_should_call_with_empty_context
225
+ assert @callback.call(@object, {})
226
+ end
227
+
228
+ def test_should_not_call_if_from_not_included
229
+ assert !@callback.call(@object, :from => :idling)
230
+ end
231
+
232
+ def test_should_not_call_if_to_not_included
233
+ assert !@callback.call(@object, :to => :parked)
234
+ end
235
+
236
+ def test_should_not_call_if_on_not_included
237
+ assert !@callback.call(@object, :on => :park)
238
+ end
239
+
240
+ def test_should_call_if_all_requirements_met
241
+ assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
242
+ end
243
+
244
+ def test_should_include_in_known_states
245
+ assert_equal [:parked, :idling], @callback.known_states
246
+ end
247
+ end
248
+
249
+ class CallbackWithImplicitRequirementsTest < Test::Unit::TestCase
250
+ def setup
251
+ @object = Object.new
252
+ @callback = StateMachine::Callback.new(:before, :parked => :idling, :on => :ignite, :do => lambda {})
253
+ end
254
+
255
+ def test_should_call_with_empty_context
256
+ assert @callback.call(@object, {})
257
+ end
258
+
259
+ def test_should_not_call_if_from_not_included
260
+ assert !@callback.call(@object, :from => :idling)
261
+ end
262
+
263
+ def test_should_not_call_if_to_not_included
264
+ assert !@callback.call(@object, :to => :parked)
265
+ end
266
+
267
+ def test_should_not_call_if_on_not_included
268
+ assert !@callback.call(@object, :on => :park)
269
+ end
270
+
271
+ def test_should_call_if_all_requirements_met
272
+ assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
273
+ end
274
+
275
+ def test_should_include_in_known_states
276
+ assert_equal [:parked, :idling], @callback.known_states
277
+ end
278
+ end
279
+
280
+ class CallbackWithIfConditionTest < Test::Unit::TestCase
281
+ def setup
282
+ @object = Object.new
283
+ end
284
+
285
+ def test_should_call_if_true
286
+ callback = StateMachine::Callback.new(:before, :if => lambda {true}, :do => lambda {})
287
+ assert callback.call(@object)
288
+ end
289
+
290
+ def test_should_not_call_if_false
291
+ callback = StateMachine::Callback.new(:before, :if => lambda {false}, :do => lambda {})
292
+ assert !callback.call(@object)
293
+ end
294
+ end
295
+
296
+ class CallbackWithUnlessConditionTest < Test::Unit::TestCase
297
+ def setup
298
+ @object = Object.new
299
+ end
300
+
301
+ def test_should_call_if_false
302
+ callback = StateMachine::Callback.new(:before, :unless => lambda {false}, :do => lambda {})
303
+ assert callback.call(@object)
304
+ end
305
+
306
+ def test_should_not_call_if_true
307
+ callback = StateMachine::Callback.new(:before, :unless => lambda {true}, :do => lambda {})
308
+ assert !callback.call(@object)
309
+ end
310
+ end
311
+
312
+ class CallbackWithoutTerminatorTest < Test::Unit::TestCase
313
+ def setup
314
+ @object = Object.new
315
+ end
316
+
317
+ def test_should_not_halt_if_result_is_false
318
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => nil)
319
+ assert_nothing_thrown { callback.call(@object) }
320
+ end
321
+ end
322
+
323
+ class CallbackWithTerminatorTest < Test::Unit::TestCase
324
+ def setup
325
+ @object = Object.new
326
+ end
327
+
328
+ def test_should_not_halt_if_terminator_does_not_match
329
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == true})
330
+ assert_nothing_thrown { callback.call(@object) }
331
+ end
332
+
333
+ def test_should_halt_if_terminator_matches
334
+ callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == false})
335
+ assert_throws(:halt) { callback.call(@object) }
336
+ end
337
+
338
+ def test_should_halt_if_terminator_matches_any_method
339
+ callback = StateMachine::Callback.new(:before, :do => [lambda {true}, lambda {false}], :terminator => lambda {|result| result == false})
340
+ assert_throws(:halt) { callback.call(@object) }
341
+ end
342
+ end
343
+
344
+ class CallbackWithoutArgumentsTest < Test::Unit::TestCase
345
+ def setup
346
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|object| @arg = object})
347
+
348
+ @object = Object.new
349
+ @callback.call(@object, {}, 1, 2, 3)
350
+ end
351
+
352
+ def test_should_call_method_with_object_as_argument
353
+ assert_equal @object, @arg
354
+ end
355
+ end
356
+
357
+ class CallbackWithArgumentsTest < Test::Unit::TestCase
358
+ def setup
359
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
360
+
361
+ @object = Object.new
362
+ @callback.call(@object, {}, 1, 2, 3)
363
+ end
364
+
365
+ def test_should_call_method_with_all_arguments
366
+ assert_equal [@object, 1, 2, 3], @args
367
+ end
368
+ end
369
+
370
+ class CallbackWithUnboundMethodTest < Test::Unit::TestCase
371
+ def setup
372
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @context = args.unshift(self)})
373
+
374
+ @object = Object.new
375
+ @callback.call(@object, {}, 1, 2, 3)
376
+ end
377
+
378
+ def test_should_call_method_outside_the_context_of_the_object
379
+ assert_equal [self, @object, 1, 2, 3], @context
380
+ end
381
+ end
382
+
383
+ class CallbackWithBoundMethodTest < Test::Unit::TestCase
384
+ def setup
385
+ @object = Object.new
386
+ end
387
+
388
+ def test_should_call_method_within_the_context_of_the_object_for_block_methods
389
+ context = nil
390
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = [self] + args}, :bind_to_object => true)
391
+ callback.call(@object, {}, 1, 2, 3)
392
+
393
+ assert_equal [@object, 1, 2, 3], context
394
+ end
395
+
396
+ def test_should_ignore_option_for_symbolic_methods
397
+ class << @object
398
+ attr_reader :context
399
+
400
+ def after_ignite(*args)
401
+ @context = args
402
+ end
403
+ end
404
+
405
+ callback = StateMachine::Callback.new(:before, :do => :after_ignite, :bind_to_object => true)
406
+ callback.call(@object)
407
+
408
+ assert_equal [], @object.context
409
+ end
410
+
411
+ def test_should_ignore_option_for_string_methods
412
+ callback = StateMachine::Callback.new(:before, :do => '[1, 2, 3]', :bind_to_object => true)
413
+ assert callback.call(@object)
414
+ end
415
+ end
416
+
417
+ class CallbackWithMultipleBoundMethodsTest < Test::Unit::TestCase
418
+ def setup
419
+ @object = Object.new
420
+
421
+ first_context = nil
422
+ second_context = nil
423
+
424
+ @callback = StateMachine::Callback.new(:before, :do => [lambda {first_context = self}, lambda {second_context = self}], :bind_to_object => true)
425
+ @callback.call(@object)
426
+
427
+ @first_context = first_context
428
+ @second_context = second_context
429
+ end
430
+
431
+ def test_should_call_each_method_within_the_context_of_the_object
432
+ assert_equal @object, @first_context
433
+ assert_equal @object, @second_context
434
+ end
435
+ end
436
+
437
+ class CallbackWithApplicationBoundObjectTest < Test::Unit::TestCase
438
+ def setup
439
+ @original_bind_to_object = StateMachine::Callback.bind_to_object
440
+ StateMachine::Callback.bind_to_object = true
441
+
442
+ context = nil
443
+ @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = self})
444
+
445
+ @object = Object.new
446
+ @callback.call(@object)
447
+ @context = context
448
+ end
449
+
450
+ def test_should_call_method_within_the_context_of_the_object
451
+ assert_equal @object, @context
452
+ end
453
+
454
+ def teardown
455
+ StateMachine::Callback.bind_to_object = @original_bind_to_object
456
+ end
457
+ end
458
+
459
+ class CallbackWithBoundMethodAndArgumentsTest < Test::Unit::TestCase
460
+ def setup
461
+ @object = Object.new
462
+ end
463
+
464
+ def test_should_include_single_argument_if_specified
465
+ context = nil
466
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1| context = [arg1]}, :bind_to_object => true)
467
+ callback.call(@object, {}, 1)
468
+ assert_equal [1], context
469
+ end
470
+
471
+ def test_should_include_multiple_arguments_if_specified
472
+ context = nil
473
+ callback = StateMachine::Callback.new(:before, :do => lambda {|arg1, arg2, arg3| context = [arg1, arg2, arg3]}, :bind_to_object => true)
474
+ callback.call(@object, {}, 1, 2, 3)
475
+ assert_equal [1, 2, 3], context
476
+ end
477
+
478
+ def test_should_include_arguments_if_splat_used
479
+ context = nil
480
+ callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = args}, :bind_to_object => true)
481
+ callback.call(@object, {}, 1, 2, 3)
482
+ assert_equal [1, 2, 3], context
483
+ end
484
+ end
485
+
486
+ class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
487
+ def setup
488
+ @original_terminator = StateMachine::Callback.terminator
489
+ StateMachine::Callback.terminator = lambda {|result| result == false}
490
+
491
+ @object = Object.new
492
+ end
493
+
494
+ def test_should_not_halt_if_terminator_does_not_match
495
+ callback = StateMachine::Callback.new(:before, :do => lambda {true})
496
+ assert_nothing_thrown { callback.call(@object) }
497
+ end
498
+
499
+ def test_should_halt_if_terminator_matches
500
+ callback = StateMachine::Callback.new(:before, :do => lambda {false})
501
+ assert_throws(:halt) { callback.call(@object) }
502
+ end
503
+
504
+ def teardown
505
+ StateMachine::Callback.terminator = @original_terminator
506
+ end
507
+ end
508
+
509
+ class CallbackWithAroundTypeAndBlockTest < Test::Unit::TestCase
510
+ def setup
511
+ @object = Object.new
512
+ @callbacks = []
513
+ end
514
+
515
+ def test_should_evaluate_before_without_after
516
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
517
+ assert callback.call(@object)
518
+ assert_equal [@object], @args
519
+ end
520
+
521
+ def test_should_evaluate_after_without_before
522
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; block.call; @args = args})
523
+ assert callback.call(@object)
524
+ assert_equal [@object], @args
525
+ end
526
+
527
+ def test_should_halt_if_not_yielded
528
+ callback = StateMachine::Callback.new(:around, lambda {|block|})
529
+ assert_throws(:halt) { callback.call(@object) }
530
+ end
531
+
532
+ def test_should_call_block_after_before
533
+ callback = StateMachine::Callback.new(:around, lambda {|block| @callbacks << :before; block.call})
534
+ assert callback.call(@object) { @callbacks << :block }
535
+ assert_equal [:before, :block], @callbacks
536
+ end
537
+
538
+ def test_should_call_block_before_after
539
+ @callbacks = []
540
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
541
+ assert callback.call(@object) { @callbacks << :block }
542
+ assert_equal [:block, :after], @callbacks
543
+ end
544
+
545
+ def test_should_halt_if_block_halts
546
+ callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
547
+ assert_throws(:halt) { callback.call(@object) { throw :halt } }
548
+ assert_equal [], @callbacks
549
+ end
550
+ end
551
+
552
+ class CallbackWithAroundTypeAndMultipleMethodsTest < Test::Unit::TestCase
553
+ def setup
554
+ @callback = StateMachine::Callback.new(:around, :run_1, :run_2)
555
+
556
+ class << @object = Object.new
557
+ attr_accessor :before_callbacks
558
+ attr_accessor :after_callbacks
559
+
560
+ def run_1
561
+ (@before_callbacks ||= []) << :run_1
562
+ yield
563
+ (@after_callbacks ||= []) << :run_1
564
+ end
565
+
566
+ def run_2
567
+ (@before_callbacks ||= []) << :run_2
568
+ yield
569
+ (@after_callbacks ||= []) << :run_2
570
+ end
571
+ end
572
+ end
573
+
574
+ def test_should_succeed
575
+ assert @callback.call(@object)
576
+ end
577
+
578
+ def test_should_evaluate_before_callbacks_in_order
579
+ @callback.call(@object)
580
+ assert_equal [:run_1, :run_2], @object.before_callbacks
581
+ end
582
+
583
+ def test_should_evaluate_after_callbacks_in_reverse_order
584
+ @callback.call(@object)
585
+ assert_equal [:run_2, :run_1], @object.after_callbacks
586
+ end
587
+
588
+ def test_should_call_block_after_before_callbacks
589
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
590
+ assert_equal [:run_1, :run_2, :block], @object.before_callbacks
591
+ end
592
+
593
+ def test_should_call_block_before_after_callbacks
594
+ @callback.call(@object) { (@object.after_callbacks ||= []) << :block }
595
+ assert_equal [:block, :run_2, :run_1], @object.after_callbacks
596
+ end
597
+
598
+ def test_should_halt_if_first_doesnt_yield
599
+ class << @object
600
+ remove_method :run_1
601
+ def run_1
602
+ (@before_callbacks ||= []) << :run_1
603
+ end
604
+ end
605
+
606
+ catch(:halt) do
607
+ @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
608
+ end
609
+
610
+ assert_equal [:run_1], @object.before_callbacks
611
+ assert_nil @object.after_callbacks
612
+ end
613
+
614
+ def test_should_halt_if_last_doesnt_yield
615
+ class << @object
616
+ remove_method :run_2
617
+ def run_2
618
+ (@before_callbacks ||= []) << :run_2
619
+ end
620
+ end
621
+
622
+ catch(:halt) { @callback.call(@object) }
623
+ assert_equal [:run_1, :run_2], @object.before_callbacks
624
+ assert_nil @object.after_callbacks
625
+ end
626
+
627
+ def test_should_not_evaluate_further_methods_if_after_halts
628
+ class << @object
629
+ remove_method :run_2
630
+ def run_2
631
+ (@before_callbacks ||= []) << :run_2
632
+ yield
633
+ (@after_callbacks ||= []) << :run_2
634
+ throw :halt
635
+ end
636
+ end
637
+
638
+ catch(:halt) { @callback.call(@object) }
639
+ assert_equal [:run_1, :run_2], @object.before_callbacks
640
+ assert_equal [:run_2], @object.after_callbacks
641
+ end
642
+ end
643
+
644
+ class CallbackWithAroundTypeAndArgumentsTest < Test::Unit::TestCase
645
+ def setup
646
+ @object = Object.new
647
+ end
648
+
649
+ def test_should_include_object_if_specified
650
+ callback = StateMachine::Callback.new(:around, lambda {|object, block| @args = [object]; block.call})
651
+ callback.call(@object)
652
+ assert_equal [@object], @args
653
+ end
654
+
655
+ def test_should_include_arguments_if_specified
656
+ callback = StateMachine::Callback.new(:around, lambda {|object, arg1, arg2, arg3, block| @args = [object, arg1, arg2, arg3]; block.call})
657
+ callback.call(@object, {}, 1, 2, 3)
658
+ assert_equal [@object, 1, 2, 3], @args
659
+ end
660
+
661
+ def test_should_include_arguments_if_splat_used
662
+ callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
663
+ callback.call(@object, {}, 1, 2, 3)
664
+ assert_equal [@object, 1, 2, 3], @args
665
+ end
666
+ end
667
+
668
+ class CallbackWithAroundTypeAndTerminatorTest < Test::Unit::TestCase
669
+ def setup
670
+ @object = Object.new
671
+ end
672
+
673
+ def test_should_not_halt_if_terminator_does_not_match
674
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == true})
675
+ assert_nothing_thrown { callback.call(@object) }
676
+ end
677
+
678
+ def test_should_not_halt_if_terminator_matches
679
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == false})
680
+ assert_nothing_thrown { callback.call(@object) }
681
+ end
682
+ end
683
+
684
+ class CallbackWithAroundTypeAndBoundMethodTest < Test::Unit::TestCase
685
+ def setup
686
+ @object = Object.new
687
+ end
688
+
689
+ def test_should_call_method_within_the_context_of_the_object
690
+ context = nil
691
+ callback = StateMachine::Callback.new(:around, :do => lambda {|block| context = self; block.call}, :bind_to_object => true)
692
+ callback.call(@object, {}, 1, 2, 3)
693
+
694
+ assert_equal @object, context
695
+ end
696
+
697
+ def test_should_include_arguments_if_specified
698
+ context = nil
699
+ callback = StateMachine::Callback.new(:around, :do => lambda {|*args| block = args.pop; context = args; block.call}, :bind_to_object => true)
700
+ callback.call(@object, {}, 1, 2, 3)
701
+
702
+ assert_equal [1, 2, 3], context
703
+ end
704
+ end