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,23 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
4
+
1
5
  module StateMachines
2
6
  # Represents a collection of paths that are generated based on a set of
3
7
  # requirements regarding what states to start and end on
4
8
  class PathCollection < Array
5
-
6
-
7
9
  # The object whose state machine is being walked
8
10
  attr_reader :object
9
-
11
+
10
12
  # The state machine these path are walking
11
13
  attr_reader :machine
12
-
14
+
13
15
  # The initial state to start each path from
14
16
  attr_reader :from_name
15
-
17
+
16
18
  # The target state for each path
17
19
  attr_reader :to_name
18
-
20
+
19
21
  # Creates a new collection of paths with the given requirements.
20
- #
22
+ #
21
23
  # Configuration options:
22
24
  # * <tt>:from</tt> - The initial state to start from
23
25
  # * <tt>:to</tt> - The target end state
@@ -25,64 +27,65 @@ module StateMachines
25
27
  # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
26
28
  # conditionals defined for each one
27
29
  def initialize(object, machine, options = {})
28
- options = {:deep => false, :from => machine.states.match!(object).name}.merge(options)
29
- options.assert_valid_keys( :from, :to, :deep, :guard)
30
-
30
+ options = { deep: false, from: machine.states.match!(object).name }.merge(options)
31
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :from, :to, :deep, :guard)
32
+
31
33
  @object = object
32
34
  @machine = machine
33
35
  @from_name = machine.states.fetch(options[:from]).name
34
36
  @to_name = options[:to] && machine.states.fetch(options[:to]).name
35
37
  @guard = options[:guard]
36
38
  @deep = options[:deep]
37
-
38
- initial_paths.each {|path| walk(path)}
39
+
40
+ initial_paths.each { |path| walk(path) }
39
41
  end
40
-
42
+
41
43
  # Lists all of the states that can be transitioned from through the paths in
42
44
  # this collection.
43
- #
45
+ #
44
46
  # For example,
45
- #
47
+ #
46
48
  # paths.from_states # => [:parked, :idling, :first_gear, ...]
47
49
  def from_states
48
50
  flat_map(&:from_states).uniq
49
51
  end
50
-
52
+
51
53
  # Lists all of the states that can be transitioned to through the paths in
52
54
  # this collection.
53
- #
55
+ #
54
56
  # For example,
55
- #
57
+ #
56
58
  # paths.to_states # => [:idling, :first_gear, :second_gear, ...]
57
59
  def to_states
58
60
  flat_map(&:to_states).uniq
59
61
  end
60
-
62
+
61
63
  # Lists all of the events that can be fired through the paths in this
62
64
  # collection.
63
- #
65
+ #
64
66
  # For example,
65
- #
67
+ #
66
68
  # paths.events # => [:park, :ignite, :shift_up, ...]
67
69
  def events
68
70
  flat_map(&:events).uniq
69
71
  end
70
-
72
+
71
73
  private
72
- # Gets the initial set of paths to walk
73
- def initial_paths
74
- machine.events.transitions_for(object, :from => from_name, :guard => @guard).map do |transition|
75
- path = Path.new(object, machine, :target => to_name, :guard => @guard)
76
- path << transition
77
- path
78
- end
79
- end
80
-
81
- # Walks down the given path. Each new path that matches the configured
82
- # requirements will be added to this collection.
83
- def walk(path)
84
- self << path if path.complete?
85
- path.walk {|next_path| walk(next_path)} unless to_name && path.complete? && !@deep
74
+
75
+ # Gets the initial set of paths to walk
76
+ def initial_paths
77
+ machine.events.transitions_for(object, from: from_name, guard: @guard).map do |transition|
78
+ path = Path.new(object, machine, target: to_name, guard: @guard)
79
+ path << transition
80
+ path
86
81
  end
82
+ end
83
+
84
+ # Walks down the given path. Each new path that matches the configured
85
+ # requirements will be added to this collection.
86
+ def walk(path)
87
+ self << path if path.complete?
88
+ path.walk { |next_path| walk(next_path) } unless to_name && path.complete? && !@deep
89
+ end
87
90
  end
88
91
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
4
+
1
5
  module StateMachines
2
6
  # A state defines a value that an attribute can be in after being transitioned
3
7
  # 0 or more times. States can represent a value of any type in Ruby, though
@@ -8,7 +12,6 @@ module StateMachines
8
12
  # StateMachines::Machine#state for more information about how state-driven
9
13
  # behavior can be utilized.
10
14
  class State
11
-
12
15
  # The state machine for which this state is defined
13
16
  attr_reader :machine
14
17
 
@@ -31,7 +34,7 @@ module StateMachines
31
34
 
32
35
  # Whether or not this state is the initial state to use for new objects
33
36
  attr_accessor :initial
34
- alias_method :initial?, :initial
37
+ alias initial? initial
35
38
 
36
39
  # A custom lambda block for determining whether a given value matches this
37
40
  # state
@@ -50,38 +53,59 @@ module StateMachines
50
53
  # (e.g. :value => lambda {Time.now}, :if => lambda {|state| !state.nil?}).
51
54
  # By default, the configured value is matched.
52
55
  # * <tt>:human_name</tt> - The human-readable version of this state's name
53
- def initialize(machine, name, options = {}) #:nodoc:
54
- options.assert_valid_keys(:initial, :value, :cache, :if, :human_name)
56
+ def initialize(machine, name, options = nil, initial: false, value: :__not_provided__, cache: nil, if: nil, human_name: nil, **extra_options) # :nodoc:
57
+ # Handle both old hash style and new kwargs style for backward compatibility
58
+ case options
59
+ in Hash
60
+ # Old style: initialize(machine, name, {initial: true, value: 'foo'})
61
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :initial, :value, :cache, :if, :human_name)
62
+ initial = options.fetch(:initial, false)
63
+ value = options.include?(:value) ? options[:value] : :__not_provided__
64
+ cache = options[:cache]
65
+ if_condition = options[:if]
66
+ human_name = options[:human_name]
67
+ in nil
68
+ # New style: initialize(machine, name, initial: true, value: 'foo')
69
+ StateMachines::OptionsValidator.assert_valid_keys!(extra_options, :initial, :value, :cache, :if, :human_name) unless extra_options.empty?
70
+ if_condition = binding.local_variable_get(:if) # 'if' is a keyword, need special handling
71
+ else
72
+ # Handle unexpected options
73
+ raise ArgumentError, "Unexpected positional argument in State initialize: #{options.inspect}"
74
+ end
55
75
 
56
76
  @machine = machine
57
77
  @name = name
58
78
  @qualified_name = name && machine.namespace ? :"#{machine.namespace}_#{name}" : name
59
- @human_name = options[:human_name] || (@name ? @name.to_s.tr('_', ' ') : 'nil')
60
- @value = options.include?(:value) ? options[:value] : name && name.to_s
61
- @cache = options[:cache]
62
- @matcher = options[:if]
63
- @initial = options[:initial] == true
79
+ @human_name = human_name || (@name ? @name.to_s.tr('_', ' ') : 'nil')
80
+ @value = value == :__not_provided__ ? name&.to_s : value
81
+ @cache = cache
82
+ @matcher = if_condition
83
+ @initial = initial == true
64
84
  @context = StateContext.new(self)
65
85
 
66
- if name
67
- conflicting_machines = machine.owner_class.state_machines.select { |other_name, other_machine| other_machine != machine && other_machine.states[qualified_name, :qualified_name] }
68
-
69
- # Output a warning if another machine has a conflicting qualified name
70
- # for a different attribute
71
- if conflict = conflicting_machines.detect { |other_name, other_machine| other_machine.attribute != machine.attribute }
72
- name, other_machine = conflict
73
- warn "State #{qualified_name.inspect} for #{machine.name.inspect} is already defined in #{other_machine.name.inspect}"
74
- elsif conflicting_machines.empty?
75
- # Only bother adding predicates when another machine for the same
76
- # attribute hasn't already done so
77
- add_predicate
78
- end
86
+ return unless name
87
+
88
+ conflicting_machines = machine.owner_class.state_machines.select do |_other_name, other_machine|
89
+ other_machine != machine && other_machine.states[qualified_name, :qualified_name]
90
+ end
91
+
92
+ # Output a warning if another machine has a conflicting qualified name
93
+ # for a different attribute
94
+ if (conflict = conflicting_machines.detect do |_other_name, other_machine|
95
+ other_machine.attribute != machine.attribute
96
+ end)
97
+ _name, other_machine = conflict
98
+ warn "State #{qualified_name.inspect} for #{machine.name.inspect} is already defined in #{other_machine.name.inspect}"
99
+ elsif conflicting_machines.empty?
100
+ # Only bother adding predicates when another machine for the same
101
+ # attribute hasn't already done so
102
+ add_predicate
79
103
  end
80
104
  end
81
105
 
82
106
  # Creates a copy of this state, excluding the context to prevent conflicts
83
107
  # across different machines.
84
- def initialize_copy(orig) #:nodoc:
108
+ def initialize_copy(orig) # :nodoc:
85
109
  super
86
110
  @context = StateContext.new(self)
87
111
  end
@@ -96,10 +120,10 @@ module StateMachines
96
120
  # Any objects in a final state will remain so forever given the current
97
121
  # machine's definition.
98
122
  def final?
99
- !machine.events.any? do |event|
123
+ machine.events.none? do |event|
100
124
  event.branches.any? do |branch|
101
125
  branch.state_requirements.any? do |requirement|
102
- requirement[:from].matches?(name) && !requirement[:to].matches?(name, :from => name)
126
+ requirement[:from].matches?(name) && !requirement[:to].matches?(name, from: name)
103
127
  end
104
128
  end
105
129
  end
@@ -126,7 +150,7 @@ module StateMachines
126
150
  # description or just the internal name
127
151
  def description(options = {})
128
152
  label = options[:human_name] ? human_name : name
129
- description = label ? label.to_s : label.inspect
153
+ description = +(label ? label.to_s : label.inspect)
130
154
  description << " (#{@value.is_a?(Proc) ? '*' : @value.inspect})" unless name.to_s == @value.to_s
131
155
  description
132
156
  end
@@ -178,27 +202,27 @@ module StateMachines
178
202
  #
179
203
  # This can be called multiple times. Each time a new context is created,
180
204
  # a new module will be included in the owner class.
181
- def context(&block)
205
+ def context(&)
182
206
  # Include the context
183
207
  context = @context
184
208
  machine.owner_class.class_eval { include context }
185
209
 
186
210
  # Evaluate the method definitions and track which ones were added
187
211
  old_methods = context_methods
188
- context.class_eval(&block)
189
- new_methods = context_methods.to_a.select { |(name, method)| old_methods[name] != method }
212
+ context.class_eval(&)
213
+ new_methods = context_methods.to_a.reject { |(name, method)| old_methods[name] == method }
190
214
 
191
215
  # Alias new methods so that the only execute when the object is in this state
192
216
  new_methods.each do |(method_name, _method)|
193
217
  context_name = context_name_for(method_name)
194
- context.class_eval <<-end_eval, __FILE__, __LINE__ + 1
218
+ context.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
195
219
  alias_method :"#{context_name}", :#{method_name}
196
220
  def #{method_name}(*args, &block)
197
221
  state = self.class.state_machine(#{machine.name.inspect}).states.fetch(#{name.inspect})
198
222
  options = {:method_missing => lambda {super(*args, &block)}, :method_name => #{method_name.inspect}}
199
223
  state.call(self, :"#{context_name}", *(args + [options]), &block)
200
224
  end
201
- end_eval
225
+ END_EVAL
202
226
  end
203
227
 
204
228
  true
@@ -216,31 +240,30 @@ module StateMachines
216
240
  #
217
241
  # If the method has never been defined for this state, then a NoMethodError
218
242
  # will be raised.
219
- def call(object, method, *args, &block)
243
+ def call(object, method, *args, &)
220
244
  options = args.last.is_a?(Hash) ? args.pop : {}
221
- options = {:method_name => method}.merge(options)
245
+ options = { method_name: method }.merge(options)
222
246
  state = machine.states.match!(object)
223
247
 
224
248
  if state == self && object.respond_to?(method)
225
- object.send(method, *args, &block)
226
- elsif method_missing = options[:method_missing]
249
+ object.send(method, *args, &)
250
+ elsif (method_missing = options[:method_missing])
227
251
  # Dispatch to the superclass since the object either isn't in this state
228
252
  # or this state doesn't handle the method
229
253
  begin
230
254
  method_missing.call
231
- rescue NoMethodError => ex
232
- if ex.name.to_s == options[:method_name].to_s && ex.args == args
233
- # No valid context for this method
234
- raise InvalidContext.new(object, "State #{state.name.inspect} for #{machine.name.inspect} is not a valid context for calling ##{options[:method_name]}")
235
- else
236
- raise
237
- end
255
+ rescue NoMethodError => e
256
+ raise unless e.name.to_s == options[:method_name].to_s && e.args == args
257
+
258
+ # No valid context for this method
259
+ raise InvalidContext.new(object,
260
+ "State #{state.name.inspect} for #{machine.name.inspect} is not a valid context for calling ##{options[:method_name]}")
238
261
  end
239
262
  end
240
263
  end
241
264
 
242
- def draw(graph, options = {})
243
- fail NotImplementedError
265
+ def draw(graph, options = {}, io = $stdout)
266
+ machine.renderer.draw_state(self, graph, options, io)
244
267
  end
245
268
 
246
269
  # Generates a nicely formatted description of this state's contents.
@@ -255,6 +278,7 @@ module StateMachines
255
278
  end
256
279
 
257
280
  private
281
+
258
282
  # Should the value be cached after it's evaluated for the first time?
259
283
  def cache_value?
260
284
  @cache
@@ -263,9 +287,16 @@ module StateMachines
263
287
  # Adds a predicate method to the owner class so long as a name has
264
288
  # actually been configured for the state
265
289
  def add_predicate
266
- # Checks whether the current value matches this state
267
- machine.define_helper(:instance, "#{qualified_name}?") do |machine, object|
268
- machine.states.matches?(object, name)
290
+ predicate_method = "#{qualified_name}?"
291
+
292
+ if machine.send(:owner_class_ancestor_has_method?, :instance, predicate_method)
293
+ warn_about_method_conflict(predicate_method, machine.owner_class.ancestors.first)
294
+ elsif machine.send(:owner_class_has_method?, :instance, predicate_method)
295
+ warn_about_method_conflict(predicate_method, machine.owner_class)
296
+ else
297
+ machine.define_helper(:instance, predicate_method) do |machine, object|
298
+ machine.states.matches?(object, name)
299
+ end
269
300
  end
270
301
  end
271
302
 
@@ -273,5 +304,11 @@ module StateMachines
273
304
  def context_name_for(method)
274
305
  :"__#{machine.name}_#{name}_#{method}_#{@context.object_id}__"
275
306
  end
307
+
308
+ def warn_about_method_conflict(method, defined_in)
309
+ return if StateMachines::Machine.ignore_method_conflicts
310
+
311
+ warn "Instance method #{method.inspect} is already defined in #{defined_in.inspect}, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true."
312
+ end
276
313
  end
277
314
  end
@@ -1,26 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Represents a collection of states in a state machine
3
5
  class StateCollection < NodeCollection
4
- def initialize(machine) #:nodoc:
5
- super(machine, :index => [:name, :qualified_name, :value])
6
+ def initialize(machine) # :nodoc:
7
+ super(machine, index: %i[name qualified_name value])
6
8
  end
7
9
 
8
10
  # Determines whether the given object is in a specific state. If the
9
11
  # object's current value doesn't match the state, then this will return
10
12
  # false, otherwise true. If the given state is unknown, then an IndexError
11
13
  # will be raised.
12
- #
14
+ #
13
15
  # == Examples
14
- #
16
+ #
15
17
  # class Vehicle
16
18
  # state_machine :initial => :parked do
17
19
  # other_states :idling
18
20
  # end
19
21
  # end
20
- #
22
+ #
21
23
  # states = Vehicle.state_machine.states
22
24
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
23
- #
25
+ #
24
26
  # states.matches?(vehicle, :parked) # => true
25
27
  # states.matches?(vehicle, :idling) # => false
26
28
  # states.matches?(vehicle, :invalid) # => IndexError: :invalid is an invalid key for :name index
@@ -31,23 +33,23 @@ module StateMachines
31
33
  # Determines the current state of the given object as configured by this
32
34
  # state machine. This will attempt to find a known state that matches
33
35
  # the value of the attribute on the object.
34
- #
36
+ #
35
37
  # == Examples
36
- #
38
+ #
37
39
  # class Vehicle
38
40
  # state_machine :initial => :parked do
39
41
  # other_states :idling
40
42
  # end
41
43
  # end
42
- #
44
+ #
43
45
  # states = Vehicle.state_machine.states
44
- #
46
+ #
45
47
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
46
48
  # states.match(vehicle) # => #<StateMachines::State name=:parked value="parked" initial=true>
47
- #
49
+ #
48
50
  # vehicle.state = 'idling'
49
51
  # states.match(vehicle) # => #<StateMachines::State name=:idling value="idling" initial=true>
50
- #
52
+ #
51
53
  # vehicle.state = 'invalid'
52
54
  # states.match(vehicle) # => nil
53
55
  def match(object)
@@ -58,20 +60,20 @@ module StateMachines
58
60
  # Determines the current state of the given object as configured by this
59
61
  # state machine. If no state is found, then an ArgumentError will be
60
62
  # raised.
61
- #
63
+ #
62
64
  # == Examples
63
- #
65
+ #
64
66
  # class Vehicle
65
67
  # state_machine :initial => :parked do
66
68
  # other_states :idling
67
69
  # end
68
70
  # end
69
- #
71
+ #
70
72
  # states = Vehicle.state_machine.states
71
- #
73
+ #
72
74
  # vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
73
75
  # states.match!(vehicle) # => #<StateMachines::State name=:parked value="parked" initial=true>
74
- #
76
+ #
75
77
  # vehicle.state = 'invalid'
76
78
  # states.match!(vehicle) # => ArgumentError: "invalid" is not a known state value
77
79
  def match!(object)
@@ -80,13 +82,13 @@ module StateMachines
80
82
 
81
83
  # Gets the order in which states should be displayed based on where they
82
84
  # were first referenced. This will order states in the following priority:
83
- #
85
+ #
84
86
  # 1. Initial state
85
87
  # 2. Event transitions (:from, :except_from, :to, :except_to options)
86
88
  # 3. States with behaviors
87
89
  # 4. States referenced via +state+ or +other_states+
88
90
  # 5. States referenced in callbacks
89
- #
91
+ #
90
92
  # This order will determine how the GraphViz visualizations are rendered.
91
93
  def by_priority
92
94
  order = select { |state| state.initial }.map { |state| state.name }
@@ -102,6 +104,7 @@ module StateMachines
102
104
  end
103
105
 
104
106
  private
107
+
105
108
  # Gets the value for the given attribute on the node
106
109
  def value(node, attribute)
107
110
  attribute == :value ? node.value(false) : super
@@ -1,133 +1,134 @@
1
- module StateMachines
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
2
4
 
3
-
5
+ module StateMachines
4
6
  # Represents a module which will get evaluated within the context of a state.
5
- #
7
+ #
6
8
  # Class-level methods are proxied to the owner class, injecting a custom
7
9
  # <tt>:if</tt> condition along with method. This assumes that the method has
8
10
  # support for a set of configuration options, including <tt>:if</tt>. This
9
11
  # condition will check that the object's state matches this context's state.
10
- #
12
+ #
11
13
  # Instance-level methods are used to define state-driven behavior on the
12
14
  # state's owner class.
13
- #
15
+ #
14
16
  # == Examples
15
- #
17
+ #
16
18
  # class Vehicle
17
19
  # class << self
18
20
  # attr_accessor :validations
19
- #
21
+ #
20
22
  # def validate(options, &block)
21
23
  # validations << options
22
24
  # end
23
25
  # end
24
- #
26
+ #
25
27
  # self.validations = []
26
28
  # attr_accessor :state, :simulate
27
- #
29
+ #
28
30
  # def moving?
29
31
  # self.class.validations.all? {|validation| validation[:if].call(self)}
30
32
  # end
31
33
  # end
32
- #
34
+ #
33
35
  # In the above class, a simple set of validation behaviors have been defined.
34
36
  # Each validation consists of a configuration like so:
35
- #
37
+ #
36
38
  # Vehicle.validate :unless => :simulate
37
39
  # Vehicle.validate :if => lambda {|vehicle| ...}
38
- #
40
+ #
39
41
  # In order to scope validations to a particular state context, the class-level
40
42
  # +validate+ method can be invoked like so:
41
- #
43
+ #
42
44
  # machine = StateMachines::Machine.new(Vehicle)
43
45
  # context = StateMachines::StateContext.new(machine.state(:first_gear))
44
46
  # context.validate(:unless => :simulate)
45
- #
47
+ #
46
48
  # vehicle = Vehicle.new # => #<Vehicle:0xb7ce491c @simulate=nil, @state=nil>
47
49
  # vehicle.moving? # => false
48
- #
50
+ #
49
51
  # vehicle.state = 'first_gear'
50
52
  # vehicle.moving? # => true
51
- #
53
+ #
52
54
  # vehicle.simulate = true
53
55
  # vehicle.moving? # => false
54
56
  class StateContext < Module
55
-
56
57
  include EvalHelpers
57
-
58
+
58
59
  # The state machine for which this context's state is defined
59
60
  attr_reader :machine
60
-
61
+
61
62
  # The state that must be present in an object for this context to be active
62
63
  attr_reader :state
63
-
64
+
64
65
  # Creates a new context for the given state
65
66
  def initialize(state)
66
67
  @state = state
67
68
  @machine = state.machine
68
-
69
+
69
70
  state_name = state.name
70
71
  machine_name = machine.name
71
- @condition = lambda {|object| object.class.state_machine(machine_name).states.matches?(object, state_name)}
72
+ @condition = ->(object) { object.class.state_machine(machine_name).states.matches?(object, state_name) }
72
73
  end
73
-
74
+
74
75
  # Creates a new transition that determines what to change the current state
75
76
  # to when an event fires from this state.
76
- #
77
+ #
77
78
  # Since this transition is being defined within a state context, you do
78
79
  # *not* need to specify the <tt>:from</tt> option for the transition. For
79
80
  # example:
80
- #
81
+ #
81
82
  # state_machine do
82
83
  # state :parked do
83
84
  # transition :to => :idling, :on => [:ignite, :shift_up] # Transitions to :idling
84
85
  # transition :from => [:idling, :parked], :on => :park, :unless => :seatbelt_on? # Transitions to :parked if seatbelt is off
85
86
  # end
86
87
  # end
87
- #
88
+ #
88
89
  # See StateMachines::Machine#transition for a description of the possible
89
90
  # configurations for defining transitions.
90
91
  def transition(options)
91
- options.assert_valid_keys(:from, :to, :on, :if, :unless)
92
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :from, :to, :on, :if, :unless)
92
93
  raise ArgumentError, 'Must specify :on event' unless options[:on]
93
94
  raise ArgumentError, 'Must specify either :to or :from state' unless !options[:to] ^ !options[:from]
94
-
95
- machine.transition(options.merge(options[:to] ? {:from => state.name} : {:to => state.name}))
95
+
96
+ machine.transition(options.merge(options[:to] ? { from: state.name } : { to: state.name }))
96
97
  end
97
-
98
+
98
99
  # Hooks in condition-merging to methods that don't exist in this module
99
- def method_missing(*args, &block)
100
+ def method_missing(*args, &)
100
101
  # Get the configuration
101
102
  if args.last.is_a?(Hash)
102
103
  options = args.last
103
104
  else
104
105
  args << options = {}
105
106
  end
106
-
107
+
107
108
  # Get any existing condition that may need to be merged
108
109
  if_condition = options.delete(:if)
109
110
  unless_condition = options.delete(:unless)
110
-
111
+
111
112
  # Provide scope access to configuration in case the block is evaluated
112
113
  # within the object instance
113
114
  proxy = self
114
115
  proxy_condition = @condition
115
-
116
+
116
117
  # Replace the configuration condition with the one configured for this
117
118
  # proxy, merging together any existing conditions
118
119
  options[:if] = lambda do |*condition_args|
119
120
  # Block may be executed within the context of the actual object, so
120
121
  # it'll either be the first argument or the executing context
121
122
  object = condition_args.first || self
122
-
123
+
123
124
  proxy.evaluate_method(object, proxy_condition) &&
124
- Array(if_condition).all? {|condition| proxy.evaluate_method(object, condition)} &&
125
- !Array(unless_condition).any? {|condition| proxy.evaluate_method(object, condition)}
125
+ Array(if_condition).all? { |condition| proxy.evaluate_method(object, condition) } &&
126
+ !Array(unless_condition).any? { |condition| proxy.evaluate_method(object, condition) }
126
127
  end
127
-
128
+
128
129
  # Evaluate the method on the owner class with the condition proxied
129
130
  # through
130
- machine.owner_class.send(*args, &block)
131
+ machine.owner_class.send(*args, &)
131
132
  end
132
133
  end
133
134
  end