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.
- checksums.yaml +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +443 -22
- data/lib/state_machines/async_mode/async_event_extensions.rb +49 -0
- data/lib/state_machines/async_mode/async_events.rb +282 -0
- data/lib/state_machines/async_mode/async_machine.rb +60 -0
- data/lib/state_machines/async_mode/async_transition_collection.rb +141 -0
- data/lib/state_machines/async_mode/thread_safe_state.rb +47 -0
- data/lib/state_machines/async_mode.rb +64 -0
- data/lib/state_machines/branch.rb +146 -86
- data/lib/state_machines/callback.rb +35 -32
- data/lib/state_machines/core.rb +3 -3
- data/lib/state_machines/core_ext/class/state_machine.rb +2 -0
- data/lib/state_machines/core_ext.rb +2 -0
- data/lib/state_machines/error.rb +7 -4
- data/lib/state_machines/eval_helpers.rb +197 -39
- data/lib/state_machines/event.rb +77 -58
- data/lib/state_machines/event_collection.rb +49 -39
- data/lib/state_machines/extensions.rb +6 -4
- data/lib/state_machines/helper_module.rb +4 -2
- data/lib/state_machines/integrations/base.rb +3 -1
- data/lib/state_machines/integrations.rb +19 -20
- data/lib/state_machines/machine/action_hooks.rb +53 -0
- data/lib/state_machines/machine/async_extensions.rb +88 -0
- data/lib/state_machines/machine/callbacks.rb +59 -0
- data/lib/state_machines/machine/class_methods.rb +97 -0
- data/lib/state_machines/machine/configuration.rb +134 -0
- data/lib/state_machines/machine/event_methods.rb +59 -0
- data/lib/state_machines/machine/helper_generators.rb +125 -0
- data/lib/state_machines/machine/integration.rb +70 -0
- data/lib/state_machines/machine/parsing.rb +77 -0
- data/lib/state_machines/machine/rendering.rb +17 -0
- data/lib/state_machines/machine/scoping.rb +44 -0
- data/lib/state_machines/machine/state_methods.rb +101 -0
- data/lib/state_machines/machine/utilities.rb +85 -0
- data/lib/state_machines/machine/validation.rb +39 -0
- data/lib/state_machines/machine.rb +425 -1011
- data/lib/state_machines/machine_collection.rb +28 -19
- data/lib/state_machines/macro_methods.rb +104 -102
- data/lib/state_machines/matcher.rb +31 -28
- data/lib/state_machines/matcher_helpers.rb +14 -12
- data/lib/state_machines/node_collection.rb +36 -29
- data/lib/state_machines/options_validator.rb +72 -0
- data/lib/state_machines/path.rb +60 -57
- data/lib/state_machines/path_collection.rb +39 -36
- data/lib/state_machines/state.rb +84 -47
- data/lib/state_machines/state_collection.rb +22 -19
- data/lib/state_machines/state_context.rb +40 -39
- data/lib/state_machines/stdio_renderer.rb +74 -0
- data/lib/state_machines/syntax_validator.rb +57 -0
- data/lib/state_machines/test_helper.rb +896 -0
- data/lib/state_machines/transition.rb +215 -199
- data/lib/state_machines/transition_collection.rb +187 -170
- data/lib/state_machines/version.rb +3 -1
- data/lib/state_machines.rb +4 -1
- metadata +39 -446
- data/.gitignore +0 -21
- data/.rspec +0 -3
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -16
- data/Changelog.md +0 -22
- data/Contributors.md +0 -39
- data/Gemfile +0 -8
- data/Rakefile +0 -12
- data/Testing.md +0 -0
- data/lib/state_machines/assertions.rb +0 -40
- data/state_machines.gemspec +0 -22
- data/test/files/integrations/event_on_failure_integration.rb +0 -10
- data/test/files/integrations/vehicle.rb +0 -7
- data/test/files/models/auto_shop.rb +0 -31
- data/test/files/models/car.rb +0 -21
- data/test/files/models/driver.rb +0 -13
- data/test/files/models/model_base.rb +0 -6
- data/test/files/models/motorcycle.rb +0 -16
- data/test/files/models/traffic_light.rb +0 -47
- data/test/files/models/vehicle.rb +0 -127
- data/test/files/node.rb +0 -5
- data/test/files/switch.rb +0 -15
- data/test/functional/auto_shop_available_test.rb +0 -20
- data/test/functional/auto_shop_busy_test.rb +0 -25
- data/test/functional/car_backing_up_test.rb +0 -45
- data/test/functional/car_test.rb +0 -49
- data/test/functional/driver_default_nonstandard_test.rb +0 -13
- data/test/functional/motorcycle_test.rb +0 -52
- data/test/functional/traffic_light_caution_test.rb +0 -17
- data/test/functional/traffic_light_proceed_test.rb +0 -17
- data/test/functional/traffic_light_stop_test.rb +0 -26
- data/test/functional/vehicle_first_gear_test.rb +0 -42
- data/test/functional/vehicle_idling_test.rb +0 -59
- data/test/functional/vehicle_locked_test.rb +0 -29
- data/test/functional/vehicle_parked_test.rb +0 -53
- data/test/functional/vehicle_repaired_test.rb +0 -20
- data/test/functional/vehicle_second_gear_test.rb +0 -42
- data/test/functional/vehicle_stalled_test.rb +0 -65
- data/test/functional/vehicle_test.rb +0 -20
- data/test/functional/vehicle_third_gear_test.rb +0 -42
- data/test/functional/vehicle_unsaved_test.rb +0 -181
- data/test/functional/vehicle_with_event_attributes_test.rb +0 -30
- data/test/functional/vehicle_with_parallel_events_test.rb +0 -36
- data/test/test_helper.rb +0 -15
- data/test/unit/assertions/assert_exclusive_keys_test.rb +0 -22
- data/test/unit/assertions/assert_valid_key_test.rb +0 -12
- data/test/unit/branch/branch_test.rb +0 -28
- data/test/unit/branch/branch_with_conflicting_conditionals_test.rb +0 -27
- data/test/unit/branch/branch_with_conflicting_from_requirements_test.rb +0 -8
- data/test/unit/branch/branch_with_conflicting_on_requirements_test.rb +0 -8
- data/test/unit/branch/branch_with_conflicting_to_requirements_test.rb +0 -8
- data/test/unit/branch/branch_with_different_requirements_test.rb +0 -41
- data/test/unit/branch/branch_with_except_from_matcher_requirement_test.rb +0 -8
- data/test/unit/branch/branch_with_except_from_requirement_test.rb +0 -36
- data/test/unit/branch/branch_with_except_on_matcher_requirement_test.rb +0 -8
- data/test/unit/branch/branch_with_except_on_requirement_test.rb +0 -36
- data/test/unit/branch/branch_with_except_to_matcher_requirement_test.rb +0 -8
- data/test/unit/branch/branch_with_except_to_requirement_test.rb +0 -36
- data/test/unit/branch/branch_with_from_matcher_requirement_test.rb +0 -20
- data/test/unit/branch/branch_with_from_requirement_test.rb +0 -45
- data/test/unit/branch/branch_with_if_conditional_test.rb +0 -27
- data/test/unit/branch/branch_with_implicit_and_explicit_requirements_test.rb +0 -23
- data/test/unit/branch/branch_with_implicit_from_requirement_matcher_test.rb +0 -20
- data/test/unit/branch/branch_with_implicit_requirement_test.rb +0 -20
- data/test/unit/branch/branch_with_implicit_to_requirement_matcher_test.rb +0 -16
- data/test/unit/branch/branch_with_multiple_except_from_requirements_test.rb +0 -20
- data/test/unit/branch/branch_with_multiple_except_on_requirements_test.rb +0 -16
- data/test/unit/branch/branch_with_multiple_except_to_requirements_test.rb +0 -20
- data/test/unit/branch/branch_with_multiple_from_requirements_test.rb +0 -16
- data/test/unit/branch/branch_with_multiple_if_conditionals_test.rb +0 -20
- data/test/unit/branch/branch_with_multiple_implicit_requirements_test.rb +0 -53
- data/test/unit/branch/branch_with_multiple_to_requirements_test.rb +0 -20
- data/test/unit/branch/branch_with_multiple_unless_conditionals_test.rb +0 -20
- data/test/unit/branch/branch_with_nil_requirements_test.rb +0 -28
- data/test/unit/branch/branch_with_no_requirements_test.rb +0 -36
- data/test/unit/branch/branch_with_on_matcher_requirement_test.rb +0 -16
- data/test/unit/branch/branch_with_on_requirement_test.rb +0 -45
- data/test/unit/branch/branch_with_to_matcher_requirement_test.rb +0 -20
- data/test/unit/branch/branch_with_to_requirement_test.rb +0 -45
- data/test/unit/branch/branch_with_unless_conditional_test.rb +0 -27
- data/test/unit/branch/branch_without_guards_test.rb +0 -27
- data/test/unit/callback/callback_by_default_test.rb +0 -25
- data/test/unit/callback/callback_test.rb +0 -53
- data/test/unit/callback/callback_with_application_bound_object_test.rb +0 -23
- data/test/unit/callback/callback_with_application_terminator_test.rb +0 -24
- data/test/unit/callback/callback_with_arguments_test.rb +0 -14
- data/test/unit/callback/callback_with_around_type_and_arguments_test.rb +0 -25
- data/test/unit/callback/callback_with_around_type_and_block_test.rb +0 -44
- data/test/unit/callback/callback_with_around_type_and_bound_method_test.rb +0 -23
- data/test/unit/callback/callback_with_around_type_and_multiple_methods_test.rb +0 -93
- data/test/unit/callback/callback_with_around_type_and_terminator_test.rb +0 -17
- data/test/unit/callback/callback_with_block_test.rb +0 -20
- data/test/unit/callback/callback_with_bound_method_and_arguments_test.rb +0 -28
- data/test/unit/callback/callback_with_bound_method_test.rb +0 -35
- data/test/unit/callback/callback_with_do_method_test.rb +0 -18
- data/test/unit/callback/callback_with_explicit_requirements_test.rb +0 -32
- data/test/unit/callback/callback_with_if_condition_test.rb +0 -17
- data/test/unit/callback/callback_with_implicit_requirements_test.rb +0 -32
- data/test/unit/callback/callback_with_method_argument_test.rb +0 -18
- data/test/unit/callback/callback_with_mixed_methods_test.rb +0 -31
- data/test/unit/callback/callback_with_multiple_bound_methods_test.rb +0 -21
- data/test/unit/callback/callback_with_multiple_do_methods_test.rb +0 -29
- data/test/unit/callback/callback_with_multiple_method_arguments_test.rb +0 -29
- data/test/unit/callback/callback_with_terminator_test.rb +0 -22
- data/test/unit/callback/callback_with_unbound_method_test.rb +0 -14
- data/test/unit/callback/callback_with_unless_condition_test.rb +0 -17
- data/test/unit/callback/callback_without_arguments_test.rb +0 -14
- data/test/unit/callback/callback_without_terminator_test.rb +0 -12
- data/test/unit/error/error_by_default_test.rb +0 -21
- data/test/unit/error/error_with_message_test.rb +0 -23
- data/test/unit/eval_helper/eval_helpers_base_test.rb +0 -8
- data/test/unit/eval_helper/eval_helpers_proc_block_and_explicit_arguments_test.rb +0 -14
- data/test/unit/eval_helper/eval_helpers_proc_block_and_implicit_arguments_test.rb +0 -14
- data/test/unit/eval_helper/eval_helpers_proc_test.rb +0 -13
- data/test/unit/eval_helper/eval_helpers_proc_with_arguments_test.rb +0 -13
- data/test/unit/eval_helper/eval_helpers_proc_with_block_test.rb +0 -13
- data/test/unit/eval_helper/eval_helpers_proc_with_block_without_arguments_test.rb +0 -18
- data/test/unit/eval_helper/eval_helpers_proc_with_block_without_object_test.rb +0 -14
- data/test/unit/eval_helper/eval_helpers_proc_without_arguments_test.rb +0 -19
- data/test/unit/eval_helper/eval_helpers_string_test.rb +0 -25
- data/test/unit/eval_helper/eval_helpers_string_with_block_test.rb +0 -12
- data/test/unit/eval_helper/eval_helpers_symbol_method_missing_test.rb +0 -20
- data/test/unit/eval_helper/eval_helpers_symbol_private_test.rb +0 -17
- data/test/unit/eval_helper/eval_helpers_symbol_protected_test.rb +0 -17
- data/test/unit/eval_helper/eval_helpers_symbol_tainted_method_test.rb +0 -18
- data/test/unit/eval_helper/eval_helpers_symbol_test.rb +0 -16
- data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_and_block_test.rb +0 -16
- data/test/unit/eval_helper/eval_helpers_symbol_with_arguments_test.rb +0 -16
- data/test/unit/eval_helper/eval_helpers_symbol_with_block_test.rb +0 -16
- data/test/unit/eval_helper/eval_helpers_test.rb +0 -13
- data/test/unit/event/event_after_being_copied_test.rb +0 -17
- data/test/unit/event/event_by_default_test.rb +0 -60
- data/test/unit/event/event_context_test.rb +0 -16
- data/test/unit/event/event_on_failure_test.rb +0 -44
- data/test/unit/event/event_test.rb +0 -34
- data/test/unit/event/event_transitions_test.rb +0 -62
- data/test/unit/event/event_with_conflicting_helpers_after_definition_test.rb +0 -79
- data/test/unit/event/event_with_conflicting_helpers_before_definition_test.rb +0 -58
- data/test/unit/event/event_with_conflicting_machine_test.rb +0 -48
- data/test/unit/event/event_with_dynamic_human_name_test.rb +0 -26
- data/test/unit/event/event_with_human_name_test.rb +0 -13
- data/test/unit/event/event_with_invalid_current_state_test.rb +0 -30
- data/test/unit/event/event_with_machine_action_test.rb +0 -33
- data/test/unit/event/event_with_marshalling_test.rb +0 -47
- data/test/unit/event/event_with_matching_disabled_transitions_test.rb +0 -115
- data/test/unit/event/event_with_matching_enabled_transitions_test.rb +0 -75
- data/test/unit/event/event_with_multiple_transitions_test.rb +0 -61
- data/test/unit/event/event_with_namespace_test.rb +0 -34
- data/test/unit/event/event_with_transition_with_blacklisted_to_state_test.rb +0 -60
- data/test/unit/event/event_with_transition_with_loopback_state_test.rb +0 -36
- data/test/unit/event/event_with_transition_with_nil_to_state_test.rb +0 -36
- data/test/unit/event/event_with_transition_with_whitelisted_to_state_test.rb +0 -51
- data/test/unit/event/event_with_transition_without_to_state_test.rb +0 -36
- data/test/unit/event/event_with_transitions_test.rb +0 -32
- data/test/unit/event/event_without_matching_transitions_test.rb +0 -41
- data/test/unit/event/event_without_transitions_test.rb +0 -28
- data/test/unit/event/invalid_event_test.rb +0 -20
- data/test/unit/event_collection/event_collection_attribute_with_machine_action_test.rb +0 -62
- data/test/unit/event_collection/event_collection_attribute_with_namespaced_machine_test.rb +0 -36
- data/test/unit/event_collection/event_collection_by_default_test.rb +0 -26
- data/test/unit/event_collection/event_collection_test.rb +0 -39
- data/test/unit/event_collection/event_collection_with_custom_machine_attribute_test.rb +0 -31
- data/test/unit/event_collection/event_collection_with_events_with_transitions_test.rb +0 -76
- data/test/unit/event_collection/event_collection_with_multiple_events_test.rb +0 -27
- data/test/unit/event_collection/event_collection_with_validations_test.rb +0 -74
- data/test/unit/event_collection/event_collection_without_machine_action_test.rb +0 -18
- data/test/unit/event_collection/event_string_collection_test.rb +0 -31
- data/test/unit/helper_module_test.rb +0 -17
- data/test/unit/integrations/integration_finder_test.rb +0 -16
- data/test/unit/integrations/integration_matcher_test.rb +0 -29
- data/test/unit/invalid_transition/invalid_parallel_transition_test.rb +0 -18
- data/test/unit/invalid_transition/invalid_transition_test.rb +0 -47
- data/test/unit/invalid_transition/invalid_transition_with_integration_test.rb +0 -45
- data/test/unit/invalid_transition/invalid_transition_with_namespace_test.rb +0 -32
- data/test/unit/machine/machine_after_being_copied_test.rb +0 -62
- data/test/unit/machine/machine_after_changing_initial_state.rb +0 -28
- data/test/unit/machine/machine_after_changing_owner_class_test.rb +0 -31
- data/test/unit/machine/machine_by_default_test.rb +0 -160
- data/test/unit/machine/machine_finder_custom_options_test.rb +0 -17
- data/test/unit/machine/machine_finder_with_existing_machine_on_superclass_test.rb +0 -85
- data/test/unit/machine/machine_finder_with_existing_on_same_class_test.rb +0 -23
- data/test/unit/machine/machine_finder_without_existing_machine_test.rb +0 -25
- data/test/unit/machine/machine_persistence_test.rb +0 -52
- data/test/unit/machine/machine_state_initialization_test.rb +0 -56
- data/test/unit/machine/machine_test.rb +0 -30
- data/test/unit/machine/machine_with_action_already_overridden_test.rb +0 -23
- data/test/unit/machine/machine_with_action_defined_in_class_test.rb +0 -37
- data/test/unit/machine/machine_with_action_defined_in_included_module_test.rb +0 -46
- data/test/unit/machine/machine_with_action_defined_in_superclass_test.rb +0 -43
- data/test/unit/machine/machine_with_action_undefined_test.rb +0 -33
- data/test/unit/machine/machine_with_cached_state_test.rb +0 -20
- data/test/unit/machine/machine_with_class_helpers_test.rb +0 -179
- data/test/unit/machine/machine_with_conflicting_helpers_after_definition_test.rb +0 -244
- data/test/unit/machine/machine_with_conflicting_helpers_before_definition_test.rb +0 -175
- data/test/unit/machine/machine_with_custom_action_test.rb +0 -11
- data/test/unit/machine/machine_with_custom_attribute_test.rb +0 -103
- data/test/unit/machine/machine_with_custom_initialize_test.rb +0 -24
- data/test/unit/machine/machine_with_custom_integration_test.rb +0 -72
- data/test/unit/machine/machine_with_custom_invalidation_test.rb +0 -39
- data/test/unit/machine/machine_with_custom_name_test.rb +0 -57
- data/test/unit/machine/machine_with_custom_plural_test.rb +0 -52
- data/test/unit/machine/machine_with_dynamic_initial_state_test.rb +0 -65
- data/test/unit/machine/machine_with_event_matchers_test.rb +0 -41
- data/test/unit/machine/machine_with_events_test.rb +0 -52
- data/test/unit/machine/machine_with_events_with_custom_human_names_test.rb +0 -18
- data/test/unit/machine/machine_with_events_with_transitions_test.rb +0 -37
- data/test/unit/machine/machine_with_existing_event_test.rb +0 -17
- data/test/unit/machine/machine_with_existing_machines_on_owner_class_test.rb +0 -20
- data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_class_test.rb +0 -71
- data/test/unit/machine/machine_with_existing_machines_with_same_attributes_on_owner_subclass_test.rb +0 -31
- data/test/unit/machine/machine_with_existing_state_test.rb +0 -27
- data/test/unit/machine/machine_with_failure_callbacks_test.rb +0 -48
- data/test/unit/machine/machine_with_helpers_test.rb +0 -14
- data/test/unit/machine/machine_with_initial_state_with_value_and_owner_default.rb +0 -25
- data/test/unit/machine/machine_with_initialize_and_super_test.rb +0 -17
- data/test/unit/machine/machine_with_initialize_arguments_and_block_test.rb +0 -31
- data/test/unit/machine/machine_with_initialize_without_super_test.rb +0 -17
- data/test/unit/machine/machine_with_instance_helpers_test.rb +0 -179
- data/test/unit/machine/machine_with_integration_test.rb +0 -72
- data/test/unit/machine/machine_with_multiple_events_test.rb +0 -32
- data/test/unit/machine/machine_with_namespace_test.rb +0 -48
- data/test/unit/machine/machine_with_nil_action_test.rb +0 -27
- data/test/unit/machine/machine_with_other_states.rb +0 -22
- data/test/unit/machine/machine_with_owner_subclass_test.rb +0 -18
- data/test/unit/machine/machine_with_paths_test.rb +0 -25
- data/test/unit/machine/machine_with_private_action_test.rb +0 -43
- data/test/unit/machine/machine_with_state_matchers_test.rb +0 -41
- data/test/unit/machine/machine_with_state_with_matchers_test.rb +0 -19
- data/test/unit/machine/machine_with_states_test.rb +0 -55
- data/test/unit/machine/machine_with_states_with_behaviors_test.rb +0 -23
- data/test/unit/machine/machine_with_states_with_custom_human_names_test.rb +0 -18
- data/test/unit/machine/machine_with_states_with_custom_values_test.rb +0 -21
- data/test/unit/machine/machine_with_states_with_runtime_dependencies_test.rb +0 -19
- data/test/unit/machine/machine_with_static_initial_state_test.rb +0 -49
- data/test/unit/machine/machine_with_superclass_conflicting_helpers_after_definition_test.rb +0 -36
- data/test/unit/machine/machine_with_transition_callbacks_test.rb +0 -144
- data/test/unit/machine/machine_with_transitions_test.rb +0 -87
- data/test/unit/machine/machine_without_initialization_test.rb +0 -31
- data/test/unit/machine/machine_without_initialize_test.rb +0 -14
- data/test/unit/machine/machine_without_integration_test.rb +0 -31
- data/test/unit/machine_collection/machine_collection_by_default_test.rb +0 -11
- data/test/unit/machine_collection/machine_collection_fire_test.rb +0 -80
- data/test/unit/machine_collection/machine_collection_fire_with_transactions_test.rb +0 -54
- data/test/unit/machine_collection/machine_collection_fire_with_validations_test.rb +0 -76
- data/test/unit/machine_collection/machine_collection_state_initialization_test.rb +0 -111
- data/test/unit/machine_collection/machine_collection_transitions_with_blank_events_test.rb +0 -25
- data/test/unit/machine_collection/machine_collection_transitions_with_custom_options_test.rb +0 -20
- data/test/unit/machine_collection/machine_collection_transitions_with_different_actions_test.rb +0 -26
- data/test/unit/machine_collection/machine_collection_transitions_with_exisiting_transitions_test.rb +0 -25
- data/test/unit/machine_collection/machine_collection_transitions_with_invalid_events_test.rb +0 -25
- data/test/unit/machine_collection/machine_collection_transitions_with_same_actions_test.rb +0 -31
- data/test/unit/machine_collection/machine_collection_transitions_with_transition_test.rb +0 -26
- data/test/unit/machine_collection/machine_collection_transitions_without_events_test.rb +0 -25
- data/test/unit/machine_collection/machine_collection_transitions_without_transition_test.rb +0 -27
- data/test/unit/matcher/all_matcher_test.rb +0 -29
- data/test/unit/matcher/blacklist_matcher_test.rb +0 -30
- data/test/unit/matcher/loopback_matcher_test.rb +0 -27
- data/test/unit/matcher/matcher_by_default_test.rb +0 -15
- data/test/unit/matcher/matcher_with_multiple_values_test.rb +0 -15
- data/test/unit/matcher/matcher_with_value_test.rb +0 -15
- data/test/unit/matcher/whitelist_matcher_test.rb +0 -30
- data/test/unit/matcher_helpers/matcher_helpers_all_test.rb +0 -14
- data/test/unit/matcher_helpers/matcher_helpers_any_test.rb +0 -14
- data/test/unit/matcher_helpers/matcher_helpers_same_test.rb +0 -13
- data/test/unit/node_collection/node_collection_after_being_copied_test.rb +0 -46
- data/test/unit/node_collection/node_collection_after_update_test.rb +0 -36
- data/test/unit/node_collection/node_collection_by_default_test.rb +0 -22
- data/test/unit/node_collection/node_collection_test.rb +0 -23
- data/test/unit/node_collection/node_collection_with_indices_test.rb +0 -42
- data/test/unit/node_collection/node_collection_with_matcher_contexts_test.rb +0 -25
- data/test/unit/node_collection/node_collection_with_nodes_test.rb +0 -46
- data/test/unit/node_collection/node_collection_with_numeric_index_test.rb +0 -24
- data/test/unit/node_collection/node_collection_with_postdefined_contexts_test.rb +0 -22
- data/test/unit/node_collection/node_collection_with_predefined_contexts_test.rb +0 -23
- data/test/unit/node_collection/node_collection_with_string_index_test.rb +0 -20
- data/test/unit/node_collection/node_collection_with_symbol_index_test.rb +0 -20
- data/test/unit/node_collection/node_collection_without_indices_test.rb +0 -30
- data/test/unit/path/path_by_default_test.rb +0 -54
- data/test/unit/path/path_test.rb +0 -14
- data/test/unit/path/path_with_available_transitions_after_reaching_target_test.rb +0 -40
- data/test/unit/path/path_with_available_transitions_test.rb +0 -54
- data/test/unit/path/path_with_deep_target_reached_test.rb +0 -50
- data/test/unit/path/path_with_deep_target_test.rb +0 -40
- data/test/unit/path/path_with_duplicates_test.rb +0 -32
- data/test/unit/path/path_with_encountered_transitions_test.rb +0 -34
- data/test/unit/path/path_with_guarded_transitions_test.rb +0 -42
- data/test/unit/path/path_with_reached_target_test.rb +0 -35
- data/test/unit/path/path_with_transitions_test.rb +0 -54
- data/test/unit/path/path_with_unreached_target_test.rb +0 -31
- data/test/unit/path/path_without_transitions_test.rb +0 -24
- data/test/unit/path_collection/path_collection_by_default_test.rb +0 -46
- data/test/unit/path_collection/path_collection_test.rb +0 -24
- data/test/unit/path_collection/path_collection_with_deep_paths_test.rb +0 -43
- data/test/unit/path_collection/path_collection_with_duplicate_nodes_test.rb +0 -31
- data/test/unit/path_collection/path_collection_with_from_state_test.rb +0 -27
- data/test/unit/path_collection/path_collection_with_paths_test.rb +0 -47
- data/test/unit/path_collection/path_collection_with_to_state_test.rb +0 -29
- data/test/unit/path_collection/path_with_guarded_paths_test.rb +0 -25
- data/test/unit/state/state_after_being_copied_test.rb +0 -19
- data/test/unit/state/state_by_default_test.rb +0 -41
- data/test/unit/state/state_final_test.rb +0 -28
- data/test/unit/state/state_initial_test.rb +0 -13
- data/test/unit/state/state_not_final_test.rb +0 -32
- data/test/unit/state/state_not_initial_test.rb +0 -13
- data/test/unit/state/state_test.rb +0 -44
- data/test/unit/state/state_with_cached_lambda_value_test.rb +0 -29
- data/test/unit/state/state_with_conflicting_helpers_after_definition_test.rb +0 -38
- data/test/unit/state/state_with_conflicting_helpers_before_definition_test.rb +0 -29
- data/test/unit/state/state_with_conflicting_machine_name_test.rb +0 -20
- data/test/unit/state/state_with_conflicting_machine_test.rb +0 -37
- data/test/unit/state/state_with_context_test.rb +0 -60
- data/test/unit/state/state_with_dynamic_human_name_test.rb +0 -25
- data/test/unit/state/state_with_existing_context_method_test.rb +0 -24
- data/test/unit/state/state_with_human_name_test.rb +0 -13
- data/test/unit/state/state_with_integer_value_test.rb +0 -32
- data/test/unit/state/state_with_invalid_method_call_test.rb +0 -21
- data/test/unit/state/state_with_lambda_value_test.rb +0 -37
- data/test/unit/state/state_with_matcher_test.rb +0 -18
- data/test/unit/state/state_with_multiple_contexts_test.rb +0 -57
- data/test/unit/state/state_with_name_test.rb +0 -43
- data/test/unit/state/state_with_namespace_test.rb +0 -22
- data/test/unit/state/state_with_nil_value_test.rb +0 -35
- data/test/unit/state/state_with_redefined_context_method_test.rb +0 -45
- data/test/unit/state/state_with_symbolic_value_test.rb +0 -32
- data/test/unit/state/state_with_valid_inherited_method_call_for_current_state_test.rb +0 -40
- data/test/unit/state/state_with_valid_method_call_for_current_state_test.rb +0 -33
- data/test/unit/state/state_with_valid_method_call_for_different_state_test.rb +0 -41
- data/test/unit/state/state_without_cached_lambda_value_test.rb +0 -25
- data/test/unit/state/state_without_name_test.rb +0 -39
- data/test/unit/state_collection/state_collection_by_default_test.rb +0 -21
- data/test/unit/state_collection/state_collection_string_test.rb +0 -35
- data/test/unit/state_collection/state_collection_test.rb +0 -74
- data/test/unit/state_collection/state_collection_with_custom_state_values_test.rb +0 -29
- data/test/unit/state_collection/state_collection_with_event_transitions_test.rb +0 -39
- data/test/unit/state_collection/state_collection_with_initial_state_test.rb +0 -40
- data/test/unit/state_collection/state_collection_with_namespace_test.rb +0 -21
- data/test/unit/state_collection/state_collection_with_state_behaviors_test.rb +0 -40
- data/test/unit/state_collection/state_collection_with_state_matchers_test.rb +0 -29
- data/test/unit/state_collection/state_collection_with_transition_callbacks_test.rb +0 -40
- data/test/unit/state_context/state_context_proxy_test.rb +0 -26
- data/test/unit/state_context/state_context_proxy_with_if_and_unless_conditions_test.rb +0 -42
- data/test/unit/state_context/state_context_proxy_with_if_condition_test.rb +0 -64
- data/test/unit/state_context/state_context_proxy_with_multiple_if_conditions_test.rb +0 -32
- data/test/unit/state_context/state_context_proxy_with_multiple_unless_conditions_test.rb +0 -32
- data/test/unit/state_context/state_context_proxy_with_unless_condition_test.rb +0 -64
- data/test/unit/state_context/state_context_proxy_without_conditions_test.rb +0 -31
- data/test/unit/state_context/state_context_test.rb +0 -28
- data/test/unit/state_context/state_context_transition_test.rb +0 -104
- data/test/unit/state_context/state_context_with_matching_transition_test.rb +0 -27
- data/test/unit/state_machine/state_machine_by_default_test.rb +0 -12
- data/test/unit/state_machine/state_machine_test.rb +0 -20
- data/test/unit/transition/transition_after_being_performed_test.rb +0 -48
- data/test/unit/transition/transition_after_being_persisted_test.rb +0 -46
- data/test/unit/transition/transition_after_being_rolled_back_test.rb +0 -35
- data/test/unit/transition/transition_equality_test.rb +0 -52
- data/test/unit/transition/transition_loopback_test.rb +0 -18
- data/test/unit/transition/transition_test.rb +0 -96
- data/test/unit/transition/transition_transient_test.rb +0 -20
- data/test/unit/transition/transition_with_action_test.rb +0 -27
- data/test/unit/transition/transition_with_after_callbacks_skipped_test.rb +0 -127
- data/test/unit/transition/transition_with_after_callbacks_test.rb +0 -93
- data/test/unit/transition/transition_with_around_callbacks_test.rb +0 -141
- data/test/unit/transition/transition_with_before_callbacks_skipped_test.rb +0 -30
- data/test/unit/transition/transition_with_before_callbacks_test.rb +0 -104
- data/test/unit/transition/transition_with_custom_machine_attribute_test.rb +0 -28
- data/test/unit/transition/transition_with_different_states_test.rb +0 -18
- data/test/unit/transition/transition_with_dynamic_to_value_test.rb +0 -19
- data/test/unit/transition/transition_with_failure_callbacks_test.rb +0 -84
- data/test/unit/transition/transition_with_invalid_nodes_test.rb +0 -29
- data/test/unit/transition/transition_with_mixed_callbacks_test.rb +0 -105
- data/test/unit/transition/transition_with_multiple_after_callbacks_test.rb +0 -40
- data/test/unit/transition/transition_with_multiple_around_callbacks_test.rb +0 -114
- data/test/unit/transition/transition_with_multiple_before_callbacks_test.rb +0 -40
- data/test/unit/transition/transition_with_multiple_failure_callbacks_test.rb +0 -40
- data/test/unit/transition/transition_with_namespace_test.rb +0 -47
- data/test/unit/transition/transition_with_perform_arguments_test.rb +0 -35
- data/test/unit/transition/transition_with_transactions_test.rb +0 -42
- data/test/unit/transition/transition_without_callbacks_test.rb +0 -33
- data/test/unit/transition/transition_without_reading_state_test.rb +0 -22
- data/test/unit/transition/transition_without_running_action_test.rb +0 -47
- data/test/unit/transition_collection/attribute_transition_collection_by_default_test.rb +0 -23
- data/test/unit/transition_collection/attribute_transition_collection_marshalling_test.rb +0 -64
- data/test/unit/transition_collection/attribute_transition_collection_with_action_error_test.rb +0 -44
- data/test/unit/transition_collection/attribute_transition_collection_with_action_failed_test.rb +0 -44
- data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_error_test.rb +0 -32
- data/test/unit/transition_collection/attribute_transition_collection_with_after_callback_halt_test.rb +0 -33
- data/test/unit/transition_collection/attribute_transition_collection_with_around_after_yield_callback_error_test.rb +0 -32
- data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_error_test.rb +0 -32
- data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_after_yield_halt_test.rb +0 -33
- data/test/unit/transition_collection/attribute_transition_collection_with_around_callback_before_yield_halt_test.rb +0 -33
- data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_error_test.rb +0 -32
- data/test/unit/transition_collection/attribute_transition_collection_with_before_callback_halt_test.rb +0 -33
- data/test/unit/transition_collection/attribute_transition_collection_with_callbacks_test.rb +0 -68
- data/test/unit/transition_collection/attribute_transition_collection_with_event_transitions_test.rb +0 -41
- data/test/unit/transition_collection/attribute_transition_collection_with_events_test.rb +0 -44
- data/test/unit/transition_collection/attribute_transition_collection_with_skipped_after_callbacks_test.rb +0 -42
- data/test/unit/transition_collection/transition_collection_by_default_test.rb +0 -23
- data/test/unit/transition_collection/transition_collection_empty_with_block_test.rb +0 -23
- data/test/unit/transition_collection/transition_collection_empty_without_block_test.rb +0 -12
- data/test/unit/transition_collection/transition_collection_invalid_test.rb +0 -21
- data/test/unit/transition_collection/transition_collection_partial_invalid_test.rb +0 -69
- data/test/unit/transition_collection/transition_collection_test.rb +0 -26
- data/test/unit/transition_collection/transition_collection_valid_test.rb +0 -57
- data/test/unit/transition_collection/transition_collection_with_action_error_test.rb +0 -66
- data/test/unit/transition_collection/transition_collection_with_action_failed_test.rb +0 -60
- data/test/unit/transition_collection/transition_collection_with_action_hook_and_block_test.rb +0 -17
- data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_action_test.rb +0 -17
- data/test/unit/transition_collection/transition_collection_with_action_hook_and_skipped_after_callbacks_test.rb +0 -37
- data/test/unit/transition_collection/transition_collection_with_action_hook_base_test.rb +0 -34
- data/test/unit/transition_collection/transition_collection_with_action_hook_error_test.rb +0 -29
- data/test/unit/transition_collection/transition_collection_with_action_hook_invalid_test.rb +0 -17
- data/test/unit/transition_collection/transition_collection_with_action_hook_multiple_test.rb +0 -79
- data/test/unit/transition_collection/transition_collection_with_action_hook_test.rb +0 -45
- data/test/unit/transition_collection/transition_collection_with_action_hook_with_different_actions_test.rb +0 -48
- data/test/unit/transition_collection/transition_collection_with_action_hook_with_nil_action_test.rb +0 -42
- data/test/unit/transition_collection/transition_collection_with_after_callback_halt_test.rb +0 -47
- data/test/unit/transition_collection/transition_collection_with_before_callback_halt_test.rb +0 -51
- data/test/unit/transition_collection/transition_collection_with_block_test.rb +0 -46
- data/test/unit/transition_collection/transition_collection_with_callbacks_test.rb +0 -135
- data/test/unit/transition_collection/transition_collection_with_different_actions_test.rb +0 -189
- data/test/unit/transition_collection/transition_collection_with_duplicate_actions_test.rb +0 -48
- data/test/unit/transition_collection/transition_collection_with_empty_actions_test.rb +0 -41
- data/test/unit/transition_collection/transition_collection_with_mixed_actions_test.rb +0 -41
- data/test/unit/transition_collection/transition_collection_with_skipped_actions_and_block_test.rb +0 -34
- data/test/unit/transition_collection/transition_collection_with_skipped_actions_test.rb +0 -69
- data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_and_around_callbacks_test.rb +0 -53
- data/test/unit/transition_collection/transition_collection_with_skipped_after_callbacks_test.rb +0 -34
- data/test/unit/transition_collection/transition_collection_with_transactions_test.rb +0 -65
- data/test/unit/transition_collection/transition_collection_without_transactions_test.rb +0 -29
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
# Represents a collection of events in a state machine
|
3
5
|
class EventCollection < NodeCollection
|
4
|
-
def initialize(machine)
|
5
|
-
super(machine, :
|
6
|
+
def initialize(machine) # :nodoc:
|
7
|
+
super(machine, index: %i[name qualified_name])
|
6
8
|
end
|
7
9
|
|
8
10
|
# Gets the list of events that can be fired on the given object.
|
9
|
-
#
|
11
|
+
#
|
10
12
|
# Valid requirement options:
|
11
13
|
# * <tt>:from</tt> - One or more states being transitioned from. If none
|
12
14
|
# are specified, then this will be the object's current state.
|
@@ -16,26 +18,26 @@ module StateMachines
|
|
16
18
|
# are specified, then this will match any event.
|
17
19
|
# * <tt>:guard</tt> - Whether to guard transitions with the if/unless
|
18
20
|
# conditionals defined for each one. Default is true.
|
19
|
-
#
|
21
|
+
#
|
20
22
|
# == Examples
|
21
|
-
#
|
23
|
+
#
|
22
24
|
# class Vehicle
|
23
25
|
# state_machine :initial => :parked do
|
24
26
|
# event :park do
|
25
27
|
# transition :idling => :parked
|
26
28
|
# end
|
27
|
-
#
|
29
|
+
#
|
28
30
|
# event :ignite do
|
29
31
|
# transition :parked => :idling
|
30
32
|
# end
|
31
33
|
# end
|
32
34
|
# end
|
33
|
-
#
|
35
|
+
#
|
34
36
|
# events = Vehicle.state_machine(:state).events
|
35
|
-
#
|
37
|
+
#
|
36
38
|
# vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
|
37
39
|
# events.valid_for(vehicle) # => [#<StateMachines::Event name=:ignite transitions=[:parked => :idling]>]
|
38
|
-
#
|
40
|
+
#
|
39
41
|
# vehicle.state = 'idling'
|
40
42
|
# events.valid_for(vehicle) # => [#<StateMachines::Event name=:park transitions=[:idling => :parked]>]
|
41
43
|
def valid_for(object, requirements = {})
|
@@ -43,7 +45,7 @@ module StateMachines
|
|
43
45
|
end
|
44
46
|
|
45
47
|
# Gets the list of transitions that can be run on the given object.
|
46
|
-
#
|
48
|
+
#
|
47
49
|
# Valid requirement options:
|
48
50
|
# * <tt>:from</tt> - One or more states being transitioned from. If none
|
49
51
|
# are specified, then this will be the object's current state.
|
@@ -53,29 +55,29 @@ module StateMachines
|
|
53
55
|
# are specified, then this will match any event.
|
54
56
|
# * <tt>:guard</tt> - Whether to guard transitions with the if/unless
|
55
57
|
# conditionals defined for each one. Default is true.
|
56
|
-
#
|
58
|
+
#
|
57
59
|
# == Examples
|
58
|
-
#
|
60
|
+
#
|
59
61
|
# class Vehicle
|
60
62
|
# state_machine :initial => :parked do
|
61
63
|
# event :park do
|
62
64
|
# transition :idling => :parked
|
63
65
|
# end
|
64
|
-
#
|
66
|
+
#
|
65
67
|
# event :ignite do
|
66
68
|
# transition :parked => :idling
|
67
69
|
# end
|
68
70
|
# end
|
69
71
|
# end
|
70
|
-
#
|
72
|
+
#
|
71
73
|
# events = Vehicle.state_machine.events
|
72
|
-
#
|
74
|
+
#
|
73
75
|
# vehicle = Vehicle.new # => #<Vehicle:0xb7c464b0 @state="parked">
|
74
76
|
# events.transitions_for(vehicle) # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
|
75
|
-
#
|
77
|
+
#
|
76
78
|
# vehicle.state = 'idling'
|
77
79
|
# events.transitions_for(vehicle) # => [#<StateMachines::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>]
|
78
|
-
#
|
80
|
+
#
|
79
81
|
# # Search for explicit transitions regardless of the current state
|
80
82
|
# events.transitions_for(vehicle, :from => :parked) # => [#<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
|
81
83
|
def transitions_for(object, requirements = {})
|
@@ -86,12 +88,12 @@ module StateMachines
|
|
86
88
|
# given object's event attribute. This also takes an additional parameter
|
87
89
|
# for automatically invalidating the object if the event or transition are
|
88
90
|
# invalid. By default, this is turned off.
|
89
|
-
#
|
91
|
+
#
|
90
92
|
# *Note* that if a transition has already been generated for the event, then
|
91
93
|
# that transition will be used.
|
92
|
-
#
|
94
|
+
#
|
93
95
|
# == Examples
|
94
|
-
#
|
96
|
+
#
|
95
97
|
# class Vehicle < ActiveRecord::Base
|
96
98
|
# state_machine :initial => :parked do
|
97
99
|
# event :ignite do
|
@@ -99,40 +101,48 @@ module StateMachines
|
|
99
101
|
# end
|
100
102
|
# end
|
101
103
|
# end
|
102
|
-
#
|
104
|
+
#
|
103
105
|
# vehicle = Vehicle.new # => #<Vehicle id: nil, state: "parked">
|
104
106
|
# events = Vehicle.state_machine.events
|
105
|
-
#
|
107
|
+
#
|
106
108
|
# vehicle.state_event = nil
|
107
109
|
# events.attribute_transition_for(vehicle) # => nil # Event isn't defined
|
108
|
-
#
|
110
|
+
#
|
109
111
|
# vehicle.state_event = 'invalid'
|
110
112
|
# events.attribute_transition_for(vehicle) # => false # Event is invalid
|
111
|
-
#
|
113
|
+
#
|
112
114
|
# vehicle.state_event = 'ignite'
|
113
115
|
# events.attribute_transition_for(vehicle) # => #<StateMachines::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
|
114
116
|
def attribute_transition_for(object, invalidate = false)
|
115
117
|
return unless machine.action
|
116
118
|
|
117
119
|
# TODO, simplify
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
120
|
+
# First try the regular event_transition
|
121
|
+
transition = machine.read(object, :event_transition)
|
122
|
+
|
123
|
+
# If not found and we have stored transitions by machine (issue #91)
|
124
|
+
if !transition && (transitions_by_machine = object.instance_variable_get(:@_state_machine_event_transitions))
|
125
|
+
transition = transitions_by_machine[machine.name]
|
126
|
+
end
|
127
|
+
|
128
|
+
transition || if event_name = machine.read(object, :event)
|
129
|
+
if event = self[event_name.to_sym, :name]
|
130
|
+
event.transition_for(object) || begin
|
131
|
+
# No valid transition: invalidate
|
132
|
+
machine.invalidate(object, :event, :invalid_event, [[:state, machine.states.match!(object).human_name(object.class)]]) if invalidate
|
133
|
+
false
|
134
|
+
end
|
135
|
+
else
|
136
|
+
# Event is unknown: invalidate
|
137
|
+
machine.invalidate(object, :event, :invalid) if invalidate
|
138
|
+
false
|
139
|
+
end
|
140
|
+
end
|
132
141
|
end
|
133
142
|
|
134
143
|
private
|
135
|
-
|
144
|
+
|
145
|
+
def match(requirements) # :nodoc:
|
136
146
|
requirements && requirements[:on] ? [fetch(requirements.delete(:on))] : self
|
137
147
|
end
|
138
148
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
module ClassMethods
|
3
|
-
def self.extended(base)
|
5
|
+
def self.extended(base) # :nodoc:
|
4
6
|
base.class_eval do
|
5
7
|
@state_machines = MachineCollection.new
|
6
8
|
end
|
@@ -136,13 +138,13 @@ module StateMachines
|
|
136
138
|
# vehicle.fire_events!(:ignite, :disable_alarm) # => StateMachines::InvalidParallelTransition: Cannot run events in parallel: ignite, disable_alarm
|
137
139
|
def fire_events!(*events)
|
138
140
|
run_action = [true, false].include?(events.last) ? events.pop : true
|
139
|
-
fire_events(*(events + [run_action])) ||
|
141
|
+
fire_events(*(events + [run_action])) || raise(StateMachines::InvalidParallelTransition.new(self, events))
|
140
142
|
end
|
141
143
|
|
142
144
|
protected
|
143
145
|
|
144
|
-
def initialize_state_machines(options = {}, &
|
145
|
-
self.class.state_machines.initialize_states(self, options, &
|
146
|
+
def initialize_state_machines(options = {}, &) # :nodoc:
|
147
|
+
self.class.state_machines.initialize_states(self, options, &)
|
146
148
|
end
|
147
149
|
end
|
148
150
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
# Represents a type of module that defines instance / class methods for a
|
3
5
|
# state machine
|
4
|
-
class HelperModule < Module
|
6
|
+
class HelperModule < Module # :nodoc:
|
5
7
|
def initialize(machine, kind)
|
6
8
|
@machine = machine
|
7
9
|
@kind = kind
|
8
10
|
end
|
9
|
-
|
11
|
+
|
10
12
|
# Provides a human-readable description of the module
|
11
13
|
def to_s
|
12
14
|
owner_class = @machine.owner_class
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
module Integrations
|
3
5
|
# Provides a set of base helpers for managing individual integrations
|
@@ -33,7 +35,7 @@ module StateMachines
|
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
def self.included(base)
|
38
|
+
def self.included(base) # :nodoc:
|
37
39
|
base.extend ClassMethods
|
38
40
|
end
|
39
41
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
# Integrations allow state machines to take advantage of features within the
|
3
5
|
# context of a particular library. This is currently most useful with
|
@@ -9,10 +11,10 @@ module StateMachines
|
|
9
11
|
# * Scopes
|
10
12
|
# * Callbacks
|
11
13
|
# * Validation errors
|
12
|
-
#
|
14
|
+
#
|
13
15
|
# This type of integration allows the user to work with state machines in a
|
14
16
|
# fashion similar to other object models in their application.
|
15
|
-
#
|
17
|
+
#
|
16
18
|
# The integration interface is loosely defined by various unimplemented
|
17
19
|
# methods in the StateMachines::Machine class. See that class or the various
|
18
20
|
# built-in integrations for more information about how to define additional
|
@@ -24,15 +26,15 @@ module StateMachines
|
|
24
26
|
# Register integration
|
25
27
|
def register(name_or_module)
|
26
28
|
case name_or_module.class.to_s
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
when 'Module'
|
30
|
+
add(name_or_module)
|
31
|
+
else
|
32
|
+
raise IntegrationError
|
31
33
|
end
|
32
34
|
true
|
33
35
|
end
|
34
36
|
|
35
|
-
def reset
|
37
|
+
def reset # :nodoc:#
|
36
38
|
@integrations = []
|
37
39
|
end
|
38
40
|
|
@@ -45,30 +47,27 @@ module StateMachines
|
|
45
47
|
# StateMachines::Integrations.register(StateMachines::Integrations::ActiveModel)
|
46
48
|
# StateMachines::Integrations.integrations
|
47
49
|
# # => [StateMachines::Integrations::ActiveModel]
|
48
|
-
|
49
|
-
# Register all namespaced integrations
|
50
|
-
@integrations
|
51
|
-
end
|
50
|
+
attr_reader :integrations
|
52
51
|
|
53
|
-
|
52
|
+
alias list integrations
|
54
53
|
|
55
54
|
# Attempts to find an integration that matches the given class. This will
|
56
55
|
# look through all of the built-in integrations under the StateMachines::Integrations
|
57
56
|
# namespace and find one that successfully matches the class.
|
58
|
-
#
|
57
|
+
#
|
59
58
|
# == Examples
|
60
|
-
#
|
59
|
+
#
|
61
60
|
# class Vehicle
|
62
61
|
# end
|
63
|
-
#
|
62
|
+
#
|
64
63
|
# class ActiveModelVehicle
|
65
64
|
# include ActiveModel::Observing
|
66
65
|
# include ActiveModel::Validations
|
67
66
|
# end
|
68
|
-
#
|
67
|
+
#
|
69
68
|
# class ActiveRecordVehicle < ActiveRecord::Base
|
70
69
|
# end
|
71
|
-
#
|
70
|
+
#
|
72
71
|
# StateMachines::Integrations.match(Vehicle) # => nil
|
73
72
|
# StateMachines::Integrations.match(ActiveModelVehicle) # => StateMachines::Integrations::ActiveModel
|
74
73
|
# StateMachines::Integrations.match(ActiveRecordVehicle) # => StateMachines::Integrations::ActiveRecord
|
@@ -103,9 +102,9 @@ module StateMachines
|
|
103
102
|
private
|
104
103
|
|
105
104
|
def add(integration)
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
return unless integration.respond_to?(:integration_name)
|
106
|
+
|
107
|
+
@integrations.insert(0, integration) unless @integrations.include?(integration)
|
109
108
|
end
|
110
109
|
end
|
111
110
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StateMachines
|
4
|
+
class Machine
|
5
|
+
module ActionHooks
|
6
|
+
protected
|
7
|
+
|
8
|
+
# Determines whether action helpers should be defined for this machine.
|
9
|
+
# This is only true if there is an action configured and no other machines
|
10
|
+
# have process this same configuration already.
|
11
|
+
def define_action_helpers?
|
12
|
+
action && owner_class.state_machines.none? { |_name, machine| machine.action == action && machine != self }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Adds helper methods for automatically firing events when an action
|
16
|
+
# is invoked
|
17
|
+
def define_action_helpers
|
18
|
+
return unless action_hook
|
19
|
+
|
20
|
+
@action_hook_defined = true
|
21
|
+
define_action_hook
|
22
|
+
end
|
23
|
+
|
24
|
+
# Hooks directly into actions by defining the same method in an included
|
25
|
+
# module. As a result, when the action gets invoked, any state events
|
26
|
+
# defined for the object will get run. Method visibility is preserved.
|
27
|
+
def define_action_hook
|
28
|
+
action_hook = self.action_hook
|
29
|
+
action = self.action
|
30
|
+
private_action_hook = owner_class.private_method_defined?(action_hook)
|
31
|
+
|
32
|
+
# Only define helper if it hasn't
|
33
|
+
define_helper :instance, <<-END_EVAL, __FILE__, __LINE__ + 1
|
34
|
+
def #{action_hook}(*)
|
35
|
+
self.class.state_machines.transitions(self, #{action.inspect}).perform { super }
|
36
|
+
end
|
37
|
+
|
38
|
+
private #{action_hook.inspect} if #{private_action_hook}
|
39
|
+
END_EVAL
|
40
|
+
end
|
41
|
+
|
42
|
+
# The method to hook into for triggering transitions when invoked. By
|
43
|
+
# default, this is the action configured for the machine.
|
44
|
+
#
|
45
|
+
# Since the default hook technique relies on module inheritance, the
|
46
|
+
# action must be defined in an ancestor of the owner classs in order for
|
47
|
+
# it to be the action hook.
|
48
|
+
def action_hook
|
49
|
+
action && owner_class_ancestor_has_method?(:instance, action) ? action : nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file provides optional async extensions for the Machine class.
|
4
|
+
# It should only be loaded when async functionality is explicitly requested.
|
5
|
+
|
6
|
+
module StateMachines
|
7
|
+
class Machine
|
8
|
+
# AsyncMode extensions for the Machine class
|
9
|
+
# Provides async-aware methods while maintaining backward compatibility
|
10
|
+
module AsyncExtensions
|
11
|
+
# Instance methods added to Machine for async support
|
12
|
+
|
13
|
+
# Configure this specific machine instance for async mode
|
14
|
+
#
|
15
|
+
# Example:
|
16
|
+
# class Vehicle
|
17
|
+
# state_machine initial: :parked do
|
18
|
+
# configure_async_mode! # Enable async for this machine
|
19
|
+
#
|
20
|
+
# event :ignite do
|
21
|
+
# transition parked: :idling
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
def configure_async_mode!(enabled = true)
|
26
|
+
if enabled
|
27
|
+
begin
|
28
|
+
require 'state_machines/async_mode'
|
29
|
+
@async_mode_enabled = true
|
30
|
+
|
31
|
+
owner_class.include(StateMachines::AsyncMode::ThreadSafeState)
|
32
|
+
owner_class.include(StateMachines::AsyncMode::AsyncEvents)
|
33
|
+
self.extend(StateMachines::AsyncMode::AsyncMachine)
|
34
|
+
|
35
|
+
# Extend events to generate async versions
|
36
|
+
events.each do |event|
|
37
|
+
event.extend(StateMachines::AsyncMode::AsyncEventExtensions)
|
38
|
+
end
|
39
|
+
rescue LoadError => e
|
40
|
+
# Fallback to sync mode with warning (only once per class)
|
41
|
+
unless owner_class.instance_variable_get(:@async_fallback_warned)
|
42
|
+
warn <<~WARNING
|
43
|
+
⚠️ #{owner_class.name}: Async mode requested but not available on #{RUBY_ENGINE}.
|
44
|
+
|
45
|
+
#{e.message}
|
46
|
+
|
47
|
+
⚠️ Falling back to synchronous mode. Results may be unpredictable due to engine limitations.
|
48
|
+
For production async support, use MRI Ruby (CRuby) 3.2+
|
49
|
+
WARNING
|
50
|
+
owner_class.instance_variable_set(:@async_fallback_warned, true)
|
51
|
+
end
|
52
|
+
|
53
|
+
@async_mode_enabled = false
|
54
|
+
end
|
55
|
+
else
|
56
|
+
@async_mode_enabled = false
|
57
|
+
end
|
58
|
+
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Check if this specific machine instance has async mode enabled
|
63
|
+
def async_mode_enabled?
|
64
|
+
@async_mode_enabled || false
|
65
|
+
end
|
66
|
+
|
67
|
+
# Thread-safe version of state reading
|
68
|
+
def read_safely(object, attribute, ivar = false)
|
69
|
+
object.read_state_safely(self, attribute, ivar)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Thread-safe version of state writing
|
73
|
+
def write_safely(object, attribute, value, ivar = false)
|
74
|
+
object.write_state_safely(self, attribute, value, ivar)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Thread-safe callback execution for async operations
|
78
|
+
def run_callbacks_safely(type, object, context, transition)
|
79
|
+
object.state_machine_mutex.with_write_lock do
|
80
|
+
callbacks[type].each { |callback| callback.call(object, context, transition) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Include async extensions by default (but only load AsyncMode when requested)
|
86
|
+
include AsyncExtensions
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StateMachines
|
4
|
+
class Machine
|
5
|
+
module Callbacks
|
6
|
+
# Creates a callback that will be invoked *before* a transition is
|
7
|
+
# performed so long as the given requirements match the transition.
|
8
|
+
def before_transition(*args, **options, &)
|
9
|
+
# Extract legacy positional arguments and merge with keyword options
|
10
|
+
parsed_options = parse_callback_arguments(args, options)
|
11
|
+
|
12
|
+
# Only validate callback-specific options, not state transition requirements
|
13
|
+
callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
|
14
|
+
StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
|
15
|
+
|
16
|
+
add_callback(:before, parsed_options, &)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Creates a callback that will be invoked *after* a transition is
|
20
|
+
# performed so long as the given requirements match the transition.
|
21
|
+
def after_transition(*args, **options, &)
|
22
|
+
# Extract legacy positional arguments and merge with keyword options
|
23
|
+
parsed_options = parse_callback_arguments(args, options)
|
24
|
+
|
25
|
+
# Only validate callback-specific options, not state transition requirements
|
26
|
+
callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
|
27
|
+
StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
|
28
|
+
|
29
|
+
add_callback(:after, parsed_options, &)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates a callback that will be invoked *around* a transition so long
|
33
|
+
# as the given requirements match the transition.
|
34
|
+
def around_transition(*args, **options, &)
|
35
|
+
# Extract legacy positional arguments and merge with keyword options
|
36
|
+
parsed_options = parse_callback_arguments(args, options)
|
37
|
+
|
38
|
+
# Only validate callback-specific options, not state transition requirements
|
39
|
+
callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
|
40
|
+
StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
|
41
|
+
|
42
|
+
add_callback(:around, parsed_options, &)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a callback that will be invoked after a transition has failed
|
46
|
+
# to be performed.
|
47
|
+
def after_failure(*args, **options, &)
|
48
|
+
# Extract legacy positional arguments and merge with keyword options
|
49
|
+
parsed_options = parse_callback_arguments(args, options)
|
50
|
+
|
51
|
+
# Only validate callback-specific options, not state transition requirements
|
52
|
+
callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
|
53
|
+
StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
|
54
|
+
|
55
|
+
add_callback(:failure, parsed_options, &)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StateMachines
|
4
|
+
class Machine
|
5
|
+
module ClassMethods
|
6
|
+
# Attempts to find or create a state machine for the given class. For
|
7
|
+
# example,
|
8
|
+
#
|
9
|
+
# StateMachines::Machine.find_or_create(Vehicle)
|
10
|
+
# StateMachines::Machine.find_or_create(Vehicle, :initial => :parked)
|
11
|
+
# StateMachines::Machine.find_or_create(Vehicle, :status)
|
12
|
+
# StateMachines::Machine.find_or_create(Vehicle, :status, :initial => :parked)
|
13
|
+
#
|
14
|
+
# If a machine of the given name already exists in one of the class's
|
15
|
+
# superclasses, then a copy of that machine will be created and stored
|
16
|
+
# in the new owner class (the original will remain unchanged).
|
17
|
+
def find_or_create(owner_class, *args, &)
|
18
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
19
|
+
name = args.first || :state
|
20
|
+
|
21
|
+
# Find an existing machine
|
22
|
+
machine = (owner_class.respond_to?(:state_machines) &&
|
23
|
+
((args.first && owner_class.state_machines[name]) || (!args.first &&
|
24
|
+
owner_class.state_machines.values.first))) || nil
|
25
|
+
|
26
|
+
if machine
|
27
|
+
# Only create a new copy if changes are being made to the machine in
|
28
|
+
# a subclass
|
29
|
+
if machine.owner_class != owner_class && (options.any? || block_given?)
|
30
|
+
machine = machine.clone
|
31
|
+
machine.initial_state = options[:initial] if options.include?(:initial)
|
32
|
+
machine.owner_class = owner_class
|
33
|
+
# Configure async mode if requested in options
|
34
|
+
if options.include?(:async)
|
35
|
+
machine.configure_async_mode!(options[:async])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Evaluate DSL
|
40
|
+
machine.instance_eval(&) if block_given?
|
41
|
+
else
|
42
|
+
# No existing machine: create a new one
|
43
|
+
machine = new(owner_class, name, options, &)
|
44
|
+
end
|
45
|
+
|
46
|
+
machine
|
47
|
+
end
|
48
|
+
|
49
|
+
def draw(*)
|
50
|
+
raise NotImplementedError
|
51
|
+
end
|
52
|
+
|
53
|
+
# Default messages to use for validation errors in ORM integrations
|
54
|
+
# Thread-safe access via atomic operations on simple values
|
55
|
+
attr_accessor :ignore_method_conflicts
|
56
|
+
|
57
|
+
def default_messages
|
58
|
+
@default_messages ||= {
|
59
|
+
invalid: 'is invalid',
|
60
|
+
invalid_event: 'cannot transition when %s',
|
61
|
+
invalid_transition: 'cannot transition via "%1$s"'
|
62
|
+
}.freeze
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_messages=(messages)
|
66
|
+
# Atomic replacement with frozen object
|
67
|
+
@default_messages = deep_freeze_hash(messages)
|
68
|
+
end
|
69
|
+
|
70
|
+
def replace_messages(message_hash)
|
71
|
+
# Atomic replacement: read current messages, merge with new ones, replace atomically
|
72
|
+
current_messages = @default_messages || {}
|
73
|
+
merged_messages = current_messages.merge(message_hash)
|
74
|
+
@default_messages = deep_freeze_hash(merged_messages)
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_writer :renderer
|
78
|
+
|
79
|
+
def renderer
|
80
|
+
return @renderer if @renderer
|
81
|
+
|
82
|
+
STDIORenderer
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Deep freezes a hash and all its string values for thread safety
|
88
|
+
def deep_freeze_hash(hash)
|
89
|
+
hash.each_with_object({}) do |(key, value), frozen_hash|
|
90
|
+
frozen_key = key.respond_to?(:freeze) ? key.freeze : key
|
91
|
+
frozen_value = value.respond_to?(:freeze) ? value.freeze : value
|
92
|
+
frozen_hash[frozen_key] = frozen_value
|
93
|
+
end.freeze
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|