state_machines 0.5.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +443 -22
  4. data/lib/state_machines/async_mode/async_event_extensions.rb +49 -0
  5. data/lib/state_machines/async_mode/async_events.rb +282 -0
  6. data/lib/state_machines/async_mode/async_machine.rb +60 -0
  7. data/lib/state_machines/async_mode/async_transition_collection.rb +141 -0
  8. data/lib/state_machines/async_mode/thread_safe_state.rb +47 -0
  9. data/lib/state_machines/async_mode.rb +64 -0
  10. data/lib/state_machines/branch.rb +146 -86
  11. data/lib/state_machines/callback.rb +35 -32
  12. data/lib/state_machines/core.rb +3 -3
  13. data/lib/state_machines/core_ext/class/state_machine.rb +2 -0
  14. data/lib/state_machines/core_ext.rb +2 -0
  15. data/lib/state_machines/error.rb +7 -4
  16. data/lib/state_machines/eval_helpers.rb +197 -39
  17. data/lib/state_machines/event.rb +77 -58
  18. data/lib/state_machines/event_collection.rb +49 -39
  19. data/lib/state_machines/extensions.rb +6 -4
  20. data/lib/state_machines/helper_module.rb +4 -2
  21. data/lib/state_machines/integrations/base.rb +3 -1
  22. data/lib/state_machines/integrations.rb +19 -20
  23. data/lib/state_machines/machine/action_hooks.rb +53 -0
  24. data/lib/state_machines/machine/async_extensions.rb +88 -0
  25. data/lib/state_machines/machine/callbacks.rb +59 -0
  26. data/lib/state_machines/machine/class_methods.rb +97 -0
  27. data/lib/state_machines/machine/configuration.rb +134 -0
  28. data/lib/state_machines/machine/event_methods.rb +59 -0
  29. data/lib/state_machines/machine/helper_generators.rb +125 -0
  30. data/lib/state_machines/machine/integration.rb +70 -0
  31. data/lib/state_machines/machine/parsing.rb +77 -0
  32. data/lib/state_machines/machine/rendering.rb +17 -0
  33. data/lib/state_machines/machine/scoping.rb +44 -0
  34. data/lib/state_machines/machine/state_methods.rb +101 -0
  35. data/lib/state_machines/machine/utilities.rb +85 -0
  36. data/lib/state_machines/machine/validation.rb +39 -0
  37. data/lib/state_machines/machine.rb +425 -1011
  38. data/lib/state_machines/machine_collection.rb +28 -19
  39. data/lib/state_machines/macro_methods.rb +104 -102
  40. data/lib/state_machines/matcher.rb +31 -28
  41. data/lib/state_machines/matcher_helpers.rb +14 -12
  42. data/lib/state_machines/node_collection.rb +36 -29
  43. data/lib/state_machines/options_validator.rb +72 -0
  44. data/lib/state_machines/path.rb +60 -57
  45. data/lib/state_machines/path_collection.rb +39 -36
  46. data/lib/state_machines/state.rb +84 -47
  47. data/lib/state_machines/state_collection.rb +22 -19
  48. data/lib/state_machines/state_context.rb +40 -39
  49. data/lib/state_machines/stdio_renderer.rb +74 -0
  50. data/lib/state_machines/syntax_validator.rb +57 -0
  51. data/lib/state_machines/test_helper.rb +896 -0
  52. data/lib/state_machines/transition.rb +215 -199
  53. data/lib/state_machines/transition_collection.rb +187 -170
  54. data/lib/state_machines/version.rb +3 -1
  55. data/lib/state_machines.rb +4 -1
  56. metadata +39 -446
  57. data/.gitignore +0 -21
  58. data/.rspec +0 -3
  59. data/.ruby-gemset +0 -1
  60. data/.ruby-version +0 -1
  61. data/.travis.yml +0 -16
  62. data/Changelog.md +0 -22
  63. data/Contributors.md +0 -39
  64. data/Gemfile +0 -8
  65. data/Rakefile +0 -12
  66. data/Testing.md +0 -0
  67. data/lib/state_machines/assertions.rb +0 -40
  68. data/state_machines.gemspec +0 -22
  69. data/test/files/integrations/event_on_failure_integration.rb +0 -10
  70. data/test/files/integrations/vehicle.rb +0 -7
  71. data/test/files/models/auto_shop.rb +0 -31
  72. data/test/files/models/car.rb +0 -21
  73. data/test/files/models/driver.rb +0 -13
  74. data/test/files/models/model_base.rb +0 -6
  75. data/test/files/models/motorcycle.rb +0 -16
  76. data/test/files/models/traffic_light.rb +0 -47
  77. data/test/files/models/vehicle.rb +0 -127
  78. data/test/files/node.rb +0 -5
  79. data/test/files/switch.rb +0 -15
  80. data/test/functional/auto_shop_available_test.rb +0 -20
  81. data/test/functional/auto_shop_busy_test.rb +0 -25
  82. data/test/functional/car_backing_up_test.rb +0 -45
  83. data/test/functional/car_test.rb +0 -49
  84. data/test/functional/driver_default_nonstandard_test.rb +0 -13
  85. data/test/functional/motorcycle_test.rb +0 -52
  86. data/test/functional/traffic_light_caution_test.rb +0 -17
  87. data/test/functional/traffic_light_proceed_test.rb +0 -17
  88. data/test/functional/traffic_light_stop_test.rb +0 -26
  89. data/test/functional/vehicle_first_gear_test.rb +0 -42
  90. data/test/functional/vehicle_idling_test.rb +0 -59
  91. data/test/functional/vehicle_locked_test.rb +0 -29
  92. data/test/functional/vehicle_parked_test.rb +0 -53
  93. data/test/functional/vehicle_repaired_test.rb +0 -20
  94. data/test/functional/vehicle_second_gear_test.rb +0 -42
  95. data/test/functional/vehicle_stalled_test.rb +0 -65
  96. data/test/functional/vehicle_test.rb +0 -20
  97. data/test/functional/vehicle_third_gear_test.rb +0 -42
  98. data/test/functional/vehicle_unsaved_test.rb +0 -181
  99. data/test/functional/vehicle_with_event_attributes_test.rb +0 -30
  100. data/test/functional/vehicle_with_parallel_events_test.rb +0 -36
  101. data/test/test_helper.rb +0 -15
  102. data/test/unit/assertions/assert_exclusive_keys_test.rb +0 -22
  103. data/test/unit/assertions/assert_valid_key_test.rb +0 -12
  104. data/test/unit/branch/branch_test.rb +0 -28
  105. data/test/unit/branch/branch_with_conflicting_conditionals_test.rb +0 -27
  106. data/test/unit/branch/branch_with_conflicting_from_requirements_test.rb +0 -8
  107. data/test/unit/branch/branch_with_conflicting_on_requirements_test.rb +0 -8
  108. data/test/unit/branch/branch_with_conflicting_to_requirements_test.rb +0 -8
  109. data/test/unit/branch/branch_with_different_requirements_test.rb +0 -41
  110. data/test/unit/branch/branch_with_except_from_matcher_requirement_test.rb +0 -8
  111. data/test/unit/branch/branch_with_except_from_requirement_test.rb +0 -36
  112. data/test/unit/branch/branch_with_except_on_matcher_requirement_test.rb +0 -8
  113. data/test/unit/branch/branch_with_except_on_requirement_test.rb +0 -36
  114. data/test/unit/branch/branch_with_except_to_matcher_requirement_test.rb +0 -8
  115. data/test/unit/branch/branch_with_except_to_requirement_test.rb +0 -36
  116. data/test/unit/branch/branch_with_from_matcher_requirement_test.rb +0 -20
  117. data/test/unit/branch/branch_with_from_requirement_test.rb +0 -45
  118. data/test/unit/branch/branch_with_if_conditional_test.rb +0 -27
  119. data/test/unit/branch/branch_with_implicit_and_explicit_requirements_test.rb +0 -23
  120. data/test/unit/branch/branch_with_implicit_from_requirement_matcher_test.rb +0 -20
  121. data/test/unit/branch/branch_with_implicit_requirement_test.rb +0 -20
  122. data/test/unit/branch/branch_with_implicit_to_requirement_matcher_test.rb +0 -16
  123. data/test/unit/branch/branch_with_multiple_except_from_requirements_test.rb +0 -20
  124. data/test/unit/branch/branch_with_multiple_except_on_requirements_test.rb +0 -16
  125. data/test/unit/branch/branch_with_multiple_except_to_requirements_test.rb +0 -20
  126. data/test/unit/branch/branch_with_multiple_from_requirements_test.rb +0 -16
  127. data/test/unit/branch/branch_with_multiple_if_conditionals_test.rb +0 -20
  128. data/test/unit/branch/branch_with_multiple_implicit_requirements_test.rb +0 -53
  129. data/test/unit/branch/branch_with_multiple_to_requirements_test.rb +0 -20
  130. data/test/unit/branch/branch_with_multiple_unless_conditionals_test.rb +0 -20
  131. data/test/unit/branch/branch_with_nil_requirements_test.rb +0 -28
  132. data/test/unit/branch/branch_with_no_requirements_test.rb +0 -36
  133. data/test/unit/branch/branch_with_on_matcher_requirement_test.rb +0 -16
  134. data/test/unit/branch/branch_with_on_requirement_test.rb +0 -45
  135. data/test/unit/branch/branch_with_to_matcher_requirement_test.rb +0 -20
  136. data/test/unit/branch/branch_with_to_requirement_test.rb +0 -45
  137. data/test/unit/branch/branch_with_unless_conditional_test.rb +0 -27
  138. data/test/unit/branch/branch_without_guards_test.rb +0 -27
  139. data/test/unit/callback/callback_by_default_test.rb +0 -25
  140. data/test/unit/callback/callback_test.rb +0 -53
  141. data/test/unit/callback/callback_with_application_bound_object_test.rb +0 -23
  142. data/test/unit/callback/callback_with_application_terminator_test.rb +0 -24
  143. data/test/unit/callback/callback_with_arguments_test.rb +0 -14
  144. data/test/unit/callback/callback_with_around_type_and_arguments_test.rb +0 -25
  145. data/test/unit/callback/callback_with_around_type_and_block_test.rb +0 -44
  146. data/test/unit/callback/callback_with_around_type_and_bound_method_test.rb +0 -23
  147. data/test/unit/callback/callback_with_around_type_and_multiple_methods_test.rb +0 -93
  148. data/test/unit/callback/callback_with_around_type_and_terminator_test.rb +0 -17
  149. data/test/unit/callback/callback_with_block_test.rb +0 -20
  150. data/test/unit/callback/callback_with_bound_method_and_arguments_test.rb +0 -28
  151. data/test/unit/callback/callback_with_bound_method_test.rb +0 -35
  152. data/test/unit/callback/callback_with_do_method_test.rb +0 -18
  153. data/test/unit/callback/callback_with_explicit_requirements_test.rb +0 -32
  154. data/test/unit/callback/callback_with_if_condition_test.rb +0 -17
  155. data/test/unit/callback/callback_with_implicit_requirements_test.rb +0 -32
  156. data/test/unit/callback/callback_with_method_argument_test.rb +0 -18
  157. data/test/unit/callback/callback_with_mixed_methods_test.rb +0 -31
  158. data/test/unit/callback/callback_with_multiple_bound_methods_test.rb +0 -21
  159. data/test/unit/callback/callback_with_multiple_do_methods_test.rb +0 -29
  160. data/test/unit/callback/callback_with_multiple_method_arguments_test.rb +0 -29
  161. data/test/unit/callback/callback_with_terminator_test.rb +0 -22
  162. data/test/unit/callback/callback_with_unbound_method_test.rb +0 -14
  163. data/test/unit/callback/callback_with_unless_condition_test.rb +0 -17
  164. data/test/unit/callback/callback_without_arguments_test.rb +0 -14
  165. data/test/unit/callback/callback_without_terminator_test.rb +0 -12
  166. data/test/unit/error/error_by_default_test.rb +0 -21
  167. data/test/unit/error/error_with_message_test.rb +0 -23
  168. data/test/unit/eval_helper/eval_helpers_base_test.rb +0 -8
  169. data/test/unit/eval_helper/eval_helpers_proc_block_and_explicit_arguments_test.rb +0 -14
  170. data/test/unit/eval_helper/eval_helpers_proc_block_and_implicit_arguments_test.rb +0 -14
  171. data/test/unit/eval_helper/eval_helpers_proc_test.rb +0 -13
  172. data/test/unit/eval_helper/eval_helpers_proc_with_arguments_test.rb +0 -13
  173. data/test/unit/eval_helper/eval_helpers_proc_with_block_test.rb +0 -13
  174. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_arguments_test.rb +0 -18
  175. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_object_test.rb +0 -14
  176. data/test/unit/eval_helper/eval_helpers_proc_without_arguments_test.rb +0 -19
  177. data/test/unit/eval_helper/eval_helpers_string_test.rb +0 -25
  178. data/test/unit/eval_helper/eval_helpers_string_with_block_test.rb +0 -12
  179. data/test/unit/eval_helper/eval_helpers_symbol_method_missing_test.rb +0 -20
  180. data/test/unit/eval_helper/eval_helpers_symbol_private_test.rb +0 -17
  181. data/test/unit/eval_helper/eval_helpers_symbol_protected_test.rb +0 -17
  182. data/test/unit/eval_helper/eval_helpers_symbol_tainted_method_test.rb +0 -18
  183. data/test/unit/eval_helper/eval_helpers_symbol_test.rb +0 -16
  184. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_and_block_test.rb +0 -16
  185. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_test.rb +0 -16
  186. data/test/unit/eval_helper/eval_helpers_symbol_with_block_test.rb +0 -16
  187. data/test/unit/eval_helper/eval_helpers_test.rb +0 -13
  188. data/test/unit/event/event_after_being_copied_test.rb +0 -17
  189. data/test/unit/event/event_by_default_test.rb +0 -60
  190. data/test/unit/event/event_context_test.rb +0 -16
  191. data/test/unit/event/event_on_failure_test.rb +0 -44
  192. data/test/unit/event/event_test.rb +0 -34
  193. data/test/unit/event/event_transitions_test.rb +0 -62
  194. data/test/unit/event/event_with_conflicting_helpers_after_definition_test.rb +0 -79
  195. data/test/unit/event/event_with_conflicting_helpers_before_definition_test.rb +0 -58
  196. data/test/unit/event/event_with_conflicting_machine_test.rb +0 -48
  197. data/test/unit/event/event_with_dynamic_human_name_test.rb +0 -26
  198. data/test/unit/event/event_with_human_name_test.rb +0 -13
  199. data/test/unit/event/event_with_invalid_current_state_test.rb +0 -30
  200. data/test/unit/event/event_with_machine_action_test.rb +0 -33
  201. data/test/unit/event/event_with_marshalling_test.rb +0 -47
  202. data/test/unit/event/event_with_matching_disabled_transitions_test.rb +0 -115
  203. data/test/unit/event/event_with_matching_enabled_transitions_test.rb +0 -75
  204. data/test/unit/event/event_with_multiple_transitions_test.rb +0 -61
  205. data/test/unit/event/event_with_namespace_test.rb +0 -34
  206. data/test/unit/event/event_with_transition_with_blacklisted_to_state_test.rb +0 -60
  207. data/test/unit/event/event_with_transition_with_loopback_state_test.rb +0 -36
  208. data/test/unit/event/event_with_transition_with_nil_to_state_test.rb +0 -36
  209. data/test/unit/event/event_with_transition_with_whitelisted_to_state_test.rb +0 -51
  210. data/test/unit/event/event_with_transition_without_to_state_test.rb +0 -36
  211. data/test/unit/event/event_with_transitions_test.rb +0 -32
  212. data/test/unit/event/event_without_matching_transitions_test.rb +0 -41
  213. data/test/unit/event/event_without_transitions_test.rb +0 -28
  214. data/test/unit/event/invalid_event_test.rb +0 -20
  215. data/test/unit/event_collection/event_collection_attribute_with_machine_action_test.rb +0 -62
  216. data/test/unit/event_collection/event_collection_attribute_with_namespaced_machine_test.rb +0 -36
  217. data/test/unit/event_collection/event_collection_by_default_test.rb +0 -26
  218. data/test/unit/event_collection/event_collection_test.rb +0 -39
  219. data/test/unit/event_collection/event_collection_with_custom_machine_attribute_test.rb +0 -31
  220. data/test/unit/event_collection/event_collection_with_events_with_transitions_test.rb +0 -76
  221. data/test/unit/event_collection/event_collection_with_multiple_events_test.rb +0 -27
  222. data/test/unit/event_collection/event_collection_with_validations_test.rb +0 -74
  223. data/test/unit/event_collection/event_collection_without_machine_action_test.rb +0 -18
  224. data/test/unit/event_collection/event_string_collection_test.rb +0 -31
  225. data/test/unit/helper_module_test.rb +0 -17
  226. data/test/unit/integrations/integration_finder_test.rb +0 -16
  227. data/test/unit/integrations/integration_matcher_test.rb +0 -29
  228. data/test/unit/invalid_transition/invalid_parallel_transition_test.rb +0 -18
  229. data/test/unit/invalid_transition/invalid_transition_test.rb +0 -47
  230. data/test/unit/invalid_transition/invalid_transition_with_integration_test.rb +0 -45
  231. data/test/unit/invalid_transition/invalid_transition_with_namespace_test.rb +0 -32
  232. data/test/unit/machine/machine_after_being_copied_test.rb +0 -62
  233. data/test/unit/machine/machine_after_changing_initial_state.rb +0 -28
  234. data/test/unit/machine/machine_after_changing_owner_class_test.rb +0 -31
  235. data/test/unit/machine/machine_by_default_test.rb +0 -160
  236. data/test/unit/machine/machine_finder_custom_options_test.rb +0 -17
  237. data/test/unit/machine/machine_finder_with_existing_machine_on_superclass_test.rb +0 -85
  238. data/test/unit/machine/machine_finder_with_existing_on_same_class_test.rb +0 -23
  239. data/test/unit/machine/machine_finder_without_existing_machine_test.rb +0 -25
  240. data/test/unit/machine/machine_persistence_test.rb +0 -52
  241. data/test/unit/machine/machine_state_initialization_test.rb +0 -56
  242. data/test/unit/machine/machine_test.rb +0 -30
  243. data/test/unit/machine/machine_with_action_already_overridden_test.rb +0 -23
  244. data/test/unit/machine/machine_with_action_defined_in_class_test.rb +0 -37
  245. data/test/unit/machine/machine_with_action_defined_in_included_module_test.rb +0 -46
  246. data/test/unit/machine/machine_with_action_defined_in_superclass_test.rb +0 -43
  247. data/test/unit/machine/machine_with_action_undefined_test.rb +0 -33
  248. data/test/unit/machine/machine_with_cached_state_test.rb +0 -20
  249. data/test/unit/machine/machine_with_class_helpers_test.rb +0 -179
  250. data/test/unit/machine/machine_with_conflicting_helpers_after_definition_test.rb +0 -244
  251. data/test/unit/machine/machine_with_conflicting_helpers_before_definition_test.rb +0 -175
  252. data/test/unit/machine/machine_with_custom_action_test.rb +0 -11
  253. data/test/unit/machine/machine_with_custom_attribute_test.rb +0 -103
  254. data/test/unit/machine/machine_with_custom_initialize_test.rb +0 -24
  255. data/test/unit/machine/machine_with_custom_integration_test.rb +0 -72
  256. data/test/unit/machine/machine_with_custom_invalidation_test.rb +0 -39
  257. data/test/unit/machine/machine_with_custom_name_test.rb +0 -57
  258. data/test/unit/machine/machine_with_custom_plural_test.rb +0 -52
  259. data/test/unit/machine/machine_with_dynamic_initial_state_test.rb +0 -65
  260. data/test/unit/machine/machine_with_event_matchers_test.rb +0 -41
  261. data/test/unit/machine/machine_with_events_test.rb +0 -52
  262. data/test/unit/machine/machine_with_events_with_custom_human_names_test.rb +0 -18
  263. data/test/unit/machine/machine_with_events_with_transitions_test.rb +0 -37
  264. data/test/unit/machine/machine_with_existing_event_test.rb +0 -17
  265. data/test/unit/machine/machine_with_existing_machines_on_owner_class_test.rb +0 -20
  266. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_class_test.rb +0 -71
  267. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_subclass_test.rb +0 -31
  268. data/test/unit/machine/machine_with_existing_state_test.rb +0 -27
  269. data/test/unit/machine/machine_with_failure_callbacks_test.rb +0 -48
  270. data/test/unit/machine/machine_with_helpers_test.rb +0 -14
  271. data/test/unit/machine/machine_with_initial_state_with_value_and_owner_default.rb +0 -25
  272. data/test/unit/machine/machine_with_initialize_and_super_test.rb +0 -17
  273. data/test/unit/machine/machine_with_initialize_arguments_and_block_test.rb +0 -31
  274. data/test/unit/machine/machine_with_initialize_without_super_test.rb +0 -17
  275. data/test/unit/machine/machine_with_instance_helpers_test.rb +0 -179
  276. data/test/unit/machine/machine_with_integration_test.rb +0 -72
  277. data/test/unit/machine/machine_with_multiple_events_test.rb +0 -32
  278. data/test/unit/machine/machine_with_namespace_test.rb +0 -48
  279. data/test/unit/machine/machine_with_nil_action_test.rb +0 -27
  280. data/test/unit/machine/machine_with_other_states.rb +0 -22
  281. data/test/unit/machine/machine_with_owner_subclass_test.rb +0 -18
  282. data/test/unit/machine/machine_with_paths_test.rb +0 -25
  283. data/test/unit/machine/machine_with_private_action_test.rb +0 -43
  284. data/test/unit/machine/machine_with_state_matchers_test.rb +0 -41
  285. data/test/unit/machine/machine_with_state_with_matchers_test.rb +0 -19
  286. data/test/unit/machine/machine_with_states_test.rb +0 -55
  287. data/test/unit/machine/machine_with_states_with_behaviors_test.rb +0 -23
  288. data/test/unit/machine/machine_with_states_with_custom_human_names_test.rb +0 -18
  289. data/test/unit/machine/machine_with_states_with_custom_values_test.rb +0 -21
  290. data/test/unit/machine/machine_with_states_with_runtime_dependencies_test.rb +0 -19
  291. data/test/unit/machine/machine_with_static_initial_state_test.rb +0 -49
  292. data/test/unit/machine/machine_with_superclass_conflicting_helpers_after_definition_test.rb +0 -36
  293. data/test/unit/machine/machine_with_transition_callbacks_test.rb +0 -144
  294. data/test/unit/machine/machine_with_transitions_test.rb +0 -87
  295. data/test/unit/machine/machine_without_initialization_test.rb +0 -31
  296. data/test/unit/machine/machine_without_initialize_test.rb +0 -14
  297. data/test/unit/machine/machine_without_integration_test.rb +0 -31
  298. data/test/unit/machine_collection/machine_collection_by_default_test.rb +0 -11
  299. data/test/unit/machine_collection/machine_collection_fire_test.rb +0 -80
  300. data/test/unit/machine_collection/machine_collection_fire_with_transactions_test.rb +0 -54
  301. data/test/unit/machine_collection/machine_collection_fire_with_validations_test.rb +0 -76
  302. data/test/unit/machine_collection/machine_collection_state_initialization_test.rb +0 -111
  303. data/test/unit/machine_collection/machine_collection_transitions_with_blank_events_test.rb +0 -25
  304. data/test/unit/machine_collection/machine_collection_transitions_with_custom_options_test.rb +0 -20
  305. data/test/unit/machine_collection/machine_collection_transitions_with_different_actions_test.rb +0 -26
  306. data/test/unit/machine_collection/machine_collection_transitions_with_exisiting_transitions_test.rb +0 -25
  307. data/test/unit/machine_collection/machine_collection_transitions_with_invalid_events_test.rb +0 -25
  308. data/test/unit/machine_collection/machine_collection_transitions_with_same_actions_test.rb +0 -31
  309. data/test/unit/machine_collection/machine_collection_transitions_with_transition_test.rb +0 -26
  310. data/test/unit/machine_collection/machine_collection_transitions_without_events_test.rb +0 -25
  311. data/test/unit/machine_collection/machine_collection_transitions_without_transition_test.rb +0 -27
  312. data/test/unit/matcher/all_matcher_test.rb +0 -29
  313. data/test/unit/matcher/blacklist_matcher_test.rb +0 -30
  314. data/test/unit/matcher/loopback_matcher_test.rb +0 -27
  315. data/test/unit/matcher/matcher_by_default_test.rb +0 -15
  316. data/test/unit/matcher/matcher_with_multiple_values_test.rb +0 -15
  317. data/test/unit/matcher/matcher_with_value_test.rb +0 -15
  318. data/test/unit/matcher/whitelist_matcher_test.rb +0 -30
  319. data/test/unit/matcher_helpers/matcher_helpers_all_test.rb +0 -14
  320. data/test/unit/matcher_helpers/matcher_helpers_any_test.rb +0 -14
  321. data/test/unit/matcher_helpers/matcher_helpers_same_test.rb +0 -13
  322. data/test/unit/node_collection/node_collection_after_being_copied_test.rb +0 -46
  323. data/test/unit/node_collection/node_collection_after_update_test.rb +0 -36
  324. data/test/unit/node_collection/node_collection_by_default_test.rb +0 -22
  325. data/test/unit/node_collection/node_collection_test.rb +0 -23
  326. data/test/unit/node_collection/node_collection_with_indices_test.rb +0 -42
  327. data/test/unit/node_collection/node_collection_with_matcher_contexts_test.rb +0 -25
  328. data/test/unit/node_collection/node_collection_with_nodes_test.rb +0 -46
  329. data/test/unit/node_collection/node_collection_with_numeric_index_test.rb +0 -24
  330. data/test/unit/node_collection/node_collection_with_postdefined_contexts_test.rb +0 -22
  331. data/test/unit/node_collection/node_collection_with_predefined_contexts_test.rb +0 -23
  332. data/test/unit/node_collection/node_collection_with_string_index_test.rb +0 -20
  333. data/test/unit/node_collection/node_collection_with_symbol_index_test.rb +0 -20
  334. data/test/unit/node_collection/node_collection_without_indices_test.rb +0 -30
  335. data/test/unit/path/path_by_default_test.rb +0 -54
  336. data/test/unit/path/path_test.rb +0 -14
  337. data/test/unit/path/path_with_available_transitions_after_reaching_target_test.rb +0 -40
  338. data/test/unit/path/path_with_available_transitions_test.rb +0 -54
  339. data/test/unit/path/path_with_deep_target_reached_test.rb +0 -50
  340. data/test/unit/path/path_with_deep_target_test.rb +0 -40
  341. data/test/unit/path/path_with_duplicates_test.rb +0 -32
  342. data/test/unit/path/path_with_encountered_transitions_test.rb +0 -34
  343. data/test/unit/path/path_with_guarded_transitions_test.rb +0 -42
  344. data/test/unit/path/path_with_reached_target_test.rb +0 -35
  345. data/test/unit/path/path_with_transitions_test.rb +0 -54
  346. data/test/unit/path/path_with_unreached_target_test.rb +0 -31
  347. data/test/unit/path/path_without_transitions_test.rb +0 -24
  348. data/test/unit/path_collection/path_collection_by_default_test.rb +0 -46
  349. data/test/unit/path_collection/path_collection_test.rb +0 -24
  350. data/test/unit/path_collection/path_collection_with_deep_paths_test.rb +0 -43
  351. data/test/unit/path_collection/path_collection_with_duplicate_nodes_test.rb +0 -31
  352. data/test/unit/path_collection/path_collection_with_from_state_test.rb +0 -27
  353. data/test/unit/path_collection/path_collection_with_paths_test.rb +0 -47
  354. data/test/unit/path_collection/path_collection_with_to_state_test.rb +0 -29
  355. data/test/unit/path_collection/path_with_guarded_paths_test.rb +0 -25
  356. data/test/unit/state/state_after_being_copied_test.rb +0 -19
  357. data/test/unit/state/state_by_default_test.rb +0 -41
  358. data/test/unit/state/state_final_test.rb +0 -28
  359. data/test/unit/state/state_initial_test.rb +0 -13
  360. data/test/unit/state/state_not_final_test.rb +0 -32
  361. data/test/unit/state/state_not_initial_test.rb +0 -13
  362. data/test/unit/state/state_test.rb +0 -44
  363. data/test/unit/state/state_with_cached_lambda_value_test.rb +0 -29
  364. data/test/unit/state/state_with_conflicting_helpers_after_definition_test.rb +0 -38
  365. data/test/unit/state/state_with_conflicting_helpers_before_definition_test.rb +0 -29
  366. data/test/unit/state/state_with_conflicting_machine_name_test.rb +0 -20
  367. data/test/unit/state/state_with_conflicting_machine_test.rb +0 -37
  368. data/test/unit/state/state_with_context_test.rb +0 -60
  369. data/test/unit/state/state_with_dynamic_human_name_test.rb +0 -25
  370. data/test/unit/state/state_with_existing_context_method_test.rb +0 -24
  371. data/test/unit/state/state_with_human_name_test.rb +0 -13
  372. data/test/unit/state/state_with_integer_value_test.rb +0 -32
  373. data/test/unit/state/state_with_invalid_method_call_test.rb +0 -21
  374. data/test/unit/state/state_with_lambda_value_test.rb +0 -37
  375. data/test/unit/state/state_with_matcher_test.rb +0 -18
  376. data/test/unit/state/state_with_multiple_contexts_test.rb +0 -57
  377. data/test/unit/state/state_with_name_test.rb +0 -43
  378. data/test/unit/state/state_with_namespace_test.rb +0 -22
  379. data/test/unit/state/state_with_nil_value_test.rb +0 -35
  380. data/test/unit/state/state_with_redefined_context_method_test.rb +0 -45
  381. data/test/unit/state/state_with_symbolic_value_test.rb +0 -32
  382. data/test/unit/state/state_with_valid_inherited_method_call_for_current_state_test.rb +0 -40
  383. data/test/unit/state/state_with_valid_method_call_for_current_state_test.rb +0 -33
  384. data/test/unit/state/state_with_valid_method_call_for_different_state_test.rb +0 -41
  385. data/test/unit/state/state_without_cached_lambda_value_test.rb +0 -25
  386. data/test/unit/state/state_without_name_test.rb +0 -39
  387. data/test/unit/state_collection/state_collection_by_default_test.rb +0 -21
  388. data/test/unit/state_collection/state_collection_string_test.rb +0 -35
  389. data/test/unit/state_collection/state_collection_test.rb +0 -74
  390. data/test/unit/state_collection/state_collection_with_custom_state_values_test.rb +0 -29
  391. data/test/unit/state_collection/state_collection_with_event_transitions_test.rb +0 -39
  392. data/test/unit/state_collection/state_collection_with_initial_state_test.rb +0 -40
  393. data/test/unit/state_collection/state_collection_with_namespace_test.rb +0 -21
  394. data/test/unit/state_collection/state_collection_with_state_behaviors_test.rb +0 -40
  395. data/test/unit/state_collection/state_collection_with_state_matchers_test.rb +0 -29
  396. data/test/unit/state_collection/state_collection_with_transition_callbacks_test.rb +0 -40
  397. data/test/unit/state_context/state_context_proxy_test.rb +0 -26
  398. data/test/unit/state_context/state_context_proxy_with_if_and_unless_conditions_test.rb +0 -42
  399. data/test/unit/state_context/state_context_proxy_with_if_condition_test.rb +0 -64
  400. data/test/unit/state_context/state_context_proxy_with_multiple_if_conditions_test.rb +0 -32
  401. data/test/unit/state_context/state_context_proxy_with_multiple_unless_conditions_test.rb +0 -32
  402. data/test/unit/state_context/state_context_proxy_with_unless_condition_test.rb +0 -64
  403. data/test/unit/state_context/state_context_proxy_without_conditions_test.rb +0 -31
  404. data/test/unit/state_context/state_context_test.rb +0 -28
  405. data/test/unit/state_context/state_context_transition_test.rb +0 -104
  406. data/test/unit/state_context/state_context_with_matching_transition_test.rb +0 -27
  407. data/test/unit/state_machine/state_machine_by_default_test.rb +0 -12
  408. data/test/unit/state_machine/state_machine_test.rb +0 -20
  409. data/test/unit/transition/transition_after_being_performed_test.rb +0 -48
  410. data/test/unit/transition/transition_after_being_persisted_test.rb +0 -46
  411. data/test/unit/transition/transition_after_being_rolled_back_test.rb +0 -35
  412. data/test/unit/transition/transition_equality_test.rb +0 -52
  413. data/test/unit/transition/transition_loopback_test.rb +0 -18
  414. data/test/unit/transition/transition_test.rb +0 -96
  415. data/test/unit/transition/transition_transient_test.rb +0 -20
  416. data/test/unit/transition/transition_with_action_test.rb +0 -27
  417. data/test/unit/transition/transition_with_after_callbacks_skipped_test.rb +0 -127
  418. data/test/unit/transition/transition_with_after_callbacks_test.rb +0 -93
  419. data/test/unit/transition/transition_with_around_callbacks_test.rb +0 -141
  420. data/test/unit/transition/transition_with_before_callbacks_skipped_test.rb +0 -30
  421. data/test/unit/transition/transition_with_before_callbacks_test.rb +0 -104
  422. data/test/unit/transition/transition_with_custom_machine_attribute_test.rb +0 -28
  423. data/test/unit/transition/transition_with_different_states_test.rb +0 -18
  424. data/test/unit/transition/transition_with_dynamic_to_value_test.rb +0 -19
  425. data/test/unit/transition/transition_with_failure_callbacks_test.rb +0 -84
  426. data/test/unit/transition/transition_with_invalid_nodes_test.rb +0 -29
  427. data/test/unit/transition/transition_with_mixed_callbacks_test.rb +0 -105
  428. data/test/unit/transition/transition_with_multiple_after_callbacks_test.rb +0 -40
  429. data/test/unit/transition/transition_with_multiple_around_callbacks_test.rb +0 -114
  430. data/test/unit/transition/transition_with_multiple_before_callbacks_test.rb +0 -40
  431. data/test/unit/transition/transition_with_multiple_failure_callbacks_test.rb +0 -40
  432. data/test/unit/transition/transition_with_namespace_test.rb +0 -47
  433. data/test/unit/transition/transition_with_perform_arguments_test.rb +0 -35
  434. data/test/unit/transition/transition_with_transactions_test.rb +0 -42
  435. data/test/unit/transition/transition_without_callbacks_test.rb +0 -33
  436. data/test/unit/transition/transition_without_reading_state_test.rb +0 -22
  437. data/test/unit/transition/transition_without_running_action_test.rb +0 -47
  438. data/test/unit/transition_collection/attribute_transition_collection_by_default_test.rb +0 -23
  439. data/test/unit/transition_collection/attribute_transition_collection_marshalling_test.rb +0 -64
  440. data/test/unit/transition_collection/attribute_transition_collection_with_action_error_test.rb +0 -44
  441. data/test/unit/transition_collection/attribute_transition_collection_with_action_failed_test.rb +0 -44
  442. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_error_test.rb +0 -32
  443. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_halt_test.rb +0 -33
  444. data/test/unit/transition_collection/attribute_transition_collection_with_around_after_yield_callback_error_test.rb +0 -32
  445. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_error_test.rb +0 -32
  446. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_halt_test.rb +0 -33
  447. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_before_yield_halt_test.rb +0 -33
  448. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_error_test.rb +0 -32
  449. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_halt_test.rb +0 -33
  450. data/test/unit/transition_collection/attribute_transition_collection_with_callbacks_test.rb +0 -68
  451. data/test/unit/transition_collection/attribute_transition_collection_with_event_transitions_test.rb +0 -41
  452. data/test/unit/transition_collection/attribute_transition_collection_with_events_test.rb +0 -44
  453. data/test/unit/transition_collection/attribute_transition_collection_with_skipped_after_callbacks_test.rb +0 -42
  454. data/test/unit/transition_collection/transition_collection_by_default_test.rb +0 -23
  455. data/test/unit/transition_collection/transition_collection_empty_with_block_test.rb +0 -23
  456. data/test/unit/transition_collection/transition_collection_empty_without_block_test.rb +0 -12
  457. data/test/unit/transition_collection/transition_collection_invalid_test.rb +0 -21
  458. data/test/unit/transition_collection/transition_collection_partial_invalid_test.rb +0 -69
  459. data/test/unit/transition_collection/transition_collection_test.rb +0 -26
  460. data/test/unit/transition_collection/transition_collection_valid_test.rb +0 -57
  461. data/test/unit/transition_collection/transition_collection_with_action_error_test.rb +0 -66
  462. data/test/unit/transition_collection/transition_collection_with_action_failed_test.rb +0 -60
  463. data/test/unit/transition_collection/transition_collection_with_action_hook_and_block_test.rb +0 -17
  464. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_action_test.rb +0 -17
  465. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_after_callbacks_test.rb +0 -37
  466. data/test/unit/transition_collection/transition_collection_with_action_hook_base_test.rb +0 -34
  467. data/test/unit/transition_collection/transition_collection_with_action_hook_error_test.rb +0 -29
  468. data/test/unit/transition_collection/transition_collection_with_action_hook_invalid_test.rb +0 -17
  469. data/test/unit/transition_collection/transition_collection_with_action_hook_multiple_test.rb +0 -79
  470. data/test/unit/transition_collection/transition_collection_with_action_hook_test.rb +0 -45
  471. data/test/unit/transition_collection/transition_collection_with_action_hook_with_different_actions_test.rb +0 -48
  472. data/test/unit/transition_collection/transition_collection_with_action_hook_with_nil_action_test.rb +0 -42
  473. data/test/unit/transition_collection/transition_collection_with_after_callback_halt_test.rb +0 -47
  474. data/test/unit/transition_collection/transition_collection_with_before_callback_halt_test.rb +0 -51
  475. data/test/unit/transition_collection/transition_collection_with_block_test.rb +0 -46
  476. data/test/unit/transition_collection/transition_collection_with_callbacks_test.rb +0 -135
  477. data/test/unit/transition_collection/transition_collection_with_different_actions_test.rb +0 -189
  478. data/test/unit/transition_collection/transition_collection_with_duplicate_actions_test.rb +0 -48
  479. data/test/unit/transition_collection/transition_collection_with_empty_actions_test.rb +0 -41
  480. data/test/unit/transition_collection/transition_collection_with_mixed_actions_test.rb +0 -41
  481. data/test/unit/transition_collection/transition_collection_with_skipped_actions_and_block_test.rb +0 -34
  482. data/test/unit/transition_collection/transition_collection_with_skipped_actions_test.rb +0 -69
  483. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_and_around_callbacks_test.rb +0 -53
  484. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_test.rb +0 -34
  485. data/test/unit/transition_collection/transition_collection_with_transactions_test.rb +0 -65
  486. data/test/unit/transition_collection/transition_collection_without_transactions_test.rb +0 -29
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Represents a collection of events in a state machine
3
5
  class EventCollection < NodeCollection
4
- def initialize(machine) #:nodoc:
5
- super(machine, :index => [:name, :qualified_name])
6
+ def initialize(machine) # :nodoc:
7
+ super(machine, index: %i[name qualified_name])
6
8
  end
7
9
 
8
10
  # Gets the list of events that can be fired on the given object.
9
- #
11
+ #
10
12
  # Valid requirement options:
11
13
  # * <tt>:from</tt> - One or more states being transitioned from. If none
12
14
  # are specified, then this will be the object's current state.
@@ -16,26 +18,26 @@ module StateMachines
16
18
  # are specified, then this will match any event.
17
19
  # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
18
20
  # conditionals defined for each one. Default is true.
19
- #
21
+ #
20
22
  # == Examples
21
- #
23
+ #
22
24
  # class Vehicle
23
25
  # state_machine :initial => :parked do
24
26
  # event :park do
25
27
  # transition :idling => :parked
26
28
  # end
27
- #
29
+ #
28
30
  # event :ignite do
29
31
  # transition :parked => :idling
30
32
  # end
31
33
  # end
32
34
  # end
33
- #
35
+ #
34
36
  # events = Vehicle.state_machine(:state).events
35
- #
37
+ #
36
38
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
37
39
  # events.valid_for(vehicle) # => [#<StateMachines::Event name=:ignite transitions=[:parked => :idling]>]
38
- #
40
+ #
39
41
  # vehicle.state = 'idling'
40
42
  # events.valid_for(vehicle) # => [#<StateMachines::Event name=:park transitions=[:idling => :parked]>]
41
43
  def valid_for(object, requirements = {})
@@ -43,7 +45,7 @@ module StateMachines
43
45
  end
44
46
 
45
47
  # Gets the list of transitions that can be run on the given object.
46
- #
48
+ #
47
49
  # Valid requirement options:
48
50
  # * <tt>:from</tt> - One or more states being transitioned from. If none
49
51
  # are specified, then this will be the object's current state.
@@ -53,29 +55,29 @@ module StateMachines
53
55
  # are specified, then this will match any event.
54
56
  # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
55
57
  # conditionals defined for each one. Default is true.
56
- #
58
+ #
57
59
  # == Examples
58
- #
60
+ #
59
61
  # class Vehicle
60
62
  # state_machine :initial => :parked do
61
63
  # event :park do
62
64
  # transition :idling => :parked
63
65
  # end
64
- #
66
+ #
65
67
  # event :ignite do
66
68
  # transition :parked => :idling
67
69
  # end
68
70
  # end
69
71
  # end
70
- #
72
+ #
71
73
  # events = Vehicle.state_machine.events
72
- #
74
+ #
73
75
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
74
76
  # events.transitions_for(vehicle) # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
75
- #
77
+ #
76
78
  # vehicle.state = 'idling'
77
79
  # events.transitions_for(vehicle) # => [#<StateMachines::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>]
78
- #
80
+ #
79
81
  # # Search for explicit transitions regardless of the current state
80
82
  # events.transitions_for(vehicle, :from => :parked) # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
81
83
  def transitions_for(object, requirements = {})
@@ -86,12 +88,12 @@ module StateMachines
86
88
  # given object's event attribute. This also takes an additional parameter
87
89
  # for automatically invalidating the object if the event or transition are
88
90
  # invalid. By default, this is turned off.
89
- #
91
+ #
90
92
  # *Note* that if a transition has already been generated for the event, then
91
93
  # that transition will be used.
92
- #
94
+ #
93
95
  # == Examples
94
- #
96
+ #
95
97
  # class Vehicle < ActiveRecord::Base
96
98
  # state_machine :initial => :parked do
97
99
  # event :ignite do
@@ -99,40 +101,48 @@ module StateMachines
99
101
  # end
100
102
  # end
101
103
  # end
102
- #
104
+ #
103
105
  # vehicle = Vehicle.new # => #<Vehicle id: nil, state: "parked">
104
106
  # events = Vehicle.state_machine.events
105
- #
107
+ #
106
108
  # vehicle.state_event = nil
107
109
  # events.attribute_transition_for(vehicle) # => nil # Event isn't defined
108
- #
110
+ #
109
111
  # vehicle.state_event = 'invalid'
110
112
  # events.attribute_transition_for(vehicle) # => false # Event is invalid
111
- #
113
+ #
112
114
  # vehicle.state_event = 'ignite'
113
115
  # events.attribute_transition_for(vehicle) # => #<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
114
116
  def attribute_transition_for(object, invalidate = false)
115
117
  return unless machine.action
116
118
 
117
119
  # TODO, simplify
118
- machine.read(object, :event_transition) || if event_name = machine.read(object, :event)
119
- if event = self[event_name.to_sym, :name]
120
- event.transition_for(object) || begin
121
- # No valid transition: invalidate
122
- machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).human_name(object.class)]]) if invalidate
123
- false
124
- end
125
- else
126
- # Event is unknown: invalidate
127
- machine.invalidate(object, :event, :invalid) if invalidate
128
- false
129
- end
130
- end
131
-
120
+ # First try the regular event_transition
121
+ transition = machine.read(object, :event_transition)
122
+
123
+ # If not found and we have stored transitions by machine (issue #91)
124
+ if !transition && (transitions_by_machine = object.instance_variable_get(:@_state_machine_event_transitions))
125
+ transition = transitions_by_machine[machine.name]
126
+ end
127
+
128
+ transition || if event_name = machine.read(object, :event)
129
+ if event = self[event_name.to_sym, :name]
130
+ event.transition_for(object) || begin
131
+ # No valid transition: invalidate
132
+ machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).human_name(object.class)]]) if invalidate
133
+ false
134
+ end
135
+ else
136
+ # Event is unknown: invalidate
137
+ machine.invalidate(object, :event, :invalid) if invalidate
138
+ false
139
+ end
140
+ end
132
141
  end
133
142
 
134
143
  private
135
- def match(requirements) #:nodoc:
144
+
145
+ def match(requirements) # :nodoc:
136
146
  requirements && requirements[:on] ? [fetch(requirements.delete(:on))] : self
137
147
  end
138
148
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  module ClassMethods
3
- def self.extended(base) #:nodoc:
5
+ def self.extended(base) # :nodoc:
4
6
  base.class_eval do
5
7
  @state_machines = MachineCollection.new
6
8
  end
@@ -136,13 +138,13 @@ module StateMachines
136
138
  # vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachines::InvalidParallelTransition: Cannot run events in parallel: ignite, disable_alarm
137
139
  def fire_events!(*events)
138
140
  run_action = [true, false].include?(events.last) ? events.pop : true
139
- fire_events(*(events + [run_action])) || fail(StateMachines::InvalidParallelTransition.new(self, events))
141
+ fire_events(*(events + [run_action])) || raise(StateMachines::InvalidParallelTransition.new(self, events))
140
142
  end
141
143
 
142
144
  protected
143
145
 
144
- def initialize_state_machines(options = {}, &block) #:nodoc:
145
- self.class.state_machines.initialize_states(self, options, &block)
146
+ def initialize_state_machines(options = {}, &) # :nodoc:
147
+ self.class.state_machines.initialize_states(self, options, &)
146
148
  end
147
149
  end
148
150
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Represents a type of module that defines instance / class methods for a
3
5
  # state machine
4
- class HelperModule < Module #:nodoc:
6
+ class HelperModule < Module # :nodoc:
5
7
  def initialize(machine, kind)
6
8
  @machine = machine
7
9
  @kind = kind
8
10
  end
9
-
11
+
10
12
  # Provides a human-readable description of the module
11
13
  def to_s
12
14
  owner_class = @machine.owner_class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  module Integrations
3
5
  # Provides a set of base helpers for managing individual integrations
@@ -33,7 +35,7 @@ module StateMachines
33
35
  end
34
36
  end
35
37
 
36
- def self.included(base) #:nodoc:
38
+ def self.included(base) # :nodoc:
37
39
  base.extend ClassMethods
38
40
  end
39
41
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Integrations allow state machines to take advantage of features within the
3
5
  # context of a particular library. This is currently most useful with
@@ -9,10 +11,10 @@ module StateMachines
9
11
  # * Scopes
10
12
  # * Callbacks
11
13
  # * Validation errors
12
- #
14
+ #
13
15
  # This type of integration allows the user to work with state machines in a
14
16
  # fashion similar to other object models in their application.
15
- #
17
+ #
16
18
  # The integration interface is loosely defined by various unimplemented
17
19
  # methods in the StateMachines::Machine class. See that class or the various
18
20
  # built-in integrations for more information about how to define additional
@@ -24,15 +26,15 @@ module StateMachines
24
26
  # Register integration
25
27
  def register(name_or_module)
26
28
  case name_or_module.class.to_s
27
- when 'Module'
28
- add(name_or_module)
29
- else
30
- fail IntegrationError
29
+ when 'Module'
30
+ add(name_or_module)
31
+ else
32
+ raise IntegrationError
31
33
  end
32
34
  true
33
35
  end
34
36
 
35
- def reset #:nodoc:#
37
+ def reset # :nodoc:#
36
38
  @integrations = []
37
39
  end
38
40
 
@@ -45,30 +47,27 @@ module StateMachines
45
47
  # StateMachines::Integrations.register(StateMachines::Integrations::ActiveModel)
46
48
  # StateMachines::Integrations.integrations
47
49
  # # => [StateMachines::Integrations::ActiveModel]
48
- def integrations
49
- # Register all namespaced integrations
50
- @integrations
51
- end
50
+ attr_reader :integrations
52
51
 
53
- alias_method :list, :integrations
52
+ alias list integrations
54
53
 
55
54
  # Attempts to find an integration that matches the given class. This will
56
55
  # look through all of the built-in integrations under the StateMachines::Integrations
57
56
  # namespace and find one that successfully matches the class.
58
- #
57
+ #
59
58
  # == Examples
60
- #
59
+ #
61
60
  # class Vehicle
62
61
  # end
63
- #
62
+ #
64
63
  # class ActiveModelVehicle
65
64
  # include ActiveModel::Observing
66
65
  # include ActiveModel::Validations
67
66
  # end
68
- #
67
+ #
69
68
  # class ActiveRecordVehicle < ActiveRecord::Base
70
69
  # end
71
- #
70
+ #
72
71
  # StateMachines::Integrations.match(Vehicle) # => nil
73
72
  # StateMachines::Integrations.match(ActiveModelVehicle) # => StateMachines::Integrations::ActiveModel
74
73
  # StateMachines::Integrations.match(ActiveRecordVehicle) # => StateMachines::Integrations::ActiveRecord
@@ -103,9 +102,9 @@ module StateMachines
103
102
  private
104
103
 
105
104
  def add(integration)
106
- if integration.respond_to?(:integration_name)
107
- @integrations.insert(0, integration) unless @integrations.include?(integration)
108
- end
105
+ return unless integration.respond_to?(:integration_name)
106
+
107
+ @integrations.insert(0, integration) unless @integrations.include?(integration)
109
108
  end
110
109
  end
111
110
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module ActionHooks
6
+ protected
7
+
8
+ # Determines whether action helpers should be defined for this machine.
9
+ # This is only true if there is an action configured and no other machines
10
+ # have process this same configuration already.
11
+ def define_action_helpers?
12
+ action && owner_class.state_machines.none? { |_name, machine| machine.action == action && machine != self }
13
+ end
14
+
15
+ # Adds helper methods for automatically firing events when an action
16
+ # is invoked
17
+ def define_action_helpers
18
+ return unless action_hook
19
+
20
+ @action_hook_defined = true
21
+ define_action_hook
22
+ end
23
+
24
+ # Hooks directly into actions by defining the same method in an included
25
+ # module. As a result, when the action gets invoked, any state events
26
+ # defined for the object will get run. Method visibility is preserved.
27
+ def define_action_hook
28
+ action_hook = self.action_hook
29
+ action = self.action
30
+ private_action_hook = owner_class.private_method_defined?(action_hook)
31
+
32
+ # Only define helper if it hasn't
33
+ define_helper :instance, <<-END_EVAL, __FILE__, __LINE__ + 1
34
+ def #{action_hook}(*)
35
+ self.class.state_machines.transitions(self, #{action.inspect}).perform { super }
36
+ end
37
+
38
+ private #{action_hook.inspect} if #{private_action_hook}
39
+ END_EVAL
40
+ end
41
+
42
+ # The method to hook into for triggering transitions when invoked. By
43
+ # default, this is the action configured for the machine.
44
+ #
45
+ # Since the default hook technique relies on module inheritance, the
46
+ # action must be defined in an ancestor of the owner classs in order for
47
+ # it to be the action hook.
48
+ def action_hook
49
+ action && owner_class_ancestor_has_method?(:instance, action) ? action : nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file provides optional async extensions for the Machine class.
4
+ # It should only be loaded when async functionality is explicitly requested.
5
+
6
+ module StateMachines
7
+ class Machine
8
+ # AsyncMode extensions for the Machine class
9
+ # Provides async-aware methods while maintaining backward compatibility
10
+ module AsyncExtensions
11
+ # Instance methods added to Machine for async support
12
+
13
+ # Configure this specific machine instance for async mode
14
+ #
15
+ # Example:
16
+ # class Vehicle
17
+ # state_machine initial: :parked do
18
+ # configure_async_mode! # Enable async for this machine
19
+ #
20
+ # event :ignite do
21
+ # transition parked: :idling
22
+ # end
23
+ # end
24
+ # end
25
+ def configure_async_mode!(enabled = true)
26
+ if enabled
27
+ begin
28
+ require 'state_machines/async_mode'
29
+ @async_mode_enabled = true
30
+
31
+ owner_class.include(StateMachines::AsyncMode::ThreadSafeState)
32
+ owner_class.include(StateMachines::AsyncMode::AsyncEvents)
33
+ self.extend(StateMachines::AsyncMode::AsyncMachine)
34
+
35
+ # Extend events to generate async versions
36
+ events.each do |event|
37
+ event.extend(StateMachines::AsyncMode::AsyncEventExtensions)
38
+ end
39
+ rescue LoadError => e
40
+ # Fallback to sync mode with warning (only once per class)
41
+ unless owner_class.instance_variable_get(:@async_fallback_warned)
42
+ warn <<~WARNING
43
+ ⚠️ #{owner_class.name}: Async mode requested but not available on #{RUBY_ENGINE}.
44
+
45
+ #{e.message}
46
+
47
+ ⚠️ Falling back to synchronous mode. Results may be unpredictable due to engine limitations.
48
+ For production async support, use MRI Ruby (CRuby) 3.2+
49
+ WARNING
50
+ owner_class.instance_variable_set(:@async_fallback_warned, true)
51
+ end
52
+
53
+ @async_mode_enabled = false
54
+ end
55
+ else
56
+ @async_mode_enabled = false
57
+ end
58
+
59
+ self
60
+ end
61
+
62
+ # Check if this specific machine instance has async mode enabled
63
+ def async_mode_enabled?
64
+ @async_mode_enabled || false
65
+ end
66
+
67
+ # Thread-safe version of state reading
68
+ def read_safely(object, attribute, ivar = false)
69
+ object.read_state_safely(self, attribute, ivar)
70
+ end
71
+
72
+ # Thread-safe version of state writing
73
+ def write_safely(object, attribute, value, ivar = false)
74
+ object.write_state_safely(self, attribute, value, ivar)
75
+ end
76
+
77
+ # Thread-safe callback execution for async operations
78
+ def run_callbacks_safely(type, object, context, transition)
79
+ object.state_machine_mutex.with_write_lock do
80
+ callbacks[type].each { |callback| callback.call(object, context, transition) }
81
+ end
82
+ end
83
+ end
84
+
85
+ # Include async extensions by default (but only load AsyncMode when requested)
86
+ include AsyncExtensions
87
+ end
88
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module Callbacks
6
+ # Creates a callback that will be invoked *before* a transition is
7
+ # performed so long as the given requirements match the transition.
8
+ def before_transition(*args, **options, &)
9
+ # Extract legacy positional arguments and merge with keyword options
10
+ parsed_options = parse_callback_arguments(args, options)
11
+
12
+ # Only validate callback-specific options, not state transition requirements
13
+ callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
14
+ StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
15
+
16
+ add_callback(:before, parsed_options, &)
17
+ end
18
+
19
+ # Creates a callback that will be invoked *after* a transition is
20
+ # performed so long as the given requirements match the transition.
21
+ def after_transition(*args, **options, &)
22
+ # Extract legacy positional arguments and merge with keyword options
23
+ parsed_options = parse_callback_arguments(args, options)
24
+
25
+ # Only validate callback-specific options, not state transition requirements
26
+ callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
27
+ StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
28
+
29
+ add_callback(:after, parsed_options, &)
30
+ end
31
+
32
+ # Creates a callback that will be invoked *around* a transition so long
33
+ # as the given requirements match the transition.
34
+ def around_transition(*args, **options, &)
35
+ # Extract legacy positional arguments and merge with keyword options
36
+ parsed_options = parse_callback_arguments(args, options)
37
+
38
+ # Only validate callback-specific options, not state transition requirements
39
+ callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
40
+ StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
41
+
42
+ add_callback(:around, parsed_options, &)
43
+ end
44
+
45
+ # Creates a callback that will be invoked after a transition has failed
46
+ # to be performed.
47
+ def after_failure(*args, **options, &)
48
+ # Extract legacy positional arguments and merge with keyword options
49
+ parsed_options = parse_callback_arguments(args, options)
50
+
51
+ # Only validate callback-specific options, not state transition requirements
52
+ callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
53
+ StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
54
+
55
+ add_callback(:failure, parsed_options, &)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module ClassMethods
6
+ # Attempts to find or create a state machine for the given class. For
7
+ # example,
8
+ #
9
+ # StateMachines::Machine.find_or_create(Vehicle)
10
+ # StateMachines::Machine.find_or_create(Vehicle, :initial => :parked)
11
+ # StateMachines::Machine.find_or_create(Vehicle, :status)
12
+ # StateMachines::Machine.find_or_create(Vehicle, :status, :initial => :parked)
13
+ #
14
+ # If a machine of the given name already exists in one of the class's
15
+ # superclasses, then a copy of that machine will be created and stored
16
+ # in the new owner class (the original will remain unchanged).
17
+ def find_or_create(owner_class, *args, &)
18
+ options = args.last.is_a?(Hash) ? args.pop : {}
19
+ name = args.first || :state
20
+
21
+ # Find an existing machine
22
+ machine = (owner_class.respond_to?(:state_machines) &&
23
+ ((args.first && owner_class.state_machines[name]) || (!args.first &&
24
+ owner_class.state_machines.values.first))) || nil
25
+
26
+ if machine
27
+ # Only create a new copy if changes are being made to the machine in
28
+ # a subclass
29
+ if machine.owner_class != owner_class && (options.any? || block_given?)
30
+ machine = machine.clone
31
+ machine.initial_state = options[:initial] if options.include?(:initial)
32
+ machine.owner_class = owner_class
33
+ # Configure async mode if requested in options
34
+ if options.include?(:async)
35
+ machine.configure_async_mode!(options[:async])
36
+ end
37
+ end
38
+
39
+ # Evaluate DSL
40
+ machine.instance_eval(&) if block_given?
41
+ else
42
+ # No existing machine: create a new one
43
+ machine = new(owner_class, name, options, &)
44
+ end
45
+
46
+ machine
47
+ end
48
+
49
+ def draw(*)
50
+ raise NotImplementedError
51
+ end
52
+
53
+ # Default messages to use for validation errors in ORM integrations
54
+ # Thread-safe access via atomic operations on simple values
55
+ attr_accessor :ignore_method_conflicts
56
+
57
+ def default_messages
58
+ @default_messages ||= {
59
+ invalid: 'is invalid',
60
+ invalid_event: 'cannot transition when %s',
61
+ invalid_transition: 'cannot transition via "%1$s"'
62
+ }.freeze
63
+ end
64
+
65
+ def default_messages=(messages)
66
+ # Atomic replacement with frozen object
67
+ @default_messages = deep_freeze_hash(messages)
68
+ end
69
+
70
+ def replace_messages(message_hash)
71
+ # Atomic replacement: read current messages, merge with new ones, replace atomically
72
+ current_messages = @default_messages || {}
73
+ merged_messages = current_messages.merge(message_hash)
74
+ @default_messages = deep_freeze_hash(merged_messages)
75
+ end
76
+
77
+ attr_writer :renderer
78
+
79
+ def renderer
80
+ return @renderer if @renderer
81
+
82
+ STDIORenderer
83
+ end
84
+
85
+ private
86
+
87
+ # Deep freezes a hash and all its string values for thread safety
88
+ def deep_freeze_hash(hash)
89
+ hash.each_with_object({}) do |(key, value), frozen_hash|
90
+ frozen_key = key.respond_to?(:freeze) ? key.freeze : key
91
+ frozen_value = value.respond_to?(:freeze) ? value.freeze : value
92
+ frozen_hash[frozen_key] = frozen_value
93
+ end.freeze
94
+ end
95
+ end
96
+ end
97
+ end