state_machines 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (455) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +7 -4
  4. data/lib/state_machines/branch.rb +81 -79
  5. data/lib/state_machines/callback.rb +22 -21
  6. data/lib/state_machines/eval_helpers.rb +15 -15
  7. data/lib/state_machines/event.rb +31 -28
  8. data/lib/state_machines/event_collection.rb +26 -25
  9. data/lib/state_machines/extensions.rb +1 -1
  10. data/lib/state_machines/helper_module.rb +1 -1
  11. data/lib/state_machines/integrations.rb +8 -8
  12. data/lib/state_machines/machine.rb +372 -369
  13. data/lib/state_machines/machine_collection.rb +11 -10
  14. data/lib/state_machines/macro_methods.rb +100 -100
  15. data/lib/state_machines/matcher.rb +23 -23
  16. data/lib/state_machines/matcher_helpers.rb +11 -11
  17. data/lib/state_machines/node_collection.rb +15 -13
  18. data/lib/state_machines/path.rb +56 -55
  19. data/lib/state_machines/path_collection.rb +35 -35
  20. data/lib/state_machines/state.rb +7 -6
  21. data/lib/state_machines/state_collection.rb +20 -19
  22. data/lib/state_machines/state_context.rb +33 -35
  23. data/lib/state_machines/transition.rb +180 -178
  24. data/lib/state_machines/transition_collection.rb +170 -168
  25. data/lib/state_machines/version.rb +1 -1
  26. metadata +4 -434
  27. data/.gitignore +0 -21
  28. data/.rspec +0 -3
  29. data/.ruby-gemset +0 -1
  30. data/.ruby-version +0 -1
  31. data/.travis.yml +0 -16
  32. data/Changelog.md +0 -22
  33. data/Contributors.md +0 -39
  34. data/Gemfile +0 -8
  35. data/Rakefile +0 -12
  36. data/Testing.md +0 -0
  37. data/state_machines.gemspec +0 -22
  38. data/test/files/integrations/event_on_failure_integration.rb +0 -10
  39. data/test/files/integrations/vehicle.rb +0 -7
  40. data/test/files/models/auto_shop.rb +0 -31
  41. data/test/files/models/car.rb +0 -21
  42. data/test/files/models/driver.rb +0 -13
  43. data/test/files/models/model_base.rb +0 -6
  44. data/test/files/models/motorcycle.rb +0 -16
  45. data/test/files/models/traffic_light.rb +0 -47
  46. data/test/files/models/vehicle.rb +0 -127
  47. data/test/files/node.rb +0 -5
  48. data/test/files/switch.rb +0 -15
  49. data/test/functional/auto_shop_available_test.rb +0 -20
  50. data/test/functional/auto_shop_busy_test.rb +0 -25
  51. data/test/functional/car_backing_up_test.rb +0 -45
  52. data/test/functional/car_test.rb +0 -49
  53. data/test/functional/driver_default_nonstandard_test.rb +0 -13
  54. data/test/functional/motorcycle_test.rb +0 -52
  55. data/test/functional/traffic_light_caution_test.rb +0 -17
  56. data/test/functional/traffic_light_proceed_test.rb +0 -17
  57. data/test/functional/traffic_light_stop_test.rb +0 -26
  58. data/test/functional/vehicle_first_gear_test.rb +0 -42
  59. data/test/functional/vehicle_idling_test.rb +0 -59
  60. data/test/functional/vehicle_locked_test.rb +0 -29
  61. data/test/functional/vehicle_parked_test.rb +0 -53
  62. data/test/functional/vehicle_repaired_test.rb +0 -20
  63. data/test/functional/vehicle_second_gear_test.rb +0 -42
  64. data/test/functional/vehicle_stalled_test.rb +0 -65
  65. data/test/functional/vehicle_test.rb +0 -20
  66. data/test/functional/vehicle_third_gear_test.rb +0 -42
  67. data/test/functional/vehicle_unsaved_test.rb +0 -181
  68. data/test/functional/vehicle_with_event_attributes_test.rb +0 -30
  69. data/test/functional/vehicle_with_parallel_events_test.rb +0 -36
  70. data/test/test_helper.rb +0 -15
  71. data/test/unit/assertions/assert_exclusive_keys_test.rb +0 -22
  72. data/test/unit/assertions/assert_valid_key_test.rb +0 -12
  73. data/test/unit/branch/branch_test.rb +0 -28
  74. data/test/unit/branch/branch_with_conflicting_conditionals_test.rb +0 -27
  75. data/test/unit/branch/branch_with_conflicting_from_requirements_test.rb +0 -8
  76. data/test/unit/branch/branch_with_conflicting_on_requirements_test.rb +0 -8
  77. data/test/unit/branch/branch_with_conflicting_to_requirements_test.rb +0 -8
  78. data/test/unit/branch/branch_with_different_requirements_test.rb +0 -41
  79. data/test/unit/branch/branch_with_except_from_matcher_requirement_test.rb +0 -8
  80. data/test/unit/branch/branch_with_except_from_requirement_test.rb +0 -36
  81. data/test/unit/branch/branch_with_except_on_matcher_requirement_test.rb +0 -8
  82. data/test/unit/branch/branch_with_except_on_requirement_test.rb +0 -36
  83. data/test/unit/branch/branch_with_except_to_matcher_requirement_test.rb +0 -8
  84. data/test/unit/branch/branch_with_except_to_requirement_test.rb +0 -36
  85. data/test/unit/branch/branch_with_from_matcher_requirement_test.rb +0 -20
  86. data/test/unit/branch/branch_with_from_requirement_test.rb +0 -45
  87. data/test/unit/branch/branch_with_if_conditional_test.rb +0 -27
  88. data/test/unit/branch/branch_with_implicit_and_explicit_requirements_test.rb +0 -23
  89. data/test/unit/branch/branch_with_implicit_from_requirement_matcher_test.rb +0 -20
  90. data/test/unit/branch/branch_with_implicit_requirement_test.rb +0 -20
  91. data/test/unit/branch/branch_with_implicit_to_requirement_matcher_test.rb +0 -16
  92. data/test/unit/branch/branch_with_multiple_except_from_requirements_test.rb +0 -20
  93. data/test/unit/branch/branch_with_multiple_except_on_requirements_test.rb +0 -16
  94. data/test/unit/branch/branch_with_multiple_except_to_requirements_test.rb +0 -20
  95. data/test/unit/branch/branch_with_multiple_from_requirements_test.rb +0 -16
  96. data/test/unit/branch/branch_with_multiple_if_conditionals_test.rb +0 -20
  97. data/test/unit/branch/branch_with_multiple_implicit_requirements_test.rb +0 -53
  98. data/test/unit/branch/branch_with_multiple_to_requirements_test.rb +0 -20
  99. data/test/unit/branch/branch_with_multiple_unless_conditionals_test.rb +0 -20
  100. data/test/unit/branch/branch_with_nil_requirements_test.rb +0 -28
  101. data/test/unit/branch/branch_with_no_requirements_test.rb +0 -36
  102. data/test/unit/branch/branch_with_on_matcher_requirement_test.rb +0 -16
  103. data/test/unit/branch/branch_with_on_requirement_test.rb +0 -45
  104. data/test/unit/branch/branch_with_to_matcher_requirement_test.rb +0 -20
  105. data/test/unit/branch/branch_with_to_requirement_test.rb +0 -45
  106. data/test/unit/branch/branch_with_unless_conditional_test.rb +0 -27
  107. data/test/unit/branch/branch_without_guards_test.rb +0 -27
  108. data/test/unit/callback/callback_by_default_test.rb +0 -25
  109. data/test/unit/callback/callback_test.rb +0 -53
  110. data/test/unit/callback/callback_with_application_bound_object_test.rb +0 -23
  111. data/test/unit/callback/callback_with_application_terminator_test.rb +0 -24
  112. data/test/unit/callback/callback_with_arguments_test.rb +0 -14
  113. data/test/unit/callback/callback_with_around_type_and_arguments_test.rb +0 -25
  114. data/test/unit/callback/callback_with_around_type_and_block_test.rb +0 -44
  115. data/test/unit/callback/callback_with_around_type_and_bound_method_test.rb +0 -23
  116. data/test/unit/callback/callback_with_around_type_and_multiple_methods_test.rb +0 -93
  117. data/test/unit/callback/callback_with_around_type_and_terminator_test.rb +0 -17
  118. data/test/unit/callback/callback_with_block_test.rb +0 -20
  119. data/test/unit/callback/callback_with_bound_method_and_arguments_test.rb +0 -28
  120. data/test/unit/callback/callback_with_bound_method_test.rb +0 -35
  121. data/test/unit/callback/callback_with_do_method_test.rb +0 -18
  122. data/test/unit/callback/callback_with_explicit_requirements_test.rb +0 -32
  123. data/test/unit/callback/callback_with_if_condition_test.rb +0 -17
  124. data/test/unit/callback/callback_with_implicit_requirements_test.rb +0 -32
  125. data/test/unit/callback/callback_with_method_argument_test.rb +0 -18
  126. data/test/unit/callback/callback_with_mixed_methods_test.rb +0 -31
  127. data/test/unit/callback/callback_with_multiple_bound_methods_test.rb +0 -21
  128. data/test/unit/callback/callback_with_multiple_do_methods_test.rb +0 -29
  129. data/test/unit/callback/callback_with_multiple_method_arguments_test.rb +0 -29
  130. data/test/unit/callback/callback_with_terminator_test.rb +0 -22
  131. data/test/unit/callback/callback_with_unbound_method_test.rb +0 -14
  132. data/test/unit/callback/callback_with_unless_condition_test.rb +0 -17
  133. data/test/unit/callback/callback_without_arguments_test.rb +0 -14
  134. data/test/unit/callback/callback_without_terminator_test.rb +0 -12
  135. data/test/unit/error/error_by_default_test.rb +0 -21
  136. data/test/unit/error/error_with_message_test.rb +0 -23
  137. data/test/unit/eval_helper/eval_helpers_base_test.rb +0 -8
  138. data/test/unit/eval_helper/eval_helpers_proc_block_and_explicit_arguments_test.rb +0 -14
  139. data/test/unit/eval_helper/eval_helpers_proc_block_and_implicit_arguments_test.rb +0 -14
  140. data/test/unit/eval_helper/eval_helpers_proc_test.rb +0 -13
  141. data/test/unit/eval_helper/eval_helpers_proc_with_arguments_test.rb +0 -13
  142. data/test/unit/eval_helper/eval_helpers_proc_with_block_test.rb +0 -13
  143. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_arguments_test.rb +0 -18
  144. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_object_test.rb +0 -14
  145. data/test/unit/eval_helper/eval_helpers_proc_without_arguments_test.rb +0 -19
  146. data/test/unit/eval_helper/eval_helpers_string_test.rb +0 -25
  147. data/test/unit/eval_helper/eval_helpers_string_with_block_test.rb +0 -12
  148. data/test/unit/eval_helper/eval_helpers_symbol_method_missing_test.rb +0 -20
  149. data/test/unit/eval_helper/eval_helpers_symbol_private_test.rb +0 -17
  150. data/test/unit/eval_helper/eval_helpers_symbol_protected_test.rb +0 -17
  151. data/test/unit/eval_helper/eval_helpers_symbol_tainted_method_test.rb +0 -18
  152. data/test/unit/eval_helper/eval_helpers_symbol_test.rb +0 -16
  153. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_and_block_test.rb +0 -16
  154. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_test.rb +0 -16
  155. data/test/unit/eval_helper/eval_helpers_symbol_with_block_test.rb +0 -16
  156. data/test/unit/eval_helper/eval_helpers_test.rb +0 -13
  157. data/test/unit/event/event_after_being_copied_test.rb +0 -17
  158. data/test/unit/event/event_by_default_test.rb +0 -60
  159. data/test/unit/event/event_context_test.rb +0 -16
  160. data/test/unit/event/event_on_failure_test.rb +0 -44
  161. data/test/unit/event/event_test.rb +0 -34
  162. data/test/unit/event/event_transitions_test.rb +0 -62
  163. data/test/unit/event/event_with_conflicting_helpers_after_definition_test.rb +0 -79
  164. data/test/unit/event/event_with_conflicting_helpers_before_definition_test.rb +0 -58
  165. data/test/unit/event/event_with_conflicting_machine_test.rb +0 -48
  166. data/test/unit/event/event_with_dynamic_human_name_test.rb +0 -26
  167. data/test/unit/event/event_with_human_name_test.rb +0 -13
  168. data/test/unit/event/event_with_invalid_current_state_test.rb +0 -30
  169. data/test/unit/event/event_with_machine_action_test.rb +0 -33
  170. data/test/unit/event/event_with_marshalling_test.rb +0 -47
  171. data/test/unit/event/event_with_matching_disabled_transitions_test.rb +0 -115
  172. data/test/unit/event/event_with_matching_enabled_transitions_test.rb +0 -75
  173. data/test/unit/event/event_with_multiple_transitions_test.rb +0 -61
  174. data/test/unit/event/event_with_namespace_test.rb +0 -34
  175. data/test/unit/event/event_with_transition_with_blacklisted_to_state_test.rb +0 -60
  176. data/test/unit/event/event_with_transition_with_loopback_state_test.rb +0 -36
  177. data/test/unit/event/event_with_transition_with_nil_to_state_test.rb +0 -36
  178. data/test/unit/event/event_with_transition_with_whitelisted_to_state_test.rb +0 -51
  179. data/test/unit/event/event_with_transition_without_to_state_test.rb +0 -36
  180. data/test/unit/event/event_with_transitions_test.rb +0 -32
  181. data/test/unit/event/event_without_matching_transitions_test.rb +0 -41
  182. data/test/unit/event/event_without_transitions_test.rb +0 -28
  183. data/test/unit/event/invalid_event_test.rb +0 -20
  184. data/test/unit/event_collection/event_collection_attribute_with_machine_action_test.rb +0 -62
  185. data/test/unit/event_collection/event_collection_attribute_with_namespaced_machine_test.rb +0 -36
  186. data/test/unit/event_collection/event_collection_by_default_test.rb +0 -26
  187. data/test/unit/event_collection/event_collection_test.rb +0 -39
  188. data/test/unit/event_collection/event_collection_with_custom_machine_attribute_test.rb +0 -31
  189. data/test/unit/event_collection/event_collection_with_events_with_transitions_test.rb +0 -76
  190. data/test/unit/event_collection/event_collection_with_multiple_events_test.rb +0 -27
  191. data/test/unit/event_collection/event_collection_with_validations_test.rb +0 -74
  192. data/test/unit/event_collection/event_collection_without_machine_action_test.rb +0 -18
  193. data/test/unit/event_collection/event_string_collection_test.rb +0 -31
  194. data/test/unit/helper_module_test.rb +0 -17
  195. data/test/unit/integrations/integration_finder_test.rb +0 -16
  196. data/test/unit/integrations/integration_matcher_test.rb +0 -29
  197. data/test/unit/invalid_transition/invalid_parallel_transition_test.rb +0 -18
  198. data/test/unit/invalid_transition/invalid_transition_test.rb +0 -47
  199. data/test/unit/invalid_transition/invalid_transition_with_integration_test.rb +0 -45
  200. data/test/unit/invalid_transition/invalid_transition_with_namespace_test.rb +0 -32
  201. data/test/unit/machine/machine_after_being_copied_test.rb +0 -62
  202. data/test/unit/machine/machine_after_changing_initial_state.rb +0 -28
  203. data/test/unit/machine/machine_after_changing_owner_class_test.rb +0 -31
  204. data/test/unit/machine/machine_by_default_test.rb +0 -160
  205. data/test/unit/machine/machine_finder_custom_options_test.rb +0 -17
  206. data/test/unit/machine/machine_finder_with_existing_machine_on_superclass_test.rb +0 -85
  207. data/test/unit/machine/machine_finder_with_existing_on_same_class_test.rb +0 -23
  208. data/test/unit/machine/machine_finder_without_existing_machine_test.rb +0 -25
  209. data/test/unit/machine/machine_persistence_test.rb +0 -52
  210. data/test/unit/machine/machine_state_initialization_test.rb +0 -56
  211. data/test/unit/machine/machine_test.rb +0 -30
  212. data/test/unit/machine/machine_with_action_already_overridden_test.rb +0 -23
  213. data/test/unit/machine/machine_with_action_defined_in_class_test.rb +0 -37
  214. data/test/unit/machine/machine_with_action_defined_in_included_module_test.rb +0 -46
  215. data/test/unit/machine/machine_with_action_defined_in_superclass_test.rb +0 -43
  216. data/test/unit/machine/machine_with_action_undefined_test.rb +0 -33
  217. data/test/unit/machine/machine_with_cached_state_test.rb +0 -20
  218. data/test/unit/machine/machine_with_class_helpers_test.rb +0 -179
  219. data/test/unit/machine/machine_with_conflicting_helpers_after_definition_test.rb +0 -244
  220. data/test/unit/machine/machine_with_conflicting_helpers_before_definition_test.rb +0 -175
  221. data/test/unit/machine/machine_with_custom_action_test.rb +0 -11
  222. data/test/unit/machine/machine_with_custom_attribute_test.rb +0 -103
  223. data/test/unit/machine/machine_with_custom_initialize_test.rb +0 -24
  224. data/test/unit/machine/machine_with_custom_integration_test.rb +0 -72
  225. data/test/unit/machine/machine_with_custom_invalidation_test.rb +0 -39
  226. data/test/unit/machine/machine_with_custom_name_test.rb +0 -57
  227. data/test/unit/machine/machine_with_custom_plural_test.rb +0 -52
  228. data/test/unit/machine/machine_with_dynamic_initial_state_test.rb +0 -65
  229. data/test/unit/machine/machine_with_event_matchers_test.rb +0 -41
  230. data/test/unit/machine/machine_with_events_test.rb +0 -52
  231. data/test/unit/machine/machine_with_events_with_custom_human_names_test.rb +0 -18
  232. data/test/unit/machine/machine_with_events_with_transitions_test.rb +0 -37
  233. data/test/unit/machine/machine_with_existing_event_test.rb +0 -17
  234. data/test/unit/machine/machine_with_existing_machines_on_owner_class_test.rb +0 -20
  235. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_class_test.rb +0 -71
  236. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_subclass_test.rb +0 -31
  237. data/test/unit/machine/machine_with_existing_state_test.rb +0 -27
  238. data/test/unit/machine/machine_with_failure_callbacks_test.rb +0 -48
  239. data/test/unit/machine/machine_with_helpers_test.rb +0 -14
  240. data/test/unit/machine/machine_with_initial_state_with_value_and_owner_default.rb +0 -25
  241. data/test/unit/machine/machine_with_initialize_and_super_test.rb +0 -17
  242. data/test/unit/machine/machine_with_initialize_arguments_and_block_test.rb +0 -31
  243. data/test/unit/machine/machine_with_initialize_without_super_test.rb +0 -17
  244. data/test/unit/machine/machine_with_instance_helpers_test.rb +0 -179
  245. data/test/unit/machine/machine_with_integration_test.rb +0 -72
  246. data/test/unit/machine/machine_with_multiple_events_test.rb +0 -32
  247. data/test/unit/machine/machine_with_namespace_test.rb +0 -48
  248. data/test/unit/machine/machine_with_nil_action_test.rb +0 -27
  249. data/test/unit/machine/machine_with_other_states.rb +0 -22
  250. data/test/unit/machine/machine_with_owner_subclass_test.rb +0 -18
  251. data/test/unit/machine/machine_with_paths_test.rb +0 -25
  252. data/test/unit/machine/machine_with_private_action_test.rb +0 -43
  253. data/test/unit/machine/machine_with_state_matchers_test.rb +0 -41
  254. data/test/unit/machine/machine_with_state_with_matchers_test.rb +0 -19
  255. data/test/unit/machine/machine_with_states_test.rb +0 -55
  256. data/test/unit/machine/machine_with_states_with_behaviors_test.rb +0 -23
  257. data/test/unit/machine/machine_with_states_with_custom_human_names_test.rb +0 -18
  258. data/test/unit/machine/machine_with_states_with_custom_values_test.rb +0 -21
  259. data/test/unit/machine/machine_with_states_with_runtime_dependencies_test.rb +0 -19
  260. data/test/unit/machine/machine_with_static_initial_state_test.rb +0 -49
  261. data/test/unit/machine/machine_with_superclass_conflicting_helpers_after_definition_test.rb +0 -36
  262. data/test/unit/machine/machine_with_transition_callbacks_test.rb +0 -144
  263. data/test/unit/machine/machine_with_transitions_test.rb +0 -87
  264. data/test/unit/machine/machine_without_initialization_test.rb +0 -31
  265. data/test/unit/machine/machine_without_initialize_test.rb +0 -14
  266. data/test/unit/machine/machine_without_integration_test.rb +0 -31
  267. data/test/unit/machine_collection/machine_collection_by_default_test.rb +0 -11
  268. data/test/unit/machine_collection/machine_collection_fire_test.rb +0 -80
  269. data/test/unit/machine_collection/machine_collection_fire_with_transactions_test.rb +0 -54
  270. data/test/unit/machine_collection/machine_collection_fire_with_validations_test.rb +0 -76
  271. data/test/unit/machine_collection/machine_collection_state_initialization_test.rb +0 -111
  272. data/test/unit/machine_collection/machine_collection_transitions_with_blank_events_test.rb +0 -25
  273. data/test/unit/machine_collection/machine_collection_transitions_with_custom_options_test.rb +0 -20
  274. data/test/unit/machine_collection/machine_collection_transitions_with_different_actions_test.rb +0 -26
  275. data/test/unit/machine_collection/machine_collection_transitions_with_exisiting_transitions_test.rb +0 -25
  276. data/test/unit/machine_collection/machine_collection_transitions_with_invalid_events_test.rb +0 -25
  277. data/test/unit/machine_collection/machine_collection_transitions_with_same_actions_test.rb +0 -31
  278. data/test/unit/machine_collection/machine_collection_transitions_with_transition_test.rb +0 -26
  279. data/test/unit/machine_collection/machine_collection_transitions_without_events_test.rb +0 -25
  280. data/test/unit/machine_collection/machine_collection_transitions_without_transition_test.rb +0 -27
  281. data/test/unit/matcher/all_matcher_test.rb +0 -29
  282. data/test/unit/matcher/blacklist_matcher_test.rb +0 -30
  283. data/test/unit/matcher/loopback_matcher_test.rb +0 -27
  284. data/test/unit/matcher/matcher_by_default_test.rb +0 -15
  285. data/test/unit/matcher/matcher_with_multiple_values_test.rb +0 -15
  286. data/test/unit/matcher/matcher_with_value_test.rb +0 -15
  287. data/test/unit/matcher/whitelist_matcher_test.rb +0 -30
  288. data/test/unit/matcher_helpers/matcher_helpers_all_test.rb +0 -14
  289. data/test/unit/matcher_helpers/matcher_helpers_any_test.rb +0 -14
  290. data/test/unit/matcher_helpers/matcher_helpers_same_test.rb +0 -13
  291. data/test/unit/node_collection/node_collection_after_being_copied_test.rb +0 -46
  292. data/test/unit/node_collection/node_collection_after_update_test.rb +0 -36
  293. data/test/unit/node_collection/node_collection_by_default_test.rb +0 -22
  294. data/test/unit/node_collection/node_collection_test.rb +0 -23
  295. data/test/unit/node_collection/node_collection_with_indices_test.rb +0 -42
  296. data/test/unit/node_collection/node_collection_with_matcher_contexts_test.rb +0 -25
  297. data/test/unit/node_collection/node_collection_with_nodes_test.rb +0 -46
  298. data/test/unit/node_collection/node_collection_with_numeric_index_test.rb +0 -24
  299. data/test/unit/node_collection/node_collection_with_postdefined_contexts_test.rb +0 -22
  300. data/test/unit/node_collection/node_collection_with_predefined_contexts_test.rb +0 -23
  301. data/test/unit/node_collection/node_collection_with_string_index_test.rb +0 -20
  302. data/test/unit/node_collection/node_collection_with_symbol_index_test.rb +0 -20
  303. data/test/unit/node_collection/node_collection_without_indices_test.rb +0 -30
  304. data/test/unit/path/path_by_default_test.rb +0 -54
  305. data/test/unit/path/path_test.rb +0 -14
  306. data/test/unit/path/path_with_available_transitions_after_reaching_target_test.rb +0 -40
  307. data/test/unit/path/path_with_available_transitions_test.rb +0 -54
  308. data/test/unit/path/path_with_deep_target_reached_test.rb +0 -50
  309. data/test/unit/path/path_with_deep_target_test.rb +0 -40
  310. data/test/unit/path/path_with_duplicates_test.rb +0 -32
  311. data/test/unit/path/path_with_encountered_transitions_test.rb +0 -34
  312. data/test/unit/path/path_with_guarded_transitions_test.rb +0 -42
  313. data/test/unit/path/path_with_reached_target_test.rb +0 -35
  314. data/test/unit/path/path_with_transitions_test.rb +0 -54
  315. data/test/unit/path/path_with_unreached_target_test.rb +0 -31
  316. data/test/unit/path/path_without_transitions_test.rb +0 -24
  317. data/test/unit/path_collection/path_collection_by_default_test.rb +0 -46
  318. data/test/unit/path_collection/path_collection_test.rb +0 -24
  319. data/test/unit/path_collection/path_collection_with_deep_paths_test.rb +0 -43
  320. data/test/unit/path_collection/path_collection_with_duplicate_nodes_test.rb +0 -31
  321. data/test/unit/path_collection/path_collection_with_from_state_test.rb +0 -27
  322. data/test/unit/path_collection/path_collection_with_paths_test.rb +0 -47
  323. data/test/unit/path_collection/path_collection_with_to_state_test.rb +0 -29
  324. data/test/unit/path_collection/path_with_guarded_paths_test.rb +0 -25
  325. data/test/unit/state/state_after_being_copied_test.rb +0 -19
  326. data/test/unit/state/state_by_default_test.rb +0 -41
  327. data/test/unit/state/state_final_test.rb +0 -28
  328. data/test/unit/state/state_initial_test.rb +0 -13
  329. data/test/unit/state/state_not_final_test.rb +0 -32
  330. data/test/unit/state/state_not_initial_test.rb +0 -13
  331. data/test/unit/state/state_test.rb +0 -44
  332. data/test/unit/state/state_with_cached_lambda_value_test.rb +0 -29
  333. data/test/unit/state/state_with_conflicting_helpers_after_definition_test.rb +0 -38
  334. data/test/unit/state/state_with_conflicting_helpers_before_definition_test.rb +0 -29
  335. data/test/unit/state/state_with_conflicting_machine_name_test.rb +0 -20
  336. data/test/unit/state/state_with_conflicting_machine_test.rb +0 -37
  337. data/test/unit/state/state_with_context_test.rb +0 -60
  338. data/test/unit/state/state_with_dynamic_human_name_test.rb +0 -25
  339. data/test/unit/state/state_with_existing_context_method_test.rb +0 -24
  340. data/test/unit/state/state_with_human_name_test.rb +0 -13
  341. data/test/unit/state/state_with_integer_value_test.rb +0 -32
  342. data/test/unit/state/state_with_invalid_method_call_test.rb +0 -21
  343. data/test/unit/state/state_with_lambda_value_test.rb +0 -37
  344. data/test/unit/state/state_with_matcher_test.rb +0 -18
  345. data/test/unit/state/state_with_multiple_contexts_test.rb +0 -57
  346. data/test/unit/state/state_with_name_test.rb +0 -43
  347. data/test/unit/state/state_with_namespace_test.rb +0 -22
  348. data/test/unit/state/state_with_nil_value_test.rb +0 -35
  349. data/test/unit/state/state_with_redefined_context_method_test.rb +0 -45
  350. data/test/unit/state/state_with_symbolic_value_test.rb +0 -32
  351. data/test/unit/state/state_with_valid_inherited_method_call_for_current_state_test.rb +0 -40
  352. data/test/unit/state/state_with_valid_method_call_for_current_state_test.rb +0 -33
  353. data/test/unit/state/state_with_valid_method_call_for_different_state_test.rb +0 -41
  354. data/test/unit/state/state_without_cached_lambda_value_test.rb +0 -25
  355. data/test/unit/state/state_without_name_test.rb +0 -39
  356. data/test/unit/state_collection/state_collection_by_default_test.rb +0 -21
  357. data/test/unit/state_collection/state_collection_string_test.rb +0 -35
  358. data/test/unit/state_collection/state_collection_test.rb +0 -74
  359. data/test/unit/state_collection/state_collection_with_custom_state_values_test.rb +0 -29
  360. data/test/unit/state_collection/state_collection_with_event_transitions_test.rb +0 -39
  361. data/test/unit/state_collection/state_collection_with_initial_state_test.rb +0 -40
  362. data/test/unit/state_collection/state_collection_with_namespace_test.rb +0 -21
  363. data/test/unit/state_collection/state_collection_with_state_behaviors_test.rb +0 -40
  364. data/test/unit/state_collection/state_collection_with_state_matchers_test.rb +0 -29
  365. data/test/unit/state_collection/state_collection_with_transition_callbacks_test.rb +0 -40
  366. data/test/unit/state_context/state_context_proxy_test.rb +0 -26
  367. data/test/unit/state_context/state_context_proxy_with_if_and_unless_conditions_test.rb +0 -42
  368. data/test/unit/state_context/state_context_proxy_with_if_condition_test.rb +0 -64
  369. data/test/unit/state_context/state_context_proxy_with_multiple_if_conditions_test.rb +0 -32
  370. data/test/unit/state_context/state_context_proxy_with_multiple_unless_conditions_test.rb +0 -32
  371. data/test/unit/state_context/state_context_proxy_with_unless_condition_test.rb +0 -64
  372. data/test/unit/state_context/state_context_proxy_without_conditions_test.rb +0 -31
  373. data/test/unit/state_context/state_context_test.rb +0 -28
  374. data/test/unit/state_context/state_context_transition_test.rb +0 -104
  375. data/test/unit/state_context/state_context_with_matching_transition_test.rb +0 -27
  376. data/test/unit/state_machine/state_machine_by_default_test.rb +0 -12
  377. data/test/unit/state_machine/state_machine_test.rb +0 -20
  378. data/test/unit/transition/transition_after_being_performed_test.rb +0 -48
  379. data/test/unit/transition/transition_after_being_persisted_test.rb +0 -46
  380. data/test/unit/transition/transition_after_being_rolled_back_test.rb +0 -35
  381. data/test/unit/transition/transition_equality_test.rb +0 -52
  382. data/test/unit/transition/transition_loopback_test.rb +0 -18
  383. data/test/unit/transition/transition_test.rb +0 -96
  384. data/test/unit/transition/transition_transient_test.rb +0 -20
  385. data/test/unit/transition/transition_with_action_test.rb +0 -27
  386. data/test/unit/transition/transition_with_after_callbacks_skipped_test.rb +0 -127
  387. data/test/unit/transition/transition_with_after_callbacks_test.rb +0 -93
  388. data/test/unit/transition/transition_with_around_callbacks_test.rb +0 -141
  389. data/test/unit/transition/transition_with_before_callbacks_skipped_test.rb +0 -30
  390. data/test/unit/transition/transition_with_before_callbacks_test.rb +0 -104
  391. data/test/unit/transition/transition_with_custom_machine_attribute_test.rb +0 -28
  392. data/test/unit/transition/transition_with_different_states_test.rb +0 -18
  393. data/test/unit/transition/transition_with_dynamic_to_value_test.rb +0 -19
  394. data/test/unit/transition/transition_with_failure_callbacks_test.rb +0 -84
  395. data/test/unit/transition/transition_with_invalid_nodes_test.rb +0 -29
  396. data/test/unit/transition/transition_with_mixed_callbacks_test.rb +0 -105
  397. data/test/unit/transition/transition_with_multiple_after_callbacks_test.rb +0 -40
  398. data/test/unit/transition/transition_with_multiple_around_callbacks_test.rb +0 -114
  399. data/test/unit/transition/transition_with_multiple_before_callbacks_test.rb +0 -40
  400. data/test/unit/transition/transition_with_multiple_failure_callbacks_test.rb +0 -40
  401. data/test/unit/transition/transition_with_namespace_test.rb +0 -47
  402. data/test/unit/transition/transition_with_perform_arguments_test.rb +0 -35
  403. data/test/unit/transition/transition_with_transactions_test.rb +0 -42
  404. data/test/unit/transition/transition_without_callbacks_test.rb +0 -33
  405. data/test/unit/transition/transition_without_reading_state_test.rb +0 -22
  406. data/test/unit/transition/transition_without_running_action_test.rb +0 -47
  407. data/test/unit/transition_collection/attribute_transition_collection_by_default_test.rb +0 -23
  408. data/test/unit/transition_collection/attribute_transition_collection_marshalling_test.rb +0 -64
  409. data/test/unit/transition_collection/attribute_transition_collection_with_action_error_test.rb +0 -44
  410. data/test/unit/transition_collection/attribute_transition_collection_with_action_failed_test.rb +0 -44
  411. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_error_test.rb +0 -32
  412. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_halt_test.rb +0 -33
  413. data/test/unit/transition_collection/attribute_transition_collection_with_around_after_yield_callback_error_test.rb +0 -32
  414. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_error_test.rb +0 -32
  415. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_halt_test.rb +0 -33
  416. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_before_yield_halt_test.rb +0 -33
  417. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_error_test.rb +0 -32
  418. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_halt_test.rb +0 -33
  419. data/test/unit/transition_collection/attribute_transition_collection_with_callbacks_test.rb +0 -68
  420. data/test/unit/transition_collection/attribute_transition_collection_with_event_transitions_test.rb +0 -41
  421. data/test/unit/transition_collection/attribute_transition_collection_with_events_test.rb +0 -44
  422. data/test/unit/transition_collection/attribute_transition_collection_with_skipped_after_callbacks_test.rb +0 -42
  423. data/test/unit/transition_collection/transition_collection_by_default_test.rb +0 -23
  424. data/test/unit/transition_collection/transition_collection_empty_with_block_test.rb +0 -23
  425. data/test/unit/transition_collection/transition_collection_empty_without_block_test.rb +0 -12
  426. data/test/unit/transition_collection/transition_collection_invalid_test.rb +0 -21
  427. data/test/unit/transition_collection/transition_collection_partial_invalid_test.rb +0 -69
  428. data/test/unit/transition_collection/transition_collection_test.rb +0 -26
  429. data/test/unit/transition_collection/transition_collection_valid_test.rb +0 -57
  430. data/test/unit/transition_collection/transition_collection_with_action_error_test.rb +0 -66
  431. data/test/unit/transition_collection/transition_collection_with_action_failed_test.rb +0 -60
  432. data/test/unit/transition_collection/transition_collection_with_action_hook_and_block_test.rb +0 -17
  433. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_action_test.rb +0 -17
  434. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_after_callbacks_test.rb +0 -37
  435. data/test/unit/transition_collection/transition_collection_with_action_hook_base_test.rb +0 -34
  436. data/test/unit/transition_collection/transition_collection_with_action_hook_error_test.rb +0 -29
  437. data/test/unit/transition_collection/transition_collection_with_action_hook_invalid_test.rb +0 -17
  438. data/test/unit/transition_collection/transition_collection_with_action_hook_multiple_test.rb +0 -79
  439. data/test/unit/transition_collection/transition_collection_with_action_hook_test.rb +0 -45
  440. data/test/unit/transition_collection/transition_collection_with_action_hook_with_different_actions_test.rb +0 -48
  441. data/test/unit/transition_collection/transition_collection_with_action_hook_with_nil_action_test.rb +0 -42
  442. data/test/unit/transition_collection/transition_collection_with_after_callback_halt_test.rb +0 -47
  443. data/test/unit/transition_collection/transition_collection_with_before_callback_halt_test.rb +0 -51
  444. data/test/unit/transition_collection/transition_collection_with_block_test.rb +0 -46
  445. data/test/unit/transition_collection/transition_collection_with_callbacks_test.rb +0 -135
  446. data/test/unit/transition_collection/transition_collection_with_different_actions_test.rb +0 -189
  447. data/test/unit/transition_collection/transition_collection_with_duplicate_actions_test.rb +0 -48
  448. data/test/unit/transition_collection/transition_collection_with_empty_actions_test.rb +0 -41
  449. data/test/unit/transition_collection/transition_collection_with_mixed_actions_test.rb +0 -41
  450. data/test/unit/transition_collection/transition_collection_with_skipped_actions_and_block_test.rb +0 -34
  451. data/test/unit/transition_collection/transition_collection_with_skipped_actions_test.rb +0 -69
  452. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_and_around_callbacks_test.rb +0 -53
  453. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_test.rb +0 -34
  454. data/test/unit/transition_collection/transition_collection_with_transactions_test.rb +0 -65
  455. data/test/unit/transition_collection/transition_collection_without_transactions_test.rb +0 -29
@@ -2,327 +2,327 @@ module StateMachines
2
2
  # Represents a state machine for a particular attribute. State machines
3
3
  # consist of states, events and a set of transitions that define how the
4
4
  # state changes after a particular event is fired.
5
- #
5
+ #
6
6
  # A state machine will not know all of the possible states for an object
7
7
  # unless they are referenced *somewhere* in the state machine definition.
8
8
  # As a result, any unused states should be defined with the +other_states+
9
9
  # or +state+ helper.
10
- #
10
+ #
11
11
  # == Actions
12
- #
12
+ #
13
13
  # When an action is configured for a state machine, it is invoked when an
14
14
  # object transitions via an event. The success of the event becomes
15
15
  # dependent on the success of the action. If the action is successful, then
16
16
  # the transitioned state remains persisted. However, if the action fails
17
17
  # (by returning false), the transitioned state will be rolled back.
18
- #
18
+ #
19
19
  # For example,
20
- #
20
+ #
21
21
  # class Vehicle
22
22
  # attr_accessor :fail, :saving_state
23
- #
23
+ #
24
24
  # state_machine :initial => :parked, :action => :save do
25
25
  # event :ignite do
26
26
  # transition :parked => :idling
27
27
  # end
28
- #
28
+ #
29
29
  # event :park do
30
30
  # transition :idling => :parked
31
31
  # end
32
32
  # end
33
- #
33
+ #
34
34
  # def save
35
35
  # @saving_state = state
36
36
  # fail != true
37
37
  # end
38
38
  # end
39
- #
39
+ #
40
40
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c27024 @state="parked">
41
41
  # vehicle.save # => true
42
42
  # vehicle.saving_state # => "parked" # The state was "parked" was save was called
43
- #
43
+ #
44
44
  # # Successful event
45
45
  # vehicle.ignite # => true
46
46
  # vehicle.saving_state # => "idling" # The state was "idling" when save was called
47
47
  # vehicle.state # => "idling"
48
- #
48
+ #
49
49
  # # Failed event
50
50
  # vehicle.fail = true
51
51
  # vehicle.park # => false
52
52
  # vehicle.saving_state # => "parked"
53
53
  # vehicle.state # => "idling"
54
- #
54
+ #
55
55
  # As shown, even though the state is set prior to calling the +save+ action
56
56
  # on the object, it will be rolled back to the original state if the action
57
57
  # fails. *Note* that this will also be the case if an exception is raised
58
58
  # while calling the action.
59
- #
59
+ #
60
60
  # === Indirect transitions
61
- #
61
+ #
62
62
  # In addition to the action being run as the _result_ of an event, the action
63
63
  # can also be used to run events itself. For example, using the above as an
64
64
  # example:
65
- #
65
+ #
66
66
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c27024 @state="parked">
67
- #
67
+ #
68
68
  # vehicle.state_event = 'ignite'
69
69
  # vehicle.save # => true
70
70
  # vehicle.state # => "idling"
71
71
  # vehicle.state_event # => nil
72
- #
72
+ #
73
73
  # As can be seen, the +save+ action automatically invokes the event stored in
74
74
  # the +state_event+ attribute (<tt>:ignite</tt> in this case).
75
- #
75
+ #
76
76
  # One important note about using this technique for running transitions is
77
77
  # that if the class in which the state machine is defined *also* defines the
78
78
  # action being invoked (and not a superclass), then it must manually run the
79
79
  # StateMachine hook that checks for event attributes.
80
- #
80
+ #
81
81
  # For example, in ActiveRecord, DataMapper, Mongoid, MongoMapper, and Sequel,
82
82
  # the default action (+save+) is already defined in a base class. As a result,
83
83
  # when a state machine is defined in a model / resource, StateMachine can
84
84
  # automatically hook into the +save+ action.
85
- #
85
+ #
86
86
  # On the other hand, the Vehicle class from above defined its own +save+
87
87
  # method (and there is no +save+ method in its superclass). As a result, it
88
88
  # must be modified like so:
89
- #
89
+ #
90
90
  # def save
91
91
  # self.class.state_machines.transitions(self, :save).perform do
92
92
  # @saving_state = state
93
93
  # fail != true
94
94
  # end
95
95
  # end
96
- #
96
+ #
97
97
  # This will add in the functionality for firing the event stored in the
98
98
  # +state_event+ attribute.
99
- #
99
+ #
100
100
  # == Callbacks
101
- #
101
+ #
102
102
  # Callbacks are supported for hooking before and after every possible
103
103
  # transition in the machine. Each callback is invoked in the order in which
104
104
  # it was defined. See StateMachines::Machine#before_transition and
105
105
  # StateMachines::Machine#after_transition for documentation on how to define
106
106
  # new callbacks.
107
- #
107
+ #
108
108
  # *Note* that callbacks only get executed within the context of an event. As
109
109
  # a result, if a class has an initial state when it's created, any callbacks
110
110
  # that would normally get executed when the object enters that state will
111
111
  # *not* get triggered.
112
- #
112
+ #
113
113
  # For example,
114
- #
114
+ #
115
115
  # class Vehicle
116
- # state_machine :initial => :parked do
116
+ # state_machine initial: :parked do
117
117
  # after_transition all => :parked do
118
118
  # raise ArgumentError
119
119
  # end
120
120
  # ...
121
121
  # end
122
122
  # end
123
- #
123
+ #
124
124
  # vehicle = Vehicle.new # => #<Vehicle id: 1, state: "parked">
125
125
  # vehicle.save # => true (no exception raised)
126
- #
126
+ #
127
127
  # If you need callbacks to get triggered when an object is created, this
128
128
  # should be done by one of the following techniques:
129
129
  # * Use a <tt>before :create</tt> or equivalent hook:
130
- #
130
+ #
131
131
  # class Vehicle
132
132
  # before :create, :track_initial_transition
133
- #
133
+ #
134
134
  # state_machine do
135
135
  # ...
136
136
  # end
137
137
  # end
138
- #
138
+ #
139
139
  # * Set an initial state and use the correct event to create the
140
140
  # object with the proper state, resulting in callbacks being triggered and
141
141
  # the object getting persisted (note that the <tt>:pending</tt> state is
142
142
  # actually stored as nil):
143
- #
143
+ #
144
144
  # class Vehicle
145
- # state_machine :initial => :pending
146
- # after_transition :pending => :parked, :do => :track_initial_transition
147
- #
145
+ # state_machine initial: :pending
146
+ # after_transition pending: :parked, do: :track_initial_transition
147
+ #
148
148
  # event :park do
149
- # transition :pending => :parked
149
+ # transition pending: :parked
150
150
  # end
151
- #
152
- # state :pending, :value => nil
151
+ #
152
+ # state :pending, value: nil
153
153
  # end
154
154
  # end
155
- #
155
+ #
156
156
  # vehicle = Vehicle.new
157
157
  # vehicle.park
158
- #
158
+ #
159
159
  # * Use a default event attribute that will automatically trigger when the
160
160
  # configured action gets run (note that the <tt>:pending</tt> state is
161
161
  # actually stored as nil):
162
- #
162
+ #
163
163
  # class Vehicle < ActiveRecord::Base
164
- # state_machine :initial => :pending
165
- # after_transition :pending => :parked, :do => :track_initial_transition
166
- #
164
+ # state_machine initial: :pending
165
+ # after_transition pending: :parked, do: :track_initial_transition
166
+ #
167
167
  # event :park do
168
- # transition :pending => :parked
168
+ # transition pending: :parked
169
169
  # end
170
- #
171
- # state :pending, :value => nil
170
+ #
171
+ # state :pending, value: nil
172
172
  # end
173
- #
173
+ #
174
174
  # def initialize(*)
175
175
  # super
176
176
  # self.state_event = 'park'
177
177
  # end
178
178
  # end
179
- #
179
+ #
180
180
  # vehicle = Vehicle.new
181
181
  # vehicle.save
182
- #
182
+ #
183
183
  # === Canceling callbacks
184
- #
184
+ #
185
185
  # Callbacks can be canceled by throwing :halt at any point during the
186
186
  # callback. For example,
187
- #
187
+ #
188
188
  # ...
189
189
  # throw :halt
190
190
  # ...
191
- #
191
+ #
192
192
  # If a +before+ callback halts the chain, the associated transition and all
193
193
  # later callbacks are canceled. If an +after+ callback halts the chain,
194
194
  # the later callbacks are canceled, but the transition is still successful.
195
- #
195
+ #
196
196
  # These same rules apply to +around+ callbacks with the exception that any
197
197
  # +around+ callback that doesn't yield will essentially result in :halt being
198
198
  # thrown. Any code executed after the yield will behave in the same way as
199
199
  # +after+ callbacks.
200
- #
200
+ #
201
201
  # *Note* that if a +before+ callback fails and the bang version of an event
202
202
  # was invoked, an exception will be raised instead of returning false. For
203
203
  # example,
204
- #
204
+ #
205
205
  # class Vehicle
206
206
  # state_machine :initial => :parked do
207
207
  # before_transition any => :idling, :do => lambda {|vehicle| throw :halt}
208
208
  # ...
209
209
  # end
210
210
  # end
211
- #
211
+ #
212
212
  # vehicle = Vehicle.new
213
213
  # vehicle.park # => false
214
214
  # vehicle.park! # => StateMachines::InvalidTransition: Cannot transition state via :park from "idling"
215
- #
215
+ #
216
216
  # == Observers
217
- #
217
+ #
218
218
  # Observers, in the sense of external classes and *not* Ruby's Observable
219
219
  # mechanism, can hook into state machines as well. Such observers use the
220
220
  # same callback api that's used internally.
221
- #
221
+ #
222
222
  # Below are examples of defining observers for the following state machine:
223
- #
223
+ #
224
224
  # class Vehicle
225
225
  # state_machine do
226
226
  # event :park do
227
- # transition :idling => :parked
227
+ # transition idling: :parked
228
228
  # end
229
229
  # ...
230
230
  # end
231
231
  # ...
232
232
  # end
233
- #
233
+ #
234
234
  # Event/Transition behaviors:
235
- #
235
+ #
236
236
  # class VehicleObserver
237
237
  # def self.before_park(vehicle, transition)
238
238
  # logger.info "#{vehicle} instructed to park... state is: #{transition.from}, state will be: #{transition.to}"
239
239
  # end
240
- #
240
+ #
241
241
  # def self.after_park(vehicle, transition, result)
242
242
  # logger.info "#{vehicle} instructed to park... state was: #{transition.from}, state is: #{transition.to}"
243
243
  # end
244
- #
244
+ #
245
245
  # def self.before_transition(vehicle, transition)
246
246
  # logger.info "#{vehicle} instructed to #{transition.event}... #{transition.attribute} is: #{transition.from}, #{transition.attribute} will be: #{transition.to}"
247
247
  # end
248
- #
248
+ #
249
249
  # def self.after_transition(vehicle, transition)
250
250
  # logger.info "#{vehicle} instructed to #{transition.event}... #{transition.attribute} was: #{transition.from}, #{transition.attribute} is: #{transition.to}"
251
251
  # end
252
- #
252
+ #
253
253
  # def self.around_transition(vehicle, transition)
254
254
  # logger.info Benchmark.measure { yield }
255
255
  # end
256
256
  # end
257
- #
257
+ #
258
258
  # Vehicle.state_machine do
259
259
  # before_transition :on => :park, :do => VehicleObserver.method(:before_park)
260
260
  # before_transition VehicleObserver.method(:before_transition)
261
- #
261
+ #
262
262
  # after_transition :on => :park, :do => VehicleObserver.method(:after_park)
263
263
  # after_transition VehicleObserver.method(:after_transition)
264
- #
264
+ #
265
265
  # around_transition VehicleObserver.method(:around_transition)
266
266
  # end
267
- #
267
+ #
268
268
  # One common callback is to record transitions for all models in the system
269
269
  # for auditing/debugging purposes. Below is an example of an observer that
270
270
  # can easily automate this process for all models:
271
- #
271
+ #
272
272
  # class StateMachineObserver
273
273
  # def self.before_transition(object, transition)
274
274
  # Audit.log_transition(object.attributes)
275
275
  # end
276
276
  # end
277
- #
277
+ #
278
278
  # [Vehicle, Switch, Project].each do |klass|
279
279
  # klass.state_machines.each do |attribute, machine|
280
280
  # machine.before_transition StateMachineObserver.method(:before_transition)
281
281
  # end
282
282
  # end
283
- #
283
+ #
284
284
  # Additional observer-like behavior may be exposed by the various integrations
285
285
  # available. See below for more information on integrations.
286
- #
286
+ #
287
287
  # == Overriding instance / class methods
288
- #
288
+ #
289
289
  # Hooking in behavior to the generated instance / class methods from the
290
290
  # state machine, events, and states is very simple because of the way these
291
291
  # methods are generated on the class. Using the class's ancestors, the
292
292
  # original generated method can be referred to via +super+. For example,
293
- #
293
+ #
294
294
  # class Vehicle
295
295
  # state_machine do
296
296
  # event :park do
297
297
  # ...
298
298
  # end
299
299
  # end
300
- #
300
+ #
301
301
  # def park(*args)
302
302
  # logger.info "..."
303
303
  # super
304
304
  # end
305
305
  # end
306
- #
306
+ #
307
307
  # In the above example, the +park+ instance method that's generated on the
308
308
  # Vehicle class (by the associated event) is overridden with custom behavior.
309
309
  # Once this behavior is complete, the original method from the state machine
310
310
  # is invoked by simply calling +super+.
311
- #
311
+ #
312
312
  # The same technique can be used for +state+, +state_name+, and all other
313
313
  # instance *and* class methods on the Vehicle class.
314
314
  #
315
315
  # == Method conflicts
316
- #
316
+ #
317
317
  # By default state_machine does not redefine methods that exist on
318
318
  # superclasses (*including* Object) or any modules (*including* Kernel) that
319
319
  # were included before it was defined. This is in order to ensure that
320
320
  # existing behavior on the class is not broken by the inclusion of
321
321
  # state_machine.
322
- #
322
+ #
323
323
  # If a conflicting method is detected, state_machine will generate a warning.
324
324
  # For example, consider the following class:
325
- #
325
+ #
326
326
  # class Vehicle
327
327
  # state_machine do
328
328
  # event :open do
@@ -330,67 +330,67 @@ module StateMachines
330
330
  # end
331
331
  # end
332
332
  # end
333
- #
333
+ #
334
334
  # In the above class, an event named "open" is defined for its state machine.
335
335
  # However, "open" is already defined as an instance method in Ruby's Kernel
336
336
  # module that gets included in every Object. As a result, state_machine will
337
337
  # generate the following warning:
338
- #
338
+ #
339
339
  # Instance method "open" is already defined in Object, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true.
340
- #
340
+ #
341
341
  # Even though you may not be using Kernel's implementation of the "open"
342
342
  # instance method, state_machine isn't aware of this and, as a result, stays
343
343
  # safe and just skips redefining the method.
344
- #
344
+ #
345
345
  # As with almost all helpers methods defined by state_machine in your class,
346
346
  # there are generic methods available for working around this method conflict.
347
347
  # In the example above, you can invoke the "open" event like so:
348
- #
348
+ #
349
349
  # vehicle = Vehicle.new # => #<Vehicle:0xb72686b4 @state=nil>
350
350
  # vehicle.fire_events(:open) # => true
351
- #
351
+ #
352
352
  # # This will not work
353
353
  # vehicle.open # => NoMethodError: private method `open' called for #<Vehicle:0xb72686b4 @state=nil>
354
- #
354
+ #
355
355
  # If you want to take on the risk of overriding existing methods and just
356
356
  # ignore method conflicts altogether, you can do so by setting the following
357
357
  # configuration:
358
- #
358
+ #
359
359
  # StateMachines::Machine.ignore_method_conflicts = true
360
- #
360
+ #
361
361
  # This will allow you to define events like "open" as described above and
362
362
  # still generate the "open" instance helper method. For example:
363
- #
363
+ #
364
364
  # StateMachines::Machine.ignore_method_conflicts = true
365
- #
365
+ #
366
366
  # class Vehicle
367
367
  # state_machine do
368
368
  # event :open do
369
369
  # ...
370
370
  # end
371
371
  # end
372
- #
372
+ #
373
373
  # vehicle = Vehicle.new # => #<Vehicle:0xb72686b4 @state=nil>
374
374
  # vehicle.open # => true
375
- #
375
+ #
376
376
  # By default, state_machine helps prevent you from making mistakes and
377
377
  # accidentally overriding methods that you didn't intend to. Once you
378
378
  # understand this and what the consequences are, setting the
379
379
  # +ignore_method_conflicts+ option is a perfectly reasonable workaround.
380
- #
380
+ #
381
381
  # == Integrations
382
- #
382
+ #
383
383
  # By default, state machines are library-agnostic, meaning that they work
384
384
  # on any Ruby class and have no external dependencies. However, there are
385
385
  # certain libraries which expose additional behavior that can be taken
386
386
  # advantage of by state machines.
387
- #
387
+ #
388
388
  # This library is built to work out of the box with a few popular Ruby
389
389
  # libraries that allow for additional behavior to provide a cleaner and
390
390
  # smoother experience. This is especially the case for objects backed by a
391
391
  # database that may allow for transactions, persistent storage,
392
392
  # search/filters, callbacks, etc.
393
- #
393
+ #
394
394
  # When a state machine is defined for classes using any of the above libraries,
395
395
  # it will try to automatically determine the integration to use (Agnostic,
396
396
  # ActiveModel, ActiveRecord, DataMapper, Mongoid, MongoMapper, or Sequel)
@@ -405,12 +405,12 @@ module StateMachines
405
405
  class << self
406
406
  # Attempts to find or create a state machine for the given class. For
407
407
  # example,
408
- #
408
+ #
409
409
  # StateMachines::Machine.find_or_create(Vehicle)
410
410
  # StateMachines::Machine.find_or_create(Vehicle, :initial => :parked)
411
411
  # StateMachines::Machine.find_or_create(Vehicle, :status)
412
412
  # StateMachines::Machine.find_or_create(Vehicle, :status, :initial => :parked)
413
- #
413
+ #
414
414
  # If a machine of the given name already exists in one of the class's
415
415
  # superclasses, then a copy of that machine will be created and stored
416
416
  # in the new owner class (the original will remain unchanged).
@@ -452,9 +452,9 @@ module StateMachines
452
452
  attr_accessor :ignore_method_conflicts
453
453
  end
454
454
  @default_messages = {
455
- :invalid => 'is invalid',
456
- :invalid_event => 'cannot transition when %s',
457
- :invalid_transition => 'cannot transition via "%1$s"'
455
+ invalid: 'is invalid',
456
+ invalid_event: 'cannot transition when %s',
457
+ invalid_transition: 'cannot transition via "%1$s"'
458
458
  }
459
459
 
460
460
  # Whether to ignore any conflicts that are detected for helper methods that
@@ -479,12 +479,12 @@ module StateMachines
479
479
  # * Event transitions (:to, :from, and :except_from options)
480
480
  # * Transition callbacks (:to, :from, :except_to, and :except_from options)
481
481
  # * Unreferenced states (using +other_states+ helper)
482
- #
482
+ #
483
483
  # These are sorted, by default, in the order in which they were referenced.
484
484
  attr_reader :states
485
485
 
486
486
  # The callbacks to invoke before/after a transition is performed
487
- #
487
+ #
488
488
  # Maps :before => callbacks and :after => callbacks
489
489
  attr_reader :callbacks
490
490
 
@@ -517,14 +517,14 @@ module StateMachines
517
517
  end
518
518
 
519
519
  # Add machine-wide defaults
520
- options = {:use_transactions => true, :initialize => true}.merge(options)
520
+ options = {use_transactions: true, initialize: true}.merge(options)
521
521
 
522
522
  # Set machine configuration
523
523
  @name = args.first || :state
524
524
  @attribute = options[:attribute] || @name
525
525
  @events = EventCollection.new(self)
526
526
  @states = StateCollection.new(self)
527
- @callbacks = {:before => [], :after => [], :failure => []}
527
+ @callbacks = {before: [], after: [], failure: []}
528
528
  @namespace = options[:namespace]
529
529
  @messages = options[:messages] || {}
530
530
  @action = options[:action]
@@ -556,7 +556,7 @@ module StateMachines
556
556
  @events.machine = self
557
557
  @states = @states.dup
558
558
  @states.machine = self
559
- @callbacks = {:before => @callbacks[:before].dup, :after => @callbacks[:after].dup, :failure => @callbacks[:failure].dup}
559
+ @callbacks = {before: @callbacks[:before].dup, after: @callbacks[:after].dup, failure: @callbacks[:failure].dup}
560
560
  end
561
561
 
562
562
  # Sets the class which is the owner of this state machine. Any methods
@@ -566,7 +566,7 @@ module StateMachines
566
566
  @owner_class = klass
567
567
 
568
568
  # Create modules for extending the class with state/event-specific methods
569
- @helper_modules = helper_modules = {:instance => HelperModule.new(self, :instance), :class => HelperModule.new(self, :class)}
569
+ @helper_modules = helper_modules = {instance: HelperModule.new(self, :instance), class: HelperModule.new(self, :class)}
570
570
  owner_class.class_eval do
571
571
  extend helper_modules[:class]
572
572
  include helper_modules[:instance]
@@ -612,35 +612,35 @@ module StateMachines
612
612
  # Gets the initial state of the machine for the given object. If a dynamic
613
613
  # initial state was configured for this machine, then the object will be
614
614
  # passed into the lambda block to help determine the actual state.
615
- #
615
+ #
616
616
  # == Examples
617
- #
617
+ #
618
618
  # With a static initial state:
619
- #
619
+ #
620
620
  # class Vehicle
621
621
  # state_machine :initial => :parked do
622
622
  # ...
623
623
  # end
624
624
  # end
625
- #
625
+ #
626
626
  # vehicle = Vehicle.new
627
627
  # Vehicle.state_machine.initial_state(vehicle) # => #<StateMachines::State name=:parked value="parked" initial=true>
628
- #
628
+ #
629
629
  # With a dynamic initial state:
630
- #
630
+ #
631
631
  # class Vehicle
632
632
  # attr_accessor :force_idle
633
- #
633
+ #
634
634
  # state_machine :initial => lambda {|vehicle| vehicle.force_idle ? :idling : :parked} do
635
635
  # ...
636
636
  # end
637
637
  # end
638
- #
638
+ #
639
639
  # vehicle = Vehicle.new
640
- #
640
+ #
641
641
  # vehicle.force_idle = true
642
642
  # Vehicle.state_machine.initial_state(vehicle) # => #<StateMachines::State name=:idling value="idling" initial=false>
643
- #
643
+ #
644
644
  # vehicle.force_idle = false
645
645
  # Vehicle.state_machine.initial_state(vehicle) # => #<StateMachines::State name=:parked value="parked" initial=false>
646
646
  def initial_state(object)
@@ -654,7 +654,7 @@ module StateMachines
654
654
 
655
655
  # Initializes the state on the given object. Initial values are only set if
656
656
  # the machine's attribute hasn't been previously initialized.
657
- #
657
+ #
658
658
  # Configuration options:
659
659
  # * <tt>:force</tt> - Whether to initialize the state regardless of its
660
660
  # current value
@@ -665,7 +665,7 @@ module StateMachines
665
665
  if state && (options[:force] || initialize_state?(object))
666
666
  value = state.value
667
667
 
668
- if hash = options[:to]
668
+ if (hash = options[:to])
669
669
  hash[attribute.to_s] = value
670
670
  else
671
671
  write(object, :state, value)
@@ -682,61 +682,61 @@ module StateMachines
682
682
  # Defines a new helper method in an instance or class scope with the given
683
683
  # name. If the method is already defined in the scope, then this will not
684
684
  # override it.
685
- #
685
+ #
686
686
  # If passing in a block, there are two side effects to be aware of
687
687
  # 1. The method cannot be chained, meaning that the block cannot call +super+
688
688
  # 2. If the method is already defined in an ancestor, then it will not get
689
689
  # overridden and a warning will be output.
690
- #
690
+ #
691
691
  # Example:
692
- #
692
+ #
693
693
  # # Instance helper
694
694
  # machine.define_helper(:instance, :state_name) do |machine, object|
695
695
  # machine.states.match(object).name
696
696
  # end
697
- #
697
+ #
698
698
  # # Class helper
699
699
  # machine.define_helper(:class, :state_machine_name) do |machine, klass|
700
700
  # "State"
701
701
  # end
702
- #
702
+ #
703
703
  # You can also define helpers using string evaluation like so:
704
- #
704
+ #
705
705
  # # Instance helper
706
706
  # machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
707
707
  # def state_name
708
708
  # self.class.state_machine(:state).states.match(self).name
709
709
  # end
710
710
  # end_eval
711
- #
711
+ #
712
712
  # # Class helper
713
713
  # machine.define_helper :class, <<-end_eval, __FILE__, __LINE__ + 1
714
714
  # def state_machine_name
715
715
  # "State"
716
716
  # end
717
717
  # end_eval
718
- def define_helper(scope, method, *args, &block)
718
+ def define_helper(scope, method, *args, **kwargs, &block)
719
719
  helper_module = @helper_modules.fetch(scope)
720
720
 
721
721
  if block_given?
722
- if !self.class.ignore_method_conflicts && conflicting_ancestor = owner_class_ancestor_has_method?(scope, method)
722
+ if !self.class.ignore_method_conflicts && (conflicting_ancestor = owner_class_ancestor_has_method?(scope, method))
723
723
  ancestor_name = conflicting_ancestor.name && !conflicting_ancestor.name.empty? ? conflicting_ancestor.name : conflicting_ancestor.to_s
724
724
  warn "#{scope == :class ? 'Class' : 'Instance'} method \"#{method}\" is already defined in #{ancestor_name}, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true."
725
725
  else
726
726
  name = self.name
727
727
  helper_module.class_eval do
728
- define_method(method) do |*block_args|
729
- block.call((scope == :instance ? self.class : self).state_machine(name), self, *block_args)
728
+ define_method(method) do |*block_args, **block_kwargs|
729
+ block.call((scope == :instance ? self.class : self).state_machine(name), self, *block_args, **block_kwargs)
730
730
  end
731
731
  end
732
732
  end
733
733
  else
734
- helper_module.class_eval(method, *args)
734
+ helper_module.class_eval(method, *args, **kwargs)
735
735
  end
736
736
  end
737
737
 
738
738
  # Customizes the definition of one or more states in the machine.
739
- #
739
+ #
740
740
  # Configuration options:
741
741
  # * <tt>:value</tt> - The actual value to store when an object transitions
742
742
  # to the state. Default is the name (stringified).
@@ -748,13 +748,13 @@ module StateMachines
748
748
  # * <tt>:human_name</tt> - The human-readable version of this state's name.
749
749
  # By default, this is either defined by the integration or stringifies the
750
750
  # name and converts underscores to spaces.
751
- #
751
+ #
752
752
  # == Customizing the stored value
753
- #
753
+ #
754
754
  # Whenever a state is automatically discovered in the state machine, its
755
755
  # default value is assumed to be the stringified version of the name. For
756
756
  # example,
757
- #
757
+ #
758
758
  # class Vehicle
759
759
  # state_machine :initial => :parked do
760
760
  # event :ignite do
@@ -762,124 +762,124 @@ module StateMachines
762
762
  # end
763
763
  # end
764
764
  # end
765
- #
765
+ #
766
766
  # In the above state machine, there are two states automatically discovered:
767
767
  # :parked and :idling. These states, by default, will store their stringified
768
768
  # equivalents when an object moves into that state (e.g. "parked" / "idling").
769
- #
769
+ #
770
770
  # For legacy systems or when tying state machines into existing frameworks,
771
771
  # it's oftentimes necessary to need to store a different value for a state
772
772
  # than the default. In order to continue taking advantage of an expressive
773
773
  # state machine and helper methods, every defined state can be re-configured
774
774
  # with a custom stored value. For example,
775
- #
775
+ #
776
776
  # class Vehicle
777
777
  # state_machine :initial => :parked do
778
778
  # event :ignite do
779
779
  # transition :parked => :idling
780
780
  # end
781
- #
781
+ #
782
782
  # state :idling, :value => 'IDLING'
783
783
  # state :parked, :value => 'PARKED
784
784
  # end
785
785
  # end
786
- #
786
+ #
787
787
  # This is also useful if being used in association with a database and,
788
788
  # instead of storing the state name in a column, you want to store the
789
789
  # state's foreign key:
790
- #
790
+ #
791
791
  # class VehicleState < ActiveRecord::Base
792
792
  # end
793
- #
793
+ #
794
794
  # class Vehicle < ActiveRecord::Base
795
795
  # state_machine :attribute => :state_id, :initial => :parked do
796
796
  # event :ignite do
797
797
  # transition :parked => :idling
798
798
  # end
799
- #
799
+ #
800
800
  # states.each do |state|
801
801
  # self.state(state.name, :value => lambda { VehicleState.find_by_name(state.name.to_s).id }, :cache => true)
802
802
  # end
803
803
  # end
804
804
  # end
805
- #
805
+ #
806
806
  # In the above example, each known state is configured to store it's
807
807
  # associated database id in the +state_id+ attribute. Also, notice that a
808
808
  # lambda block is used to define the state's value. This is required in
809
809
  # situations (like testing) where the model is loaded without any existing
810
810
  # data (i.e. no VehicleState records available).
811
- #
811
+ #
812
812
  # One caveat to the above example is to keep performance in mind. To avoid
813
813
  # constant db hits for looking up the VehicleState ids, the value is cached
814
814
  # by specifying the <tt>:cache</tt> option. Alternatively, a custom
815
815
  # caching strategy can be used like so:
816
- #
816
+ #
817
817
  # class VehicleState < ActiveRecord::Base
818
818
  # cattr_accessor :cache_store
819
819
  # self.cache_store = ActiveSupport::Cache::MemoryStore.new
820
- #
820
+ #
821
821
  # def self.find_by_name(name)
822
822
  # cache_store.fetch(name) { find(:first, :conditions => {:name => name}) }
823
823
  # end
824
824
  # end
825
- #
825
+ #
826
826
  # === Dynamic values
827
- #
827
+ #
828
828
  # In addition to customizing states with other value types, lambda blocks
829
829
  # can also be specified to allow for a state's value to be determined
830
830
  # dynamically at runtime. For example,
831
- #
831
+ #
832
832
  # class Vehicle
833
833
  # state_machine :purchased_at, :initial => :available do
834
834
  # event :purchase do
835
835
  # transition all => :purchased
836
836
  # end
837
- #
837
+ #
838
838
  # event :restock do
839
839
  # transition all => :available
840
840
  # end
841
- #
841
+ #
842
842
  # state :available, :value => nil
843
843
  # state :purchased, :if => lambda {|value| !value.nil?}, :value => lambda {Time.now}
844
844
  # end
845
845
  # end
846
- #
846
+ #
847
847
  # In the above definition, the <tt>:purchased</tt> state is customized with
848
848
  # both a dynamic value *and* a value matcher.
849
- #
849
+ #
850
850
  # When an object transitions to the purchased state, the value's lambda
851
851
  # block will be called. This will get the current time and store it in the
852
852
  # object's +purchased_at+ attribute.
853
- #
853
+ #
854
854
  # *Note* that the custom matcher is very important here. Since there's no
855
855
  # way for the state machine to figure out an object's state when it's set to
856
856
  # a runtime value, it must be explicitly defined. If the <tt>:if</tt> option
857
857
  # were not configured for the state, then an ArgumentError exception would
858
858
  # be raised at runtime, indicating that the state machine could not figure
859
859
  # out what the current state of the object was.
860
- #
860
+ #
861
861
  # == Behaviors
862
- #
862
+ #
863
863
  # Behaviors define a series of methods to mixin with objects when the current
864
864
  # state matches the given one(s). This allows instance methods to behave
865
865
  # a specific way depending on what the value of the object's state is.
866
- #
866
+ #
867
867
  # For example,
868
- #
868
+ #
869
869
  # class Vehicle
870
870
  # attr_accessor :driver
871
871
  # attr_accessor :passenger
872
- #
872
+ #
873
873
  # state_machine :initial => :parked do
874
874
  # event :ignite do
875
875
  # transition :parked => :idling
876
876
  # end
877
- #
877
+ #
878
878
  # state :parked do
879
879
  # def speed
880
880
  # 0
881
881
  # end
882
- #
882
+ #
883
883
  # def rotate_driver
884
884
  # driver = self.driver
885
885
  # self.driver = passenger
@@ -887,97 +887,97 @@ module StateMachines
887
887
  # true
888
888
  # end
889
889
  # end
890
- #
890
+ #
891
891
  # state :idling, :first_gear do
892
892
  # def speed
893
893
  # 20
894
894
  # end
895
- #
895
+ #
896
896
  # def rotate_driver
897
897
  # self.state = 'parked'
898
898
  # rotate_driver
899
899
  # end
900
900
  # end
901
- #
901
+ #
902
902
  # other_states :backing_up
903
903
  # end
904
904
  # end
905
- #
905
+ #
906
906
  # In the above example, there are two dynamic behaviors defined for the
907
907
  # class:
908
908
  # * +speed+
909
909
  # * +rotate_driver+
910
- #
910
+ #
911
911
  # Each of these behaviors are instance methods on the Vehicle class. However,
912
912
  # which method actually gets invoked is based on the current state of the
913
913
  # object. Using the above class as the example:
914
- #
914
+ #
915
915
  # vehicle = Vehicle.new
916
916
  # vehicle.driver = 'John'
917
917
  # vehicle.passenger = 'Jane'
918
- #
918
+ #
919
919
  # # Behaviors in the "parked" state
920
920
  # vehicle.state # => "parked"
921
921
  # vehicle.speed # => 0
922
922
  # vehicle.rotate_driver # => true
923
923
  # vehicle.driver # => "Jane"
924
924
  # vehicle.passenger # => "John"
925
- #
925
+ #
926
926
  # vehicle.ignite # => true
927
- #
927
+ #
928
928
  # # Behaviors in the "idling" state
929
929
  # vehicle.state # => "idling"
930
930
  # vehicle.speed # => 20
931
931
  # vehicle.rotate_driver # => true
932
932
  # vehicle.driver # => "John"
933
933
  # vehicle.passenger # => "Jane"
934
- #
934
+ #
935
935
  # As can be seen, both the +speed+ and +rotate_driver+ instance method
936
936
  # implementations changed how they behave based on what the current state
937
937
  # of the vehicle was.
938
- #
938
+ #
939
939
  # === Invalid behaviors
940
- #
940
+ #
941
941
  # If a specific behavior has not been defined for a state, then a
942
942
  # NoMethodError exception will be raised, indicating that that method would
943
943
  # not normally exist for an object with that state.
944
- #
944
+ #
945
945
  # Using the example from before:
946
- #
946
+ #
947
947
  # vehicle = Vehicle.new
948
948
  # vehicle.state = 'backing_up'
949
949
  # vehicle.speed # => NoMethodError: undefined method 'speed' for #<Vehicle:0xb7d296ac> in state "backing_up"
950
- #
950
+ #
951
951
  # === Using matchers
952
- #
952
+ #
953
953
  # The +all+ / +any+ matchers can be used to easily define behaviors for a
954
954
  # group of states. Note, however, that you cannot use these matchers to
955
955
  # set configurations for states. Behaviors using these matchers can be
956
956
  # defined at any point in the state machine and will always get applied to
957
957
  # the proper states.
958
- #
958
+ #
959
959
  # For example:
960
- #
960
+ #
961
961
  # state_machine :initial => :parked do
962
962
  # ...
963
- #
963
+ #
964
964
  # state all - [:parked, :idling, :stalled] do
965
965
  # validates_presence_of :speed
966
- #
966
+ #
967
967
  # def speed
968
968
  # gear * 10
969
969
  # end
970
970
  # end
971
971
  # end
972
- #
972
+ #
973
973
  # == State-aware class methods
974
- #
974
+ #
975
975
  # In addition to defining scopes for instance methods that are state-aware,
976
976
  # the same can be done for certain types of class methods.
977
- #
977
+ #
978
978
  # Some libraries have support for class-level methods that only run certain
979
979
  # behaviors based on a conditions hash passed in. For example:
980
- #
980
+ #
981
981
  # class Vehicle < ActiveRecord::Base
982
982
  # state_machine do
983
983
  # ...
@@ -987,19 +987,19 @@ module StateMachines
987
987
  # end
988
988
  # end
989
989
  # end
990
- #
990
+ #
991
991
  # In the above ActiveRecord model, two validations have been defined which
992
992
  # will *only* run when the Vehicle object is in one of the three states:
993
993
  # +first_gear+, +second_gear+, or +third_gear. Notice, also, that if/unless
994
994
  # conditions can continue to be used.
995
- #
995
+ #
996
996
  # This functionality is not library-specific and can work for any class-level
997
997
  # method that is defined like so:
998
- #
998
+ #
999
999
  # def validates_presence_of(attribute, options = {})
1000
1000
  # ...
1001
1001
  # end
1002
- #
1002
+ #
1003
1003
  # The minimum requirement is that the last argument in the method be an
1004
1004
  # options hash which contains at least <tt>:if</tt> condition support.
1005
1005
  def state(*names, &block)
@@ -1014,6 +1014,7 @@ module StateMachines
1014
1014
  # Add any states referenced in the matcher. When matchers are used,
1015
1015
  # states are not allowed to be configured.
1016
1016
  raise ArgumentError, "Cannot configure states when using matchers (using #{options.inspect})" if options.any?
1017
+
1017
1018
  states = add_states(names.first.values)
1018
1019
  else
1019
1020
  states = add_states(names)
@@ -1037,15 +1038,15 @@ module StateMachines
1037
1038
  alias_method :other_states, :state
1038
1039
 
1039
1040
  # Gets the current value stored in the given object's attribute.
1040
- #
1041
+ #
1041
1042
  # For example,
1042
- #
1043
+ #
1043
1044
  # class Vehicle
1044
1045
  # state_machine :initial => :parked do
1045
1046
  # ...
1046
1047
  # end
1047
1048
  # end
1048
- #
1049
+ #
1049
1050
  # vehicle = Vehicle.new # => #<Vehicle:0xb7d94ab0 @state="parked">
1050
1051
  # Vehicle.state_machine.read(vehicle, :state) # => "parked" # Equivalent to vehicle.state
1051
1052
  # Vehicle.state_machine.read(vehicle, :event) # => nil # Equivalent to vehicle.state_event
@@ -1059,15 +1060,15 @@ module StateMachines
1059
1060
  end
1060
1061
 
1061
1062
  # Sets a new value in the given object's attribute.
1062
- #
1063
+ #
1063
1064
  # For example,
1064
- #
1065
+ #
1065
1066
  # class Vehicle
1066
1067
  # state_machine :initial => :parked do
1067
1068
  # ...
1068
1069
  # end
1069
1070
  # end
1070
- #
1071
+ #
1071
1072
  # vehicle = Vehicle.new # => #<Vehicle:0xb7d94ab0 @state="parked">
1072
1073
  # Vehicle.state_machine.write(vehicle, :state, 'idling') # => Equivalent to vehicle.state = 'idling'
1073
1074
  # Vehicle.state_machine.write(vehicle, :event, 'park') # => Equivalent to vehicle.state_event = 'park'
@@ -1080,17 +1081,17 @@ module StateMachines
1080
1081
 
1081
1082
  # Defines one or more events for the machine and the transitions that can
1082
1083
  # be performed when those events are run.
1083
- #
1084
+ #
1084
1085
  # This method is also aliased as +on+ for improved compatibility with
1085
1086
  # using a domain-specific language.
1086
- #
1087
+ #
1087
1088
  # Configuration options:
1088
1089
  # * <tt>:human_name</tt> - The human-readable version of this event's name.
1089
1090
  # By default, this is either defined by the integration or stringifies the
1090
1091
  # name and converts underscores to spaces.
1091
- #
1092
+ #
1092
1093
  # == Instance methods
1093
- #
1094
+ #
1094
1095
  # The following instance methods are generated when a new event is defined
1095
1096
  # (the "park" event is used as an example):
1096
1097
  # * <tt>park(..., run_action = true)</tt> - Fires the "park" event,
@@ -1114,13 +1115,13 @@ module StateMachines
1114
1115
  # object or nil if no transitions can be performed. Like <tt>can_park?</tt>
1115
1116
  # this will also *not* run validations or callbacks. It will only
1116
1117
  # determine if the state machine defines a valid transition for the event.
1117
- #
1118
+ #
1118
1119
  # With a namespace of "car", the above names map to the following methods:
1119
1120
  # * <tt>can_park_car?</tt>
1120
1121
  # * <tt>park_car_transition</tt>
1121
1122
  # * <tt>park_car</tt>
1122
1123
  # * <tt>park_car!</tt>
1123
- #
1124
+ #
1124
1125
  # The <tt>can_park?</tt> and <tt>park_transition</tt> helpers both take an
1125
1126
  # optional set of requirements for determining what transitions are available
1126
1127
  # for the current object. These requirements include:
@@ -1130,58 +1131,58 @@ module StateMachines
1130
1131
  # specified, then this will match any to state.
1131
1132
  # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
1132
1133
  # conditionals defined for each one. Default is true.
1133
- #
1134
+ #
1134
1135
  # == Defining transitions
1135
- #
1136
+ #
1136
1137
  # +event+ requires a block which allows you to define the possible
1137
1138
  # transitions that can happen as a result of that event. For example,
1138
- #
1139
+ #
1139
1140
  # event :park, :stop do
1140
1141
  # transition :idling => :parked
1141
1142
  # end
1142
- #
1143
+ #
1143
1144
  # event :first_gear do
1144
1145
  # transition :parked => :first_gear, :if => :seatbelt_on?
1145
1146
  # transition :parked => same # Allow to loopback if seatbelt is off
1146
1147
  # end
1147
- #
1148
+ #
1148
1149
  # See StateMachines::Event#transition for more information on
1149
1150
  # the possible options that can be passed in.
1150
- #
1151
+ #
1151
1152
  # *Note* that this block is executed within the context of the actual event
1152
1153
  # object. As a result, you will not be able to reference any class methods
1153
1154
  # on the model without referencing the class itself. For example,
1154
- #
1155
+ #
1155
1156
  # class Vehicle
1156
1157
  # def self.safe_states
1157
1158
  # [:parked, :idling, :stalled]
1158
1159
  # end
1159
- #
1160
+ #
1160
1161
  # state_machine do
1161
1162
  # event :park do
1162
1163
  # transition Vehicle.safe_states => :parked
1163
1164
  # end
1164
1165
  # end
1165
- # end
1166
- #
1166
+ # end
1167
+ #
1167
1168
  # == Overriding the event method
1168
- #
1169
+ #
1169
1170
  # By default, this will define an instance method (with the same name as the
1170
1171
  # event) that will fire the next possible transition for that. Although the
1171
1172
  # +before_transition+, +after_transition+, and +around_transition+ hooks
1172
1173
  # allow you to define behavior that gets executed as a result of the event's
1173
1174
  # transition, you can also override the event method in order to have a
1174
1175
  # little more fine-grained control.
1175
- #
1176
+ #
1176
1177
  # For example:
1177
- #
1178
+ #
1178
1179
  # class Vehicle
1179
1180
  # state_machine do
1180
1181
  # event :park do
1181
1182
  # ...
1182
1183
  # end
1183
1184
  # end
1184
- #
1185
+ #
1185
1186
  # def park(*)
1186
1187
  # take_deep_breath # Executes before the transition (and before_transition hooks) even if no transition is possible
1187
1188
  # if result = super # Runs the transition and all before/after/around hooks
@@ -1190,33 +1191,33 @@ module StateMachines
1190
1191
  # result
1191
1192
  # end
1192
1193
  # end
1193
- #
1194
+ #
1194
1195
  # There are a few important things to note here. First, the method
1195
1196
  # signature is defined with an unlimited argument list in order to allow
1196
1197
  # callers to continue passing arguments that are expected by state_machine.
1197
1198
  # For example, it will still allow calls to +park+ with a single parameter
1198
1199
  # for skipping the configured action.
1199
- #
1200
+ #
1200
1201
  # Second, the overridden event method must call +super+ in order to run the
1201
1202
  # logic for running the next possible transition. In order to remain
1202
1203
  # consistent with other events, the result of +super+ is returned.
1203
- #
1204
+ #
1204
1205
  # Third, any behavior defined in this method will *not* get executed if
1205
1206
  # you're taking advantage of attribute-based event transitions. For example:
1206
- #
1207
+ #
1207
1208
  # vehicle = Vehicle.new
1208
1209
  # vehicle.state_event = 'park'
1209
1210
  # vehicle.save
1210
- #
1211
+ #
1211
1212
  # In this case, the +park+ event will run the before/after/around transition
1212
1213
  # hooks and transition the state, but the behavior defined in the overriden
1213
1214
  # +park+ method will *not* be executed.
1214
- #
1215
+ #
1215
1216
  # == Defining additional arguments
1216
- #
1217
+ #
1217
1218
  # Additional arguments can be passed into events and accessed by transition
1218
1219
  # hooks like so:
1219
- #
1220
+ #
1220
1221
  # class Vehicle
1221
1222
  # state_machine do
1222
1223
  # after_transition :on => :park do |vehicle, transition|
@@ -1224,80 +1225,80 @@ module StateMachines
1224
1225
  # ...
1225
1226
  # end
1226
1227
  # after_transition :on => :park, :do => :take_deep_breath
1227
- #
1228
+ #
1228
1229
  # event :park do
1229
1230
  # ...
1230
1231
  # end
1231
- #
1232
+ #
1232
1233
  # def take_deep_breath(transition)
1233
1234
  # kind = *transition.args # :parallel
1234
1235
  # ...
1235
1236
  # end
1236
1237
  # end
1237
1238
  # end
1238
- #
1239
+ #
1239
1240
  # vehicle = Vehicle.new
1240
1241
  # vehicle.park(:parallel)
1241
- #
1242
+ #
1242
1243
  # *Remember* that if the last argument is a boolean, it will be used as the
1243
1244
  # +run_action+ parameter to the event action. Using the +park+ action
1244
1245
  # example from above, you can might call it like so:
1245
- #
1246
+ #
1246
1247
  # vehicle.park # => Uses default args and runs machine action
1247
1248
  # vehicle.park(:parallel) # => Specifies the +kind+ argument and runs the machine action
1248
1249
  # vehicle.park(:parallel, false) # => Specifies the +kind+ argument and *skips* the machine action
1249
- #
1250
+ #
1250
1251
  # If you decide to override the +park+ event method *and* define additional
1251
1252
  # arguments, you can do so as shown below:
1252
- #
1253
+ #
1253
1254
  # class Vehicle
1254
1255
  # state_machine do
1255
1256
  # event :park do
1256
1257
  # ...
1257
1258
  # end
1258
1259
  # end
1259
- #
1260
+ #
1260
1261
  # def park(kind = :parallel, *args)
1261
1262
  # take_deep_breath if kind == :parallel
1262
1263
  # super
1263
1264
  # end
1264
1265
  # end
1265
- #
1266
+ #
1266
1267
  # Note that +super+ is called instead of <tt>super(*args)</tt>. This allow
1267
1268
  # the entire arguments list to be accessed by transition callbacks through
1268
1269
  # StateMachines::Transition#args.
1269
- #
1270
+ #
1270
1271
  # === Using matchers
1271
- #
1272
+ #
1272
1273
  # The +all+ / +any+ matchers can be used to easily execute blocks for a
1273
1274
  # group of events. Note, however, that you cannot use these matchers to
1274
1275
  # set configurations for events. Blocks using these matchers can be
1275
1276
  # defined at any point in the state machine and will always get applied to
1276
1277
  # the proper events.
1277
- #
1278
+ #
1278
1279
  # For example:
1279
- #
1280
+ #
1280
1281
  # state_machine :initial => :parked do
1281
1282
  # ...
1282
- #
1283
+ #
1283
1284
  # event all - [:crash] do
1284
1285
  # transition :stalled => :parked
1285
1286
  # end
1286
1287
  # end
1287
- #
1288
+ #
1288
1289
  # == Example
1289
- #
1290
+ #
1290
1291
  # class Vehicle
1291
1292
  # state_machine do
1292
1293
  # # The park, stop, and halt events will all share the given transitions
1293
1294
  # event :park, :stop, :halt do
1294
1295
  # transition [:idling, :backing_up] => :parked
1295
1296
  # end
1296
- #
1297
+ #
1297
1298
  # event :stop do
1298
1299
  # transition :first_gear => :idling
1299
1300
  # end
1300
- #
1301
+ #
1301
1302
  # event :ignite do
1302
1303
  # transition :parked => :idling
1303
1304
  # transition :idling => same # Allow ignite while still idling
@@ -1316,6 +1317,7 @@ module StateMachines
1316
1317
  # Add any events referenced in the matcher. When matchers are used,
1317
1318
  # events are not allowed to be configured.
1318
1319
  raise ArgumentError, "Cannot configure events when using matchers (using #{options.inspect})" if options.any?
1320
+
1319
1321
  events = add_events(names.first.values)
1320
1322
  else
1321
1323
  events = add_events(names)
@@ -1336,45 +1338,45 @@ module StateMachines
1336
1338
 
1337
1339
  # Creates a new transition that determines what to change the current state
1338
1340
  # to when an event fires.
1339
- #
1341
+ #
1340
1342
  # == Defining transitions
1341
- #
1343
+ #
1342
1344
  # The options for a new transition uses the Hash syntax to map beginning
1343
1345
  # states to ending states. For example,
1344
- #
1346
+ #
1345
1347
  # transition :parked => :idling, :idling => :first_gear, :on => :ignite
1346
- #
1348
+ #
1347
1349
  # In this case, when the +ignite+ event is fired, this transition will cause
1348
1350
  # the state to be +idling+ if it's current state is +parked+ or +first_gear+
1349
1351
  # if it's current state is +idling+.
1350
- #
1352
+ #
1351
1353
  # To help define these implicit transitions, a set of helpers are available
1352
1354
  # for slightly more complex matching:
1353
1355
  # * <tt>all</tt> - Matches every state in the machine
1354
1356
  # * <tt>all - [:parked, :idling, ...]</tt> - Matches every state except those specified
1355
1357
  # * <tt>any</tt> - An alias for +all+ (matches every state in the machine)
1356
1358
  # * <tt>same</tt> - Matches the same state being transitioned from
1357
- #
1359
+ #
1358
1360
  # See StateMachines::MatcherHelpers for more information.
1359
- #
1361
+ #
1360
1362
  # Examples:
1361
- #
1363
+ #
1362
1364
  # transition all => nil, :on => :ignite # Transitions to nil regardless of the current state
1363
1365
  # transition all => :idling, :on => :ignite # Transitions to :idling regardless of the current state
1364
1366
  # transition all - [:idling, :first_gear] => :idling, :on => :ignite # Transitions every state but :idling and :first_gear to :idling
1365
1367
  # transition nil => :idling, :on => :ignite # Transitions to :idling from the nil state
1366
1368
  # transition :parked => :idling, :on => :ignite # Transitions to :idling if :parked
1367
1369
  # transition [:parked, :stalled] => :idling, :on => :ignite # Transitions to :idling if :parked or :stalled
1368
- #
1370
+ #
1369
1371
  # transition :parked => same, :on => :park # Loops :parked back to :parked
1370
1372
  # transition [:parked, :stalled] => same, :on => [:park, :stall] # Loops either :parked or :stalled back to the same state on the park and stall events
1371
1373
  # transition all - :parked => same, :on => :noop # Loops every state but :parked back to the same state
1372
- #
1374
+ #
1373
1375
  # # Transitions to :idling if :parked, :first_gear if :idling, or :second_gear if :first_gear
1374
1376
  # transition :parked => :idling, :idling => :first_gear, :first_gear => :second_gear, :on => :shift_up
1375
- #
1377
+ #
1376
1378
  # == Verbose transitions
1377
- #
1379
+ #
1378
1380
  # Transitions can also be defined use an explicit set of configuration
1379
1381
  # options:
1380
1382
  # * <tt>:from</tt> - A state or array of states that can be transitioned from.
@@ -1383,24 +1385,24 @@ module StateMachines
1383
1385
  # then the transition will simply loop back (i.e. the state will not change).
1384
1386
  # * <tt>:except_from</tt> - A state or array of states that *cannot* be
1385
1387
  # transitioned from.
1386
- #
1388
+ #
1387
1389
  # These options must be used when defining transitions within the context
1388
1390
  # of a state.
1389
- #
1391
+ #
1390
1392
  # Examples:
1391
- #
1393
+ #
1392
1394
  # transition :to => nil, :on => :park
1393
1395
  # transition :to => :idling, :on => :ignite
1394
1396
  # transition :except_from => [:idling, :first_gear], :to => :idling, :on => :ignite
1395
1397
  # transition :from => nil, :to => :idling, :on => :ignite
1396
1398
  # transition :from => [:parked, :stalled], :to => :idling, :on => :ignite
1397
- #
1399
+ #
1398
1400
  # == Conditions
1399
- #
1401
+ #
1400
1402
  # In addition to the state requirements for each transition, a condition
1401
1403
  # can also be defined to help determine whether that transition is
1402
1404
  # available. These options will work on both the normal and verbose syntax.
1403
- #
1405
+ #
1404
1406
  # Configuration options:
1405
1407
  # * <tt>:if</tt> - A method, proc or string to call to determine if the
1406
1408
  # transition should occur (e.g. :if => :moving?, or :if => lambda {|vehicle| vehicle.speed > 60}).
@@ -1408,18 +1410,18 @@ module StateMachines
1408
1410
  # * <tt>:unless</tt> - A method, proc or string to call to determine if the
1409
1411
  # transition should not occur (e.g. :unless => :stopped?, or :unless => lambda {|vehicle| vehicle.speed <= 60}).
1410
1412
  # The condition should return or evaluate to true or false.
1411
- #
1413
+ #
1412
1414
  # Examples:
1413
- #
1415
+ #
1414
1416
  # transition :parked => :idling, :on => :ignite, :if => :moving?
1415
1417
  # transition :parked => :idling, :on => :ignite, :unless => :stopped?
1416
1418
  # transition :idling => :first_gear, :first_gear => :second_gear, :on => :shift_up, :if => :seatbelt_on?
1417
- #
1419
+ #
1418
1420
  # transition :from => :parked, :to => :idling, :on => ignite, :if => :moving?
1419
1421
  # transition :from => :parked, :to => :idling, :on => ignite, :unless => :stopped?
1420
- #
1422
+ #
1421
1423
  # == Order of operations
1422
- #
1424
+ #
1423
1425
  # Transitions are evaluated in the order in which they're defined. As a
1424
1426
  # result, if more than one transition applies to a given object, then the
1425
1427
  # first transition that matches will be performed.
@@ -1435,12 +1437,12 @@ module StateMachines
1435
1437
 
1436
1438
  # Creates a callback that will be invoked *before* a transition is
1437
1439
  # performed so long as the given requirements match the transition.
1438
- #
1440
+ #
1439
1441
  # == The callback
1440
- #
1442
+ #
1441
1443
  # Callbacks must be defined as either an argument, in the :do option, or
1442
1444
  # as a block. For example,
1443
- #
1445
+ #
1444
1446
  # class Vehicle
1445
1447
  # state_machine do
1446
1448
  # before_transition :set_alarm
@@ -1452,13 +1454,13 @@ module StateMachines
1452
1454
  # ...
1453
1455
  # end
1454
1456
  # end
1455
- #
1457
+ #
1456
1458
  # Notice that the first three callbacks are the same in terms of how the
1457
1459
  # methods to invoke are defined. However, using the <tt>:do</tt> can
1458
1460
  # provide for a more fluid DSL.
1459
- #
1461
+ #
1460
1462
  # In addition, multiple callbacks can be defined like so:
1461
- #
1463
+ #
1462
1464
  # class Vehicle
1463
1465
  # state_machine do
1464
1466
  # before_transition :set_alarm, :lock_doors, all => :parked
@@ -1468,54 +1470,54 @@ module StateMachines
1468
1470
  # end
1469
1471
  # end
1470
1472
  # end
1471
- #
1473
+ #
1472
1474
  # Notice that the different ways of configuring methods can be mixed.
1473
- #
1475
+ #
1474
1476
  # == State requirements
1475
- #
1477
+ #
1476
1478
  # Callbacks can require that the machine be transitioning from and to
1477
1479
  # specific states. These requirements use a Hash syntax to map beginning
1478
1480
  # states to ending states. For example,
1479
- #
1481
+ #
1480
1482
  # before_transition :parked => :idling, :idling => :first_gear, :do => :set_alarm
1481
- #
1483
+ #
1482
1484
  # In this case, the +set_alarm+ callback will only be called if the machine
1483
1485
  # is transitioning from +parked+ to +idling+ or from +idling+ to +parked+.
1484
- #
1486
+ #
1485
1487
  # To help define state requirements, a set of helpers are available for
1486
1488
  # slightly more complex matching:
1487
1489
  # * <tt>all</tt> - Matches every state/event in the machine
1488
1490
  # * <tt>all - [:parked, :idling, ...]</tt> - Matches every state/event except those specified
1489
1491
  # * <tt>any</tt> - An alias for +all+ (matches every state/event in the machine)
1490
1492
  # * <tt>same</tt> - Matches the same state being transitioned from
1491
- #
1493
+ #
1492
1494
  # See StateMachines::MatcherHelpers for more information.
1493
- #
1495
+ #
1494
1496
  # Examples:
1495
- #
1497
+ #
1496
1498
  # before_transition :parked => [:idling, :first_gear], :do => ... # Matches from parked to idling or first_gear
1497
1499
  # before_transition all - [:parked, :idling] => :idling, :do => ... # Matches from every state except parked and idling to idling
1498
1500
  # before_transition all => :parked, :do => ... # Matches all states to parked
1499
1501
  # before_transition any => same, :do => ... # Matches every loopback
1500
- #
1502
+ #
1501
1503
  # == Event requirements
1502
- #
1504
+ #
1503
1505
  # In addition to state requirements, an event requirement can be defined so
1504
1506
  # that the callback is only invoked on specific events using the +on+
1505
1507
  # option. This can also use the same matcher helpers as the state
1506
1508
  # requirements.
1507
- #
1509
+ #
1508
1510
  # Examples:
1509
- #
1511
+ #
1510
1512
  # before_transition :on => :ignite, :do => ... # Matches only on ignite
1511
1513
  # before_transition :on => all - :ignite, :do => ... # Matches on every event except ignite
1512
1514
  # before_transition :parked => :idling, :on => :ignite, :do => ... # Matches from parked to idling on ignite
1513
- #
1515
+ #
1514
1516
  # == Verbose Requirements
1515
- #
1517
+ #
1516
1518
  # Requirements can also be defined using verbose options rather than the
1517
1519
  # implicit Hash syntax and helper methods described above.
1518
- #
1520
+ #
1519
1521
  # Configuration options:
1520
1522
  # * <tt>:from</tt> - One or more states being transitioned from. If none
1521
1523
  # are specified, then all states will match.
@@ -1526,116 +1528,116 @@ module StateMachines
1526
1528
  # * <tt>:except_from</tt> - One or more states *not* being transitioned from
1527
1529
  # * <tt>:except_to</tt> - One more states *not* being transitioned to
1528
1530
  # * <tt>:except_on</tt> - One or more events that *did not* fire the transition
1529
- #
1531
+ #
1530
1532
  # Examples:
1531
- #
1533
+ #
1532
1534
  # before_transition :from => :ignite, :to => :idling, :on => :park, :do => ...
1533
1535
  # before_transition :except_from => :ignite, :except_to => :idling, :except_on => :park, :do => ...
1534
- #
1536
+ #
1535
1537
  # == Conditions
1536
- #
1538
+ #
1537
1539
  # In addition to the state/event requirements, a condition can also be
1538
1540
  # defined to help determine whether the callback should be invoked.
1539
- #
1541
+ #
1540
1542
  # Configuration options:
1541
1543
  # * <tt>:if</tt> - A method, proc or string to call to determine if the
1542
1544
  # callback should occur (e.g. :if => :allow_callbacks, or
1543
1545
  # :if => lambda {|user| user.signup_step > 2}). The method, proc or string
1544
- # should return or evaluate to a true or false value.
1546
+ # should return or evaluate to a true or false value.
1545
1547
  # * <tt>:unless</tt> - A method, proc or string to call to determine if the
1546
1548
  # callback should not occur (e.g. :unless => :skip_callbacks, or
1547
1549
  # :unless => lambda {|user| user.signup_step <= 2}). The method, proc or
1548
- # string should return or evaluate to a true or false value.
1549
- #
1550
+ # string should return or evaluate to a true or false value.
1551
+ #
1550
1552
  # Examples:
1551
- #
1553
+ #
1552
1554
  # before_transition :parked => :idling, :if => :moving?, :do => ...
1553
1555
  # before_transition :on => :ignite, :unless => :seatbelt_on?, :do => ...
1554
- #
1556
+ #
1555
1557
  # == Accessing the transition
1556
- #
1558
+ #
1557
1559
  # In addition to passing the object being transitioned, the actual
1558
1560
  # transition describing the context (e.g. event, from, to) can be accessed
1559
1561
  # as well. This additional argument is only passed if the callback allows
1560
1562
  # for it.
1561
- #
1563
+ #
1562
1564
  # For example,
1563
- #
1565
+ #
1564
1566
  # class Vehicle
1565
1567
  # # Only specifies one parameter (the object being transitioned)
1566
1568
  # before_transition all => :parked do |vehicle|
1567
1569
  # vehicle.set_alarm
1568
1570
  # end
1569
- #
1571
+ #
1570
1572
  # # Specifies 2 parameters (object being transitioned and actual transition)
1571
1573
  # before_transition all => :parked do |vehicle, transition|
1572
1574
  # vehicle.set_alarm(transition)
1573
1575
  # end
1574
1576
  # end
1575
- #
1577
+ #
1576
1578
  # *Note* that the object in the callback will only be passed in as an
1577
1579
  # argument if callbacks are configured to *not* be bound to the object
1578
1580
  # involved. This is the default and may change on a per-integration basis.
1579
- #
1581
+ #
1580
1582
  # See StateMachines::Transition for more information about the
1581
1583
  # attributes available on the transition.
1582
- #
1584
+ #
1583
1585
  # == Usage with delegates
1584
- #
1586
+ #
1585
1587
  # As noted above, state_machine uses the callback method's argument list
1586
1588
  # arity to determine whether to include the transition in the method call.
1587
1589
  # If you're using delegates, such as those defined in ActiveSupport or
1588
1590
  # Forwardable, the actual arity of the delegated method gets masked. This
1589
1591
  # means that callbacks which reference delegates will always get passed the
1590
1592
  # transition as an argument. For example:
1591
- #
1593
+ #
1592
1594
  # class Vehicle
1593
1595
  # extend Forwardable
1594
1596
  # delegate :refresh => :dashboard
1595
- #
1597
+ #
1596
1598
  # state_machine do
1597
1599
  # before_transition :refresh
1598
1600
  # ...
1599
1601
  # end
1600
- #
1602
+ #
1601
1603
  # def dashboard
1602
1604
  # @dashboard ||= Dashboard.new
1603
1605
  # end
1604
1606
  # end
1605
- #
1607
+ #
1606
1608
  # class Dashboard
1607
1609
  # def refresh(transition)
1608
1610
  # # ...
1609
1611
  # end
1610
1612
  # end
1611
- #
1613
+ #
1612
1614
  # In the above example, <tt>Dashboard#refresh</tt> *must* defined a
1613
1615
  # +transition+ argument. Otherwise, an +ArgumentError+ exception will get
1614
1616
  # raised. The only way around this is to avoid the use of delegates and
1615
1617
  # manually define the delegate method so that the correct arity is used.
1616
- #
1618
+ #
1617
1619
  # == Examples
1618
- #
1620
+ #
1619
1621
  # Below is an example of a class with one state machine and various types
1620
1622
  # of +before+ transitions defined for it:
1621
- #
1623
+ #
1622
1624
  # class Vehicle
1623
1625
  # state_machine do
1624
1626
  # # Before all transitions
1625
1627
  # before_transition :update_dashboard
1626
- #
1628
+ #
1627
1629
  # # Before specific transition:
1628
1630
  # before_transition [:first_gear, :idling] => :parked, :on => :park, :do => :take_off_seatbelt
1629
- #
1631
+ #
1630
1632
  # # With conditional callback:
1631
1633
  # before_transition all => :parked, :do => :take_off_seatbelt, :if => :seatbelt_on?
1632
- #
1634
+ #
1633
1635
  # # Using helpers:
1634
1636
  # before_transition all - :stalled => same, :on => any - :crash, :do => :update_dashboard
1635
1637
  # ...
1636
1638
  # end
1637
1639
  # end
1638
- #
1640
+ #
1639
1641
  # As can be seen, any number of transitions can be created using various
1640
1642
  # combinations of configuration options.
1641
1643
  def before_transition(*args, &block)
@@ -1646,7 +1648,7 @@ module StateMachines
1646
1648
 
1647
1649
  # Creates a callback that will be invoked *after* a transition is
1648
1650
  # performed so long as the given requirements match the transition.
1649
- #
1651
+ #
1650
1652
  # See +before_transition+ for a description of the possible configurations
1651
1653
  # for defining callbacks.
1652
1654
  def after_transition(*args, &block)
@@ -1657,32 +1659,32 @@ module StateMachines
1657
1659
 
1658
1660
  # Creates a callback that will be invoked *around* a transition so long as
1659
1661
  # the given requirements match the transition.
1660
- #
1662
+ #
1661
1663
  # == The callback
1662
- #
1664
+ #
1663
1665
  # Around callbacks wrap transitions, executing code both before and after.
1664
1666
  # These callbacks are defined in the exact same manner as before / after
1665
1667
  # callbacks with the exception that the transition must be yielded to in
1666
1668
  # order to finish running it.
1667
- #
1669
+ #
1668
1670
  # If defining +around+ callbacks using blocks, you must yield within the
1669
1671
  # transition by directly calling the block (since yielding is not allowed
1670
1672
  # within blocks).
1671
- #
1673
+ #
1672
1674
  # For example,
1673
- #
1675
+ #
1674
1676
  # class Vehicle
1675
1677
  # state_machine do
1676
1678
  # around_transition do |block|
1677
1679
  # Benchmark.measure { block.call }
1678
1680
  # end
1679
- #
1681
+ #
1680
1682
  # around_transition do |vehicle, block|
1681
1683
  # logger.info "vehicle was #{state}..."
1682
1684
  # block.call
1683
1685
  # logger.info "...and is now #{state}"
1684
1686
  # end
1685
- #
1687
+ #
1686
1688
  # around_transition do |vehicle, transition, block|
1687
1689
  # logger.info "before #{transition.event}: #{vehicle.state}"
1688
1690
  # block.call
@@ -1690,24 +1692,24 @@ module StateMachines
1690
1692
  # end
1691
1693
  # end
1692
1694
  # end
1693
- #
1695
+ #
1694
1696
  # Notice that referencing the block is similar to doing so within an
1695
1697
  # actual method definition in that it is always the last argument.
1696
- #
1698
+ #
1697
1699
  # On the other hand, if you're defining +around+ callbacks using method
1698
1700
  # references, you can yield like normal:
1699
- #
1701
+ #
1700
1702
  # class Vehicle
1701
1703
  # state_machine do
1702
1704
  # around_transition :benchmark
1703
1705
  # ...
1704
1706
  # end
1705
- #
1707
+ #
1706
1708
  # def benchmark
1707
1709
  # Benchmark.measure { yield }
1708
1710
  # end
1709
1711
  # end
1710
- #
1712
+ #
1711
1713
  # See +before_transition+ for a description of the possible configurations
1712
1714
  # for defining callbacks.
1713
1715
  def around_transition(*args, &block)
@@ -1718,29 +1720,29 @@ module StateMachines
1718
1720
 
1719
1721
  # Creates a callback that will be invoked *after* a transition failures to
1720
1722
  # be performed so long as the given requirements match the transition.
1721
- #
1723
+ #
1722
1724
  # See +before_transition+ for a description of the possible configurations
1723
1725
  # for defining callbacks. *Note* however that you cannot define the state
1724
1726
  # requirements in these callbacks. You may only define event requirements.
1725
- #
1727
+ #
1726
1728
  # = The callback
1727
- #
1729
+ #
1728
1730
  # Failure callbacks get invoked whenever an event fails to execute. This
1729
1731
  # can happen when no transition is available, a +before+ callback halts
1730
1732
  # execution, or the action associated with this machine fails to succeed.
1731
1733
  # In any of these cases, any failure callback that matches the attempted
1732
1734
  # transition will be run.
1733
- #
1735
+ #
1734
1736
  # For example,
1735
- #
1737
+ #
1736
1738
  # class Vehicle
1737
1739
  # state_machine do
1738
1740
  # after_failure do |vehicle, transition|
1739
1741
  # logger.error "vehicle #{vehicle} failed to transition on #{transition.event}"
1740
1742
  # end
1741
- #
1743
+ #
1742
1744
  # after_failure :on => :ignite, :do => :log_ignition_failure
1743
- #
1745
+ #
1744
1746
  # ...
1745
1747
  # end
1746
1748
  # end
@@ -1756,7 +1758,7 @@ module StateMachines
1756
1758
  # the given object. These paths can reveal all of the possible states and
1757
1759
  # events that can be encountered in the object's state machine based on the
1758
1760
  # object's current state.
1759
- #
1761
+ #
1760
1762
  # Configuration options:
1761
1763
  # * +from+ - The initial state to start all paths from. By default, this
1762
1764
  # is the object's current state.
@@ -1767,31 +1769,31 @@ module StateMachines
1767
1769
  # state (if specified) is reached. If this is enabled, then paths can
1768
1770
  # continue even after reaching the target state; they will stop when
1769
1771
  # reaching the target state a second time.
1770
- #
1772
+ #
1771
1773
  # *Note* that the object is never modified when the list of paths is
1772
1774
  # generated.
1773
- #
1775
+ #
1774
1776
  # == Examples
1775
- #
1777
+ #
1776
1778
  # class Vehicle
1777
1779
  # state_machine :initial => :parked do
1778
1780
  # event :ignite do
1779
1781
  # transition :parked => :idling
1780
1782
  # end
1781
- #
1783
+ #
1782
1784
  # event :shift_up do
1783
1785
  # transition :idling => :first_gear, :first_gear => :second_gear
1784
1786
  # end
1785
- #
1787
+ #
1786
1788
  # event :shift_down do
1787
1789
  # transition :second_gear => :first_gear, :first_gear => :idling
1788
1790
  # end
1789
1791
  # end
1790
1792
  # end
1791
- #
1793
+ #
1792
1794
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c27024 @state="parked">
1793
1795
  # vehicle.state # => "parked"
1794
- #
1796
+ #
1795
1797
  # vehicle.state_paths
1796
1798
  # # => [
1797
1799
  # # [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>,
@@ -1799,26 +1801,26 @@ module StateMachines
1799
1801
  # # #<StateMachines::Transition attribute=:state event=:shift_up from="first_gear" from_name=:first_gear to="second_gear" to_name=:second_gear>,
1800
1802
  # # #<StateMachines::Transition attribute=:state event=:shift_down from="second_gear" from_name=:second_gear to="first_gear" to_name=:first_gear>,
1801
1803
  # # #<StateMachines::Transition attribute=:state event=:shift_down from="first_gear" from_name=:first_gear to="idling" to_name=:idling>],
1802
- # #
1804
+ # #
1803
1805
  # # [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>,
1804
1806
  # # #<StateMachines::Transition attribute=:state event=:shift_up from="idling" from_name=:idling to="first_gear" to_name=:first_gear>,
1805
1807
  # # #<StateMachines::Transition attribute=:state event=:shift_down from="first_gear" from_name=:first_gear to="idling" to_name=:idling>]
1806
1808
  # # ]
1807
- #
1809
+ #
1808
1810
  # vehicle.state_paths(:from => :parked, :to => :second_gear)
1809
1811
  # # => [
1810
1812
  # # [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>,
1811
1813
  # # #<StateMachines::Transition attribute=:state event=:shift_up from="idling" from_name=:idling to="first_gear" to_name=:first_gear>,
1812
1814
  # # #<StateMachines::Transition attribute=:state event=:shift_up from="first_gear" from_name=:first_gear to="second_gear" to_name=:second_gear>]
1813
1815
  # # ]
1814
- #
1816
+ #
1815
1817
  # In addition to getting the possible paths that can be accessed, you can
1816
1818
  # also get summary information about the states / events that can be
1817
1819
  # accessed at some point along one of the paths. For example:
1818
- #
1820
+ #
1819
1821
  # # Get the list of states that can be accessed from the current state
1820
1822
  # vehicle.state_paths.to_states # => [:idling, :first_gear, :second_gear]
1821
- #
1823
+ #
1822
1824
  # # Get the list of events that can be accessed from the current state
1823
1825
  # vehicle.state_paths.events # => [:ignite, :shift_up, :shift_down]
1824
1826
  def paths_for(object, requirements = {})
@@ -1826,7 +1828,7 @@ module StateMachines
1826
1828
  end
1827
1829
 
1828
1830
  # Marks the given object as invalid with the given message.
1829
- #
1831
+ #
1830
1832
  # By default, this is a no-op.
1831
1833
  def invalidate(_object, _attribute, _message, _values = [])
1832
1834
  end
@@ -1839,7 +1841,7 @@ module StateMachines
1839
1841
  end
1840
1842
 
1841
1843
  # Resets any errors previously added when invalidating the given object.
1842
- #
1844
+ #
1843
1845
  # By default, this is a no-op.
1844
1846
  def reset(_object)
1845
1847
  end
@@ -1859,7 +1861,7 @@ module StateMachines
1859
1861
  end
1860
1862
 
1861
1863
  # Runs a transaction, rolling back any changes if the yielded block fails.
1862
- #
1864
+ #
1863
1865
  # This is only applicable to integrations that involve databases. By
1864
1866
  # default, this will not run any transactions since the changes aren't
1865
1867
  # taking place within the context of a database.
@@ -1882,7 +1884,8 @@ module StateMachines
1882
1884
  @action_hook_defined || !self_only && owner_class.state_machines.any? { |name, machine| machine.action == action && machine != self && machine.action_hook?(true) }
1883
1885
  end
1884
1886
 
1885
- protected
1887
+ protected
1888
+
1886
1889
  # Runs additional initialization hooks. By default, this is a no-op.
1887
1890
  def after_initialize
1888
1891
  end
@@ -2030,7 +2033,7 @@ module StateMachines
2030
2033
  def #{action_hook}(*)
2031
2034
  self.class.state_machines.transitions(self, #{action.inspect}).perform { super }
2032
2035
  end
2033
-
2036
+
2034
2037
  private #{action_hook.inspect} if #{private_action_hook}
2035
2038
  end_eval
2036
2039
  end
@@ -2052,7 +2055,7 @@ module StateMachines
2052
2055
  def owner_class_ancestor_has_method?(scope, method)
2053
2056
  return false unless owner_class_has_method?(scope, method)
2054
2057
 
2055
- superclasses = owner_class.ancestors[1..-1].select { |ancestor| ancestor.is_a?(Class) }
2058
+ superclasses = owner_class.ancestors.select { |ancestor| ancestor.is_a?(Class) }[1..-1]
2056
2059
 
2057
2060
  if scope == :class
2058
2061
  current = owner_class.singleton_class
@@ -2116,7 +2119,7 @@ module StateMachines
2116
2119
  [name, plural].map { |s| s.to_s }.uniq.each do |suffix|
2117
2120
  method = "#{kind}_#{suffix}"
2118
2121
 
2119
- if scope = send("create_#{kind}_scope", method)
2122
+ if (scope = send("create_#{kind}_scope", method))
2120
2123
  # Converts state names to their corresponding values so that they
2121
2124
  # can be looked up properly
2122
2125
  define_helper(:class, method) do |machine, klass, *states|
@@ -2130,7 +2133,7 @@ module StateMachines
2130
2133
  # Generates the results for the given scope based on one or more states to
2131
2134
  # filter by
2132
2135
  def run_scope(scope, machine, klass, states)
2133
- values = states.flatten.map { |state| machine.states.fetch(state).value }
2136
+ values = states.flatten.compact.map { |state| machine.states.fetch(state).value }
2134
2137
  scope.call(klass, values)
2135
2138
  end
2136
2139
 
@@ -2198,11 +2201,11 @@ module StateMachines
2198
2201
  new_states.map do |new_state|
2199
2202
  # Check for other states that use a different class type for their name.
2200
2203
  # This typically prevents string / symbol misuse.
2201
- if new_state && conflict = states.detect { |state| state.name && state.name.class != new_state.class }
2204
+ if new_state && (conflict = states.detect { |state| state.name && state.name.class != new_state.class })
2202
2205
  raise ArgumentError, "#{new_state.inspect} state defined as #{new_state.class}, #{conflict.name.inspect} defined as #{conflict.name.class}; all states must be consistent"
2203
2206
  end
2204
2207
 
2205
- unless state = states[new_state]
2208
+ unless (state = states[new_state])
2206
2209
  states << state = State.new(self, new_state)
2207
2210
 
2208
2211
  # Copy states over to sibling machines
@@ -2219,11 +2222,11 @@ module StateMachines
2219
2222
  new_events.map do |new_event|
2220
2223
  # Check for other states that use a different class type for their name.
2221
2224
  # This typically prevents string / symbol misuse.
2222
- if conflict = events.detect { |event| event.name.class != new_event.class }
2225
+ if (conflict = events.detect { |event| event.name.class != new_event.class })
2223
2226
  raise ArgumentError, "#{new_event.inspect} event defined as #{new_event.class}, #{conflict.name.inspect} defined as #{conflict.name.class}; all events must be consistent"
2224
2227
  end
2225
2228
 
2226
- unless event = events[new_event]
2229
+ unless (event = events[new_event])
2227
2230
  events << event = Event.new(self, new_event)
2228
2231
  end
2229
2232