state_machine 1.1.2 → 1.2.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 (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,8 +2,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
3
  class EventCollectionByDefaultTest < Test::Unit::TestCase
4
4
  def setup
5
- @machine = StateMachine::Machine.new(Class.new)
5
+ @klass = Class.new
6
+ @machine = StateMachine::Machine.new(@klass)
6
7
  @events = StateMachine::EventCollection.new(@machine)
8
+ @object = @klass.new
7
9
  end
8
10
 
9
11
  def test_should_not_have_any_nodes
@@ -376,11 +376,6 @@ class EventTransitionsTest < Test::Unit::TestCase
376
376
  assert_equal [:ignite], branch.event_requirement.values
377
377
  end
378
378
 
379
- def test_should_not_allow_except_to_option
380
- exception = assert_raise(ArgumentError) {@event.transition(:except_to => :parked)}
381
- assert_equal 'Invalid key(s): except_to', exception.message
382
- end
383
-
384
379
  def test_should_not_allow_except_on_option
385
380
  exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)}
386
381
  assert_equal 'Invalid key(s): except_on', exception.message
@@ -398,6 +393,10 @@ class EventTransitionsTest < Test::Unit::TestCase
398
393
  assert_nothing_raised {@event.transition(:except_from => :idling)}
399
394
  end
400
395
 
396
+ def test_should_allow_except_to_option
397
+ assert_nothing_raised {@event.transition(:except_to => :idling)}
398
+ end
399
+
401
400
  def test_should_allow_transitioning_from_a_single_state
402
401
  assert @event.transition(:parked => :idling)
403
402
  end
@@ -405,6 +404,10 @@ class EventTransitionsTest < Test::Unit::TestCase
405
404
  def test_should_allow_transitioning_from_multiple_states
406
405
  assert @event.transition([:parked, :idling] => :idling)
407
406
  end
407
+
408
+ def test_should_allow_transitions_to_multiple_states
409
+ assert @event.transition(:parked => [:parked, :idling])
410
+ end
408
411
 
409
412
  def test_should_have_transitions
410
413
  branch = @event.transition(:to => :idling)
@@ -775,6 +778,150 @@ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
775
778
  end
776
779
  end
777
780
 
781
+ class EventWithTransitionWithLoopbackStateTest < Test::Unit::TestCase
782
+ def setup
783
+ @klass = Class.new
784
+ @machine = StateMachine::Machine.new(@klass)
785
+ @machine.state :parked
786
+
787
+ @machine.events << @event = StateMachine::Event.new(@machine, :park)
788
+ @event.transition(:from => :parked, :to => StateMachine::LoopbackMatcher.instance)
789
+
790
+ @object = @klass.new
791
+ @object.state = 'parked'
792
+ end
793
+
794
+ def test_should_be_able_to_fire
795
+ assert @event.can_fire?(@object)
796
+ end
797
+
798
+ def test_should_have_a_transition
799
+ transition = @event.transition_for(@object)
800
+ assert_not_nil transition
801
+ assert_equal 'parked', transition.from
802
+ assert_equal 'parked', transition.to
803
+ assert_equal :park, transition.event
804
+ end
805
+
806
+ def test_should_fire
807
+ assert @event.fire(@object)
808
+ end
809
+
810
+ def test_should_not_change_the_current_state
811
+ @event.fire(@object)
812
+ assert_equal 'parked', @object.state
813
+ end
814
+ end
815
+
816
+ class EventWithTransitionWithBlacklistedToStateTest < Test::Unit::TestCase
817
+ def setup
818
+ @klass = Class.new
819
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
820
+ @machine.state :parked, :idling, :first_gear, :second_gear
821
+
822
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
823
+ @event.transition(:from => :parked, :to => StateMachine::BlacklistMatcher.new([:parked, :idling]))
824
+
825
+ @object = @klass.new
826
+ @object.state = 'parked'
827
+ end
828
+
829
+ def test_should_be_able_to_fire
830
+ assert @event.can_fire?(@object)
831
+ end
832
+
833
+ def test_should_have_a_transition
834
+ transition = @event.transition_for(@object)
835
+ assert_not_nil transition
836
+ assert_equal 'parked', transition.from
837
+ assert_equal 'first_gear', transition.to
838
+ assert_equal :ignite, transition.event
839
+ end
840
+
841
+ def test_should_allow_loopback_first_when_possible
842
+ @event.transition(:from => :second_gear, :to => StateMachine::BlacklistMatcher.new([:parked, :idling]))
843
+ @object.state = 'second_gear'
844
+
845
+ transition = @event.transition_for(@object)
846
+ assert_not_nil transition
847
+ assert_equal 'second_gear', transition.from
848
+ assert_equal 'second_gear', transition.to
849
+ assert_equal :ignite, transition.event
850
+ end
851
+
852
+ def test_should_allow_specific_transition_selection_using_to
853
+ transition = @event.transition_for(@object, :from => :parked, :to => :second_gear)
854
+
855
+ assert_not_nil transition
856
+ assert_equal 'parked', transition.from
857
+ assert_equal 'second_gear', transition.to
858
+ assert_equal :ignite, transition.event
859
+ end
860
+
861
+ def test_should_not_allow_transition_selection_if_not_matching
862
+ transition = @event.transition_for(@object, :from => :parked, :to => :parked)
863
+ assert_nil transition
864
+ end
865
+
866
+ def test_should_fire
867
+ assert @event.fire(@object)
868
+ end
869
+
870
+ def test_should_change_the_current_state
871
+ @event.fire(@object)
872
+ assert_equal 'first_gear', @object.state
873
+ end
874
+ end
875
+
876
+ class EventWithTransitionWithWhitelistedToStateTest < Test::Unit::TestCase
877
+ def setup
878
+ @klass = Class.new
879
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
880
+ @machine.state :parked, :idling, :first_gear, :second_gear
881
+
882
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
883
+ @event.transition(:from => :parked, :to => StateMachine::WhitelistMatcher.new([:first_gear, :second_gear]))
884
+
885
+ @object = @klass.new
886
+ @object.state = 'parked'
887
+ end
888
+
889
+ def test_should_be_able_to_fire
890
+ assert @event.can_fire?(@object)
891
+ end
892
+
893
+ def test_should_have_a_transition
894
+ transition = @event.transition_for(@object)
895
+ assert_not_nil transition
896
+ assert_equal 'parked', transition.from
897
+ assert_equal 'first_gear', transition.to
898
+ assert_equal :ignite, transition.event
899
+ end
900
+
901
+ def test_should_allow_specific_transition_selection_using_to
902
+ transition = @event.transition_for(@object, :from => :parked, :to => :second_gear)
903
+
904
+ assert_not_nil transition
905
+ assert_equal 'parked', transition.from
906
+ assert_equal 'second_gear', transition.to
907
+ assert_equal :ignite, transition.event
908
+ end
909
+
910
+ def test_should_not_allow_transition_selection_if_not_matching
911
+ transition = @event.transition_for(@object, :from => :parked, :to => :parked)
912
+ assert_nil transition
913
+ end
914
+
915
+ def test_should_fire
916
+ assert @event.fire(@object)
917
+ end
918
+
919
+ def test_should_change_the_current_state
920
+ @event.fire(@object)
921
+ assert_equal 'first_gear', @object.state
922
+ end
923
+ end
924
+
778
925
  class EventWithMultipleTransitionsTest < Test::Unit::TestCase
779
926
  def setup
780
927
  @klass = Class.new
@@ -783,7 +930,7 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
783
930
 
784
931
  @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
785
932
  @event.transition(:idling => :idling)
786
- @event.transition(:parked => :idling) # This one should get used
933
+ @event.transition(:parked => :idling)
787
934
  @event.transition(:parked => :parked)
788
935
 
789
936
  @object = @klass.new
@@ -973,6 +1120,7 @@ class EventWithMarshallingTest < Test::Unit::TestCase
973
1120
 
974
1121
  def test_should_marshal_during_action
975
1122
  @klass.class_eval do
1123
+ remove_method :save
976
1124
  def save
977
1125
  Marshal.dump(self)
978
1126
  end
@@ -1002,25 +1150,47 @@ begin
1002
1150
  @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
1003
1151
  @machine.other_states(*states)
1004
1152
 
1005
- graph = GraphViz.new('G')
1006
- states.each {|state| graph.add_node(state.to_s)}
1153
+ @graph = StateMachine::Graph.new('test')
1154
+ states.each {|state| @graph.add_nodes(state.to_s)}
1007
1155
 
1008
1156
  @machine.events << @event = StateMachine::Event.new(@machine , :park)
1009
1157
  @event.transition :parked => :idling
1010
1158
  @event.transition :first_gear => :parked
1011
1159
  @event.transition :except_from => :parked, :to => :parked
1012
1160
 
1013
- @edges = @event.draw(graph)
1161
+ @event.draw(@graph)
1014
1162
  end
1015
1163
 
1016
1164
  def test_should_generate_edges_for_each_transition
1017
- assert_equal 4, @edges.size
1165
+ assert_equal 4, @graph.edge_count
1018
1166
  end
1019
1167
 
1020
1168
  def test_should_use_event_name_for_edge_label
1021
- assert_equal 'park', @edges.first['label'].to_s.gsub('"', '')
1169
+ assert_equal 'park', @graph.get_edge_at_index(0)['label'].to_s.gsub('"', '')
1170
+ end
1171
+ end
1172
+
1173
+ class EventDrawingWithHumanNameTest < Test::Unit::TestCase
1174
+ def setup
1175
+ states = [:parked, :idling]
1176
+
1177
+ @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
1178
+ @machine.other_states(*states)
1179
+
1180
+ graph = StateMachine::Graph.new('test')
1181
+ states.each {|state| graph.add_nodes(state.to_s)}
1182
+
1183
+ @machine.events << @event = StateMachine::Event.new(@machine , :park, :human_name => 'Park')
1184
+ @event.transition :parked => :idling
1185
+
1186
+ @event.draw(graph, :human_name => true)
1187
+ @edge = graph.get_edge_at_index(0)
1188
+ end
1189
+
1190
+ def test_should_use_event_human_name_for_edge_label
1191
+ assert_equal 'Park', @edge['label'].to_s.gsub('"', '')
1022
1192
  end
1023
1193
  end
1024
1194
  rescue LoadError
1025
- $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
1195
+ $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
1026
1196
  end unless ENV['TRAVIS']
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ begin
4
+ # Load library
5
+ require 'graphviz'
6
+
7
+ class GraphDefaultTest < Test::Unit::TestCase
8
+ def setup
9
+ @graph = StateMachine::Graph.new('test')
10
+ end
11
+
12
+ def test_should_have_a_default_font
13
+ assert_equal 'Arial', @graph.font
14
+ end
15
+
16
+ def test_should_use_current_directory_for_filepath
17
+ assert_equal './test.png', @graph.file_path
18
+ end
19
+
20
+ def test_should_have_a_default_file_format
21
+ assert_equal 'png', @graph.file_format
22
+ end
23
+
24
+ def test_should_have_a_default_orientation
25
+ assert_equal 'TB', @graph[:rankdir].source
26
+ end
27
+ end
28
+
29
+ class GraphNodesTest < Test::Unit::TestCase
30
+ def setup
31
+ @graph = StateMachine::Graph.new('test')
32
+ @node = @graph.add_nodes('parked', :shape => 'ellipse')
33
+ end
34
+
35
+ def test_should_return_generated_node
36
+ assert_not_nil @node
37
+ end
38
+
39
+ def test_should_use_specified_name
40
+ assert_equal @node, @graph.get_node('parked')
41
+ end
42
+
43
+ def test_should_use_specified_options
44
+ assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
45
+ end
46
+
47
+ def test_should_set_default_font
48
+ assert_equal 'Arial', @node['fontname'].to_s.gsub('"', '')
49
+ end
50
+ end
51
+
52
+ class GraphEdgesTest < Test::Unit::TestCase
53
+ def setup
54
+ @graph = StateMachine::Graph.new('test')
55
+ @graph.add_nodes('parked', :shape => 'ellipse')
56
+ @graph.add_nodes('idling', :shape => 'ellipse')
57
+ @edge = @graph.add_edges('parked', 'idling', :label => 'ignite')
58
+ end
59
+
60
+ def test_should_return_generated_edge
61
+ assert_not_nil @edge
62
+ end
63
+
64
+ def test_should_use_specified_nodes
65
+ assert_equal 'parked', @edge.node_one(false)
66
+ assert_equal 'idling', @edge.node_two(false)
67
+ end
68
+
69
+ def test_should_use_specified_options
70
+ assert_equal 'ignite', @edge['label'].to_s.gsub('"', '')
71
+ end
72
+
73
+ def test_should_set_default_font
74
+ assert_equal 'Arial', @edge['fontname'].to_s.gsub('"', '')
75
+ end
76
+ end
77
+
78
+ class GraphOutputTest < Test::Unit::TestCase
79
+ def setup
80
+ @graph_name = "test_#{rand(1000000)}"
81
+ @graph = StateMachine::Graph.new(@graph_name)
82
+ @graph.add_nodes('parked', :shape => 'ellipse')
83
+ @graph.add_nodes('idling', :shape => 'ellipse')
84
+ @graph.add_edges('parked', 'idling', :label => 'ignite')
85
+ @graph.output
86
+ end
87
+
88
+ def test_should_save_file
89
+ assert File.exist?("./#{@graph_name}.png")
90
+ end
91
+
92
+ def teardown
93
+ FileUtils.rm Dir["./#{@graph_name}.png"]
94
+ end
95
+ end
96
+ rescue LoadError
97
+ $stderr.puts 'Skipping GraphViz StateMachine::Graph tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
98
+ end unless ENV['TRAVIS']
@@ -1,7 +1,12 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
2
 
3
3
  require 'active_model'
4
- require 'active_model/observing'
4
+ if defined?(ActiveModel::VERSION) && ActiveModel::VERSION::MAJOR >= 4
5
+ require 'rails/observers/active_model/active_model'
6
+ require 'active_model/mass_assignment_security'
7
+ else
8
+ require 'active_model/observing'
9
+ end
5
10
  require 'active_support/all'
6
11
 
7
12
  module ActiveModelTest
@@ -15,9 +20,9 @@ module ActiveModelTest
15
20
  # Simple ActiveModel superclass
16
21
  parent = Class.new do
17
22
  def self.model_attribute(name)
18
- define_method(name) { instance_variable_get("@#{name}") }
23
+ define_method(name) { instance_variable_defined?("@#{name}") ? instance_variable_get("@#{name}") : nil }
19
24
  define_method("#{name}=") do |value|
20
- send("#{name}_will_change!") if self.class <= ActiveModel::Dirty && value != instance_variable_get("@#{name}")
25
+ send("#{name}_will_change!") if self.class <= ActiveModel::Dirty && value != send(name)
21
26
  instance_variable_set("@#{name}", value)
22
27
  end
23
28
  end
@@ -92,7 +97,7 @@ module ActiveModelTest
92
97
  end
93
98
 
94
99
  def test_should_have_no_defaults
95
- assert_equal e = {}, StateMachine::Integrations::ActiveModel.defaults
100
+ assert_equal({}, StateMachine::Integrations::ActiveModel.defaults)
96
101
  end
97
102
 
98
103
  def test_should_have_a_locale_path
@@ -186,8 +191,7 @@ module ActiveModelTest
186
191
  end
187
192
 
188
193
  def test_should_raise_exception_for_predicate_without_parameters
189
- exception = assert_raise(ArgumentError) { @record.state? }
190
- assert_equal 'wrong number of arguments (1 for 2)', exception.message
194
+ assert_raise(ArgumentError) { @record.state? }
191
195
  end
192
196
 
193
197
  def test_should_return_false_for_predicate_if_does_not_match_current_value
@@ -232,7 +236,7 @@ module ActiveModelTest
232
236
  def setup
233
237
  @model = new_model
234
238
  @machine = StateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
235
- @machine.state nil, :idling
239
+ @machine.state :idling
236
240
  end
237
241
 
238
242
  def test_should_allow_nil_initial_state_when_static
@@ -513,11 +517,21 @@ module ActiveModelTest
513
517
  def test_should_run_around_callbacks
514
518
  before_called = false
515
519
  after_called = false
516
- @machine.around_transition {|block| before_called = true; block.call; after_called = true}
520
+ ensure_called = 0
521
+ @machine.around_transition do |block|
522
+ before_called = true
523
+ begin
524
+ block.call
525
+ ensure
526
+ ensure_called += 1
527
+ end
528
+ after_called = true
529
+ end
517
530
 
518
531
  @transition.perform
519
532
  assert before_called
520
533
  assert after_called
534
+ assert_equal ensure_called, 1
521
535
  end
522
536
 
523
537
  def test_should_include_transition_states_in_known_states
@@ -584,7 +598,7 @@ module ActiveModelTest
584
598
  end
585
599
 
586
600
  class MachineWithFailedAfterCallbacksTest < BaseTestCase
587
- def setup
601
+ def setup
588
602
  @callbacks = []
589
603
 
590
604
  @model = new_model
@@ -727,6 +741,40 @@ module ActiveModelTest
727
741
  end
728
742
  end
729
743
 
744
+ class ObserverUpdateTest < BaseTestCase
745
+ def setup
746
+ @model = new_model { include ActiveModel::Observing }
747
+ @machine = StateMachine::Machine.new(@model)
748
+ @machine.state :parked, :idling
749
+ @machine.event :ignite
750
+
751
+ @record = @model.new(:state => 'parked')
752
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
753
+
754
+ @observer_update = StateMachine::Integrations::ActiveModel::ObserverUpdate.new(:before_transition, @record, @transition)
755
+ end
756
+
757
+ def test_should_have_method
758
+ assert_equal :before_transition, @observer_update.method
759
+ end
760
+
761
+ def test_should_have_object
762
+ assert_equal @record, @observer_update.object
763
+ end
764
+
765
+ def test_should_have_transition
766
+ assert_equal @transition, @observer_update.transition
767
+ end
768
+
769
+ def test_should_include_object_and_transition_in_args
770
+ assert_equal [@record, @transition], @observer_update.args
771
+ end
772
+
773
+ def test_should_use_record_class_as_class
774
+ assert_equal @model, @observer_update.class
775
+ end
776
+ end
777
+
730
778
  class MachineWithObserversTest < BaseTestCase
731
779
  def setup
732
780
  @model = new_model { include ActiveModel::Observing }
@@ -750,7 +798,6 @@ module ActiveModelTest
750
798
  :before_transition
751
799
  ]
752
800
 
753
- notified = false
754
801
  observer = new_observer(@model) do
755
802
  callbacks.each do |callback|
756
803
  define_method(callback) do |*args|
@@ -765,6 +812,31 @@ module ActiveModelTest
765
812
  assert_equal callbacks, instance.notifications
766
813
  end
767
814
 
815
+ def test_should_call_no_transition_callbacks_when_observers_disabled
816
+ return unless ActiveModel::VERSION::MAJOR >= 3 && ActiveModel::VERSION::MINOR >= 1
817
+
818
+ callbacks = [
819
+ :before_ignite,
820
+ :before_transition
821
+ ]
822
+
823
+ observer = new_observer(@model) do
824
+ callbacks.each do |callback|
825
+ define_method(callback) do |*args|
826
+ notifications << callback
827
+ end
828
+ end
829
+ end
830
+
831
+ instance = observer.instance
832
+
833
+ @model.observers.disable(observer) do
834
+ @transition.perform
835
+ end
836
+
837
+ assert_equal [], instance.notifications
838
+ end
839
+
768
840
  def test_should_pass_record_and_transition_to_before_callbacks
769
841
  observer = new_observer(@model) do
770
842
  def before_transition(*args)
@@ -809,7 +881,6 @@ module ActiveModelTest
809
881
  :before_transition_state_from_nil
810
882
  ]
811
883
 
812
- notified = false
813
884
  observer = new_observer(@model) do
814
885
  callbacks.each do |callback|
815
886
  define_method(callback) do |*args|
@@ -833,7 +904,6 @@ module ActiveModelTest
833
904
  :before_transition_state_to_nil
834
905
  ]
835
906
 
836
- notified = false
837
907
  observer = new_observer(@model) do
838
908
  callbacks.each do |callback|
839
909
  define_method(callback) do |*args|