state_machine 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. data/.gitignore +7 -11
  2. data/.travis.yml +49 -7
  3. data/Appraisals +255 -87
  4. data/CHANGELOG.md +30 -0
  5. data/README.md +142 -21
  6. data/Rakefile +1 -11
  7. data/examples/Gemfile +5 -0
  8. data/examples/Gemfile.lock +14 -0
  9. data/examples/auto_shop.rb +2 -0
  10. data/examples/car.rb +2 -0
  11. data/examples/doc/AutoShop.html +2856 -0
  12. data/examples/doc/AutoShop_state.png +0 -0
  13. data/examples/doc/Car.html +919 -0
  14. data/examples/doc/Car_state.png +0 -0
  15. data/examples/doc/TrafficLight.html +2230 -0
  16. data/examples/doc/TrafficLight_state.png +0 -0
  17. data/examples/doc/Vehicle.html +7921 -0
  18. data/examples/doc/Vehicle_state.png +0 -0
  19. data/examples/doc/_index.html +136 -0
  20. data/examples/doc/class_list.html +47 -0
  21. data/examples/doc/css/common.css +1 -0
  22. data/examples/doc/css/full_list.css +55 -0
  23. data/examples/doc/css/style.css +322 -0
  24. data/examples/doc/file_list.html +46 -0
  25. data/examples/doc/frames.html +13 -0
  26. data/examples/doc/index.html +136 -0
  27. data/examples/doc/js/app.js +205 -0
  28. data/examples/doc/js/full_list.js +173 -0
  29. data/examples/doc/js/jquery.js +16 -0
  30. data/examples/doc/method_list.html +734 -0
  31. data/examples/doc/top-level-namespace.html +105 -0
  32. data/examples/rails-rest/migration.rb +1 -5
  33. data/examples/rails-rest/view__form.html.erb +34 -0
  34. data/examples/rails-rest/view_edit.html.erb +2 -21
  35. data/examples/rails-rest/view_index.html.erb +6 -4
  36. data/examples/rails-rest/view_new.html.erb +2 -11
  37. data/examples/rails-rest/view_show.html.erb +5 -3
  38. data/examples/traffic_light.rb +2 -0
  39. data/examples/vehicle.rb +2 -0
  40. data/gemfiles/active_model-3.0.0.gemfile.lock +9 -6
  41. data/gemfiles/active_model-3.0.5.gemfile.lock +10 -7
  42. data/gemfiles/active_model-3.1.1.gemfile.lock +12 -10
  43. data/gemfiles/{active_model-3.2.0.gemfile → active_model-3.2.1.gemfile} +1 -1
  44. data/gemfiles/{graphviz-0.9.0.gemfile → active_model-3.2.12.gemfile} +1 -1
  45. data/gemfiles/active_model-3.2.12.gemfile.lock +36 -0
  46. data/gemfiles/{active_record-3.2.0.gemfile → active_model-3.2.13.rc1.gemfile} +1 -2
  47. data/gemfiles/active_model-3.2.13.rc1.gemfile.lock +36 -0
  48. data/gemfiles/active_model-4.0.0.gemfile +9 -0
  49. data/gemfiles/active_model-4.0.0.gemfile.lock +78 -0
  50. data/gemfiles/active_record-2.0.0.gemfile +2 -1
  51. data/gemfiles/active_record-2.0.0.gemfile.lock +15 -6
  52. data/gemfiles/active_record-2.0.5.gemfile +2 -1
  53. data/gemfiles/active_record-2.0.5.gemfile.lock +15 -6
  54. data/gemfiles/active_record-2.1.0.gemfile +2 -1
  55. data/gemfiles/active_record-2.1.0.gemfile.lock +15 -6
  56. data/gemfiles/active_record-2.1.2.gemfile +2 -1
  57. data/gemfiles/active_record-2.1.2.gemfile.lock +15 -6
  58. data/gemfiles/active_record-2.2.3.gemfile +2 -1
  59. data/gemfiles/active_record-2.2.3.gemfile.lock +15 -6
  60. data/gemfiles/active_record-2.3.12.gemfile +2 -1
  61. data/gemfiles/active_record-2.3.12.gemfile.lock +15 -6
  62. data/gemfiles/active_record-2.3.5.gemfile +9 -0
  63. data/gemfiles/active_record-2.3.5.gemfile.lock +39 -0
  64. data/gemfiles/active_record-3.0.0.gemfile +2 -1
  65. data/gemfiles/active_record-3.0.0.gemfile.lock +18 -11
  66. data/gemfiles/active_record-3.0.5.gemfile +2 -1
  67. data/gemfiles/active_record-3.0.5.gemfile.lock +19 -12
  68. data/gemfiles/active_record-3.1.1.gemfile +2 -1
  69. data/gemfiles/active_record-3.1.1.gemfile.lock +22 -16
  70. data/gemfiles/active_record-3.2.12.gemfile +9 -0
  71. data/gemfiles/active_record-3.2.12.gemfile.lock +51 -0
  72. data/gemfiles/active_record-3.2.13.rc1.gemfile +9 -0
  73. data/gemfiles/active_record-3.2.13.rc1.gemfile.lock +51 -0
  74. data/gemfiles/active_record-4.0.0.gemfile +11 -0
  75. data/gemfiles/active_record-4.0.0.gemfile.lock +83 -0
  76. data/gemfiles/data_mapper-0.10.2.gemfile +1 -0
  77. data/gemfiles/data_mapper-0.10.2.gemfile.lock +13 -9
  78. data/gemfiles/data_mapper-0.9.11.gemfile +1 -0
  79. data/gemfiles/data_mapper-0.9.11.gemfile.lock +31 -7
  80. data/gemfiles/data_mapper-0.9.4.gemfile.lock +25 -14
  81. data/gemfiles/data_mapper-0.9.7.gemfile +1 -0
  82. data/gemfiles/data_mapper-0.9.7.gemfile.lock +27 -15
  83. data/gemfiles/data_mapper-1.0.0.gemfile.lock +20 -17
  84. data/gemfiles/data_mapper-1.0.1.gemfile.lock +20 -17
  85. data/gemfiles/data_mapper-1.0.2.gemfile.lock +20 -17
  86. data/gemfiles/data_mapper-1.1.0.gemfile.lock +19 -16
  87. data/gemfiles/data_mapper-1.2.0.gemfile.lock +19 -16
  88. data/gemfiles/default.gemfile.lock +8 -5
  89. data/gemfiles/graphviz-0.9.17.gemfile +7 -0
  90. data/gemfiles/graphviz-0.9.17.gemfile.lock +29 -0
  91. data/gemfiles/graphviz-0.9.21.gemfile.lock +7 -4
  92. data/gemfiles/graphviz-1.0.0.gemfile.lock +7 -4
  93. data/gemfiles/graphviz-1.0.3.gemfile +7 -0
  94. data/gemfiles/graphviz-1.0.3.gemfile.lock +29 -0
  95. data/gemfiles/graphviz-1.0.8.gemfile +7 -0
  96. data/gemfiles/graphviz-1.0.8.gemfile.lock +29 -0
  97. data/gemfiles/mongo_mapper-0.10.0.gemfile +1 -0
  98. data/gemfiles/mongo_mapper-0.10.0.gemfile.lock +14 -11
  99. data/gemfiles/mongo_mapper-0.11.1.gemfile +7 -0
  100. data/gemfiles/mongo_mapper-0.11.1.gemfile.lock +44 -0
  101. data/gemfiles/mongo_mapper-0.11.2.gemfile +9 -0
  102. data/gemfiles/mongo_mapper-0.11.2.gemfile.lock +48 -0
  103. data/gemfiles/mongo_mapper-0.12.0.gemfile +9 -0
  104. data/gemfiles/mongo_mapper-0.12.0.gemfile.lock +48 -0
  105. data/gemfiles/mongo_mapper-0.5.5.gemfile.lock +7 -4
  106. data/gemfiles/mongo_mapper-0.5.8.gemfile.lock +7 -4
  107. data/gemfiles/mongo_mapper-0.6.0.gemfile.lock +7 -4
  108. data/gemfiles/mongo_mapper-0.6.10.gemfile.lock +7 -4
  109. data/gemfiles/mongo_mapper-0.7.0.gemfile.lock +7 -4
  110. data/gemfiles/mongo_mapper-0.7.5.gemfile.lock +7 -4
  111. data/gemfiles/mongo_mapper-0.8.0.gemfile.lock +7 -4
  112. data/gemfiles/mongo_mapper-0.8.3.gemfile.lock +7 -4
  113. data/gemfiles/mongo_mapper-0.8.4.gemfile.lock +7 -4
  114. data/gemfiles/mongo_mapper-0.8.6.gemfile.lock +7 -4
  115. data/gemfiles/mongo_mapper-0.9.0.gemfile.lock +7 -4
  116. data/gemfiles/mongoid-2.0.0.gemfile +2 -0
  117. data/gemfiles/mongoid-2.0.0.gemfile.lock +22 -18
  118. data/gemfiles/mongoid-2.1.4.gemfile +2 -0
  119. data/gemfiles/mongoid-2.1.4.gemfile.lock +21 -17
  120. data/gemfiles/mongoid-2.2.4.gemfile +2 -0
  121. data/gemfiles/mongoid-2.2.4.gemfile.lock +21 -17
  122. data/gemfiles/mongoid-2.3.3.gemfile +2 -0
  123. data/gemfiles/mongoid-2.3.3.gemfile.lock +21 -17
  124. data/gemfiles/mongoid-2.4.0.gemfile +9 -0
  125. data/gemfiles/mongoid-2.4.0.gemfile.lock +47 -0
  126. data/gemfiles/mongoid-2.4.10.gemfile +9 -0
  127. data/gemfiles/mongoid-2.4.10.gemfile.lock +47 -0
  128. data/gemfiles/mongoid-2.5.2.gemfile +9 -0
  129. data/gemfiles/mongoid-2.5.2.gemfile.lock +47 -0
  130. data/gemfiles/mongoid-2.6.0.gemfile +9 -0
  131. data/gemfiles/mongoid-2.6.0.gemfile.lock +47 -0
  132. data/gemfiles/mongoid-3.0.0.gemfile +8 -0
  133. data/gemfiles/mongoid-3.0.0.gemfile.lock +45 -0
  134. data/gemfiles/mongoid-3.0.22.gemfile +8 -0
  135. data/gemfiles/mongoid-3.0.22.gemfile.lock +45 -0
  136. data/gemfiles/mongoid-3.1.0.gemfile +8 -0
  137. data/gemfiles/mongoid-3.1.0.gemfile.lock +45 -0
  138. data/gemfiles/sequel-2.11.0.gemfile +2 -1
  139. data/gemfiles/sequel-2.11.0.gemfile.lock +11 -6
  140. data/gemfiles/sequel-2.12.0.gemfile +2 -1
  141. data/gemfiles/sequel-2.12.0.gemfile.lock +11 -6
  142. data/gemfiles/sequel-2.8.0.gemfile +2 -1
  143. data/gemfiles/sequel-2.8.0.gemfile.lock +11 -6
  144. data/gemfiles/sequel-3.0.0.gemfile +2 -1
  145. data/gemfiles/sequel-3.0.0.gemfile.lock +11 -6
  146. data/gemfiles/sequel-3.10.0.gemfile +9 -0
  147. data/gemfiles/sequel-3.10.0.gemfile.lock +33 -0
  148. data/gemfiles/sequel-3.13.0.gemfile +2 -1
  149. data/gemfiles/sequel-3.13.0.gemfile.lock +11 -6
  150. data/gemfiles/sequel-3.14.0.gemfile +2 -1
  151. data/gemfiles/sequel-3.14.0.gemfile.lock +11 -6
  152. data/gemfiles/sequel-3.23.0.gemfile +2 -1
  153. data/gemfiles/sequel-3.23.0.gemfile.lock +11 -6
  154. data/gemfiles/sequel-3.24.0.gemfile +2 -1
  155. data/gemfiles/sequel-3.24.0.gemfile.lock +11 -6
  156. data/gemfiles/sequel-3.29.0.gemfile +2 -1
  157. data/gemfiles/sequel-3.29.0.gemfile.lock +11 -6
  158. data/gemfiles/sequel-3.34.0.gemfile +9 -0
  159. data/gemfiles/sequel-3.34.0.gemfile.lock +33 -0
  160. data/gemfiles/sequel-3.35.0.gemfile +9 -0
  161. data/gemfiles/sequel-3.35.0.gemfile.lock +33 -0
  162. data/gemfiles/sequel-3.4.0.gemfile +9 -0
  163. data/gemfiles/sequel-3.4.0.gemfile.lock +33 -0
  164. data/gemfiles/sequel-3.44.0.gemfile +9 -0
  165. data/gemfiles/sequel-3.44.0.gemfile.lock +33 -0
  166. data/lib/state_machine.rb +6 -0
  167. data/lib/state_machine/branch.rb +9 -8
  168. data/lib/state_machine/callback.rb +2 -2
  169. data/lib/state_machine/core.rb +10 -0
  170. data/lib/state_machine/core_ext.rb +1 -0
  171. data/lib/state_machine/eval_helpers.rb +5 -3
  172. data/lib/state_machine/event.rb +17 -6
  173. data/lib/state_machine/graph.rb +92 -0
  174. data/lib/state_machine/integrations.rb +13 -1
  175. data/lib/state_machine/integrations/active_model.rb +14 -20
  176. data/lib/state_machine/integrations/active_model/observer.rb +3 -3
  177. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  178. data/lib/state_machine/integrations/active_record.rb +52 -25
  179. data/lib/state_machine/integrations/active_record/locale.rb +1 -1
  180. data/lib/state_machine/integrations/active_record/versions.rb +1 -17
  181. data/lib/state_machine/integrations/base.rb +15 -6
  182. data/lib/state_machine/integrations/data_mapper.rb +98 -35
  183. data/lib/state_machine/integrations/data_mapper/versions.rb +46 -8
  184. data/lib/state_machine/integrations/mongo_mapper.rb +39 -12
  185. data/lib/state_machine/integrations/mongo_mapper/locale.rb +1 -1
  186. data/lib/state_machine/integrations/mongo_mapper/versions.rb +3 -20
  187. data/lib/state_machine/integrations/mongoid.rb +52 -14
  188. data/lib/state_machine/integrations/mongoid/locale.rb +1 -1
  189. data/lib/state_machine/integrations/mongoid/versions.rb +52 -26
  190. data/lib/state_machine/integrations/sequel.rb +82 -33
  191. data/lib/state_machine/integrations/sequel/versions.rb +19 -44
  192. data/lib/state_machine/machine.rb +99 -59
  193. data/lib/state_machine/machine_collection.rb +1 -2
  194. data/lib/state_machine/macro_methods.rb +29 -0
  195. data/lib/state_machine/node_collection.rb +1 -1
  196. data/lib/state_machine/state.rb +18 -10
  197. data/lib/state_machine/state_context.rb +2 -2
  198. data/lib/state_machine/transition.rb +8 -1
  199. data/lib/state_machine/transition_collection.rb +2 -1
  200. data/lib/state_machine/version.rb +1 -1
  201. data/lib/state_machine/yard.rb +8 -0
  202. data/lib/state_machine/yard/handlers.rb +12 -0
  203. data/lib/state_machine/yard/handlers/base.rb +32 -0
  204. data/lib/state_machine/yard/handlers/event.rb +25 -0
  205. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  206. data/lib/state_machine/yard/handlers/state.rb +25 -0
  207. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  208. data/lib/state_machine/yard/templates.rb +3 -0
  209. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  210. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  211. data/lib/tasks/state_machine.rb +2 -1
  212. data/lib/yard-state_machine.rb +2 -0
  213. data/state_machine.gemspec +4 -3
  214. data/test/files/switch.rb +4 -0
  215. data/test/test_helper.rb +5 -0
  216. data/test/unit/branch_test.rb +117 -36
  217. data/test/unit/callback_test.rb +5 -2
  218. data/test/unit/eval_helpers_test.rb +49 -1
  219. data/test/unit/event_collection_test.rb +3 -1
  220. data/test/unit/event_test.rb +182 -12
  221. data/test/unit/graph_test.rb +98 -0
  222. data/test/unit/integrations/active_model_test.rb +82 -12
  223. data/test/unit/integrations/active_record_test.rb +393 -37
  224. data/test/unit/integrations/base_test.rb +7 -2
  225. data/test/unit/integrations/data_mapper_test.rb +326 -72
  226. data/test/unit/integrations/mongo_mapper_test.rb +338 -44
  227. data/test/unit/integrations/mongoid_test.rb +606 -98
  228. data/test/unit/integrations/sequel_test.rb +429 -102
  229. data/test/unit/integrations_test.rb +28 -6
  230. data/test/unit/machine_collection_test.rb +6 -2
  231. data/test/unit/machine_test.rb +134 -82
  232. data/test/unit/node_collection_test.rb +2 -2
  233. data/test/unit/path_test.rb +1 -1
  234. data/test/unit/state_test.rb +65 -21
  235. data/test/unit/transition_collection_test.rb +43 -23
  236. data/test/unit/transition_test.rb +8 -2
  237. metadata +303 -221
  238. data/gemfiles/active_model-3.2.0.gemfile.lock +0 -32
  239. data/gemfiles/active_record-3.2.0.gemfile.lock +0 -43
  240. data/gemfiles/graphviz-0.9.0.gemfile.lock +0 -26
@@ -2,7 +2,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
3
  class IntegrationMatcherTest < Test::Unit::TestCase
4
4
  def setup
5
- @klass = Class.new
5
+ superclass = Class.new
6
+ self.class.const_set('Vehicle', superclass)
7
+
8
+ @klass = Class.new(superclass)
6
9
  end
7
10
 
8
11
  def test_should_return_nil_if_no_match_found
@@ -13,20 +16,39 @@ class IntegrationMatcherTest < Test::Unit::TestCase
13
16
  integration = Module.new do
14
17
  include StateMachine::Integrations::Base
15
18
 
16
- def self.available?
17
- true
19
+ def self.matching_ancestors
20
+ ['IntegrationMatcherTest::Vehicle']
18
21
  end
22
+ end
23
+ StateMachine::Integrations.const_set('Custom', integration)
24
+
25
+ assert_equal integration, StateMachine::Integrations.match(@klass)
26
+ ensure
27
+ StateMachine::Integrations.send(:remove_const, 'Custom')
28
+ end
29
+
30
+ def test_should_return_nil_if_no_match_found_with_ancestors
31
+ assert_nil StateMachine::Integrations.match_ancestors(['IntegrationMatcherTest::Fake'])
32
+ end
33
+
34
+ def test_should_return_integration_class_if_match_found_with_ancestors
35
+ integration = Module.new do
36
+ include StateMachine::Integrations::Base
19
37
 
20
- def self.matches?(klass)
21
- true
38
+ def self.matching_ancestors
39
+ ['IntegrationMatcherTest::Vehicle']
22
40
  end
23
41
  end
24
42
  StateMachine::Integrations.const_set('Custom', integration)
25
43
 
26
- assert_equal integration, StateMachine::Integrations.match(@klass)
44
+ assert_equal integration, StateMachine::Integrations.match_ancestors(['IntegrationMatcherTest::Fake', 'IntegrationMatcherTest::Vehicle'])
27
45
  ensure
28
46
  StateMachine::Integrations.send(:remove_const, 'Custom')
29
47
  end
48
+
49
+ def teardown
50
+ self.class.send(:remove_const, 'Vehicle')
51
+ end
30
52
  end
31
53
 
32
54
  class IntegrationFinderTest < Test::Unit::TestCase
@@ -67,10 +67,10 @@ class MachineCollectionStateInitializationTest < Test::Unit::TestCase
67
67
  assert_equal 'active', @object.alarm_state
68
68
  end
69
69
 
70
- def test_should_initialize_existing_static_states_by_default
70
+ def test_should_not_initialize_existing_static_states_by_default
71
71
  @object.state = 'idling'
72
72
  @machines.initialize_states(@object)
73
- assert_equal 'parked', @object.state
73
+ assert_equal 'idling', @object.state
74
74
  end
75
75
 
76
76
  def test_should_initialize_existing_static_states_if_forced
@@ -164,6 +164,8 @@ class MachineCollectionFireTest < Test::Unit::TestCase
164
164
  end
165
165
 
166
166
  def test_should_run_failure_callbacks_if_any_event_cannot_transition
167
+ @state_failure_run = @alarm_state_failure_run = false
168
+
167
169
  @machines[:state].after_failure {@state_failure_run = true}
168
170
  @machines[:alarm_state].after_failure {@alarm_state_failure_run = true}
169
171
 
@@ -246,6 +248,7 @@ class MachineCollectionFireWithTransactionsTest < Test::Unit::TestCase
246
248
 
247
249
  def test_should_run_failure_callbacks_if_not_successful
248
250
  @object.allow_save = false
251
+ @state_failure_run = @alarm_state_failure_run = false
249
252
 
250
253
  @machines[:state].after_failure {@state_failure_run = true}
251
254
  @machines[:alarm_state].after_failure {@alarm_state_failure_run = true}
@@ -313,6 +316,7 @@ class MachineCollectionFireWithValidationsTest < Test::Unit::TestCase
313
316
  def test_should_run_failure_callbacks_if_no_transitions_exist
314
317
  @object.state = 'idling'
315
318
  @object.alarm_state = 'off'
319
+ @state_failure_run = @alarm_state_failure_run = false
316
320
 
317
321
  @machines[:state].after_failure {@state_failure_run = true}
318
322
  @machines[:alarm_state].after_failure {@alarm_state_failure_run = true}
@@ -170,7 +170,7 @@ class MachineByDefaultTest < Test::Unit::TestCase
170
170
  end
171
171
 
172
172
  def test_should_extend_owner_class_with_class_methods
173
- assert (class << @klass; ancestors; end).include?(StateMachine::ClassMethods)
173
+ assert((class << @klass; ancestors; end).include?(StateMachine::ClassMethods))
174
174
  end
175
175
 
176
176
  def test_should_include_instance_methods_in_owner_class
@@ -257,13 +257,12 @@ class MachineWithoutInitializationTest < Test::Unit::TestCase
257
257
  end
258
258
 
259
259
  def test_should_still_allow_manual_initialization
260
- @klass.class_eval do
260
+ @klass.send(:include, Module.new do
261
261
  def initialize(attributes = {})
262
- attributes.each {|attr, value| send("#{attr}=", value)}
263
262
  super()
264
263
  initialize_state_machines
265
264
  end
266
- end
265
+ end)
267
266
 
268
267
  object = @klass.new
269
268
  assert_equal 'parked', object.state
@@ -299,7 +298,7 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
299
298
  assert_equal 'parked', @klass.new.state
300
299
  end
301
300
 
302
- def test_should_still_set_initial_state_even_if_not_empty
301
+ def test_not_set_initial_state_even_if_not_empty
303
302
  @klass.class_eval do
304
303
  def initialize(attributes = {})
305
304
  self.state = 'idling'
@@ -307,7 +306,7 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
307
306
  end
308
307
  end
309
308
  object = @klass.new
310
- assert_equal 'parked', object.state
309
+ assert_equal 'idling', object.state
311
310
  end
312
311
 
313
312
  def test_should_set_initial_state_prior_to_initialization
@@ -319,7 +318,7 @@ class MachineWithStaticInitialStateTest < Test::Unit::TestCase
319
318
  end
320
319
  end
321
320
  klass = Class.new(base)
322
- machine = StateMachine::Machine.new(klass, :initial => :parked)
321
+ StateMachine::Machine.new(klass, :initial => :parked)
323
322
 
324
323
  assert_equal 'parked', klass.new.state_on_init
325
324
  end
@@ -438,7 +437,7 @@ class MachineStateInitializationTest < Test::Unit::TestCase
438
437
 
439
438
  def test_should_write_to_hash_if_specified
440
439
  @machine.initialize_state(@object, :to => hash = {})
441
- assert_equal expected = {'state' => 'parked'}, hash
440
+ assert_equal({'state' => 'parked'}, hash)
442
441
  end
443
442
 
444
443
  def test_should_not_write_to_object_if_writing_to_hash
@@ -511,61 +510,65 @@ class MachineWithCustomIntegrationTest < Test::Unit::TestCase
511
510
  integration = Module.new do
512
511
  include StateMachine::Integrations::Base
513
512
 
514
- def self.available?
515
- true
516
- end
517
-
518
- def self.matches?(klass)
519
- true
513
+ def self.matching_ancestors
514
+ ['MachineWithCustomIntegrationTest::Vehicle']
520
515
  end
521
516
  end
522
517
 
523
518
  StateMachine::Integrations.const_set('Custom', integration)
519
+
520
+ superclass = Class.new
521
+ self.class.const_set('Vehicle', superclass)
522
+
523
+ @klass = Class.new(superclass)
524
524
  end
525
525
 
526
526
  def test_should_be_extended_by_the_integration_if_explicit
527
- machine = StateMachine::Machine.new(Class.new, :integration => :custom)
528
- assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
527
+ machine = StateMachine::Machine.new(@klass, :integration => :custom)
528
+ assert((class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
529
529
  end
530
530
 
531
531
  def test_should_not_be_extended_by_the_integration_if_implicit_but_not_available
532
532
  StateMachine::Integrations::Custom.class_eval do
533
- def self.available?
534
- false
533
+ class << self; remove_method :matching_ancestors; end
534
+ def self.matching_ancestors
535
+ []
535
536
  end
536
537
  end
537
538
 
538
- machine = StateMachine::Machine.new(Class.new)
539
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
539
+ machine = StateMachine::Machine.new(@klass)
540
+ assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
540
541
  end
541
542
 
542
543
  def test_should_not_be_extended_by_the_integration_if_implicit_but_not_matched
543
544
  StateMachine::Integrations::Custom.class_eval do
544
- def self.matches?(klass)
545
- false
545
+ class << self; remove_method :matching_ancestors; end
546
+ def self.matching_ancestors
547
+ []
546
548
  end
547
549
  end
548
550
 
549
- machine = StateMachine::Machine.new(Class.new)
550
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
551
+ machine = StateMachine::Machine.new(@klass)
552
+ assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
551
553
  end
552
554
 
553
555
  def test_should_be_extended_by_the_integration_if_implicit_and_available_and_matches
554
- machine = StateMachine::Machine.new(Class.new)
555
- assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
556
+ machine = StateMachine::Machine.new(@klass)
557
+ assert((class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
556
558
  end
557
559
 
558
560
  def test_should_not_be_extended_by_the_integration_if_nil
559
- machine = StateMachine::Machine.new(Class.new, :integration => nil)
560
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
561
+ machine = StateMachine::Machine.new(@klass, :integration => nil)
562
+ assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
561
563
  end
562
564
 
563
565
  def test_should_not_be_extended_by_the_integration_if_false
564
- machine = StateMachine::Machine.new(Class.new, :integration => false)
565
- assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
566
+ machine = StateMachine::Machine.new(@klass, :integration => false)
567
+ assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom))
566
568
  end
567
569
 
568
570
  def teardown
571
+ self.class.send(:remove_const, 'Vehicle')
569
572
  StateMachine::Integrations.send(:remove_const, 'Custom')
570
573
  end
571
574
  end
@@ -653,11 +656,11 @@ class MachineWithActionUndefinedTest < Test::Unit::TestCase
653
656
  end
654
657
 
655
658
  def test_should_define_an_event_transition_attribute_reader
656
- assert @object.respond_to?(:state_event_transition)
659
+ assert @object.respond_to?(:state_event_transition, true)
657
660
  end
658
661
 
659
662
  def test_should_define_an_event_transition_attribute_writer
660
- assert @object.respond_to?(:state_event_transition=)
663
+ assert @object.respond_to?(:state_event_transition=, true)
661
664
  end
662
665
 
663
666
  def test_should_not_define_action
@@ -689,11 +692,11 @@ class MachineWithActionDefinedInClassTest < Test::Unit::TestCase
689
692
  end
690
693
 
691
694
  def test_should_define_an_event_transition_attribute_reader
692
- assert @object.respond_to?(:state_event_transition)
695
+ assert @object.respond_to?(:state_event_transition, true)
693
696
  end
694
697
 
695
698
  def test_should_define_an_event_transition_attribute_writer
696
- assert @object.respond_to?(:state_event_transition=)
699
+ assert @object.respond_to?(:state_event_transition=, true)
697
700
  end
698
701
 
699
702
  def test_should_not_define_action
@@ -729,11 +732,11 @@ class MachineWithActionDefinedInIncludedModuleTest < Test::Unit::TestCase
729
732
  end
730
733
 
731
734
  def test_should_define_an_event_transition_attribute_reader
732
- assert @object.respond_to?(:state_event_transition)
735
+ assert @object.respond_to?(:state_event_transition, true)
733
736
  end
734
737
 
735
738
  def test_should_define_an_event_transition_attribute_writer
736
- assert @object.respond_to?(:state_event_transition=)
739
+ assert @object.respond_to?(:state_event_transition=, true)
737
740
  end
738
741
 
739
742
  def test_should_define_action
@@ -770,11 +773,11 @@ class MachineWithActionDefinedInSuperclassTest < Test::Unit::TestCase
770
773
  end
771
774
 
772
775
  def test_should_define_an_event_transition_attribute_reader
773
- assert @object.respond_to?(:state_event_transition)
776
+ assert @object.respond_to?(:state_event_transition, true)
774
777
  end
775
778
 
776
779
  def test_should_define_an_event_transition_attribute_writer
777
- assert @object.respond_to?(:state_event_transition=)
780
+ assert @object.respond_to?(:state_event_transition=, true)
778
781
  end
779
782
 
780
783
  def test_should_define_action
@@ -812,11 +815,11 @@ class MachineWithPrivateActionTest < Test::Unit::TestCase
812
815
  end
813
816
 
814
817
  def test_should_define_an_event_transition_attribute_reader
815
- assert @object.respond_to?(:state_event_transition)
818
+ assert @object.respond_to?(:state_event_transition, true)
816
819
  end
817
820
 
818
821
  def test_should_define_an_event_transition_attribute_writer
819
- assert @object.respond_to?(:state_event_transition=)
822
+ assert @object.respond_to?(:state_event_transition=, true)
820
823
  end
821
824
 
822
825
  def test_should_define_action
@@ -875,17 +878,28 @@ class MachineWithCustomPluralTest < Test::Unit::TestCase
875
878
  end
876
879
 
877
880
  StateMachine::Integrations.const_set('Custom', @integration)
878
- @machine = StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
879
881
  end
880
882
 
881
883
  def test_should_define_a_singular_and_plural_with_scope
884
+ StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
882
885
  assert_equal %w(with_state with_staties), @integration.with_scopes
883
886
  end
884
887
 
885
888
  def test_should_define_a_singular_and_plural_without_scope
889
+ StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
886
890
  assert_equal %w(without_state without_staties), @integration.without_scopes
887
891
  end
888
892
 
893
+ def test_should_define_single_with_scope_if_singular_same_as_plural
894
+ StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state')
895
+ assert_equal %w(with_state), @integration.with_scopes
896
+ end
897
+
898
+ def test_should_define_single_without_scope_if_singular_same_as_plural
899
+ StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state')
900
+ assert_equal %w(without_state), @integration.without_scopes
901
+ end
902
+
889
903
  def teardown
890
904
  StateMachine::Integrations.send(:remove_const, 'Custom')
891
905
  end
@@ -1561,7 +1575,7 @@ class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
1561
1575
  assert_equal :human_state_event_name, @klass.human_state_event_name
1562
1576
  end
1563
1577
 
1564
- def test_should_not_redefine_attribute_writer
1578
+ def test_should_not_redefine_attribute_reader
1565
1579
  assert_equal 'parked', @object.state
1566
1580
  end
1567
1581
 
@@ -1609,8 +1623,8 @@ class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
1609
1623
  'Instance method "state_name"',
1610
1624
  'Instance method "human_state_name"',
1611
1625
  'Class method "with_state"',
1612
- 'Class method "without_state"',
1613
1626
  'Class method "with_states"',
1627
+ 'Class method "without_state"',
1614
1628
  'Class method "without_states"'
1615
1629
  ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"}.join
1616
1630
 
@@ -1734,7 +1748,7 @@ class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
1734
1748
  assert_equal :human_state_event_name, @klass.human_state_event_name
1735
1749
  end
1736
1750
 
1737
- def test_should_not_redefine_attribute_writer
1751
+ def test_should_not_redefine_attribute_reader
1738
1752
  assert_equal 'parked', @object.state
1739
1753
  end
1740
1754
 
@@ -1975,8 +1989,9 @@ end
1975
1989
  class MachineWithCustomInitializeTest < Test::Unit::TestCase
1976
1990
  def setup
1977
1991
  @klass = Class.new do
1978
- def initialize
1979
- initialize_state_machines
1992
+ def initialize(state = nil, options = {})
1993
+ @state = state
1994
+ initialize_state_machines(options)
1980
1995
  end
1981
1996
  end
1982
1997
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
@@ -1986,6 +2001,12 @@ class MachineWithCustomInitializeTest < Test::Unit::TestCase
1986
2001
  def test_should_initialize_state
1987
2002
  assert_equal 'parked', @object.state
1988
2003
  end
2004
+
2005
+ def test_should_allow_custom_options
2006
+ @machine.state :idling
2007
+ @object = @klass.new('idling', :static => :force)
2008
+ assert_equal 'parked', @object.state
2009
+ end
1989
2010
  end
1990
2011
 
1991
2012
  class MachinePersistenceTest < Test::Unit::TestCase
@@ -2389,7 +2410,7 @@ class MachineWithEventMatchersTest < Test::Unit::TestCase
2389
2410
  end
2390
2411
 
2391
2412
  def test_should_track_referenced_events
2392
- event = @machine.event(StateMachine::BlacklistMatcher.new([:park]))
2413
+ @machine.event(StateMachine::BlacklistMatcher.new([:park]))
2393
2414
  assert_equal [:park], @machine.events.map {|event| event.name}
2394
2415
  end
2395
2416
 
@@ -2484,11 +2505,6 @@ class MachineWithTransitionsTest < Test::Unit::TestCase
2484
2505
  assert_equal 'Must specify :on event', exception.message
2485
2506
  end
2486
2507
 
2487
- def test_should_not_allow_except_to_option
2488
- exception = assert_raise(ArgumentError) {@machine.transition(:except_to => :parked, :on => :ignite)}
2489
- assert_equal 'Invalid key(s): except_to', exception.message
2490
- end
2491
-
2492
2508
  def test_should_not_allow_except_on_option
2493
2509
  exception = assert_raise(ArgumentError) {@machine.transition(:except_on => :ignite, :on => :ignite)}
2494
2510
  assert_equal 'Invalid key(s): except_on', exception.message
@@ -2506,6 +2522,10 @@ class MachineWithTransitionsTest < Test::Unit::TestCase
2506
2522
  assert_nothing_raised {@machine.transition(:except_from => :idling, :on => :ignite)}
2507
2523
  end
2508
2524
 
2525
+ def test_should_allow_except_to_option
2526
+ assert_nothing_raised {@machine.transition(:except_to => :parked, :on => :ignite)}
2527
+ end
2528
+
2509
2529
  def test_should_allow_implicit_options
2510
2530
  branch = @machine.transition(:first_gear => :second_gear, :on => :shift_up)
2511
2531
  assert_instance_of StateMachine::Branch, branch
@@ -2551,6 +2571,13 @@ class MachineWithTransitionsTest < Test::Unit::TestCase
2551
2571
  assert_equal 2, branches.length
2552
2572
  assert_equal [:ignite, :shift_up], @machine.events.map {|event| event.name}
2553
2573
  end
2574
+
2575
+ def test_should_not_modify_options
2576
+ options = {:parked => :idling, :on => :ignite}
2577
+ @machine.transition(options)
2578
+
2579
+ assert_equal options, {:parked => :idling, :on => :ignite}
2580
+ end
2554
2581
  end
2555
2582
 
2556
2583
  class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
@@ -3157,7 +3184,7 @@ class MachineFinderWithExistingMachineOnSuperclassTest < Test::Unit::TestCase
3157
3184
  end
3158
3185
 
3159
3186
  def test_should_use_the_same_integration
3160
- assert (class << @machine; ancestors; end).include?(StateMachine::Integrations::Custom)
3187
+ assert((class << @machine; ancestors; end).include?(StateMachine::Integrations::Custom))
3161
3188
  end
3162
3189
 
3163
3190
  def teardown
@@ -3188,7 +3215,7 @@ begin
3188
3215
  class MachineDrawingTest < Test::Unit::TestCase
3189
3216
  def setup
3190
3217
  @klass = Class.new do
3191
- def self.name; 'Vehicle'; end
3218
+ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3192
3219
  end
3193
3220
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
3194
3221
  @machine.event :ignite do
@@ -3201,23 +3228,27 @@ begin
3201
3228
  end
3202
3229
 
3203
3230
  def test_should_save_file_with_class_name_by_default
3204
- graph = @machine.draw
3205
- assert File.exists?('./Vehicle_state.png')
3231
+ @machine.draw
3232
+ assert File.exists?("./#{@klass.name}_state.png")
3206
3233
  end
3207
3234
 
3208
3235
  def test_should_allow_base_name_to_be_customized
3209
- graph = @machine.draw(:name => 'machine')
3210
- assert File.exists?('./machine.png')
3236
+ name = "machine_#{rand(1000000)}"
3237
+ @machine.draw(:name => name)
3238
+ @path = "./#{name}.png"
3239
+ assert File.exists?(@path)
3211
3240
  end
3212
3241
 
3213
3242
  def test_should_allow_format_to_be_customized
3214
- graph = @machine.draw(:format => 'jpg')
3215
- assert File.exists?('./Vehicle_state.jpg')
3243
+ @machine.draw(:format => 'jpg')
3244
+ @path = "./#{@klass.name}_state.jpg"
3245
+ assert File.exists?(@path)
3216
3246
  end
3217
3247
 
3218
3248
  def test_should_allow_path_to_be_customized
3219
- graph = @machine.draw(:path => "#{File.dirname(__FILE__)}/")
3220
- assert File.exists?("#{File.dirname(__FILE__)}/Vehicle_state.png")
3249
+ @machine.draw(:path => "#{File.dirname(__FILE__)}/")
3250
+ @path = "#{File.dirname(__FILE__)}/#{@klass.name}_state.png"
3251
+ assert File.exists?(@path)
3221
3252
  end
3222
3253
 
3223
3254
  def test_should_allow_orientation_to_be_landscape
@@ -3230,15 +3261,30 @@ begin
3230
3261
  assert_equal 'TB', graph['rankdir'].to_s.gsub('"', '')
3231
3262
  end
3232
3263
 
3264
+ if Constants::RGV_VERSION != '0.9.0'
3265
+ def test_should_allow_human_names_to_be_displayed
3266
+ @machine.event :ignite, :human_name => 'Ignite'
3267
+ @machine.state :parked, :human_name => 'Parked'
3268
+ @machine.state :idling, :human_name => 'Idling'
3269
+ graph = @machine.draw(:human_names => true)
3270
+
3271
+ parked_node = graph.get_node('parked')
3272
+ assert_equal 'Parked', parked_node['label'].to_s.gsub('"', '')
3273
+
3274
+ idling_node = graph.get_node('idling')
3275
+ assert_equal 'Idling', idling_node['label'].to_s.gsub('"', '')
3276
+ end
3277
+ end
3278
+
3233
3279
  def teardown
3234
- FileUtils.rm Dir["{.,#{File.dirname(__FILE__)}}/*.{png,jpg}"]
3280
+ FileUtils.rm Dir[@path || "./#{@klass.name}_state.png"]
3235
3281
  end
3236
3282
  end
3237
3283
 
3238
3284
  class MachineDrawingWithIntegerStatesTest < Test::Unit::TestCase
3239
3285
  def setup
3240
3286
  @klass = Class.new do
3241
- def self.name; 'Vehicle'; end
3287
+ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3242
3288
  end
3243
3289
  @machine = StateMachine::Machine.new(@klass, :state_id, :initial => :parked)
3244
3290
  @machine.event :ignite do
@@ -3258,16 +3304,18 @@ begin
3258
3304
  end
3259
3305
 
3260
3306
  def test_should_draw_machine
3261
- assert File.exist?('./Vehicle_state_id.png')
3262
- ensure
3263
- FileUtils.rm('./Vehicle_state_id.png')
3307
+ assert File.exist?("./#{@klass.name}_state_id.png")
3308
+ end
3309
+
3310
+ def teardown
3311
+ FileUtils.rm Dir["./#{@klass.name}_state_id.png"]
3264
3312
  end
3265
3313
  end
3266
3314
 
3267
3315
  class MachineDrawingWithNilStatesTest < Test::Unit::TestCase
3268
3316
  def setup
3269
3317
  @klass = Class.new do
3270
- def self.name; 'Vehicle'; end
3318
+ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3271
3319
  end
3272
3320
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
3273
3321
  @machine.event :ignite do
@@ -3286,16 +3334,18 @@ begin
3286
3334
  end
3287
3335
 
3288
3336
  def test_should_draw_machine
3289
- assert File.exist?('./Vehicle_state.png')
3290
- ensure
3291
- FileUtils.rm('./Vehicle_state.png')
3337
+ assert File.exist?("./#{@klass.name}_state.png")
3338
+ end
3339
+
3340
+ def teardown
3341
+ FileUtils.rm Dir["./#{@klass.name}_state.png"]
3292
3342
  end
3293
3343
  end
3294
3344
 
3295
3345
  class MachineDrawingWithDynamicStatesTest < Test::Unit::TestCase
3296
3346
  def setup
3297
3347
  @klass = Class.new do
3298
- def self.name; 'Vehicle'; end
3348
+ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3299
3349
  end
3300
3350
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
3301
3351
  @machine.event :activate do
@@ -3314,16 +3364,18 @@ begin
3314
3364
  end
3315
3365
 
3316
3366
  def test_should_draw_machine
3317
- assert File.exist?('./Vehicle_state.png')
3318
- ensure
3319
- FileUtils.rm('./Vehicle_state.png')
3367
+ assert File.exist?("./#{@klass.name}_state.png")
3368
+ end
3369
+
3370
+ def teardown
3371
+ FileUtils.rm Dir["./#{@klass.name}_state.png"]
3320
3372
  end
3321
3373
  end
3322
3374
 
3323
3375
  class MachineClassDrawingTest < Test::Unit::TestCase
3324
3376
  def setup
3325
3377
  @klass = Class.new do
3326
- def self.name; 'Vehicle'; end
3378
+ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3327
3379
  end
3328
3380
  @machine = StateMachine::Machine.new(@klass)
3329
3381
  @machine.event :ignite do
@@ -3339,17 +3391,17 @@ begin
3339
3391
  def test_should_load_files
3340
3392
  StateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb"))
3341
3393
  assert defined?(::Switch)
3342
- ensure
3343
- FileUtils.rm('./Switch_state.png')
3344
3394
  end
3345
3395
 
3346
3396
  def test_should_allow_path_and_format_to_be_customized
3347
3397
  StateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb"), :path => "#{File.dirname(__FILE__)}/", :format => 'jpg')
3348
- assert File.exist?("#{File.dirname(__FILE__)}/Switch_state.jpg")
3349
- ensure
3350
- FileUtils.rm("#{File.dirname(__FILE__)}/Switch_state.jpg")
3398
+ assert File.exist?("#{File.dirname(__FILE__)}/#{Switch.name}_state.jpg")
3399
+ end
3400
+
3401
+ def teardown
3402
+ FileUtils.rm Dir["{.,#{File.dirname(__FILE__)}}/#{Switch.name}_state.{jpg,png}"]
3351
3403
  end
3352
3404
  end
3353
3405
  rescue LoadError
3354
- $stderr.puts 'Skipping GraphViz StateMachine::Machine tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
3406
+ $stderr.puts 'Skipping GraphViz StateMachine::Machine tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
3355
3407
  end unless ENV['TRAVIS']