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