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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Provides a general strategy pattern for determining whether a match is found
3
5
  # for a value. The algorithm that actually determines the match depends on
@@ -5,114 +7,115 @@ module StateMachines
5
7
  class Matcher
6
8
  # The list of values against which queries are matched
7
9
  attr_reader :values
8
-
10
+
9
11
  # Creates a new matcher for querying against the given set of values
10
12
  def initialize(values = [])
11
13
  @values = values.is_a?(Array) ? values : [values]
12
14
  end
13
-
15
+
14
16
  # Generates a subset of values that exists in both the set of values being
15
17
  # filtered and the values configured for the matcher
16
18
  def filter(values)
17
19
  self.values & values
18
20
  end
19
21
  end
20
-
22
+
21
23
  # Matches any given value. Since there is no configuration for this type of
22
24
  # matcher, it must be used as a singleton.
23
25
  class AllMatcher < Matcher
24
26
  include Singleton
25
-
27
+
26
28
  # Generates a blacklist matcher based on the given set of values
27
- #
29
+ #
28
30
  # == Examples
29
- #
31
+ #
30
32
  # matcher = StateMachines::AllMatcher.instance - [:parked, :idling]
31
33
  # matcher.matches?(:parked) # => false
32
34
  # matcher.matches?(:first_gear) # => true
33
- def -(blacklist)
34
- BlacklistMatcher.new(blacklist)
35
+ def -(other)
36
+ BlacklistMatcher.new(other)
35
37
  end
36
-
38
+ alias except -
39
+
37
40
  # Always returns true
38
- def matches?(value, context = {})
41
+ def matches?(_value, _context = {})
39
42
  true
40
43
  end
41
-
44
+
42
45
  # Always returns the given set of values
43
46
  def filter(values)
44
47
  values
45
48
  end
46
-
49
+
47
50
  # A human-readable description of this matcher. Always "all".
48
51
  def description
49
52
  'all'
50
53
  end
51
54
  end
52
-
55
+
53
56
  # Matches a specific set of values
54
57
  class WhitelistMatcher < Matcher
55
58
  # Checks whether the given value exists within the whitelist configured
56
59
  # for this matcher.
57
- #
60
+ #
58
61
  # == Examples
59
- #
62
+ #
60
63
  # matcher = StateMachines::WhitelistMatcher.new([:parked, :idling])
61
64
  # matcher.matches?(:parked) # => true
62
65
  # matcher.matches?(:first_gear) # => false
63
- def matches?(value, context = {})
66
+ def matches?(value, _context = {})
64
67
  values.include?(value)
65
68
  end
66
-
69
+
67
70
  # A human-readable description of this matcher
68
71
  def description
69
72
  values.length == 1 ? values.first.inspect : values.inspect
70
73
  end
71
74
  end
72
-
75
+
73
76
  # Matches everything but a specific set of values
74
77
  class BlacklistMatcher < Matcher
75
78
  # Checks whether the given value exists outside the blacklist configured
76
79
  # for this matcher.
77
- #
80
+ #
78
81
  # == Examples
79
- #
82
+ #
80
83
  # matcher = StateMachines::BlacklistMatcher.new([:parked, :idling])
81
84
  # matcher.matches?(:parked) # => false
82
85
  # matcher.matches?(:first_gear) # => true
83
- def matches?(value, context = {})
86
+ def matches?(value, _context = {})
84
87
  !values.include?(value)
85
88
  end
86
-
89
+
87
90
  # Finds all values that are *not* within the blacklist configured for this
88
91
  # matcher
89
92
  def filter(values)
90
93
  values - self.values
91
94
  end
92
-
95
+
93
96
  # A human-readable description of this matcher
94
97
  def description
95
98
  "all - #{values.length == 1 ? values.first.inspect : values.inspect}"
96
99
  end
97
100
  end
98
-
101
+
99
102
  # Matches a loopback of two values within a context. Since there is no
100
103
  # configuration for this type of matcher, it must be used as a singleton.
101
104
  class LoopbackMatcher < Matcher
102
105
  include Singleton
103
-
106
+
104
107
  # Checks whether the given value matches what the value originally was.
105
108
  # This value should be defined in the context.
106
- #
109
+ #
107
110
  # == Examples
108
- #
111
+ #
109
112
  # matcher = StateMachines::LoopbackMatcher.instance
110
113
  # matcher.matches?(:parked, :from => :parked) # => true
111
114
  # matcher.matches?(:parked, :from => :idling) # => false
112
115
  def matches?(value, context)
113
116
  context[:from] == value
114
117
  end
115
-
118
+
116
119
  # A human-readable description of this matcher. Always "same".
117
120
  def description
118
121
  'same'
@@ -1,25 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StateMachines
2
4
  # Provides a set of helper methods for generating matchers
3
5
  module MatcherHelpers
4
6
  # Represents a state that matches all known states in a machine.
5
- #
7
+ #
6
8
  # == Examples
7
- #
9
+ #
8
10
  # class Vehicle
9
11
  # state_machine do
10
12
  # before_transition any => :parked, :do => lambda {...}
11
13
  # before_transition all - :parked => all - :idling, :do => lambda {}
12
- #
14
+ #
13
15
  # event :park
14
16
  # transition all => :parked
15
17
  # end
16
- #
18
+ #
17
19
  # event :crash
18
20
  # transition all - :parked => :stalled
19
21
  # end
20
22
  # end
21
23
  # end
22
- #
24
+ #
23
25
  # In the above example, +all+ will match the following states since they
24
26
  # are known:
25
27
  # * +parked+
@@ -28,13 +30,13 @@ module StateMachines
28
30
  def all
29
31
  AllMatcher.instance
30
32
  end
31
- alias_method :any, :all
32
-
33
+ alias any all
34
+
33
35
  # Represents a state that matches the original +from+ state. This is useful
34
36
  # for defining transitions which are loopbacks.
35
- #
37
+ #
36
38
  # == Examples
37
- #
39
+ #
38
40
  # class Vehicle
39
41
  # state_machine do
40
42
  # event :ignite
@@ -42,11 +44,11 @@ module StateMachines
42
44
  # end
43
45
  # end
44
46
  # end
45
- #
47
+ #
46
48
  # In the above example, +same+ will match whichever the from state is. In
47
49
  # the case of the +ignite+ event, it is essential the same as the following:
48
- #
49
- # transition :parked => :parked, :first_gear => :first_gear
50
+ #
51
+ # transition :idling => :idling, :first_gear => :first_gear
50
52
  def same
51
53
  LoopbackMatcher.instance
52
54
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
4
+
1
5
  module StateMachines
2
6
  # Represents a collection of nodes in a state machine, be it events or states.
3
7
  # Nodes will not differentiate between the String and Symbol versions of the
@@ -16,17 +20,16 @@ module StateMachines
16
20
  # hashed indices for in order to perform quick lookups. Default is to
17
21
  # index by the :name attribute
18
22
  def initialize(machine, options = {})
19
- options.assert_valid_keys(:index)
23
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :index)
20
24
  options = { index: :name }.merge(options)
21
25
 
22
26
  @machine = machine
23
27
  @nodes = []
24
28
  @index_names = Array(options[:index])
25
- @indices = @index_names.reduce({}) do |indices, name|
29
+ @indices = @index_names.each_with_object({}) do |name, indices|
26
30
  indices[name] = {}
27
31
  indices[:"#{name}_to_s"] = {}
28
32
  indices[:"#{name}_to_sym"] = {}
29
- indices
30
33
  end
31
34
  @default_index = Array(options[:index]).first
32
35
  @contexts = []
@@ -34,14 +37,16 @@ module StateMachines
34
37
 
35
38
  # Creates a copy of this collection such that modifications don't affect
36
39
  # the original collection
37
- def initialize_copy(orig) #:nodoc:
40
+ def initialize_copy(orig) # :nodoc:
38
41
  super
39
42
 
40
43
  nodes = @nodes
41
44
  contexts = @contexts
42
45
  @nodes = []
43
46
  @contexts = []
44
- @indices = @indices.reduce({}) { |indices, (name, *)| indices[name] = {}; indices }
47
+ @indices = @indices.each_with_object({}) do |(name, *), indices|
48
+ indices[name] = {}
49
+ end
45
50
 
46
51
  # Add nodes *prior* to copying over the contexts so that they don't get
47
52
  # evaluated multiple times
@@ -112,8 +117,8 @@ module StateMachines
112
117
  # ...produces:
113
118
  #
114
119
  # parked -- idling --
115
- def each
116
- @nodes.each { |node| yield node }
120
+ def each(&)
121
+ @nodes.each(&)
117
122
  self
118
123
  end
119
124
 
@@ -141,9 +146,9 @@ module StateMachines
141
146
  # If the key cannot be found, then nil will be returned.
142
147
  def [](key, index_name = @default_index)
143
148
  index(index_name)[key] ||
144
- index(:"#{index_name}_to_s")[key.to_s] ||
145
- to_sym?(key) && index(:"#{index_name}_to_sym")[:"#{key}"] ||
146
- nil
149
+ index(:"#{index_name}_to_s")[key.to_s] ||
150
+ (to_sym?(key) && index(:"#{index_name}_to_sym")[:"#{key}"]) ||
151
+ nil
147
152
  end
148
153
 
149
154
  # Gets the node indexed by the given key. By default, this will look up the
@@ -159,59 +164,61 @@ module StateMachines
159
164
  #
160
165
  # collection['invalid', :value] # => IndexError: "invalid" is an invalid value
161
166
  def fetch(key, index_name = @default_index)
162
- self[key, index_name] || fail(IndexError, "#{key.inspect} is an invalid #{index_name}")
167
+ self[key, index_name] || raise(IndexError, "#{key.inspect} is an invalid #{index_name}")
163
168
  end
164
169
 
165
170
  protected
166
- # Gets the given index. If the index does not exist, then an ArgumentError
167
- # is raised.
171
+
172
+ # Gets the given index. If the index does not exist, then an ArgumentError
173
+ # is raised.
168
174
  def index(name)
169
- fail ArgumentError, 'No indices configured' unless @indices.any?
170
- @indices[name] || fail(ArgumentError, "Invalid index: #{name.inspect}")
175
+ raise ArgumentError, 'No indices configured' unless @indices.any?
176
+
177
+ @indices[name] || raise(ArgumentError, "Invalid index: #{name.inspect}")
171
178
  end
172
179
 
173
- # Gets the value for the given attribute on the node
180
+ # Gets the value for the given attribute on the node
174
181
  def value(node, attribute)
175
182
  node.send(attribute)
176
183
  end
177
184
 
178
- # Adds the given key / node combination to an index, including the string
179
- # and symbol versions of the index
185
+ # Adds the given key / node combination to an index, including the string
186
+ # and symbol versions of the index
180
187
  def add_to_index(name, key, node)
181
188
  index(name)[key] = node
182
189
  index(:"#{name}_to_s")[key.to_s] = node
183
190
  index(:"#{name}_to_sym")[:"#{key}"] = node if to_sym?(key)
184
191
  end
185
192
 
186
- # Removes the given key from an index, including the string and symbol
187
- # versions of the index
193
+ # Removes the given key from an index, including the string and symbol
194
+ # versions of the index
188
195
  def remove_from_index(name, key)
189
196
  index(name).delete(key)
190
197
  index(:"#{name}_to_s").delete(key.to_s)
191
198
  index(:"#{name}_to_sym").delete(:"#{key}") if to_sym?(key)
192
199
  end
193
200
 
194
- # Updates the node for the given index, including the string and symbol
195
- # versions of the index
201
+ # Updates the node for the given index, including the string and symbol
202
+ # versions of the index
196
203
  def update_index(name, node)
197
204
  index = self.index(name)
198
205
  old_key = index.key(node)
199
206
  new_key = value(node, name)
200
207
 
201
208
  # Only replace the key if it's changed
202
- if old_key != new_key
203
- remove_from_index(name, old_key)
204
- add_to_index(name, new_key, node)
205
- end
209
+ return unless old_key != new_key
210
+
211
+ remove_from_index(name, old_key)
212
+ add_to_index(name, new_key, node)
206
213
  end
207
214
 
208
- # Determines whether the given value can be converted to a symbol
215
+ # Determines whether the given value can be converted to a symbol
209
216
  def to_sym?(value)
210
217
  "#{value}" != ''
211
218
  end
212
219
 
213
- # Evaluates the given context for a particular node. This will only
214
- # evaluate the context if the node matches.
220
+ # Evaluates the given context for a particular node. This will only
221
+ # evaluate the context if the node matches.
215
222
  def eval_context(context, node)
216
223
  node.context(&context[:block]) if context[:nodes].matches?(node.name)
217
224
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ # Define the module if it doesn't exist yet
5
+ # Module for validating options without monkey-patching Hash
6
+ # Provides the same functionality as the Hash monkey patch but in a cleaner way
7
+ module OptionsValidator
8
+ class << self
9
+ # Validates that all keys in the options hash are in the list of valid keys
10
+ #
11
+ # @param options [Hash] The options hash to validate
12
+ # @param valid_keys [Array<Symbol>] List of valid key names
13
+ # @param caller_info [String] Information about the calling method for better error messages
14
+ # @raise [ArgumentError] If any invalid keys are found
15
+ def assert_valid_keys!(options, *valid_keys, caller_info: nil)
16
+ return if options.empty?
17
+
18
+ valid_keys.flatten!
19
+ invalid_keys = options.keys - valid_keys
20
+
21
+ return if invalid_keys.empty?
22
+
23
+ caller_context = caller_info ? " in #{caller_info}" : ''
24
+ raise ArgumentError, "Unknown key#{'s' if invalid_keys.length > 1}: #{invalid_keys.map(&:inspect).join(', ')}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}#{caller_context}"
25
+ end
26
+
27
+ # Validates that at most one of the exclusive keys is present in the options hash
28
+ #
29
+ # @param options [Hash] The options hash to validate
30
+ # @param exclusive_keys [Array<Symbol>] List of mutually exclusive keys
31
+ # @param caller_info [String] Information about the calling method for better error messages
32
+ # @raise [ArgumentError] If more than one exclusive key is found
33
+ def assert_exclusive_keys!(options, *exclusive_keys, caller_info: nil)
34
+ return if options.empty?
35
+
36
+ conflicting_keys = exclusive_keys & options.keys
37
+ return if conflicting_keys.length <= 1
38
+
39
+ caller_context = caller_info ? " in #{caller_info}" : ''
40
+ raise ArgumentError, "Conflicting keys: #{conflicting_keys.join(', ')}#{caller_context}"
41
+ end
42
+
43
+ # Validates options using a more convenient interface that works with both
44
+ # hash-style and kwargs-style method definitions
45
+ #
46
+ # @param valid_keys [Array<Symbol>] List of valid key names
47
+ # @param exclusive_key_groups [Array<Array<Symbol>>] Groups of mutually exclusive keys
48
+ # @param caller_info [String] Information about the calling method
49
+ # @return [Proc] A validation proc that can be called with options
50
+ def validator(valid_keys: [], exclusive_key_groups: [], caller_info: nil)
51
+ proc do |options|
52
+ assert_valid_keys!(options, *valid_keys, caller_info: caller_info) unless valid_keys.empty?
53
+
54
+ exclusive_key_groups.each do |group|
55
+ assert_exclusive_keys!(options, *group, caller_info: caller_info)
56
+ end
57
+ end
58
+ end
59
+
60
+ # Helper method for backwards compatibility - allows gradual migration
61
+ # from Hash monkey patch to this module
62
+ #
63
+ # @param options [Hash] The options to validate
64
+ # @param valid_keys [Array<Symbol>] Valid keys
65
+ # @return [Hash] The same options hash (for chaining)
66
+ def validate_and_return(options, *valid_keys)
67
+ assert_valid_keys!(options, *valid_keys)
68
+ options
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,82 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
4
+
1
5
  module StateMachines
2
6
  # A path represents a sequence of transitions that can be run for a particular
3
7
  # object. Paths can walk to new transitions, revealing all of the possible
4
8
  # branches that can be encountered in the object's state machine.
5
9
  class Path < Array
6
-
7
-
8
10
  # The object whose state machine is being walked
9
11
  attr_reader :object
10
-
12
+
11
13
  # The state machine this path is walking
12
14
  attr_reader :machine
13
-
15
+
14
16
  # Creates a new transition path for the given object. Initially this is an
15
17
  # empty path. In order to start walking the path, it must be populated with
16
18
  # an initial transition.
17
- #
19
+ #
18
20
  # Configuration options:
19
21
  # * <tt>:target</tt> - The target state to end the path on
20
22
  # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
21
23
  # conditionals defined for each one
22
24
  def initialize(object, machine, options = {})
23
- options.assert_valid_keys(:target, :guard)
24
-
25
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :target, :guard)
26
+
25
27
  @object = object
26
28
  @machine = machine
27
29
  @target = options[:target]
28
30
  @guard = options[:guard]
29
31
  end
30
-
31
- def initialize_copy(orig) #:nodoc:
32
+
33
+ def initialize_copy(orig) # :nodoc:
32
34
  super
33
35
  @transitions = nil
34
36
  end
35
-
37
+
36
38
  # The initial state name for this path
37
39
  def from_name
38
- first && first.from_name
40
+ first&.from_name
39
41
  end
40
-
42
+
41
43
  # Lists all of the from states that can be reached through this path.
42
- #
44
+ #
43
45
  # For example,
44
- #
46
+ #
45
47
  # path.to_states # => [:parked, :idling, :first_gear, ...]
46
48
  def from_states
47
- map {|transition| transition.from_name}.uniq
49
+ map { |transition| transition.from_name }.uniq
48
50
  end
49
-
51
+
50
52
  # The end state name for this path. If a target state was specified for
51
53
  # the path, then that will be returned if the path is complete.
52
54
  def to_name
53
- last && last.to_name
55
+ last&.to_name
54
56
  end
55
-
57
+
56
58
  # Lists all of the to states that can be reached through this path.
57
- #
59
+ #
58
60
  # For example,
59
- #
61
+ #
60
62
  # path.to_states # => [:parked, :idling, :first_gear, ...]
61
63
  def to_states
62
- map {|transition| transition.to_name}.uniq
64
+ map { |transition| transition.to_name }.uniq
63
65
  end
64
-
66
+
65
67
  # Lists all of the events that can be fired through this path.
66
- #
68
+ #
67
69
  # For example,
68
- #
70
+ #
69
71
  # path.events # => [:park, :ignite, :shift_up, ...]
70
72
  def events
71
- map {|transition| transition.event}.uniq
73
+ map { |transition| transition.event }.uniq
72
74
  end
73
-
75
+
74
76
  # Walks down the next transitions at the end of this path. This will only
75
77
  # walk down paths that are considered valid.
76
78
  def walk
77
- transitions.each {|transition| yield dup.push(transition)}
79
+ transitions.each { |transition| yield dup.push(transition) }
78
80
  end
79
-
81
+
80
82
  # Determines whether or not this path has completed. A path is considered
81
83
  # complete when one of the following conditions is met:
82
84
  # * The last transition in the path ends on the target state
@@ -85,36 +87,37 @@ module StateMachines
85
87
  def complete?
86
88
  !empty? && (@target ? to_name == @target : transitions.empty?)
87
89
  end
88
-
90
+
89
91
  private
90
- # Calculates the number of times the given state has been walked to
91
- def times_walked_to(state)
92
- select {|transition| transition.to_name == state}.length
93
- end
94
-
95
- # Determines whether the given transition has been recently walked down in
96
- # this path. If a target is configured for this path, then this will only
97
- # look at transitions walked down since the target was last reached.
98
- def recently_walked?(transition)
99
- transitions = self
100
- if @target && @target != to_name && target_transition = detect {|t| t.to_name == @target}
101
- transitions = transitions[index(target_transition) + 1..-1]
102
- end
103
- transitions.include?(transition)
104
- end
105
-
106
- # Determines whether it's possible to walk to the given transition from
107
- # the current path. A transition can be walked to if:
108
- # * It has not been recently walked and
109
- # * If a target is specified, it has not been walked to twice yet
110
- def can_walk_to?(transition)
111
- !recently_walked?(transition) && (!@target || times_walked_to(@target) < 2)
112
- end
113
-
114
- # Get the next set of transitions that can be walked to starting from the
115
- # end of this path
116
- def transitions
117
- @transitions ||= empty? ? [] : machine.events.transitions_for(object, :from => to_name, :guard => @guard).select {|transition| can_walk_to?(transition)}
92
+
93
+ # Calculates the number of times the given state has been walked to
94
+ def times_walked_to(state)
95
+ select { |transition| transition.to_name == state }.length
96
+ end
97
+
98
+ # Determines whether the given transition has been recently walked down in
99
+ # this path. If a target is configured for this path, then this will only
100
+ # look at transitions walked down since the target was last reached.
101
+ def recently_walked?(transition)
102
+ transitions = self
103
+ if @target && @target != to_name && (target_transition = detect { |t| t.to_name == @target })
104
+ transitions = transitions[index(target_transition) + 1..-1]
118
105
  end
106
+ transitions.include?(transition)
107
+ end
108
+
109
+ # Determines whether it's possible to walk to the given transition from
110
+ # the current path. A transition can be walked to if:
111
+ # * It has not been recently walked and
112
+ # * If a target is specified, it has not been walked to twice yet
113
+ def can_walk_to?(transition)
114
+ !recently_walked?(transition) && (!@target || times_walked_to(@target) < 2)
115
+ end
116
+
117
+ # Get the next set of transitions that can be walked to starting from the
118
+ # end of this path
119
+ def transitions
120
+ @transitions ||= empty? ? [] : machine.events.transitions_for(object, from: to_name, guard: @guard).select { |transition| can_walk_to?(transition) }
121
+ end
119
122
  end
120
123
  end