state_machines 0.5.0 → 0.20.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 (466) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +99 -16
  4. data/lib/state_machines/branch.rb +88 -82
  5. data/lib/state_machines/callback.rb +24 -21
  6. data/lib/state_machines/core.rb +3 -2
  7. data/lib/state_machines/core_ext/class/state_machine.rb +2 -0
  8. data/lib/state_machines/core_ext.rb +2 -0
  9. data/lib/state_machines/error.rb +2 -0
  10. data/lib/state_machines/eval_helpers.rb +51 -22
  11. data/lib/state_machines/event.rb +53 -35
  12. data/lib/state_machines/event_collection.rb +28 -25
  13. data/lib/state_machines/extensions.rb +3 -1
  14. data/lib/state_machines/helper_module.rb +3 -1
  15. data/lib/state_machines/integrations/base.rb +2 -0
  16. data/lib/state_machines/integrations.rb +10 -8
  17. data/lib/state_machines/machine/class_methods.rb +79 -0
  18. data/lib/state_machines/machine.rb +386 -429
  19. data/lib/state_machines/machine_collection.rb +16 -11
  20. data/lib/state_machines/macro_methods.rb +102 -100
  21. data/lib/state_machines/matcher.rb +26 -23
  22. data/lib/state_machines/matcher_helpers.rb +13 -11
  23. data/lib/state_machines/node_collection.rb +20 -14
  24. data/lib/state_machines/options_validator.rb +72 -0
  25. data/lib/state_machines/path.rb +61 -56
  26. data/lib/state_machines/path_collection.rb +40 -36
  27. data/lib/state_machines/state.rb +72 -43
  28. data/lib/state_machines/state_collection.rb +22 -19
  29. data/lib/state_machines/state_context.rb +38 -36
  30. data/lib/state_machines/stdio_renderer.rb +74 -0
  31. data/lib/state_machines/test_helper.rb +305 -0
  32. data/lib/state_machines/transition.rb +182 -178
  33. data/lib/state_machines/transition_collection.rb +175 -169
  34. data/lib/state_machines/version.rb +3 -1
  35. data/lib/state_machines.rb +4 -1
  36. metadata +12 -440
  37. data/.gitignore +0 -21
  38. data/.rspec +0 -3
  39. data/.ruby-gemset +0 -1
  40. data/.ruby-version +0 -1
  41. data/.travis.yml +0 -16
  42. data/Changelog.md +0 -22
  43. data/Contributors.md +0 -39
  44. data/Gemfile +0 -8
  45. data/Rakefile +0 -12
  46. data/Testing.md +0 -0
  47. data/lib/state_machines/assertions.rb +0 -40
  48. data/state_machines.gemspec +0 -22
  49. data/test/files/integrations/event_on_failure_integration.rb +0 -10
  50. data/test/files/integrations/vehicle.rb +0 -7
  51. data/test/files/models/auto_shop.rb +0 -31
  52. data/test/files/models/car.rb +0 -21
  53. data/test/files/models/driver.rb +0 -13
  54. data/test/files/models/model_base.rb +0 -6
  55. data/test/files/models/motorcycle.rb +0 -16
  56. data/test/files/models/traffic_light.rb +0 -47
  57. data/test/files/models/vehicle.rb +0 -127
  58. data/test/files/node.rb +0 -5
  59. data/test/files/switch.rb +0 -15
  60. data/test/functional/auto_shop_available_test.rb +0 -20
  61. data/test/functional/auto_shop_busy_test.rb +0 -25
  62. data/test/functional/car_backing_up_test.rb +0 -45
  63. data/test/functional/car_test.rb +0 -49
  64. data/test/functional/driver_default_nonstandard_test.rb +0 -13
  65. data/test/functional/motorcycle_test.rb +0 -52
  66. data/test/functional/traffic_light_caution_test.rb +0 -17
  67. data/test/functional/traffic_light_proceed_test.rb +0 -17
  68. data/test/functional/traffic_light_stop_test.rb +0 -26
  69. data/test/functional/vehicle_first_gear_test.rb +0 -42
  70. data/test/functional/vehicle_idling_test.rb +0 -59
  71. data/test/functional/vehicle_locked_test.rb +0 -29
  72. data/test/functional/vehicle_parked_test.rb +0 -53
  73. data/test/functional/vehicle_repaired_test.rb +0 -20
  74. data/test/functional/vehicle_second_gear_test.rb +0 -42
  75. data/test/functional/vehicle_stalled_test.rb +0 -65
  76. data/test/functional/vehicle_test.rb +0 -20
  77. data/test/functional/vehicle_third_gear_test.rb +0 -42
  78. data/test/functional/vehicle_unsaved_test.rb +0 -181
  79. data/test/functional/vehicle_with_event_attributes_test.rb +0 -30
  80. data/test/functional/vehicle_with_parallel_events_test.rb +0 -36
  81. data/test/test_helper.rb +0 -15
  82. data/test/unit/assertions/assert_exclusive_keys_test.rb +0 -22
  83. data/test/unit/assertions/assert_valid_key_test.rb +0 -12
  84. data/test/unit/branch/branch_test.rb +0 -28
  85. data/test/unit/branch/branch_with_conflicting_conditionals_test.rb +0 -27
  86. data/test/unit/branch/branch_with_conflicting_from_requirements_test.rb +0 -8
  87. data/test/unit/branch/branch_with_conflicting_on_requirements_test.rb +0 -8
  88. data/test/unit/branch/branch_with_conflicting_to_requirements_test.rb +0 -8
  89. data/test/unit/branch/branch_with_different_requirements_test.rb +0 -41
  90. data/test/unit/branch/branch_with_except_from_matcher_requirement_test.rb +0 -8
  91. data/test/unit/branch/branch_with_except_from_requirement_test.rb +0 -36
  92. data/test/unit/branch/branch_with_except_on_matcher_requirement_test.rb +0 -8
  93. data/test/unit/branch/branch_with_except_on_requirement_test.rb +0 -36
  94. data/test/unit/branch/branch_with_except_to_matcher_requirement_test.rb +0 -8
  95. data/test/unit/branch/branch_with_except_to_requirement_test.rb +0 -36
  96. data/test/unit/branch/branch_with_from_matcher_requirement_test.rb +0 -20
  97. data/test/unit/branch/branch_with_from_requirement_test.rb +0 -45
  98. data/test/unit/branch/branch_with_if_conditional_test.rb +0 -27
  99. data/test/unit/branch/branch_with_implicit_and_explicit_requirements_test.rb +0 -23
  100. data/test/unit/branch/branch_with_implicit_from_requirement_matcher_test.rb +0 -20
  101. data/test/unit/branch/branch_with_implicit_requirement_test.rb +0 -20
  102. data/test/unit/branch/branch_with_implicit_to_requirement_matcher_test.rb +0 -16
  103. data/test/unit/branch/branch_with_multiple_except_from_requirements_test.rb +0 -20
  104. data/test/unit/branch/branch_with_multiple_except_on_requirements_test.rb +0 -16
  105. data/test/unit/branch/branch_with_multiple_except_to_requirements_test.rb +0 -20
  106. data/test/unit/branch/branch_with_multiple_from_requirements_test.rb +0 -16
  107. data/test/unit/branch/branch_with_multiple_if_conditionals_test.rb +0 -20
  108. data/test/unit/branch/branch_with_multiple_implicit_requirements_test.rb +0 -53
  109. data/test/unit/branch/branch_with_multiple_to_requirements_test.rb +0 -20
  110. data/test/unit/branch/branch_with_multiple_unless_conditionals_test.rb +0 -20
  111. data/test/unit/branch/branch_with_nil_requirements_test.rb +0 -28
  112. data/test/unit/branch/branch_with_no_requirements_test.rb +0 -36
  113. data/test/unit/branch/branch_with_on_matcher_requirement_test.rb +0 -16
  114. data/test/unit/branch/branch_with_on_requirement_test.rb +0 -45
  115. data/test/unit/branch/branch_with_to_matcher_requirement_test.rb +0 -20
  116. data/test/unit/branch/branch_with_to_requirement_test.rb +0 -45
  117. data/test/unit/branch/branch_with_unless_conditional_test.rb +0 -27
  118. data/test/unit/branch/branch_without_guards_test.rb +0 -27
  119. data/test/unit/callback/callback_by_default_test.rb +0 -25
  120. data/test/unit/callback/callback_test.rb +0 -53
  121. data/test/unit/callback/callback_with_application_bound_object_test.rb +0 -23
  122. data/test/unit/callback/callback_with_application_terminator_test.rb +0 -24
  123. data/test/unit/callback/callback_with_arguments_test.rb +0 -14
  124. data/test/unit/callback/callback_with_around_type_and_arguments_test.rb +0 -25
  125. data/test/unit/callback/callback_with_around_type_and_block_test.rb +0 -44
  126. data/test/unit/callback/callback_with_around_type_and_bound_method_test.rb +0 -23
  127. data/test/unit/callback/callback_with_around_type_and_multiple_methods_test.rb +0 -93
  128. data/test/unit/callback/callback_with_around_type_and_terminator_test.rb +0 -17
  129. data/test/unit/callback/callback_with_block_test.rb +0 -20
  130. data/test/unit/callback/callback_with_bound_method_and_arguments_test.rb +0 -28
  131. data/test/unit/callback/callback_with_bound_method_test.rb +0 -35
  132. data/test/unit/callback/callback_with_do_method_test.rb +0 -18
  133. data/test/unit/callback/callback_with_explicit_requirements_test.rb +0 -32
  134. data/test/unit/callback/callback_with_if_condition_test.rb +0 -17
  135. data/test/unit/callback/callback_with_implicit_requirements_test.rb +0 -32
  136. data/test/unit/callback/callback_with_method_argument_test.rb +0 -18
  137. data/test/unit/callback/callback_with_mixed_methods_test.rb +0 -31
  138. data/test/unit/callback/callback_with_multiple_bound_methods_test.rb +0 -21
  139. data/test/unit/callback/callback_with_multiple_do_methods_test.rb +0 -29
  140. data/test/unit/callback/callback_with_multiple_method_arguments_test.rb +0 -29
  141. data/test/unit/callback/callback_with_terminator_test.rb +0 -22
  142. data/test/unit/callback/callback_with_unbound_method_test.rb +0 -14
  143. data/test/unit/callback/callback_with_unless_condition_test.rb +0 -17
  144. data/test/unit/callback/callback_without_arguments_test.rb +0 -14
  145. data/test/unit/callback/callback_without_terminator_test.rb +0 -12
  146. data/test/unit/error/error_by_default_test.rb +0 -21
  147. data/test/unit/error/error_with_message_test.rb +0 -23
  148. data/test/unit/eval_helper/eval_helpers_base_test.rb +0 -8
  149. data/test/unit/eval_helper/eval_helpers_proc_block_and_explicit_arguments_test.rb +0 -14
  150. data/test/unit/eval_helper/eval_helpers_proc_block_and_implicit_arguments_test.rb +0 -14
  151. data/test/unit/eval_helper/eval_helpers_proc_test.rb +0 -13
  152. data/test/unit/eval_helper/eval_helpers_proc_with_arguments_test.rb +0 -13
  153. data/test/unit/eval_helper/eval_helpers_proc_with_block_test.rb +0 -13
  154. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_arguments_test.rb +0 -18
  155. data/test/unit/eval_helper/eval_helpers_proc_with_block_without_object_test.rb +0 -14
  156. data/test/unit/eval_helper/eval_helpers_proc_without_arguments_test.rb +0 -19
  157. data/test/unit/eval_helper/eval_helpers_string_test.rb +0 -25
  158. data/test/unit/eval_helper/eval_helpers_string_with_block_test.rb +0 -12
  159. data/test/unit/eval_helper/eval_helpers_symbol_method_missing_test.rb +0 -20
  160. data/test/unit/eval_helper/eval_helpers_symbol_private_test.rb +0 -17
  161. data/test/unit/eval_helper/eval_helpers_symbol_protected_test.rb +0 -17
  162. data/test/unit/eval_helper/eval_helpers_symbol_tainted_method_test.rb +0 -18
  163. data/test/unit/eval_helper/eval_helpers_symbol_test.rb +0 -16
  164. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_and_block_test.rb +0 -16
  165. data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_test.rb +0 -16
  166. data/test/unit/eval_helper/eval_helpers_symbol_with_block_test.rb +0 -16
  167. data/test/unit/eval_helper/eval_helpers_test.rb +0 -13
  168. data/test/unit/event/event_after_being_copied_test.rb +0 -17
  169. data/test/unit/event/event_by_default_test.rb +0 -60
  170. data/test/unit/event/event_context_test.rb +0 -16
  171. data/test/unit/event/event_on_failure_test.rb +0 -44
  172. data/test/unit/event/event_test.rb +0 -34
  173. data/test/unit/event/event_transitions_test.rb +0 -62
  174. data/test/unit/event/event_with_conflicting_helpers_after_definition_test.rb +0 -79
  175. data/test/unit/event/event_with_conflicting_helpers_before_definition_test.rb +0 -58
  176. data/test/unit/event/event_with_conflicting_machine_test.rb +0 -48
  177. data/test/unit/event/event_with_dynamic_human_name_test.rb +0 -26
  178. data/test/unit/event/event_with_human_name_test.rb +0 -13
  179. data/test/unit/event/event_with_invalid_current_state_test.rb +0 -30
  180. data/test/unit/event/event_with_machine_action_test.rb +0 -33
  181. data/test/unit/event/event_with_marshalling_test.rb +0 -47
  182. data/test/unit/event/event_with_matching_disabled_transitions_test.rb +0 -115
  183. data/test/unit/event/event_with_matching_enabled_transitions_test.rb +0 -75
  184. data/test/unit/event/event_with_multiple_transitions_test.rb +0 -61
  185. data/test/unit/event/event_with_namespace_test.rb +0 -34
  186. data/test/unit/event/event_with_transition_with_blacklisted_to_state_test.rb +0 -60
  187. data/test/unit/event/event_with_transition_with_loopback_state_test.rb +0 -36
  188. data/test/unit/event/event_with_transition_with_nil_to_state_test.rb +0 -36
  189. data/test/unit/event/event_with_transition_with_whitelisted_to_state_test.rb +0 -51
  190. data/test/unit/event/event_with_transition_without_to_state_test.rb +0 -36
  191. data/test/unit/event/event_with_transitions_test.rb +0 -32
  192. data/test/unit/event/event_without_matching_transitions_test.rb +0 -41
  193. data/test/unit/event/event_without_transitions_test.rb +0 -28
  194. data/test/unit/event/invalid_event_test.rb +0 -20
  195. data/test/unit/event_collection/event_collection_attribute_with_machine_action_test.rb +0 -62
  196. data/test/unit/event_collection/event_collection_attribute_with_namespaced_machine_test.rb +0 -36
  197. data/test/unit/event_collection/event_collection_by_default_test.rb +0 -26
  198. data/test/unit/event_collection/event_collection_test.rb +0 -39
  199. data/test/unit/event_collection/event_collection_with_custom_machine_attribute_test.rb +0 -31
  200. data/test/unit/event_collection/event_collection_with_events_with_transitions_test.rb +0 -76
  201. data/test/unit/event_collection/event_collection_with_multiple_events_test.rb +0 -27
  202. data/test/unit/event_collection/event_collection_with_validations_test.rb +0 -74
  203. data/test/unit/event_collection/event_collection_without_machine_action_test.rb +0 -18
  204. data/test/unit/event_collection/event_string_collection_test.rb +0 -31
  205. data/test/unit/helper_module_test.rb +0 -17
  206. data/test/unit/integrations/integration_finder_test.rb +0 -16
  207. data/test/unit/integrations/integration_matcher_test.rb +0 -29
  208. data/test/unit/invalid_transition/invalid_parallel_transition_test.rb +0 -18
  209. data/test/unit/invalid_transition/invalid_transition_test.rb +0 -47
  210. data/test/unit/invalid_transition/invalid_transition_with_integration_test.rb +0 -45
  211. data/test/unit/invalid_transition/invalid_transition_with_namespace_test.rb +0 -32
  212. data/test/unit/machine/machine_after_being_copied_test.rb +0 -62
  213. data/test/unit/machine/machine_after_changing_initial_state.rb +0 -28
  214. data/test/unit/machine/machine_after_changing_owner_class_test.rb +0 -31
  215. data/test/unit/machine/machine_by_default_test.rb +0 -160
  216. data/test/unit/machine/machine_finder_custom_options_test.rb +0 -17
  217. data/test/unit/machine/machine_finder_with_existing_machine_on_superclass_test.rb +0 -85
  218. data/test/unit/machine/machine_finder_with_existing_on_same_class_test.rb +0 -23
  219. data/test/unit/machine/machine_finder_without_existing_machine_test.rb +0 -25
  220. data/test/unit/machine/machine_persistence_test.rb +0 -52
  221. data/test/unit/machine/machine_state_initialization_test.rb +0 -56
  222. data/test/unit/machine/machine_test.rb +0 -30
  223. data/test/unit/machine/machine_with_action_already_overridden_test.rb +0 -23
  224. data/test/unit/machine/machine_with_action_defined_in_class_test.rb +0 -37
  225. data/test/unit/machine/machine_with_action_defined_in_included_module_test.rb +0 -46
  226. data/test/unit/machine/machine_with_action_defined_in_superclass_test.rb +0 -43
  227. data/test/unit/machine/machine_with_action_undefined_test.rb +0 -33
  228. data/test/unit/machine/machine_with_cached_state_test.rb +0 -20
  229. data/test/unit/machine/machine_with_class_helpers_test.rb +0 -179
  230. data/test/unit/machine/machine_with_conflicting_helpers_after_definition_test.rb +0 -244
  231. data/test/unit/machine/machine_with_conflicting_helpers_before_definition_test.rb +0 -175
  232. data/test/unit/machine/machine_with_custom_action_test.rb +0 -11
  233. data/test/unit/machine/machine_with_custom_attribute_test.rb +0 -103
  234. data/test/unit/machine/machine_with_custom_initialize_test.rb +0 -24
  235. data/test/unit/machine/machine_with_custom_integration_test.rb +0 -72
  236. data/test/unit/machine/machine_with_custom_invalidation_test.rb +0 -39
  237. data/test/unit/machine/machine_with_custom_name_test.rb +0 -57
  238. data/test/unit/machine/machine_with_custom_plural_test.rb +0 -52
  239. data/test/unit/machine/machine_with_dynamic_initial_state_test.rb +0 -65
  240. data/test/unit/machine/machine_with_event_matchers_test.rb +0 -41
  241. data/test/unit/machine/machine_with_events_test.rb +0 -52
  242. data/test/unit/machine/machine_with_events_with_custom_human_names_test.rb +0 -18
  243. data/test/unit/machine/machine_with_events_with_transitions_test.rb +0 -37
  244. data/test/unit/machine/machine_with_existing_event_test.rb +0 -17
  245. data/test/unit/machine/machine_with_existing_machines_on_owner_class_test.rb +0 -20
  246. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_class_test.rb +0 -71
  247. data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_subclass_test.rb +0 -31
  248. data/test/unit/machine/machine_with_existing_state_test.rb +0 -27
  249. data/test/unit/machine/machine_with_failure_callbacks_test.rb +0 -48
  250. data/test/unit/machine/machine_with_helpers_test.rb +0 -14
  251. data/test/unit/machine/machine_with_initial_state_with_value_and_owner_default.rb +0 -25
  252. data/test/unit/machine/machine_with_initialize_and_super_test.rb +0 -17
  253. data/test/unit/machine/machine_with_initialize_arguments_and_block_test.rb +0 -31
  254. data/test/unit/machine/machine_with_initialize_without_super_test.rb +0 -17
  255. data/test/unit/machine/machine_with_instance_helpers_test.rb +0 -179
  256. data/test/unit/machine/machine_with_integration_test.rb +0 -72
  257. data/test/unit/machine/machine_with_multiple_events_test.rb +0 -32
  258. data/test/unit/machine/machine_with_namespace_test.rb +0 -48
  259. data/test/unit/machine/machine_with_nil_action_test.rb +0 -27
  260. data/test/unit/machine/machine_with_other_states.rb +0 -22
  261. data/test/unit/machine/machine_with_owner_subclass_test.rb +0 -18
  262. data/test/unit/machine/machine_with_paths_test.rb +0 -25
  263. data/test/unit/machine/machine_with_private_action_test.rb +0 -43
  264. data/test/unit/machine/machine_with_state_matchers_test.rb +0 -41
  265. data/test/unit/machine/machine_with_state_with_matchers_test.rb +0 -19
  266. data/test/unit/machine/machine_with_states_test.rb +0 -55
  267. data/test/unit/machine/machine_with_states_with_behaviors_test.rb +0 -23
  268. data/test/unit/machine/machine_with_states_with_custom_human_names_test.rb +0 -18
  269. data/test/unit/machine/machine_with_states_with_custom_values_test.rb +0 -21
  270. data/test/unit/machine/machine_with_states_with_runtime_dependencies_test.rb +0 -19
  271. data/test/unit/machine/machine_with_static_initial_state_test.rb +0 -49
  272. data/test/unit/machine/machine_with_superclass_conflicting_helpers_after_definition_test.rb +0 -36
  273. data/test/unit/machine/machine_with_transition_callbacks_test.rb +0 -144
  274. data/test/unit/machine/machine_with_transitions_test.rb +0 -87
  275. data/test/unit/machine/machine_without_initialization_test.rb +0 -31
  276. data/test/unit/machine/machine_without_initialize_test.rb +0 -14
  277. data/test/unit/machine/machine_without_integration_test.rb +0 -31
  278. data/test/unit/machine_collection/machine_collection_by_default_test.rb +0 -11
  279. data/test/unit/machine_collection/machine_collection_fire_test.rb +0 -80
  280. data/test/unit/machine_collection/machine_collection_fire_with_transactions_test.rb +0 -54
  281. data/test/unit/machine_collection/machine_collection_fire_with_validations_test.rb +0 -76
  282. data/test/unit/machine_collection/machine_collection_state_initialization_test.rb +0 -111
  283. data/test/unit/machine_collection/machine_collection_transitions_with_blank_events_test.rb +0 -25
  284. data/test/unit/machine_collection/machine_collection_transitions_with_custom_options_test.rb +0 -20
  285. data/test/unit/machine_collection/machine_collection_transitions_with_different_actions_test.rb +0 -26
  286. data/test/unit/machine_collection/machine_collection_transitions_with_exisiting_transitions_test.rb +0 -25
  287. data/test/unit/machine_collection/machine_collection_transitions_with_invalid_events_test.rb +0 -25
  288. data/test/unit/machine_collection/machine_collection_transitions_with_same_actions_test.rb +0 -31
  289. data/test/unit/machine_collection/machine_collection_transitions_with_transition_test.rb +0 -26
  290. data/test/unit/machine_collection/machine_collection_transitions_without_events_test.rb +0 -25
  291. data/test/unit/machine_collection/machine_collection_transitions_without_transition_test.rb +0 -27
  292. data/test/unit/matcher/all_matcher_test.rb +0 -29
  293. data/test/unit/matcher/blacklist_matcher_test.rb +0 -30
  294. data/test/unit/matcher/loopback_matcher_test.rb +0 -27
  295. data/test/unit/matcher/matcher_by_default_test.rb +0 -15
  296. data/test/unit/matcher/matcher_with_multiple_values_test.rb +0 -15
  297. data/test/unit/matcher/matcher_with_value_test.rb +0 -15
  298. data/test/unit/matcher/whitelist_matcher_test.rb +0 -30
  299. data/test/unit/matcher_helpers/matcher_helpers_all_test.rb +0 -14
  300. data/test/unit/matcher_helpers/matcher_helpers_any_test.rb +0 -14
  301. data/test/unit/matcher_helpers/matcher_helpers_same_test.rb +0 -13
  302. data/test/unit/node_collection/node_collection_after_being_copied_test.rb +0 -46
  303. data/test/unit/node_collection/node_collection_after_update_test.rb +0 -36
  304. data/test/unit/node_collection/node_collection_by_default_test.rb +0 -22
  305. data/test/unit/node_collection/node_collection_test.rb +0 -23
  306. data/test/unit/node_collection/node_collection_with_indices_test.rb +0 -42
  307. data/test/unit/node_collection/node_collection_with_matcher_contexts_test.rb +0 -25
  308. data/test/unit/node_collection/node_collection_with_nodes_test.rb +0 -46
  309. data/test/unit/node_collection/node_collection_with_numeric_index_test.rb +0 -24
  310. data/test/unit/node_collection/node_collection_with_postdefined_contexts_test.rb +0 -22
  311. data/test/unit/node_collection/node_collection_with_predefined_contexts_test.rb +0 -23
  312. data/test/unit/node_collection/node_collection_with_string_index_test.rb +0 -20
  313. data/test/unit/node_collection/node_collection_with_symbol_index_test.rb +0 -20
  314. data/test/unit/node_collection/node_collection_without_indices_test.rb +0 -30
  315. data/test/unit/path/path_by_default_test.rb +0 -54
  316. data/test/unit/path/path_test.rb +0 -14
  317. data/test/unit/path/path_with_available_transitions_after_reaching_target_test.rb +0 -40
  318. data/test/unit/path/path_with_available_transitions_test.rb +0 -54
  319. data/test/unit/path/path_with_deep_target_reached_test.rb +0 -50
  320. data/test/unit/path/path_with_deep_target_test.rb +0 -40
  321. data/test/unit/path/path_with_duplicates_test.rb +0 -32
  322. data/test/unit/path/path_with_encountered_transitions_test.rb +0 -34
  323. data/test/unit/path/path_with_guarded_transitions_test.rb +0 -42
  324. data/test/unit/path/path_with_reached_target_test.rb +0 -35
  325. data/test/unit/path/path_with_transitions_test.rb +0 -54
  326. data/test/unit/path/path_with_unreached_target_test.rb +0 -31
  327. data/test/unit/path/path_without_transitions_test.rb +0 -24
  328. data/test/unit/path_collection/path_collection_by_default_test.rb +0 -46
  329. data/test/unit/path_collection/path_collection_test.rb +0 -24
  330. data/test/unit/path_collection/path_collection_with_deep_paths_test.rb +0 -43
  331. data/test/unit/path_collection/path_collection_with_duplicate_nodes_test.rb +0 -31
  332. data/test/unit/path_collection/path_collection_with_from_state_test.rb +0 -27
  333. data/test/unit/path_collection/path_collection_with_paths_test.rb +0 -47
  334. data/test/unit/path_collection/path_collection_with_to_state_test.rb +0 -29
  335. data/test/unit/path_collection/path_with_guarded_paths_test.rb +0 -25
  336. data/test/unit/state/state_after_being_copied_test.rb +0 -19
  337. data/test/unit/state/state_by_default_test.rb +0 -41
  338. data/test/unit/state/state_final_test.rb +0 -28
  339. data/test/unit/state/state_initial_test.rb +0 -13
  340. data/test/unit/state/state_not_final_test.rb +0 -32
  341. data/test/unit/state/state_not_initial_test.rb +0 -13
  342. data/test/unit/state/state_test.rb +0 -44
  343. data/test/unit/state/state_with_cached_lambda_value_test.rb +0 -29
  344. data/test/unit/state/state_with_conflicting_helpers_after_definition_test.rb +0 -38
  345. data/test/unit/state/state_with_conflicting_helpers_before_definition_test.rb +0 -29
  346. data/test/unit/state/state_with_conflicting_machine_name_test.rb +0 -20
  347. data/test/unit/state/state_with_conflicting_machine_test.rb +0 -37
  348. data/test/unit/state/state_with_context_test.rb +0 -60
  349. data/test/unit/state/state_with_dynamic_human_name_test.rb +0 -25
  350. data/test/unit/state/state_with_existing_context_method_test.rb +0 -24
  351. data/test/unit/state/state_with_human_name_test.rb +0 -13
  352. data/test/unit/state/state_with_integer_value_test.rb +0 -32
  353. data/test/unit/state/state_with_invalid_method_call_test.rb +0 -21
  354. data/test/unit/state/state_with_lambda_value_test.rb +0 -37
  355. data/test/unit/state/state_with_matcher_test.rb +0 -18
  356. data/test/unit/state/state_with_multiple_contexts_test.rb +0 -57
  357. data/test/unit/state/state_with_name_test.rb +0 -43
  358. data/test/unit/state/state_with_namespace_test.rb +0 -22
  359. data/test/unit/state/state_with_nil_value_test.rb +0 -35
  360. data/test/unit/state/state_with_redefined_context_method_test.rb +0 -45
  361. data/test/unit/state/state_with_symbolic_value_test.rb +0 -32
  362. data/test/unit/state/state_with_valid_inherited_method_call_for_current_state_test.rb +0 -40
  363. data/test/unit/state/state_with_valid_method_call_for_current_state_test.rb +0 -33
  364. data/test/unit/state/state_with_valid_method_call_for_different_state_test.rb +0 -41
  365. data/test/unit/state/state_without_cached_lambda_value_test.rb +0 -25
  366. data/test/unit/state/state_without_name_test.rb +0 -39
  367. data/test/unit/state_collection/state_collection_by_default_test.rb +0 -21
  368. data/test/unit/state_collection/state_collection_string_test.rb +0 -35
  369. data/test/unit/state_collection/state_collection_test.rb +0 -74
  370. data/test/unit/state_collection/state_collection_with_custom_state_values_test.rb +0 -29
  371. data/test/unit/state_collection/state_collection_with_event_transitions_test.rb +0 -39
  372. data/test/unit/state_collection/state_collection_with_initial_state_test.rb +0 -40
  373. data/test/unit/state_collection/state_collection_with_namespace_test.rb +0 -21
  374. data/test/unit/state_collection/state_collection_with_state_behaviors_test.rb +0 -40
  375. data/test/unit/state_collection/state_collection_with_state_matchers_test.rb +0 -29
  376. data/test/unit/state_collection/state_collection_with_transition_callbacks_test.rb +0 -40
  377. data/test/unit/state_context/state_context_proxy_test.rb +0 -26
  378. data/test/unit/state_context/state_context_proxy_with_if_and_unless_conditions_test.rb +0 -42
  379. data/test/unit/state_context/state_context_proxy_with_if_condition_test.rb +0 -64
  380. data/test/unit/state_context/state_context_proxy_with_multiple_if_conditions_test.rb +0 -32
  381. data/test/unit/state_context/state_context_proxy_with_multiple_unless_conditions_test.rb +0 -32
  382. data/test/unit/state_context/state_context_proxy_with_unless_condition_test.rb +0 -64
  383. data/test/unit/state_context/state_context_proxy_without_conditions_test.rb +0 -31
  384. data/test/unit/state_context/state_context_test.rb +0 -28
  385. data/test/unit/state_context/state_context_transition_test.rb +0 -104
  386. data/test/unit/state_context/state_context_with_matching_transition_test.rb +0 -27
  387. data/test/unit/state_machine/state_machine_by_default_test.rb +0 -12
  388. data/test/unit/state_machine/state_machine_test.rb +0 -20
  389. data/test/unit/transition/transition_after_being_performed_test.rb +0 -48
  390. data/test/unit/transition/transition_after_being_persisted_test.rb +0 -46
  391. data/test/unit/transition/transition_after_being_rolled_back_test.rb +0 -35
  392. data/test/unit/transition/transition_equality_test.rb +0 -52
  393. data/test/unit/transition/transition_loopback_test.rb +0 -18
  394. data/test/unit/transition/transition_test.rb +0 -96
  395. data/test/unit/transition/transition_transient_test.rb +0 -20
  396. data/test/unit/transition/transition_with_action_test.rb +0 -27
  397. data/test/unit/transition/transition_with_after_callbacks_skipped_test.rb +0 -127
  398. data/test/unit/transition/transition_with_after_callbacks_test.rb +0 -93
  399. data/test/unit/transition/transition_with_around_callbacks_test.rb +0 -141
  400. data/test/unit/transition/transition_with_before_callbacks_skipped_test.rb +0 -30
  401. data/test/unit/transition/transition_with_before_callbacks_test.rb +0 -104
  402. data/test/unit/transition/transition_with_custom_machine_attribute_test.rb +0 -28
  403. data/test/unit/transition/transition_with_different_states_test.rb +0 -18
  404. data/test/unit/transition/transition_with_dynamic_to_value_test.rb +0 -19
  405. data/test/unit/transition/transition_with_failure_callbacks_test.rb +0 -84
  406. data/test/unit/transition/transition_with_invalid_nodes_test.rb +0 -29
  407. data/test/unit/transition/transition_with_mixed_callbacks_test.rb +0 -105
  408. data/test/unit/transition/transition_with_multiple_after_callbacks_test.rb +0 -40
  409. data/test/unit/transition/transition_with_multiple_around_callbacks_test.rb +0 -114
  410. data/test/unit/transition/transition_with_multiple_before_callbacks_test.rb +0 -40
  411. data/test/unit/transition/transition_with_multiple_failure_callbacks_test.rb +0 -40
  412. data/test/unit/transition/transition_with_namespace_test.rb +0 -47
  413. data/test/unit/transition/transition_with_perform_arguments_test.rb +0 -35
  414. data/test/unit/transition/transition_with_transactions_test.rb +0 -42
  415. data/test/unit/transition/transition_without_callbacks_test.rb +0 -33
  416. data/test/unit/transition/transition_without_reading_state_test.rb +0 -22
  417. data/test/unit/transition/transition_without_running_action_test.rb +0 -47
  418. data/test/unit/transition_collection/attribute_transition_collection_by_default_test.rb +0 -23
  419. data/test/unit/transition_collection/attribute_transition_collection_marshalling_test.rb +0 -64
  420. data/test/unit/transition_collection/attribute_transition_collection_with_action_error_test.rb +0 -44
  421. data/test/unit/transition_collection/attribute_transition_collection_with_action_failed_test.rb +0 -44
  422. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_error_test.rb +0 -32
  423. data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_halt_test.rb +0 -33
  424. data/test/unit/transition_collection/attribute_transition_collection_with_around_after_yield_callback_error_test.rb +0 -32
  425. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_error_test.rb +0 -32
  426. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_halt_test.rb +0 -33
  427. data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_before_yield_halt_test.rb +0 -33
  428. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_error_test.rb +0 -32
  429. data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_halt_test.rb +0 -33
  430. data/test/unit/transition_collection/attribute_transition_collection_with_callbacks_test.rb +0 -68
  431. data/test/unit/transition_collection/attribute_transition_collection_with_event_transitions_test.rb +0 -41
  432. data/test/unit/transition_collection/attribute_transition_collection_with_events_test.rb +0 -44
  433. data/test/unit/transition_collection/attribute_transition_collection_with_skipped_after_callbacks_test.rb +0 -42
  434. data/test/unit/transition_collection/transition_collection_by_default_test.rb +0 -23
  435. data/test/unit/transition_collection/transition_collection_empty_with_block_test.rb +0 -23
  436. data/test/unit/transition_collection/transition_collection_empty_without_block_test.rb +0 -12
  437. data/test/unit/transition_collection/transition_collection_invalid_test.rb +0 -21
  438. data/test/unit/transition_collection/transition_collection_partial_invalid_test.rb +0 -69
  439. data/test/unit/transition_collection/transition_collection_test.rb +0 -26
  440. data/test/unit/transition_collection/transition_collection_valid_test.rb +0 -57
  441. data/test/unit/transition_collection/transition_collection_with_action_error_test.rb +0 -66
  442. data/test/unit/transition_collection/transition_collection_with_action_failed_test.rb +0 -60
  443. data/test/unit/transition_collection/transition_collection_with_action_hook_and_block_test.rb +0 -17
  444. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_action_test.rb +0 -17
  445. data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_after_callbacks_test.rb +0 -37
  446. data/test/unit/transition_collection/transition_collection_with_action_hook_base_test.rb +0 -34
  447. data/test/unit/transition_collection/transition_collection_with_action_hook_error_test.rb +0 -29
  448. data/test/unit/transition_collection/transition_collection_with_action_hook_invalid_test.rb +0 -17
  449. data/test/unit/transition_collection/transition_collection_with_action_hook_multiple_test.rb +0 -79
  450. data/test/unit/transition_collection/transition_collection_with_action_hook_test.rb +0 -45
  451. data/test/unit/transition_collection/transition_collection_with_action_hook_with_different_actions_test.rb +0 -48
  452. data/test/unit/transition_collection/transition_collection_with_action_hook_with_nil_action_test.rb +0 -42
  453. data/test/unit/transition_collection/transition_collection_with_after_callback_halt_test.rb +0 -47
  454. data/test/unit/transition_collection/transition_collection_with_before_callback_halt_test.rb +0 -51
  455. data/test/unit/transition_collection/transition_collection_with_block_test.rb +0 -46
  456. data/test/unit/transition_collection/transition_collection_with_callbacks_test.rb +0 -135
  457. data/test/unit/transition_collection/transition_collection_with_different_actions_test.rb +0 -189
  458. data/test/unit/transition_collection/transition_collection_with_duplicate_actions_test.rb +0 -48
  459. data/test/unit/transition_collection/transition_collection_with_empty_actions_test.rb +0 -41
  460. data/test/unit/transition_collection/transition_collection_with_mixed_actions_test.rb +0 -41
  461. data/test/unit/transition_collection/transition_collection_with_skipped_actions_and_block_test.rb +0 -34
  462. data/test/unit/transition_collection/transition_collection_with_skipped_actions_test.rb +0 -69
  463. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_and_around_callbacks_test.rb +0 -53
  464. data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_test.rb +0 -34
  465. data/test/unit/transition_collection/transition_collection_with_transactions_test.rb +0 -65
  466. data/test/unit/transition_collection/transition_collection_without_transactions_test.rb +0 -29
@@ -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,57 @@ 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
+ if options.is_a?(Hash)
59
+ # Old style: initialize(machine, name, {initial: true, value: 'foo'})
60
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :initial, :value, :cache, :if, :human_name)
61
+ initial = options.fetch(:initial, false)
62
+ value = options.include?(:value) ? options[:value] : :__not_provided__
63
+ cache = options[:cache]
64
+ if_condition = options[:if]
65
+ human_name = options[:human_name]
66
+ else
67
+ # New style: initialize(machine, name, initial: true, value: 'foo')
68
+ # options parameter should be nil in this case
69
+ raise ArgumentError, "Unexpected positional argument: #{options.inspect}" unless options.nil?
70
+ StateMachines::OptionsValidator.assert_valid_keys!(extra_options, :initial, :value, :cache, :if, :human_name) unless extra_options.empty?
71
+ if_condition = binding.local_variable_get(:if) # 'if' is a keyword, need special handling
72
+ end
55
73
 
56
74
  @machine = machine
57
75
  @name = name
58
76
  @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
77
+ @human_name = human_name || (@name ? @name.to_s.tr('_', ' ') : 'nil')
78
+ @value = value == :__not_provided__ ? name&.to_s : value
79
+ @cache = cache
80
+ @matcher = if_condition
81
+ @initial = initial == true
64
82
  @context = StateContext.new(self)
65
83
 
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
84
+ return unless name
85
+
86
+ conflicting_machines = machine.owner_class.state_machines.select do |_other_name, other_machine|
87
+ other_machine != machine && other_machine.states[qualified_name, :qualified_name]
88
+ end
89
+
90
+ # Output a warning if another machine has a conflicting qualified name
91
+ # for a different attribute
92
+ if (conflict = conflicting_machines.detect do |_other_name, other_machine|
93
+ other_machine.attribute != machine.attribute
94
+ end)
95
+ _name, other_machine = conflict
96
+ warn "State #{qualified_name.inspect} for #{machine.name.inspect} is already defined in #{other_machine.name.inspect}"
97
+ elsif conflicting_machines.empty?
98
+ # Only bother adding predicates when another machine for the same
99
+ # attribute hasn't already done so
100
+ add_predicate
79
101
  end
80
102
  end
81
103
 
82
104
  # Creates a copy of this state, excluding the context to prevent conflicts
83
105
  # across different machines.
84
- def initialize_copy(orig) #:nodoc:
106
+ def initialize_copy(orig) # :nodoc:
85
107
  super
86
108
  @context = StateContext.new(self)
87
109
  end
@@ -96,10 +118,10 @@ module StateMachines
96
118
  # Any objects in a final state will remain so forever given the current
97
119
  # machine's definition.
98
120
  def final?
99
- !machine.events.any? do |event|
121
+ machine.events.none? do |event|
100
122
  event.branches.any? do |branch|
101
123
  branch.state_requirements.any? do |requirement|
102
- requirement[:from].matches?(name) && !requirement[:to].matches?(name, :from => name)
124
+ requirement[:from].matches?(name) && !requirement[:to].matches?(name, from: name)
103
125
  end
104
126
  end
105
127
  end
@@ -126,7 +148,7 @@ module StateMachines
126
148
  # description or just the internal name
127
149
  def description(options = {})
128
150
  label = options[:human_name] ? human_name : name
129
- description = label ? label.to_s : label.inspect
151
+ description = +(label ? label.to_s : label.inspect)
130
152
  description << " (#{@value.is_a?(Proc) ? '*' : @value.inspect})" unless name.to_s == @value.to_s
131
153
  description
132
154
  end
@@ -186,19 +208,19 @@ module StateMachines
186
208
  # Evaluate the method definitions and track which ones were added
187
209
  old_methods = context_methods
188
210
  context.class_eval(&block)
189
- new_methods = context_methods.to_a.select { |(name, method)| old_methods[name] != method }
211
+ new_methods = context_methods.to_a.reject { |(name, method)| old_methods[name] == method }
190
212
 
191
213
  # Alias new methods so that the only execute when the object is in this state
192
214
  new_methods.each do |(method_name, _method)|
193
215
  context_name = context_name_for(method_name)
194
- context.class_eval <<-end_eval, __FILE__, __LINE__ + 1
216
+ context.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
195
217
  alias_method :"#{context_name}", :#{method_name}
196
218
  def #{method_name}(*args, &block)
197
219
  state = self.class.state_machine(#{machine.name.inspect}).states.fetch(#{name.inspect})
198
220
  options = {:method_missing => lambda {super(*args, &block)}, :method_name => #{method_name.inspect}}
199
221
  state.call(self, :"#{context_name}", *(args + [options]), &block)
200
222
  end
201
- end_eval
223
+ END_EVAL
202
224
  end
203
225
 
204
226
  true
@@ -218,29 +240,28 @@ module StateMachines
218
240
  # will be raised.
219
241
  def call(object, method, *args, &block)
220
242
  options = args.last.is_a?(Hash) ? args.pop : {}
221
- options = {:method_name => method}.merge(options)
243
+ options = { method_name: method }.merge(options)
222
244
  state = machine.states.match!(object)
223
245
 
224
246
  if state == self && object.respond_to?(method)
225
247
  object.send(method, *args, &block)
226
- elsif method_missing = options[:method_missing]
248
+ elsif (method_missing = options[:method_missing])
227
249
  # Dispatch to the superclass since the object either isn't in this state
228
250
  # or this state doesn't handle the method
229
251
  begin
230
252
  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
253
+ rescue NoMethodError => e
254
+ raise unless e.name.to_s == options[:method_name].to_s && e.args == args
255
+
256
+ # No valid context for this method
257
+ raise InvalidContext.new(object,
258
+ "State #{state.name.inspect} for #{machine.name.inspect} is not a valid context for calling ##{options[:method_name]}")
238
259
  end
239
260
  end
240
261
  end
241
262
 
242
- def draw(graph, options = {})
243
- fail NotImplementedError
263
+ def draw(graph, options = {}, io = $stdout)
264
+ machine.renderer.draw_state(self, graph, options, io)
244
265
  end
245
266
 
246
267
  # Generates a nicely formatted description of this state's contents.
@@ -255,6 +276,7 @@ module StateMachines
255
276
  end
256
277
 
257
278
  private
279
+
258
280
  # Should the value be cached after it's evaluated for the first time?
259
281
  def cache_value?
260
282
  @cache
@@ -263,9 +285,16 @@ module StateMachines
263
285
  # Adds a predicate method to the owner class so long as a name has
264
286
  # actually been configured for the state
265
287
  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)
288
+ predicate_method = "#{qualified_name}?"
289
+
290
+ if machine.send(:owner_class_ancestor_has_method?, :instance, predicate_method)
291
+ warn "Instance method #{predicate_method.inspect} is already defined in #{machine.owner_class.ancestors.first.inspect}, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true."
292
+ elsif machine.send(:owner_class_has_method?, :instance, predicate_method)
293
+ warn "Instance method #{predicate_method.inspect} is already defined in #{machine.owner_class.inspect}, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true."
294
+ else
295
+ machine.define_helper(:instance, predicate_method) do |machine, object|
296
+ machine.states.matches?(object, name)
297
+ end
269
298
  end
270
299
  end
271
300
 
@@ -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
6
  def initialize(machine) #:nodoc:
5
- super(machine, :index => [:name, :qualified_name, :value])
7
+ super(machine, index: [: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 }
@@ -101,7 +103,8 @@ module StateMachines
101
103
  order
102
104
  end
103
105
 
104
- private
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,100 +1,102 @@
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
57
 
56
58
  include EvalHelpers
57
-
59
+
58
60
  # The state machine for which this context's state is defined
59
61
  attr_reader :machine
60
-
62
+
61
63
  # The state that must be present in an object for this context to be active
62
64
  attr_reader :state
63
-
65
+
64
66
  # Creates a new context for the given state
65
67
  def initialize(state)
66
68
  @state = state
67
69
  @machine = state.machine
68
-
70
+
69
71
  state_name = state.name
70
72
  machine_name = machine.name
71
- @condition = lambda {|object| object.class.state_machine(machine_name).states.matches?(object, state_name)}
73
+ @condition = lambda { |object| object.class.state_machine(machine_name).states.matches?(object, state_name) }
72
74
  end
73
-
75
+
74
76
  # Creates a new transition that determines what to change the current state
75
77
  # to when an event fires from this state.
76
- #
78
+ #
77
79
  # Since this transition is being defined within a state context, you do
78
80
  # *not* need to specify the <tt>:from</tt> option for the transition. For
79
81
  # example:
80
- #
82
+ #
81
83
  # state_machine do
82
84
  # state :parked do
83
85
  # transition :to => :idling, :on => [:ignite, :shift_up] # Transitions to :idling
84
86
  # transition :from => [:idling, :parked], :on => :park, :unless => :seatbelt_on? # Transitions to :parked if seatbelt is off
85
87
  # end
86
88
  # end
87
- #
89
+ #
88
90
  # See StateMachines::Machine#transition for a description of the possible
89
91
  # configurations for defining transitions.
90
92
  def transition(options)
91
- options.assert_valid_keys(:from, :to, :on, :if, :unless)
93
+ StateMachines::OptionsValidator.assert_valid_keys!(options, :from, :to, :on, :if, :unless)
92
94
  raise ArgumentError, 'Must specify :on event' unless options[:on]
93
95
  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}))
96
+
97
+ machine.transition(options.merge(options[:to] ? {from: state.name} : {to: state.name}))
96
98
  end
97
-
99
+
98
100
  # Hooks in condition-merging to methods that don't exist in this module
99
101
  def method_missing(*args, &block)
100
102
  # Get the configuration
@@ -103,28 +105,28 @@ module StateMachines
103
105
  else
104
106
  args << options = {}
105
107
  end
106
-
108
+
107
109
  # Get any existing condition that may need to be merged
108
110
  if_condition = options.delete(:if)
109
111
  unless_condition = options.delete(:unless)
110
-
112
+
111
113
  # Provide scope access to configuration in case the block is evaluated
112
114
  # within the object instance
113
115
  proxy = self
114
116
  proxy_condition = @condition
115
-
117
+
116
118
  # Replace the configuration condition with the one configured for this
117
119
  # proxy, merging together any existing conditions
118
120
  options[:if] = lambda do |*condition_args|
119
121
  # Block may be executed within the context of the actual object, so
120
122
  # it'll either be the first argument or the executing context
121
123
  object = condition_args.first || self
122
-
124
+
123
125
  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)}
126
+ Array(if_condition).all? { |condition| proxy.evaluate_method(object, condition) } &&
127
+ !Array(unless_condition).any? { |condition| proxy.evaluate_method(object, condition) }
126
128
  end
127
-
129
+
128
130
  # Evaluate the method on the owner class with the condition proxied
129
131
  # through
130
132
  machine.owner_class.send(*args, &block)
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ module STDIORenderer
5
+ module_function def draw_machine(machine, io: $stdout)
6
+ draw_class(machine: machine, io: io)
7
+ draw_states(machine: machine, io: io)
8
+ draw_events(machine: machine, io: io)
9
+ end
10
+
11
+ module_function def draw_class(machine:, io: $stdout)
12
+ io.puts "Class: #{machine.owner_class.name}"
13
+ end
14
+
15
+ module_function def draw_states(machine:, io: $stdout)
16
+ io.puts " States:"
17
+ if machine.states.to_a.empty?
18
+ io.puts " - None"
19
+ else
20
+ machine.states.each do |state|
21
+ io.puts " - #{state.name}"
22
+ end
23
+ end
24
+ end
25
+
26
+ module_function def draw_event(event, graph, options: {}, io: $stdout)
27
+ io = io || options[:io] || $stdout
28
+ io.puts " Event: #{event.name}"
29
+ end
30
+
31
+ module_function def draw_branch(branch, graph, event, options: {}, io: $stdout)
32
+ io = io || options[:io] || $stdout
33
+ io.puts " Branch: #{branch.inspect}"
34
+ end
35
+
36
+ module_function def draw_state(state, graph, options: {}, io: $stdout)
37
+ io = io || options[:io] || $stdout
38
+ io.puts " State: #{state.name}"
39
+ end
40
+
41
+ module_function def draw_events(machine:, io: $stdout)
42
+ io.puts " Events:"
43
+ if machine.events.to_a.empty?
44
+ io.puts " - None"
45
+ else
46
+ machine.events.each do |event|
47
+ io.puts " - #{event.name}"
48
+ event.branches.each do |branch|
49
+ branch.state_requirements.each do |requirement|
50
+ out = +" - "
51
+ out << "#{draw_requirement(requirement[:from])} => #{draw_requirement(requirement[:to])}"
52
+ out << " IF #{branch.if_condition}" if branch.if_condition
53
+ out << " UNLESS #{branch.unless_condition}" if branch.unless_condition
54
+ io.puts out
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ module_function def draw_requirement(requirement)
62
+ case requirement
63
+ when StateMachines::BlacklistMatcher
64
+ "ALL EXCEPT #{requirement.values.join(', ')}"
65
+ when StateMachines::AllMatcher
66
+ "ALL"
67
+ when StateMachines::LoopbackMatcher
68
+ "SAME"
69
+ else
70
+ requirement.values.join(', ')
71
+ end
72
+ end
73
+ end
74
+ end