state_machines 0.5.0 → 0.10.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 +34 -15
- data/lib/state_machines/assertions.rb +2 -0
- data/lib/state_machines/branch.rb +85 -81
- data/lib/state_machines/callback.rb +24 -21
- data/lib/state_machines/core.rb +2 -0
- 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 +35 -30
- 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 +381 -425
- data/lib/state_machines/machine_collection.rb +13 -10
- 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 +17 -13
- data/lib/state_machines/path.rb +58 -55
- data/lib/state_machines/path_collection.rb +37 -35
- data/lib/state_machines/state.rb +50 -38
- data/lib/state_machines/state_collection.rb +22 -19
- data/lib/state_machines/state_context.rb +35 -35
- data/lib/state_machines/stdio_renderer.rb +74 -0
- data/lib/state_machines/transition.rb +182 -178
- data/lib/state_machines/transition_collection.rb +172 -168
- data/lib/state_machines/version.rb +3 -1
- data/lib/state_machines.rb +4 -1
- metadata +10 -439
- 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/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,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StateMachines
|
2
4
|
# A state defines a value that an attribute can be in after being transitioned
|
3
5
|
# 0 or more times. States can represent a value of any type in Ruby, though
|
@@ -8,7 +10,6 @@ module StateMachines
|
|
8
10
|
# StateMachines::Machine#state for more information about how state-driven
|
9
11
|
# behavior can be utilized.
|
10
12
|
class State
|
11
|
-
|
12
13
|
# The state machine for which this state is defined
|
13
14
|
attr_reader :machine
|
14
15
|
|
@@ -31,7 +32,7 @@ module StateMachines
|
|
31
32
|
|
32
33
|
# Whether or not this state is the initial state to use for new objects
|
33
34
|
attr_accessor :initial
|
34
|
-
|
35
|
+
alias initial? initial
|
35
36
|
|
36
37
|
# A custom lambda block for determining whether a given value matches this
|
37
38
|
# state
|
@@ -50,38 +51,42 @@ module StateMachines
|
|
50
51
|
# (e.g. :value => lambda {Time.now}, :if => lambda {|state| !state.nil?}).
|
51
52
|
# By default, the configured value is matched.
|
52
53
|
# * <tt>:human_name</tt> - The human-readable version of this state's name
|
53
|
-
def initialize(machine, name, options = {})
|
54
|
+
def initialize(machine, name, options = {}) # :nodoc:
|
54
55
|
options.assert_valid_keys(:initial, :value, :cache, :if, :human_name)
|
55
56
|
|
56
57
|
@machine = machine
|
57
58
|
@name = name
|
58
59
|
@qualified_name = name && machine.namespace ? :"#{machine.namespace}_#{name}" : name
|
59
60
|
@human_name = options[:human_name] || (@name ? @name.to_s.tr('_', ' ') : 'nil')
|
60
|
-
@value = options.include?(:value) ? options[:value] : name
|
61
|
+
@value = options.include?(:value) ? options[:value] : name&.to_s
|
61
62
|
@cache = options[:cache]
|
62
63
|
@matcher = options[:if]
|
63
64
|
@initial = options[:initial] == true
|
64
65
|
@context = StateContext.new(self)
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
67
|
+
return unless name
|
68
|
+
|
69
|
+
conflicting_machines = machine.owner_class.state_machines.select do |_other_name, other_machine|
|
70
|
+
other_machine != machine && other_machine.states[qualified_name, :qualified_name]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Output a warning if another machine has a conflicting qualified name
|
74
|
+
# for a different attribute
|
75
|
+
if (conflict = conflicting_machines.detect do |_other_name, other_machine|
|
76
|
+
other_machine.attribute != machine.attribute
|
77
|
+
end)
|
78
|
+
_name, other_machine = conflict
|
79
|
+
warn "State #{qualified_name.inspect} for #{machine.name.inspect} is already defined in #{other_machine.name.inspect}"
|
80
|
+
elsif conflicting_machines.empty?
|
81
|
+
# Only bother adding predicates when another machine for the same
|
82
|
+
# attribute hasn't already done so
|
83
|
+
add_predicate
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
82
87
|
# Creates a copy of this state, excluding the context to prevent conflicts
|
83
88
|
# across different machines.
|
84
|
-
def initialize_copy(orig)
|
89
|
+
def initialize_copy(orig) # :nodoc:
|
85
90
|
super
|
86
91
|
@context = StateContext.new(self)
|
87
92
|
end
|
@@ -96,10 +101,10 @@ module StateMachines
|
|
96
101
|
# Any objects in a final state will remain so forever given the current
|
97
102
|
# machine's definition.
|
98
103
|
def final?
|
99
|
-
|
104
|
+
machine.events.none? do |event|
|
100
105
|
event.branches.any? do |branch|
|
101
106
|
branch.state_requirements.any? do |requirement|
|
102
|
-
requirement[:from].matches?(name) && !requirement[:to].matches?(name, :
|
107
|
+
requirement[:from].matches?(name) && !requirement[:to].matches?(name, from: name)
|
103
108
|
end
|
104
109
|
end
|
105
110
|
end
|
@@ -126,7 +131,7 @@ module StateMachines
|
|
126
131
|
# description or just the internal name
|
127
132
|
def description(options = {})
|
128
133
|
label = options[:human_name] ? human_name : name
|
129
|
-
description = label ? label.to_s : label.inspect
|
134
|
+
description = +(label ? label.to_s : label.inspect)
|
130
135
|
description << " (#{@value.is_a?(Proc) ? '*' : @value.inspect})" unless name.to_s == @value.to_s
|
131
136
|
description
|
132
137
|
end
|
@@ -186,19 +191,19 @@ module StateMachines
|
|
186
191
|
# Evaluate the method definitions and track which ones were added
|
187
192
|
old_methods = context_methods
|
188
193
|
context.class_eval(&block)
|
189
|
-
new_methods = context_methods.to_a.
|
194
|
+
new_methods = context_methods.to_a.reject { |(name, method)| old_methods[name] == method }
|
190
195
|
|
191
196
|
# Alias new methods so that the only execute when the object is in this state
|
192
197
|
new_methods.each do |(method_name, _method)|
|
193
198
|
context_name = context_name_for(method_name)
|
194
|
-
context.class_eval <<-
|
199
|
+
context.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
195
200
|
alias_method :"#{context_name}", :#{method_name}
|
196
201
|
def #{method_name}(*args, &block)
|
197
202
|
state = self.class.state_machine(#{machine.name.inspect}).states.fetch(#{name.inspect})
|
198
203
|
options = {:method_missing => lambda {super(*args, &block)}, :method_name => #{method_name.inspect}}
|
199
204
|
state.call(self, :"#{context_name}", *(args + [options]), &block)
|
200
205
|
end
|
201
|
-
|
206
|
+
END_EVAL
|
202
207
|
end
|
203
208
|
|
204
209
|
true
|
@@ -218,29 +223,28 @@ module StateMachines
|
|
218
223
|
# will be raised.
|
219
224
|
def call(object, method, *args, &block)
|
220
225
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
221
|
-
options = {:
|
226
|
+
options = { method_name: method }.merge(options)
|
222
227
|
state = machine.states.match!(object)
|
223
228
|
|
224
229
|
if state == self && object.respond_to?(method)
|
225
230
|
object.send(method, *args, &block)
|
226
|
-
elsif method_missing = options[:method_missing]
|
231
|
+
elsif (method_missing = options[:method_missing])
|
227
232
|
# Dispatch to the superclass since the object either isn't in this state
|
228
233
|
# or this state doesn't handle the method
|
229
234
|
begin
|
230
235
|
method_missing.call
|
231
|
-
rescue NoMethodError =>
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
end
|
236
|
+
rescue NoMethodError => e
|
237
|
+
raise unless e.name.to_s == options[:method_name].to_s && e.args == args
|
238
|
+
|
239
|
+
# No valid context for this method
|
240
|
+
raise InvalidContext.new(object,
|
241
|
+
"State #{state.name.inspect} for #{machine.name.inspect} is not a valid context for calling ##{options[:method_name]}")
|
238
242
|
end
|
239
243
|
end
|
240
244
|
end
|
241
245
|
|
242
|
-
def draw(graph, options = {})
|
243
|
-
|
246
|
+
def draw(graph, options = {}, io = $stdout)
|
247
|
+
machine.renderer.draw_state(self, graph, options, io)
|
244
248
|
end
|
245
249
|
|
246
250
|
# Generates a nicely formatted description of this state's contents.
|
@@ -255,6 +259,7 @@ module StateMachines
|
|
255
259
|
end
|
256
260
|
|
257
261
|
private
|
262
|
+
|
258
263
|
# Should the value be cached after it's evaluated for the first time?
|
259
264
|
def cache_value?
|
260
265
|
@cache
|
@@ -263,9 +268,16 @@ module StateMachines
|
|
263
268
|
# Adds a predicate method to the owner class so long as a name has
|
264
269
|
# actually been configured for the state
|
265
270
|
def add_predicate
|
266
|
-
|
267
|
-
|
268
|
-
|
271
|
+
predicate_method = "#{qualified_name}?"
|
272
|
+
|
273
|
+
if machine.send(:owner_class_ancestor_has_method?, :instance, predicate_method)
|
274
|
+
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."
|
275
|
+
elsif machine.send(:owner_class_has_method?, :instance, predicate_method)
|
276
|
+
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."
|
277
|
+
else
|
278
|
+
machine.define_helper(:instance, predicate_method) do |machine, object|
|
279
|
+
machine.states.matches?(object, name)
|
280
|
+
end
|
269
281
|
end
|
270
282
|
end
|
271
283
|
|
@@ -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,100 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module StateMachines
|
4
4
|
# Represents a module which will get evaluated within the context of a state.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# Class-level methods are proxied to the owner class, injecting a custom
|
7
7
|
# <tt>:if</tt> condition along with method. This assumes that the method has
|
8
8
|
# support for a set of configuration options, including <tt>:if</tt>. This
|
9
9
|
# condition will check that the object's state matches this context's state.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# Instance-level methods are used to define state-driven behavior on the
|
12
12
|
# state's owner class.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# == Examples
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# class Vehicle
|
17
17
|
# class << self
|
18
18
|
# attr_accessor :validations
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# def validate(options, &block)
|
21
21
|
# validations << options
|
22
22
|
# end
|
23
23
|
# end
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# self.validations = []
|
26
26
|
# attr_accessor :state, :simulate
|
27
|
-
#
|
27
|
+
#
|
28
28
|
# def moving?
|
29
29
|
# self.class.validations.all? {|validation| validation[:if].call(self)}
|
30
30
|
# end
|
31
31
|
# end
|
32
|
-
#
|
32
|
+
#
|
33
33
|
# In the above class, a simple set of validation behaviors have been defined.
|
34
34
|
# Each validation consists of a configuration like so:
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# Vehicle.validate :unless => :simulate
|
37
37
|
# Vehicle.validate :if => lambda {|vehicle| ...}
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# In order to scope validations to a particular state context, the class-level
|
40
40
|
# +validate+ method can be invoked like so:
|
41
|
-
#
|
41
|
+
#
|
42
42
|
# machine = StateMachines::Machine.new(Vehicle)
|
43
43
|
# context = StateMachines::StateContext.new(machine.state(:first_gear))
|
44
44
|
# context.validate(:unless => :simulate)
|
45
|
-
#
|
45
|
+
#
|
46
46
|
# vehicle = Vehicle.new # => #<Vehicle:0xb7ce491c @simulate=nil, @state=nil>
|
47
47
|
# vehicle.moving? # => false
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# vehicle.state = 'first_gear'
|
50
50
|
# vehicle.moving? # => true
|
51
|
-
#
|
51
|
+
#
|
52
52
|
# vehicle.simulate = true
|
53
53
|
# vehicle.moving? # => false
|
54
54
|
class StateContext < Module
|
55
55
|
|
56
56
|
include EvalHelpers
|
57
|
-
|
57
|
+
|
58
58
|
# The state machine for which this context's state is defined
|
59
59
|
attr_reader :machine
|
60
|
-
|
60
|
+
|
61
61
|
# The state that must be present in an object for this context to be active
|
62
62
|
attr_reader :state
|
63
|
-
|
63
|
+
|
64
64
|
# Creates a new context for the given state
|
65
65
|
def initialize(state)
|
66
66
|
@state = state
|
67
67
|
@machine = state.machine
|
68
|
-
|
68
|
+
|
69
69
|
state_name = state.name
|
70
70
|
machine_name = machine.name
|
71
|
-
@condition = lambda {|object| object.class.state_machine(machine_name).states.matches?(object, state_name)}
|
71
|
+
@condition = lambda { |object| object.class.state_machine(machine_name).states.matches?(object, state_name) }
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
# Creates a new transition that determines what to change the current state
|
75
75
|
# to when an event fires from this state.
|
76
|
-
#
|
76
|
+
#
|
77
77
|
# Since this transition is being defined within a state context, you do
|
78
78
|
# *not* need to specify the <tt>:from</tt> option for the transition. For
|
79
79
|
# example:
|
80
|
-
#
|
80
|
+
#
|
81
81
|
# state_machine do
|
82
82
|
# state :parked do
|
83
83
|
# transition :to => :idling, :on => [:ignite, :shift_up] # Transitions to :idling
|
84
84
|
# transition :from => [:idling, :parked], :on => :park, :unless => :seatbelt_on? # Transitions to :parked if seatbelt is off
|
85
85
|
# end
|
86
86
|
# end
|
87
|
-
#
|
87
|
+
#
|
88
88
|
# See StateMachines::Machine#transition for a description of the possible
|
89
89
|
# configurations for defining transitions.
|
90
90
|
def transition(options)
|
91
91
|
options.assert_valid_keys(:from, :to, :on, :if, :unless)
|
92
92
|
raise ArgumentError, 'Must specify :on event' unless options[:on]
|
93
93
|
raise ArgumentError, 'Must specify either :to or :from state' unless !options[:to] ^ !options[:from]
|
94
|
-
|
95
|
-
machine.transition(options.merge(options[:to] ? {:
|
94
|
+
|
95
|
+
machine.transition(options.merge(options[:to] ? {from: state.name} : {to: state.name}))
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
# Hooks in condition-merging to methods that don't exist in this module
|
99
99
|
def method_missing(*args, &block)
|
100
100
|
# Get the configuration
|
@@ -103,28 +103,28 @@ module StateMachines
|
|
103
103
|
else
|
104
104
|
args << options = {}
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# Get any existing condition that may need to be merged
|
108
108
|
if_condition = options.delete(:if)
|
109
109
|
unless_condition = options.delete(:unless)
|
110
|
-
|
110
|
+
|
111
111
|
# Provide scope access to configuration in case the block is evaluated
|
112
112
|
# within the object instance
|
113
113
|
proxy = self
|
114
114
|
proxy_condition = @condition
|
115
|
-
|
115
|
+
|
116
116
|
# Replace the configuration condition with the one configured for this
|
117
117
|
# proxy, merging together any existing conditions
|
118
118
|
options[:if] = lambda do |*condition_args|
|
119
119
|
# Block may be executed within the context of the actual object, so
|
120
120
|
# it'll either be the first argument or the executing context
|
121
121
|
object = condition_args.first || self
|
122
|
-
|
122
|
+
|
123
123
|
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)}
|
124
|
+
Array(if_condition).all? { |condition| proxy.evaluate_method(object, condition) } &&
|
125
|
+
!Array(unless_condition).any? { |condition| proxy.evaluate_method(object, condition) }
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
# Evaluate the method on the owner class with the condition proxied
|
129
129
|
# through
|
130
130
|
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
|