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