roby 0.8.0 → 3.0.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 +7 -0
- data/.deep-cover.rb +3 -0
- data/.gitattributes +1 -0
- data/.gitignore +24 -0
- data/.simplecov +10 -0
- data/.travis.yml +17 -0
- data/.yardopts +4 -0
- data/Gemfile +15 -0
- data/README.md +11 -0
- data/Rakefile +47 -177
- data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
- data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
- data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
- data/benchmark/{genom.rb → attic/genom.rb} +0 -0
- data/benchmark/attic/transactions.rb +62 -0
- data/benchmark/plan_basic_operations.rb +28 -0
- data/benchmark/relations/graph.rb +63 -0
- data/benchmark/ruby/identity.rb +18 -0
- data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
- data/benchmark/ruby/yield_vs_block.rb +35 -0
- data/benchmark/run +5 -0
- data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
- data/benchmark/transactions.rb +99 -51
- data/bin/roby +38 -197
- data/bin/roby-display +14 -0
- data/bin/roby-log +3 -176
- data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
- data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
- data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
- data/doc/guide/{src → attic}/abstraction/index.page +1 -1
- data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
- data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
- data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
- data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
- data/doc/guide/attic/cycle/error_handling.page +98 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
- data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
- data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
- data/doc/guide/{src → attic}/cycle/index.page +1 -1
- data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
- data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
- data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
- data/doc/guide/attic/plans/building_plans.page +89 -0
- data/doc/guide/attic/plans/code.page +192 -0
- data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
- data/doc/guide/attic/plans/index.page +7 -0
- data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
- data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
- data/doc/guide/attic/plans/querying_plans.page +5 -0
- data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
- data/doc/guide/config.yaml +7 -4
- data/doc/guide/ext/extended_menu.rb +29 -0
- data/doc/guide/ext/init.rb +6 -0
- data/doc/guide/ext/rdoc_links.rb +7 -6
- data/doc/guide/src/advanced_concepts/history.page +5 -0
- data/doc/guide/src/advanced_concepts/index.page +11 -0
- data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
- data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
- data/doc/guide/src/advanced_concepts/transactions.page +5 -0
- data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
- data/doc/guide/src/base.template +96 -0
- data/doc/guide/src/basics_shell_header.txt +5 -7
- data/doc/guide/src/building/action_coordination.page +96 -0
- data/doc/guide/src/building/actions.page +124 -0
- data/doc/guide/src/building/file_layout.page +71 -0
- data/doc/guide/src/building/index.page +50 -0
- data/doc/guide/src/building/patterns.page +86 -0
- data/doc/guide/src/building/patterns_forwarding.png +0 -0
- data/doc/guide/src/building/patterns_forwarding.svg +277 -0
- data/doc/guide/src/building/runtime.page +95 -0
- data/doc/guide/src/building/task_models.page +94 -0
- data/doc/guide/src/building/tasks.page +284 -0
- data/doc/guide/src/concepts/error_handling.page +100 -0
- data/doc/guide/src/concepts/exception_propagation.png +0 -0
- data/doc/guide/src/concepts/exception_propagation.svg +445 -0
- data/doc/guide/src/concepts/execution.page +85 -0
- data/doc/guide/src/concepts/execution.png +0 -0
- data/doc/guide/src/concepts/execution.svg +573 -0
- data/doc/guide/src/concepts/execution_cycle.png +0 -0
- data/doc/guide/src/concepts/garbage_collection.page +57 -0
- data/doc/guide/src/concepts/index.page +27 -0
- data/doc/guide/src/concepts/plans.page +101 -0
- data/doc/guide/src/concepts/policy.page +31 -0
- data/doc/guide/src/concepts/reactor.page +61 -0
- data/doc/guide/src/concepts/simple_plan_example.png +0 -0
- data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
- data/doc/guide/src/default.template +9 -74
- data/doc/guide/src/event_relations/forward.page +71 -0
- data/doc/guide/src/event_relations/index.page +12 -0
- data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
- data/doc/guide/src/event_relations/signal.page +55 -0
- data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
- data/doc/guide/src/htmldoc.metainfo +21 -8
- data/doc/guide/src/index.page +8 -3
- data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
- data/doc/guide/src/installation/publications.page +14 -0
- data/doc/guide/src/{introduction → installation}/videos.page +14 -7
- data/doc/guide/src/interacting/index.page +16 -0
- data/doc/guide/src/interacting/run.page +33 -0
- data/doc/guide/src/interacting/shell.page +95 -0
- data/doc/guide/src/plugins/creating_plugins.page +72 -0
- data/doc/guide/src/plugins/index.page +27 -5
- data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
- data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
- data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
- data/doc/guide/src/style_screen.css +687 -0
- data/doc/guide/src/task_relations/dependency.page +107 -0
- data/doc/guide/src/task_relations/executed_by.page +77 -0
- data/doc/guide/src/task_relations/index.page +12 -0
- data/doc/guide/src/task_relations/new_relations.page +119 -0
- data/doc/guide/src/task_relations/planned_by.page +46 -0
- data/doc/guide/src/tutorial/app.page +117 -0
- data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
- data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
- data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
- data/doc/guide/src/tutorial/events.page +195 -0
- data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
- data/doc/guide/src/tutorial/index.page +13 -0
- data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/tutorial/relations_display.page +153 -0
- data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
- data/doc/guide/src/tutorial/shell.page +121 -0
- data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
- data/doc/guide/src/tutorial/tasks.page +374 -0
- data/lib/roby.rb +102 -47
- data/lib/roby/actions.rb +17 -0
- data/lib/roby/actions/action.rb +80 -0
- data/lib/roby/actions/interface.rb +45 -0
- data/lib/roby/actions/library.rb +23 -0
- data/lib/roby/actions/models/action.rb +224 -0
- data/lib/roby/actions/models/coordination_action.rb +58 -0
- data/lib/roby/actions/models/interface.rb +22 -0
- data/lib/roby/actions/models/interface_base.rb +294 -0
- data/lib/roby/actions/models/library.rb +12 -0
- data/lib/roby/actions/models/method_action.rb +90 -0
- data/lib/roby/actions/task.rb +114 -0
- data/lib/roby/and_generator.rb +125 -0
- data/lib/roby/app.rb +2795 -829
- data/lib/roby/app/autotest_console_reporter.rb +138 -0
- data/lib/roby/app/base.rb +21 -0
- data/lib/roby/app/cucumber.rb +2 -0
- data/lib/roby/app/cucumber/controller.rb +439 -0
- data/lib/roby/app/cucumber/helpers.rb +280 -0
- data/lib/roby/app/cucumber/world.rb +32 -0
- data/lib/roby/app/debug.rb +136 -0
- data/lib/roby/app/gen.rb +2 -0
- data/lib/roby/app/rake.rb +178 -38
- data/lib/roby/app/robot_config.rb +9 -0
- data/lib/roby/app/robot_names.rb +115 -0
- data/lib/roby/app/run.rb +3 -2
- data/lib/roby/app/scripts.rb +72 -0
- data/lib/roby/app/scripts/autotest.rb +173 -0
- data/lib/roby/app/scripts/display.rb +2 -0
- data/lib/roby/app/scripts/restart.rb +52 -0
- data/lib/roby/app/scripts/results.rb +17 -8
- data/lib/roby/app/scripts/run.rb +155 -24
- data/lib/roby/app/scripts/shell.rb +147 -62
- data/lib/roby/app/scripts/test.rb +107 -22
- data/lib/roby/app/test_reporter.rb +74 -0
- data/lib/roby/app/test_server.rb +159 -0
- data/lib/roby/app/vagrant.rb +47 -0
- data/lib/roby/backports.rb +16 -0
- data/lib/roby/cli/display.rb +190 -0
- data/lib/roby/cli/exceptions.rb +17 -0
- data/lib/roby/cli/gen/actions/class.rb +5 -0
- data/lib/roby/cli/gen/actions/test.rb +6 -0
- data/lib/roby/cli/gen/app/.yardopts +6 -0
- data/lib/roby/cli/gen/app/README.md +28 -0
- data/lib/roby/cli/gen/app/Rakefile +15 -0
- data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
- data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
- data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
- data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
- data/lib/roby/cli/gen/class/class.rb +6 -0
- data/lib/roby/cli/gen/class/test.rb +7 -0
- data/lib/roby/cli/gen/helpers.rb +203 -0
- data/lib/roby/cli/gen/module/module.rb +5 -0
- data/lib/roby/cli/gen/module/test.rb +6 -0
- data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
- data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
- data/lib/roby/cli/gen/task/class.rb +44 -0
- data/lib/roby/cli/gen/task/test.rb +6 -0
- data/lib/roby/cli/gen_main.rb +120 -0
- data/lib/roby/cli/log.rb +276 -0
- data/lib/roby/cli/log/flamegraph.html +499 -0
- data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
- data/lib/roby/cli/main.rb +153 -0
- data/lib/roby/coordination.rb +60 -0
- data/lib/roby/coordination/action_script.rb +25 -0
- data/lib/roby/coordination/action_state_machine.rb +125 -0
- data/lib/roby/coordination/actions.rb +106 -0
- data/lib/roby/coordination/base.rb +145 -0
- data/lib/roby/coordination/calculus.rb +40 -0
- data/lib/roby/coordination/child.rb +28 -0
- data/lib/roby/coordination/event.rb +29 -0
- data/lib/roby/coordination/fault_handler.rb +25 -0
- data/lib/roby/coordination/fault_handling_task.rb +13 -0
- data/lib/roby/coordination/fault_response_table.rb +110 -0
- data/lib/roby/coordination/models/action_script.rb +64 -0
- data/lib/roby/coordination/models/action_state_machine.rb +224 -0
- data/lib/roby/coordination/models/actions.rb +191 -0
- data/lib/roby/coordination/models/arguments.rb +55 -0
- data/lib/roby/coordination/models/base.rb +176 -0
- data/lib/roby/coordination/models/capture.rb +86 -0
- data/lib/roby/coordination/models/child.rb +35 -0
- data/lib/roby/coordination/models/event.rb +41 -0
- data/lib/roby/coordination/models/exceptions.rb +42 -0
- data/lib/roby/coordination/models/fault_handler.rb +219 -0
- data/lib/roby/coordination/models/fault_response_table.rb +77 -0
- data/lib/roby/coordination/models/root.rb +22 -0
- data/lib/roby/coordination/models/script.rb +283 -0
- data/lib/roby/coordination/models/task.rb +184 -0
- data/lib/roby/coordination/models/task_from_action.rb +50 -0
- data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
- data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
- data/lib/roby/coordination/models/task_from_variable.rb +27 -0
- data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
- data/lib/roby/coordination/models/variable.rb +32 -0
- data/lib/roby/coordination/script.rb +200 -0
- data/lib/roby/coordination/script_instruction.rb +12 -0
- data/lib/roby/coordination/task.rb +45 -0
- data/lib/roby/coordination/task_base.rb +69 -0
- data/lib/roby/coordination/task_script.rb +293 -0
- data/lib/roby/coordination/task_state_machine.rb +308 -0
- data/lib/roby/decision_control.rb +33 -21
- data/lib/roby/distributed_object.rb +76 -0
- data/lib/roby/droby.rb +17 -0
- data/lib/roby/droby/droby_id.rb +6 -0
- data/lib/roby/droby/enable.rb +153 -0
- data/lib/roby/droby/event_logger.rb +189 -0
- data/lib/roby/droby/event_logging.rb +57 -0
- data/lib/roby/droby/exceptions.rb +14 -0
- data/lib/roby/droby/identifiable.rb +22 -0
- data/lib/roby/droby/logfile.rb +141 -0
- data/lib/roby/droby/logfile/client.rb +176 -0
- data/lib/roby/droby/logfile/file_format.md +97 -0
- data/lib/roby/droby/logfile/index.rb +117 -0
- data/lib/roby/droby/logfile/reader.rb +139 -0
- data/lib/roby/droby/logfile/server.rb +199 -0
- data/lib/roby/droby/logfile/writer.rb +114 -0
- data/lib/roby/droby/marshal.rb +264 -0
- data/lib/roby/droby/marshallable.rb +12 -0
- data/lib/roby/droby/null_event_logger.rb +25 -0
- data/lib/roby/droby/object_manager.rb +205 -0
- data/lib/roby/droby/peer_id.rb +6 -0
- data/lib/roby/droby/plan_rebuilder.rb +373 -0
- data/lib/roby/droby/rebuilt_plan.rb +160 -0
- data/lib/roby/droby/remote_droby_id.rb +6 -0
- data/lib/roby/droby/timepoints.rb +205 -0
- data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
- data/lib/roby/droby/timepoints_ctf.rb +125 -0
- data/lib/roby/droby/v5.rb +14 -0
- data/lib/roby/droby/v5/builtin.rb +120 -0
- data/lib/roby/droby/v5/droby_class.rb +45 -0
- data/lib/roby/droby/v5/droby_constant.rb +81 -0
- data/lib/roby/droby/v5/droby_dump.rb +1026 -0
- data/lib/roby/droby/v5/droby_id.rb +44 -0
- data/lib/roby/droby/v5/droby_model.rb +82 -0
- data/lib/roby/droby/v5/peer_id.rb +10 -0
- data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
- data/lib/roby/event.rb +79 -957
- data/lib/roby/event_constraints.rb +835 -0
- data/lib/roby/event_generator.rb +1047 -0
- data/lib/roby/event_structure/causal_link.rb +6 -0
- data/lib/roby/event_structure/forwarding.rb +6 -0
- data/lib/roby/event_structure/precedence.rb +7 -0
- data/lib/roby/event_structure/signal.rb +8 -0
- data/lib/roby/event_structure/temporal_constraints.rb +640 -0
- data/lib/roby/exceptions.rb +446 -152
- data/lib/roby/executable_plan.rb +549 -0
- data/lib/roby/execution_engine.rb +1997 -950
- data/lib/roby/filter_generator.rb +26 -0
- data/lib/roby/gui/chronicle_view.rb +225 -0
- data/lib/roby/gui/chronicle_widget.rb +925 -0
- data/lib/roby/gui/dot_id.rb +11 -0
- data/lib/roby/gui/exception_view.rb +44 -0
- data/lib/roby/gui/log_display.rb +273 -0
- data/lib/roby/gui/model_views.rb +2 -0
- data/lib/roby/gui/model_views/action_interface.rb +53 -0
- data/lib/roby/gui/model_views/task.rb +47 -0
- data/lib/roby/gui/model_views/task.rhtml +41 -0
- data/lib/roby/gui/object_info_view.rb +89 -0
- data/lib/roby/gui/plan_dot_layout.rb +427 -0
- data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
- data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
- data/lib/roby/gui/relations_view.rb +278 -0
- data/lib/roby/gui/relations_view/relations.ui +139 -0
- data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
- data/lib/roby/gui/relations_view/relations_config.rb +292 -0
- data/lib/roby/gui/relations_view/relations_view.ui +53 -0
- data/lib/roby/gui/scheduler_view.css +24 -0
- data/lib/roby/gui/scheduler_view.rb +46 -0
- data/lib/roby/gui/scheduler_view.rhtml +53 -0
- data/lib/roby/gui/stepping.rb +93 -0
- data/lib/roby/gui/stepping.ui +181 -0
- data/lib/roby/gui/styles.rb +81 -0
- data/lib/roby/gui/task_display_configuration.rb +42 -0
- data/lib/roby/gui/task_state_at.rb +38 -0
- data/lib/roby/hooks.rb +26 -0
- data/lib/roby/interface.rb +136 -469
- data/lib/roby/interface/async.rb +20 -0
- data/lib/roby/interface/async/action_monitor.rb +188 -0
- data/lib/roby/interface/async/interface.rb +498 -0
- data/lib/roby/interface/async/job_monitor.rb +213 -0
- data/lib/roby/interface/async/log.rb +238 -0
- data/lib/roby/interface/async/new_job_listener.rb +79 -0
- data/lib/roby/interface/async/ui_connector.rb +183 -0
- data/lib/roby/interface/client.rb +553 -0
- data/lib/roby/interface/command.rb +24 -0
- data/lib/roby/interface/command_argument.rb +16 -0
- data/lib/roby/interface/command_library.rb +92 -0
- data/lib/roby/interface/droby_channel.rb +174 -0
- data/lib/roby/interface/exceptions.rb +22 -0
- data/lib/roby/interface/interface.rb +655 -0
- data/lib/roby/interface/job.rb +47 -0
- data/lib/roby/interface/rest.rb +10 -0
- data/lib/roby/interface/rest/api.rb +29 -0
- data/lib/roby/interface/rest/helpers.rb +24 -0
- data/lib/roby/interface/rest/server.rb +212 -0
- data/lib/roby/interface/server.rb +154 -0
- data/lib/roby/interface/shell_client.rb +468 -0
- data/lib/roby/interface/shell_subcommand.rb +24 -0
- data/lib/roby/interface/subcommand_client.rb +35 -0
- data/lib/roby/interface/tcp.rb +168 -0
- data/lib/roby/models/arguments.rb +112 -0
- data/lib/roby/models/plan_object.rb +83 -0
- data/lib/roby/models/task.rb +835 -0
- data/lib/roby/models/task_event.rb +62 -0
- data/lib/roby/models/task_service.rb +78 -0
- data/lib/roby/or_generator.rb +88 -0
- data/lib/roby/plan.rb +1751 -864
- data/lib/roby/plan_object.rb +611 -0
- data/lib/roby/plan_service.rb +200 -0
- data/lib/roby/promise.rb +332 -0
- data/lib/roby/queries.rb +23 -0
- data/lib/roby/queries/and_matcher.rb +32 -0
- data/lib/roby/queries/any.rb +27 -0
- data/lib/roby/queries/code_error_matcher.rb +58 -0
- data/lib/roby/queries/event_generator_matcher.rb +9 -0
- data/lib/roby/queries/execution_exception_matcher.rb +165 -0
- data/lib/roby/queries/index.rb +165 -0
- data/lib/roby/queries/localized_error_matcher.rb +149 -0
- data/lib/roby/queries/matcher_base.rb +107 -0
- data/lib/roby/queries/none.rb +27 -0
- data/lib/roby/queries/not_matcher.rb +30 -0
- data/lib/roby/queries/op_matcher.rb +8 -0
- data/lib/roby/queries/or_matcher.rb +30 -0
- data/lib/roby/queries/plan_object_matcher.rb +363 -0
- data/lib/roby/queries/query.rb +188 -0
- data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
- data/lib/roby/queries/task_matcher.rb +344 -0
- data/lib/roby/relations.rb +42 -678
- data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
- data/lib/roby/relations/directed_relation_support.rb +268 -0
- data/lib/roby/relations/event_relation_graph.rb +19 -0
- data/lib/roby/relations/fork_merge_visitor.rb +154 -0
- data/lib/roby/relations/graph.rb +533 -0
- data/lib/roby/relations/models/directed_relation_support.rb +11 -0
- data/lib/roby/relations/models/graph.rb +75 -0
- data/lib/roby/relations/models/task_relation_graph.rb +18 -0
- data/lib/roby/relations/space.rb +380 -0
- data/lib/roby/relations/task_relation_graph.rb +20 -0
- data/lib/roby/robot.rb +85 -38
- data/lib/roby/schedulers/basic.rb +155 -25
- data/lib/roby/schedulers/null.rb +20 -0
- data/lib/roby/schedulers/reporting.rb +31 -0
- data/lib/roby/schedulers/state.rb +129 -0
- data/lib/roby/schedulers/temporal.rb +91 -0
- data/lib/roby/singletons.rb +87 -0
- data/lib/roby/standalone.rb +4 -2
- data/lib/roby/standard_errors.rb +405 -82
- data/lib/roby/state.rb +6 -3
- data/lib/roby/state/conf_model.rb +5 -0
- data/lib/roby/state/events.rb +181 -95
- data/lib/roby/state/goal_model.rb +77 -0
- data/lib/roby/state/open_struct.rb +591 -0
- data/lib/roby/state/open_struct_model.rb +68 -0
- data/lib/roby/state/pos.rb +45 -45
- data/lib/roby/state/shapes.rb +11 -11
- data/lib/roby/state/state_model.rb +303 -0
- data/lib/roby/state/task.rb +43 -0
- data/lib/roby/support.rb +88 -148
- data/lib/roby/task.rb +1361 -1750
- data/lib/roby/task_arguments.rb +428 -0
- data/lib/roby/task_event.rb +127 -0
- data/lib/roby/task_event_generator.rb +337 -0
- data/lib/roby/task_service.rb +6 -0
- data/lib/roby/task_structure/conflicts.rb +104 -0
- data/lib/roby/task_structure/dependency.rb +932 -0
- data/lib/roby/task_structure/error_handling.rb +118 -0
- data/lib/roby/task_structure/executed_by.rb +234 -0
- data/lib/roby/task_structure/planned_by.rb +90 -0
- data/lib/roby/tasks/aggregator.rb +37 -0
- data/lib/roby/tasks/external_process.rb +275 -0
- data/lib/roby/tasks/group.rb +27 -0
- data/lib/roby/tasks/null.rb +19 -0
- data/lib/roby/tasks/parallel.rb +43 -0
- data/lib/roby/tasks/sequence.rb +88 -0
- data/lib/roby/tasks/simple.rb +21 -0
- data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
- data/lib/roby/tasks/timeout.rb +17 -0
- data/lib/roby/tasks/virtual.rb +55 -0
- data/lib/roby/template_plan.rb +7 -0
- data/lib/roby/test/aruba_minitest.rb +74 -0
- data/lib/roby/test/assertion.rb +16 -0
- data/lib/roby/test/assertions.rb +490 -0
- data/lib/roby/test/common.rb +368 -591
- data/lib/roby/test/dsl.rb +149 -0
- data/lib/roby/test/error.rb +18 -0
- data/lib/roby/test/event_reporter.rb +83 -0
- data/lib/roby/test/execution_expectations.rb +1134 -0
- data/lib/roby/test/expect_execution.rb +151 -0
- data/lib/roby/test/minitest_helpers.rb +166 -0
- data/lib/roby/test/roby_app_helpers.rb +200 -0
- data/lib/roby/test/run_planners.rb +155 -0
- data/lib/roby/test/self.rb +112 -0
- data/lib/roby/test/spec.rb +198 -0
- data/lib/roby/test/tasks/empty_task.rb +4 -4
- data/lib/roby/test/tasks/goto.rb +28 -27
- data/lib/roby/test/teardown_plans.rb +100 -0
- data/lib/roby/test/testcase.rb +239 -307
- data/lib/roby/test/tools.rb +159 -155
- data/lib/roby/test/validate_state_machine.rb +75 -0
- data/lib/roby/transaction.rb +1125 -0
- data/lib/roby/transaction/event_generator_proxy.rb +63 -0
- data/lib/roby/transaction/plan_object_proxy.rb +99 -0
- data/lib/roby/transaction/plan_service_proxy.rb +43 -0
- data/lib/roby/transaction/proxying.rb +120 -0
- data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
- data/lib/roby/transaction/task_proxy.rb +135 -0
- data/lib/roby/until_generator.rb +30 -0
- data/lib/roby/version.rb +5 -0
- data/lib/roby/yard.rb +169 -0
- data/lib/yard-roby.rb +1 -0
- data/manifest.xml +32 -6
- data/roby.gemspec +59 -0
- metadata +788 -587
- data/Manifest.txt +0 -321
- data/NOTES +0 -4
- data/README.txt +0 -166
- data/TODO.txt +0 -146
- data/app/README.txt +0 -24
- data/app/Rakefile +0 -8
- data/app/config/ROBOT.rb +0 -5
- data/app/config/init.rb +0 -33
- data/app/config/roby.yml +0 -3
- data/app/controllers/ROBOT.rb +0 -2
- data/app/planners/ROBOT/main.rb +0 -6
- data/app/planners/main.rb +0 -5
- data/app/scripts/distributed +0 -3
- data/app/scripts/generate/bookmarks +0 -3
- data/app/scripts/replay +0 -3
- data/app/scripts/results +0 -3
- data/app/scripts/run +0 -3
- data/app/scripts/server +0 -3
- data/app/scripts/shell +0 -3
- data/app/scripts/test +0 -3
- data/app/tasks/.gitattributes +0 -0
- data/app/tasks/ROBOT/.gitattributes +0 -0
- data/bin/roby-shell +0 -25
- data/doc/guide/src/basics/app.page +0 -139
- data/doc/guide/src/basics/index.page +0 -11
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/relations_display.page +0 -203
- data/doc/guide/src/basics/shell.page +0 -102
- data/doc/guide/src/default.css +0 -319
- data/doc/guide/src/introduction/index.page +0 -29
- data/doc/guide/src/introduction/publications.page +0 -14
- data/doc/guide/src/relations/dependency.page +0 -89
- data/doc/guide/src/relations/index.page +0 -12
- data/ext/droby/dump.cc +0 -175
- data/ext/droby/extconf.rb +0 -3
- data/ext/graph/algorithm.cc +0 -746
- data/ext/graph/extconf.rb +0 -7
- data/ext/graph/graph.cc +0 -575
- data/ext/graph/graph.hh +0 -183
- data/ext/graph/iterator_sequence.hh +0 -102
- data/ext/graph/undirected_dfs.hh +0 -226
- data/ext/graph/undirected_graph.hh +0 -421
- data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
- data/lib/roby/app/scripts/replay.rb +0 -31
- data/lib/roby/app/scripts/server.rb +0 -18
- data/lib/roby/basic_object.rb +0 -151
- data/lib/roby/config.rb +0 -14
- data/lib/roby/distributed.rb +0 -36
- data/lib/roby/distributed/base.rb +0 -448
- data/lib/roby/distributed/communication.rb +0 -875
- data/lib/roby/distributed/connection_space.rb +0 -616
- data/lib/roby/distributed/distributed_object.rb +0 -206
- data/lib/roby/distributed/drb.rb +0 -62
- data/lib/roby/distributed/notifications.rb +0 -531
- data/lib/roby/distributed/peer.rb +0 -555
- data/lib/roby/distributed/protocol.rb +0 -529
- data/lib/roby/distributed/proxy.rb +0 -343
- data/lib/roby/distributed/subscription.rb +0 -311
- data/lib/roby/distributed/transaction.rb +0 -498
- data/lib/roby/external_process_task.rb +0 -225
- data/lib/roby/graph.rb +0 -160
- data/lib/roby/log.rb +0 -3
- data/lib/roby/log/chronicle.rb +0 -303
- data/lib/roby/log/console.rb +0 -74
- data/lib/roby/log/data_stream.rb +0 -275
- data/lib/roby/log/dot.rb +0 -279
- data/lib/roby/log/event_stream.rb +0 -161
- data/lib/roby/log/file.rb +0 -396
- data/lib/roby/log/gui/basic_display.ui +0 -83
- data/lib/roby/log/gui/basic_display_ui.rb +0 -89
- data/lib/roby/log/gui/chronicle.rb +0 -26
- data/lib/roby/log/gui/chronicle_view.rb +0 -40
- data/lib/roby/log/gui/chronicle_view.ui +0 -70
- data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
- data/lib/roby/log/gui/data_displays.rb +0 -171
- data/lib/roby/log/gui/data_displays.ui +0 -155
- data/lib/roby/log/gui/data_displays_ui.rb +0 -146
- data/lib/roby/log/gui/notifications.rb +0 -26
- data/lib/roby/log/gui/relations.rb +0 -269
- data/lib/roby/log/gui/relations.ui +0 -123
- data/lib/roby/log/gui/relations_ui.rb +0 -120
- data/lib/roby/log/gui/relations_view.rb +0 -185
- data/lib/roby/log/gui/relations_view.ui +0 -149
- data/lib/roby/log/gui/relations_view_ui.rb +0 -144
- data/lib/roby/log/gui/replay.rb +0 -366
- data/lib/roby/log/gui/replay_controls.rb +0 -206
- data/lib/roby/log/gui/replay_controls.ui +0 -282
- data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
- data/lib/roby/log/gui/runtime.rb +0 -130
- data/lib/roby/log/hooks.rb +0 -186
- data/lib/roby/log/logger.rb +0 -203
- data/lib/roby/log/notifications.rb +0 -244
- data/lib/roby/log/plan_rebuilder.rb +0 -468
- data/lib/roby/log/relations.rb +0 -1084
- data/lib/roby/log/server.rb +0 -547
- data/lib/roby/log/sqlite.rb +0 -47
- data/lib/roby/log/timings.rb +0 -233
- data/lib/roby/plan-object.rb +0 -371
- data/lib/roby/planning.rb +0 -13
- data/lib/roby/planning/loops.rb +0 -309
- data/lib/roby/planning/model.rb +0 -1012
- data/lib/roby/planning/task.rb +0 -180
- data/lib/roby/query.rb +0 -655
- data/lib/roby/relations/conflicts.rb +0 -67
- data/lib/roby/relations/dependency.rb +0 -358
- data/lib/roby/relations/ensured.rb +0 -19
- data/lib/roby/relations/error_handling.rb +0 -22
- data/lib/roby/relations/events.rb +0 -7
- data/lib/roby/relations/executed_by.rb +0 -208
- data/lib/roby/relations/influence.rb +0 -10
- data/lib/roby/relations/planned_by.rb +0 -63
- data/lib/roby/state/information.rb +0 -55
- data/lib/roby/state/state.rb +0 -367
- data/lib/roby/task-operations.rb +0 -186
- data/lib/roby/task_index.rb +0 -80
- data/lib/roby/test/distributed.rb +0 -230
- data/lib/roby/test/tasks/simple_task.rb +0 -23
- data/lib/roby/transactions.rb +0 -507
- data/lib/roby/transactions/proxy.rb +0 -325
- data/plugins/fault_injection/History.txt +0 -4
- data/plugins/fault_injection/README.txt +0 -34
- data/plugins/fault_injection/Rakefile +0 -12
- data/plugins/fault_injection/TODO.txt +0 -0
- data/plugins/fault_injection/app.rb +0 -52
- data/plugins/fault_injection/fault_injection.rb +0 -89
- data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
- data/plugins/subsystems/README.txt +0 -37
- data/plugins/subsystems/Rakefile +0 -13
- data/plugins/subsystems/app.rb +0 -182
- data/plugins/subsystems/test/app/README +0 -24
- data/plugins/subsystems/test/app/Rakefile +0 -8
- data/plugins/subsystems/test/app/config/app.yml +0 -71
- data/plugins/subsystems/test/app/config/init.rb +0 -12
- data/plugins/subsystems/test/app/config/roby.yml +0 -3
- data/plugins/subsystems/test/app/planners/main.rb +0 -20
- data/plugins/subsystems/test/app/scripts/distributed +0 -3
- data/plugins/subsystems/test/app/scripts/replay +0 -3
- data/plugins/subsystems/test/app/scripts/results +0 -3
- data/plugins/subsystems/test/app/scripts/run +0 -3
- data/plugins/subsystems/test/app/scripts/server +0 -3
- data/plugins/subsystems/test/app/scripts/shell +0 -3
- data/plugins/subsystems/test/app/scripts/test +0 -3
- data/plugins/subsystems/test/app/tasks/services.rb +0 -15
- data/plugins/subsystems/test/test_subsystems.rb +0 -78
- data/test/distributed/test_communication.rb +0 -195
- data/test/distributed/test_connection.rb +0 -284
- data/test/distributed/test_execution.rb +0 -378
- data/test/distributed/test_mixed_plan.rb +0 -341
- data/test/distributed/test_plan_notifications.rb +0 -238
- data/test/distributed/test_protocol.rb +0 -525
- data/test/distributed/test_query.rb +0 -106
- data/test/distributed/test_remote_plan.rb +0 -491
- data/test/distributed/test_transaction.rb +0 -466
- data/test/mockups/external_process +0 -28
- data/test/mockups/tasks.rb +0 -27
- data/test/planning/test_loops.rb +0 -432
- data/test/planning/test_model.rb +0 -427
- data/test/planning/test_task.rb +0 -126
- data/test/relations/test_conflicts.rb +0 -42
- data/test/relations/test_dependency.rb +0 -324
- data/test/relations/test_ensured.rb +0 -38
- data/test/relations/test_executed_by.rb +0 -224
- data/test/relations/test_planned_by.rb +0 -56
- data/test/suite_core.rb +0 -29
- data/test/suite_distributed.rb +0 -10
- data/test/suite_planning.rb +0 -4
- data/test/suite_relations.rb +0 -8
- data/test/tasks/test_external_process.rb +0 -126
- data/test/tasks/test_thread_task.rb +0 -70
- data/test/test_bgl.rb +0 -528
- data/test/test_event.rb +0 -969
- data/test/test_exceptions.rb +0 -591
- data/test/test_execution_engine.rb +0 -987
- data/test/test_gui.rb +0 -20
- data/test/test_interface.rb +0 -43
- data/test/test_log.rb +0 -125
- data/test/test_log_server.rb +0 -133
- data/test/test_plan.rb +0 -418
- data/test/test_query.rb +0 -424
- data/test/test_relations.rb +0 -260
- data/test/test_state.rb +0 -432
- data/test/test_support.rb +0 -16
- data/test/test_task.rb +0 -1181
- data/test/test_testcase.rb +0 -138
- data/test/test_transactions.rb +0 -610
- data/test/test_transactions_proxy.rb +0 -216
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
# EventGenerator objects are the objects which manage the event generation
|
|
3
|
+
# process (propagation, event creation, ...). They can be combined
|
|
4
|
+
# logically using & and |.
|
|
5
|
+
#
|
|
6
|
+
# === Standard relations
|
|
7
|
+
# - signals: calls the *command* of an event when this generator emits
|
|
8
|
+
# - forwardings: *emits* another event when this generator emits
|
|
9
|
+
#
|
|
10
|
+
# === Hooks
|
|
11
|
+
# The following hooks are defined:
|
|
12
|
+
# * #calling
|
|
13
|
+
# * #called
|
|
14
|
+
# * #fired
|
|
15
|
+
# * #signalling
|
|
16
|
+
# * #forwarding
|
|
17
|
+
#
|
|
18
|
+
class EventGenerator < PlanObject
|
|
19
|
+
class << self
|
|
20
|
+
attr_reader :relation_spaces
|
|
21
|
+
attr_reader :all_relation_spaces
|
|
22
|
+
end
|
|
23
|
+
@relation_spaces = Array.new
|
|
24
|
+
@all_relation_spaces = Array.new
|
|
25
|
+
|
|
26
|
+
# The event class that is used to represent this generator's emissions
|
|
27
|
+
#
|
|
28
|
+
# Defaults to Event
|
|
29
|
+
attr_reader :event_model
|
|
30
|
+
|
|
31
|
+
# Creates a new Event generator which is emitted as soon as one of this
|
|
32
|
+
# object and +generator+ is emitted
|
|
33
|
+
#
|
|
34
|
+
# See OrGenerator for a complete description.
|
|
35
|
+
#
|
|
36
|
+
# Note that this operator always creates a new generator, thus
|
|
37
|
+
#
|
|
38
|
+
# a | b | c | d
|
|
39
|
+
#
|
|
40
|
+
# will create 3 OrGenerator instances. It is in general better to use |
|
|
41
|
+
# for event pairs, and use OrGenerator#<< when multiple events have to be
|
|
42
|
+
# aggregated:
|
|
43
|
+
#
|
|
44
|
+
# OrGenerator.new << a << b << c << d
|
|
45
|
+
#
|
|
46
|
+
def |(generator)
|
|
47
|
+
OrGenerator.new << self << generator
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Creates a AndGenerator object which is emitted when both this object
|
|
51
|
+
# and +generator+ are emitted
|
|
52
|
+
#
|
|
53
|
+
# See AndGenerator for a complete description.
|
|
54
|
+
#
|
|
55
|
+
# Note that this operator always creates a new generator, thus
|
|
56
|
+
#
|
|
57
|
+
# a & b & c & d
|
|
58
|
+
#
|
|
59
|
+
# will create 3 AndGenerator instances. It is in general better to use &
|
|
60
|
+
# for event pairs, and use AndGenerator#<< when multiple events have to
|
|
61
|
+
# be aggregated:
|
|
62
|
+
#
|
|
63
|
+
# AndGenerator.new << a << b << c << d
|
|
64
|
+
#
|
|
65
|
+
def &(generator)
|
|
66
|
+
AndGenerator.new << self << generator
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
attr_enumerable(:handler, :handlers) { Array.new }
|
|
70
|
+
|
|
71
|
+
def initialize_copy(old) # :nodoc:
|
|
72
|
+
super
|
|
73
|
+
|
|
74
|
+
@event_model = old.event_model
|
|
75
|
+
@preconditions = old.instance_variable_get(:@preconditions).dup
|
|
76
|
+
@handlers = old.handlers.dup
|
|
77
|
+
@emitted = old.emitted?
|
|
78
|
+
@history = old.history.dup
|
|
79
|
+
@pending = false
|
|
80
|
+
if old.command.kind_of?(Method)
|
|
81
|
+
@command = method(old.command.name)
|
|
82
|
+
end
|
|
83
|
+
@unreachable = old.unreachable?
|
|
84
|
+
@unreachable_handlers = old.unreachable_handlers.dup
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns the model object for this particular event generator. It is in
|
|
88
|
+
# general the generator class.
|
|
89
|
+
def model; self.class end
|
|
90
|
+
# The model name
|
|
91
|
+
def name; model.name end
|
|
92
|
+
|
|
93
|
+
attr_predicate :pending?, true
|
|
94
|
+
|
|
95
|
+
def plan=(plan)
|
|
96
|
+
super
|
|
97
|
+
@relation_graphs = if plan then plan.event_relation_graphs
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# call-seq:
|
|
102
|
+
# EventGenerator.new
|
|
103
|
+
# EventGenerator.new(false)
|
|
104
|
+
# EventGenerator.new(true)
|
|
105
|
+
# EventGenerator.new { |event| ... }
|
|
106
|
+
#
|
|
107
|
+
# Create a new event generator. If a block is given, the event is
|
|
108
|
+
# controlable and the block is its command. If a +true+ argument is
|
|
109
|
+
# given, the event is controlable and is 'pass-through': it is emitted
|
|
110
|
+
# as soon as its command is called. If no argument is given (or a
|
|
111
|
+
# +false+ argument), then it is not controlable
|
|
112
|
+
def initialize(command_object = nil, controlable: false, plan: TemplatePlan.new, &command_block)
|
|
113
|
+
@preconditions = []
|
|
114
|
+
@handlers = []
|
|
115
|
+
@pending = false
|
|
116
|
+
@pending_sources = []
|
|
117
|
+
@unreachable = false
|
|
118
|
+
@unreachable_events = Hash.new
|
|
119
|
+
@unreachable_handlers = []
|
|
120
|
+
@history = Array.new
|
|
121
|
+
@event_model = Event
|
|
122
|
+
|
|
123
|
+
command_object ||= controlable
|
|
124
|
+
|
|
125
|
+
if command_object || command_block
|
|
126
|
+
@command = if command_object.respond_to?(:call)
|
|
127
|
+
command_object
|
|
128
|
+
elsif command_block
|
|
129
|
+
command_block
|
|
130
|
+
else
|
|
131
|
+
method(:default_command)
|
|
132
|
+
end
|
|
133
|
+
else
|
|
134
|
+
@command = nil
|
|
135
|
+
end
|
|
136
|
+
super(plan: plan)
|
|
137
|
+
plan.register_event(self)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# The default command of emitted the event
|
|
141
|
+
def default_command(context) # :nodoc:
|
|
142
|
+
emit(*context)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# The current command block
|
|
146
|
+
attr_accessor :command
|
|
147
|
+
|
|
148
|
+
# True if this event is controlable
|
|
149
|
+
def controlable?; !!@command end
|
|
150
|
+
|
|
151
|
+
# Checks that the event can be called. Raises various exception
|
|
152
|
+
# when it is not the case.
|
|
153
|
+
def check_call_validity
|
|
154
|
+
if !plan
|
|
155
|
+
EventNotExecutable.new(self).
|
|
156
|
+
exception("#emit called on #{self} which has been removed from its plan")
|
|
157
|
+
elsif !plan.executable?
|
|
158
|
+
EventNotExecutable.new(self).
|
|
159
|
+
exception("#emit called on #{self} which is not in an executable plan")
|
|
160
|
+
elsif !controlable?
|
|
161
|
+
EventNotControlable.new(self).
|
|
162
|
+
exception("#call called on a non-controlable event")
|
|
163
|
+
elsif unreachable?
|
|
164
|
+
if unreachability_reason
|
|
165
|
+
UnreachableEvent.new(self, unreachability_reason).
|
|
166
|
+
exception("#call called on #{self} which has been made unreachable because of #{unreachability_reason}")
|
|
167
|
+
else
|
|
168
|
+
UnreachableEvent.new(self, unreachability_reason).
|
|
169
|
+
exception("#call called on #{self} which has been made unreachable")
|
|
170
|
+
end
|
|
171
|
+
elsif !execution_engine.allow_propagation?
|
|
172
|
+
PhaseMismatch.exception("call to #emit is not allowed in this context")
|
|
173
|
+
elsif !execution_engine.inside_control?
|
|
174
|
+
ThreadMismatch.exception("#call called while not in control thread")
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def check_call_validity_after_calling
|
|
179
|
+
if !executable?
|
|
180
|
+
EventNotExecutable.new(self).
|
|
181
|
+
exception("#call called on #{self} which is a non-executable event")
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Checks that the event can be emitted. Raises various exception
|
|
186
|
+
# when it is not the case.
|
|
187
|
+
def check_emission_validity
|
|
188
|
+
if !plan
|
|
189
|
+
EventNotExecutable.new(self).
|
|
190
|
+
exception("#emit called on #{self} which has been removed from its plan")
|
|
191
|
+
elsif !plan.executable?
|
|
192
|
+
EventNotExecutable.new(self).
|
|
193
|
+
exception("#emit called on #{self} which is not in an executable plan")
|
|
194
|
+
elsif !executable?
|
|
195
|
+
EventNotExecutable.new(self).
|
|
196
|
+
exception("#emit called on #{self} which is a non-executable event")
|
|
197
|
+
elsif unreachable?
|
|
198
|
+
if unreachability_reason
|
|
199
|
+
UnreachableEvent.new(self, unreachability_reason).
|
|
200
|
+
exception("#emit called on #{self} which has been made unreachable because of #{unreachability_reason}")
|
|
201
|
+
else
|
|
202
|
+
UnreachableEvent.new(self, unreachability_reason).
|
|
203
|
+
exception("#emit called on #{self} which has been made unreachable")
|
|
204
|
+
end
|
|
205
|
+
elsif !execution_engine.allow_propagation?
|
|
206
|
+
PhaseMismatch.exception("call to #emit is not allowed in this context")
|
|
207
|
+
elsif !execution_engine.inside_control?
|
|
208
|
+
ThreadMismatch.exception("#emit called while not in control thread")
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Calls the command from within the event propagation code
|
|
213
|
+
def call_without_propagation(context)
|
|
214
|
+
if error = check_call_validity
|
|
215
|
+
clear_pending
|
|
216
|
+
execution_engine.add_error(error)
|
|
217
|
+
return
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
calling(context)
|
|
221
|
+
|
|
222
|
+
if (error = check_call_validity) || (error = check_call_validity_after_calling)
|
|
223
|
+
clear_pending
|
|
224
|
+
execution_engine.add_error(error)
|
|
225
|
+
return
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
begin
|
|
229
|
+
@calling_command = true
|
|
230
|
+
@command_emitted = false
|
|
231
|
+
execution_engine.propagation_context([self]) do
|
|
232
|
+
command.call(context)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
rescue Exception => e
|
|
236
|
+
if !e.kind_of?(LocalizedError)
|
|
237
|
+
e = CommandFailed.new(e, self)
|
|
238
|
+
end
|
|
239
|
+
if command_emitted?
|
|
240
|
+
execution_engine.add_error(e)
|
|
241
|
+
else
|
|
242
|
+
emit_failed(e)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
ensure
|
|
246
|
+
@calling_command = false
|
|
247
|
+
end
|
|
248
|
+
called(context)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Right after a call to #call_without_propagation, tells the caller
|
|
252
|
+
# whether the command has emitted or not. This can be used to determine
|
|
253
|
+
# in which context errors should be raised
|
|
254
|
+
attr_predicate :command_emitted?, false
|
|
255
|
+
|
|
256
|
+
# Call the command associated with self. Note that an event might be
|
|
257
|
+
# non-controlable and respond to the :call message. Controlability must
|
|
258
|
+
# be checked using #controlable?
|
|
259
|
+
def call(*context)
|
|
260
|
+
engine = execution_engine
|
|
261
|
+
if engine && !engine.in_propagation_context?
|
|
262
|
+
Roby.warn_deprecated "calling EventGenerator#call outside of propagation context is deprecated. In tests, use execute { } or expect_execution { }.to { }"
|
|
263
|
+
engine.process_events_synchronous { call(*context) }
|
|
264
|
+
return
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
if error = check_call_validity
|
|
268
|
+
clear_pending
|
|
269
|
+
raise error
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# This test must not be done in #emit_without_propagation as the
|
|
273
|
+
# other ones: it is possible, using Distributed.update, to disable
|
|
274
|
+
# ownership tests, but that does not work if the test is in
|
|
275
|
+
# #emit_without_propagation
|
|
276
|
+
if !self_owned?
|
|
277
|
+
raise OwnershipError, "not owner"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
execution_engine.queue_signal(engine.propagation_sources, self, context, nil)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Class used to register event handler blocks along with their options
|
|
284
|
+
class EventHandler
|
|
285
|
+
attr_reader :block
|
|
286
|
+
|
|
287
|
+
def initialize(block, copy_on_replace, once)
|
|
288
|
+
@block, @copy_on_replace, @once = block, copy_on_replace, once
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def call(*args)
|
|
292
|
+
block.call(*args)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# True if this event handler should be moved to the new task in case
|
|
296
|
+
# of replacements
|
|
297
|
+
#
|
|
298
|
+
# The default in Task#on is false for non-abstract tasks and true
|
|
299
|
+
# for abstract tasks.
|
|
300
|
+
def copy_on_replace?; !!@copy_on_replace end
|
|
301
|
+
|
|
302
|
+
# True if this event handler should be called only once
|
|
303
|
+
def once?; !!@once end
|
|
304
|
+
|
|
305
|
+
# Generates an option hash valid for EventGenerator#on
|
|
306
|
+
def as_options
|
|
307
|
+
mode = if copy_on_replace? then :copy
|
|
308
|
+
else :drop
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
{ on_replace: mode, once: once? }
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def ==(other)
|
|
315
|
+
@copy_on_replace == other.copy_on_replace? &&
|
|
316
|
+
@once == other.once? &&
|
|
317
|
+
block == other.block
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# call-seq:
|
|
322
|
+
# on { |event| ... }
|
|
323
|
+
# on(on_replace: :forward) { |event| ... }
|
|
324
|
+
#
|
|
325
|
+
# Adds an event handler on this generator. The block gets an Event
|
|
326
|
+
# object which describes the parameters of the emission (context value,
|
|
327
|
+
# time, ...). See Event for details.
|
|
328
|
+
#
|
|
329
|
+
# The :on_replace option governs what will happen with this handler if
|
|
330
|
+
# this task is replaced by another.
|
|
331
|
+
#
|
|
332
|
+
# * if set to :drop, the handler is not passed on
|
|
333
|
+
# * if set to :forward, the handler is added to the replacing task
|
|
334
|
+
#
|
|
335
|
+
def on(on_replace: :drop, once: false, &handler)
|
|
336
|
+
if ![:drop, :copy].include?(on_replace)
|
|
337
|
+
raise ArgumentError, "wrong value for the :on_replace option. Expecting either :drop or :copy, got #{on_replace}"
|
|
338
|
+
end
|
|
339
|
+
check_arity(handler, 1)
|
|
340
|
+
self.handlers << EventHandler.new(handler, on_replace == :copy, once)
|
|
341
|
+
self
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def initialize_replacement(event)
|
|
345
|
+
for h in handlers
|
|
346
|
+
if h.copy_on_replace?
|
|
347
|
+
event ||= yield
|
|
348
|
+
event.on(h.as_options, &h.block)
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
for h in unreachable_handlers
|
|
353
|
+
cancel, h = h
|
|
354
|
+
if h.copy_on_replace?
|
|
355
|
+
event ||= yield
|
|
356
|
+
event.if_unreachable(cancel_at_emission: cancel, on_replace: :copy, &h.block)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
if event
|
|
361
|
+
super(event)
|
|
362
|
+
else super(nil, &Proc.new)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Adds a signal from this event to +generator+. +generator+ must be
|
|
367
|
+
# controlable.
|
|
368
|
+
#
|
|
369
|
+
# If +time+ is given it is either a delay: time association, or a
|
|
370
|
+
# at: time association. In the first case, +time+ is a floating-point
|
|
371
|
+
# delay in seconds and in the second case it is a Time object which is
|
|
372
|
+
# the absolute point in time at which this propagation must happen.
|
|
373
|
+
def signals(generator, timespec = nil)
|
|
374
|
+
if !generator.controlable?
|
|
375
|
+
raise EventNotControlable.new(self), "trying to establish a signal from #{self} to #{generator} which is not controllable"
|
|
376
|
+
end
|
|
377
|
+
timespec = ExecutionEngine.validate_timespec(timespec)
|
|
378
|
+
|
|
379
|
+
add_signal generator, timespec
|
|
380
|
+
self
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def signal(generator, timespec = nil)
|
|
384
|
+
Roby.warn_deprecated "EventGenerator#signal has been renamed into EventGenerator#signals"
|
|
385
|
+
signals(generator, timespec)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# A set of blocks called when this event cannot be emitted again
|
|
389
|
+
#
|
|
390
|
+
# @return [Array<(Boolean,EventHandler)>]
|
|
391
|
+
attr_reader :unreachable_handlers
|
|
392
|
+
|
|
393
|
+
# Calls +block+ if it is impossible that this event is ever emitted
|
|
394
|
+
#
|
|
395
|
+
# @option options [Boolean] :cancel_at_emission (false) if true, the
|
|
396
|
+
# block will only be called if the event did not get emitted since the
|
|
397
|
+
# handler got installed.
|
|
398
|
+
# @option options [:drop,:copy] :on_replace (:drop) if set to drop, the
|
|
399
|
+
# block will not be passed to events that replace this one. Otherwise,
|
|
400
|
+
# the block gets copied
|
|
401
|
+
#
|
|
402
|
+
# @yieldparam [Object] reason the unreachability reason (usually an
|
|
403
|
+
# exception)
|
|
404
|
+
# @yieldparam [EventGenerator] generator the event generator that became
|
|
405
|
+
# unreachable. This is needed when the :on_replace option is :copy,
|
|
406
|
+
# since the generator that became unreachable might be different than
|
|
407
|
+
# the one on which the handler got installed
|
|
408
|
+
def if_unreachable(options = Hash.new, &block)
|
|
409
|
+
if options == true || options == false
|
|
410
|
+
Roby.warn_deprecated "if_unreachable(cancel_at_emission) has been replaced by if_unreachable(cancel_at_emission: true or false, on_replace: :policy)"
|
|
411
|
+
options = Hash[cancel_at_emission: options]
|
|
412
|
+
end
|
|
413
|
+
options = Kernel.validate_options options,
|
|
414
|
+
cancel_at_emission: false,
|
|
415
|
+
on_replace: :drop
|
|
416
|
+
|
|
417
|
+
if ![:drop, :copy].include?(options[:on_replace])
|
|
418
|
+
raise ArgumentError, "wrong value for the :on_replace option. Expecting either :drop or :copy, got #{options[:on_replace]}"
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
check_arity(block, 2)
|
|
422
|
+
if unreachable_handlers.any? { |cancel, b| b.block == block }
|
|
423
|
+
return b.object_id
|
|
424
|
+
end
|
|
425
|
+
handler = EventHandler.new(block, options[:on_replace] == :copy, true)
|
|
426
|
+
unreachable_handlers << [options[:cancel_at_emission], handler]
|
|
427
|
+
handler.object_id
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# React to this event being unreachable
|
|
431
|
+
#
|
|
432
|
+
# If a block is given, that block will be called when the event becomes
|
|
433
|
+
# unreachable. Otherwise, the method returns an EventGenerator instance
|
|
434
|
+
# which will be emitted when it happens.
|
|
435
|
+
#
|
|
436
|
+
# The +cancel_at_emission+ flag controls if the block (resp. event)
|
|
437
|
+
# should still be called (resp. emitted) after +self+ has been emitted.
|
|
438
|
+
# If true, the handler will be removed if +self+ emits. If false, the
|
|
439
|
+
# handler will be kept.
|
|
440
|
+
def when_unreachable(cancel_at_emission = false, &block)
|
|
441
|
+
if block_given?
|
|
442
|
+
return if_unreachable(cancel_at_emission: cancel_at_emission, &block)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# NOTE: the unreachable event is not directly tied to this one from
|
|
446
|
+
# a GC point of view (being able to do this would be useful, but
|
|
447
|
+
# anyway). So, it is possible that it is GCed because the event
|
|
448
|
+
# user did not take care to use it.
|
|
449
|
+
if !@unreachable_events[cancel_at_emission] || !@unreachable_events[cancel_at_emission].plan
|
|
450
|
+
result = EventGenerator.new(true)
|
|
451
|
+
if_unreachable(cancel_at_emission: cancel_at_emission) do
|
|
452
|
+
if result.plan
|
|
453
|
+
result.emit
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
add_causal_link result
|
|
457
|
+
@unreachable_events[cancel_at_emission] = result
|
|
458
|
+
end
|
|
459
|
+
@unreachable_events[cancel_at_emission]
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def forward(generator, timespec = nil)
|
|
463
|
+
Roby.warn_deprecated "EventGenerator#forward has been renamed into EventGenerator#forward_to"
|
|
464
|
+
forward_to(generator, timespec)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# Emit +generator+ when +self+ is fired, without calling the command of
|
|
468
|
+
# +generator+, if any.
|
|
469
|
+
#
|
|
470
|
+
# If +timespec+ is given it is either a delay: time association, or a
|
|
471
|
+
# at: time association. In the first case, +time+ is a floating-point
|
|
472
|
+
# delay in seconds and in the second case it is a Time object which is
|
|
473
|
+
# the absolute point in time at which this propagation must happen.
|
|
474
|
+
def forward_to(generator, timespec = nil)
|
|
475
|
+
timespec = ExecutionEngine.validate_timespec(timespec)
|
|
476
|
+
add_forwarding generator, timespec
|
|
477
|
+
self
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
# Returns an event which is emitted +seconds+ seconds after this one
|
|
481
|
+
def delay(seconds)
|
|
482
|
+
if seconds == 0 then self
|
|
483
|
+
else
|
|
484
|
+
ev = EventGenerator.new
|
|
485
|
+
forward_to(ev, delay: seconds)
|
|
486
|
+
ev
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Signals the given target event only once
|
|
491
|
+
def signals_once(signal, delay = nil)
|
|
492
|
+
signals(signal, delay)
|
|
493
|
+
once do |context|
|
|
494
|
+
remove_signal signal
|
|
495
|
+
end
|
|
496
|
+
self
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# call-seq:
|
|
500
|
+
# once { |context| ... }
|
|
501
|
+
#
|
|
502
|
+
# Calls the provided event handler only once
|
|
503
|
+
def once(options = Hash.new, &block)
|
|
504
|
+
on(options.merge(once: true), &block)
|
|
505
|
+
self
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def forward_once(ev, delay = nil)
|
|
509
|
+
Roby.warn_deprecated "#forward_once has been renamed into #forward_to_once"
|
|
510
|
+
forward_to_once(ev)
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# Forwards to the given target event only once
|
|
514
|
+
def forward_to_once(ev, delay = nil)
|
|
515
|
+
forward_to(ev, delay)
|
|
516
|
+
once do |context|
|
|
517
|
+
remove_forwarding ev
|
|
518
|
+
end
|
|
519
|
+
self
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def to_event; self end
|
|
523
|
+
|
|
524
|
+
# Returns the set of events directly related to this one
|
|
525
|
+
def related_events(result = Set.new); related_objects(nil, result) end
|
|
526
|
+
# Returns the set of tasks that are directly linked to this events.
|
|
527
|
+
#
|
|
528
|
+
# I.e. it returns the tasks that have events which are directly related
|
|
529
|
+
# to this event, self.task excluded:
|
|
530
|
+
#
|
|
531
|
+
# ev = task.intermediate_event
|
|
532
|
+
# ev.related_tasks # => #<Set: {}>
|
|
533
|
+
# ev.add_signal task2.intermediate_event
|
|
534
|
+
# ev.related_tasks # => #<Set: {task2}>
|
|
535
|
+
def related_tasks(result = nil)
|
|
536
|
+
result ||= Set.new
|
|
537
|
+
for ev in related_events
|
|
538
|
+
if ev.respond_to?(:task)
|
|
539
|
+
result << ev.task
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
result
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# Create a new event object for +context+
|
|
546
|
+
def new(context, propagation_id = nil, time = nil) # :nodoc:
|
|
547
|
+
event_model.new(self, propagation_id || execution_engine.propagation_id,
|
|
548
|
+
context, time || Time.now)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# Do fire this event. It gathers the list of signals that are to
|
|
552
|
+
# be propagated in the next step and calls fired()
|
|
553
|
+
#
|
|
554
|
+
# This method is always called in a propagation context
|
|
555
|
+
def fire(event)
|
|
556
|
+
@emitted = true
|
|
557
|
+
clear_pending
|
|
558
|
+
fired(event)
|
|
559
|
+
|
|
560
|
+
execution_engine = self.execution_engine
|
|
561
|
+
|
|
562
|
+
signal_graph = execution_engine.signal_graph
|
|
563
|
+
each_signal do |target|
|
|
564
|
+
if self == target
|
|
565
|
+
raise PropagationError, "#{self} is trying to signal itself"
|
|
566
|
+
end
|
|
567
|
+
execution_engine.queue_signal([event], target, event.context,
|
|
568
|
+
signal_graph.edge_info(self, target))
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
forward_graph = execution_engine.forward_graph
|
|
572
|
+
each_forwarding do |target|
|
|
573
|
+
if self == target
|
|
574
|
+
raise PropagationError, "#{self} is trying to signal itself"
|
|
575
|
+
end
|
|
576
|
+
execution_engine.queue_forward([event], target, event.context,
|
|
577
|
+
forward_graph.edge_info(self, target))
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
execution_engine.propagation_context([event]) do
|
|
581
|
+
call_handlers(event)
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# Call the event handlers defined for this event generator
|
|
586
|
+
def call_handlers(event)
|
|
587
|
+
# Since we are in a gathering context, call
|
|
588
|
+
# to other objects are not done, but gathered in the
|
|
589
|
+
# :propagation TLS
|
|
590
|
+
all_handlers = enum_for(:each_handler).to_a
|
|
591
|
+
processed_once_handlers = all_handlers.find_all do |h|
|
|
592
|
+
begin
|
|
593
|
+
h.call(event)
|
|
594
|
+
rescue LocalizedError => e
|
|
595
|
+
execution_engine.add_error( e )
|
|
596
|
+
rescue Exception => e
|
|
597
|
+
execution_engine.add_error( EventHandlerError.new(e, event) )
|
|
598
|
+
end
|
|
599
|
+
h.once?
|
|
600
|
+
end
|
|
601
|
+
handlers.delete_if { |h| processed_once_handlers.include?(h) }
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Raises an exception object when an event whose command has been
|
|
605
|
+
# called won't be emitted (ever)
|
|
606
|
+
def emit_failed(error = nil, message = nil)
|
|
607
|
+
engine = execution_engine
|
|
608
|
+
if engine && !engine.in_propagation_context?
|
|
609
|
+
Roby.warn_deprecated "calling EventGenerator#emit_failed outside of propagation context is deprecated. In tests, use execute { } or expect_execution { }.to { }"
|
|
610
|
+
engine.process_events_synchronous { emit_failed(error, message) }
|
|
611
|
+
return
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
error ||= EmissionFailed
|
|
615
|
+
|
|
616
|
+
if !message && !(error.kind_of?(Class) || error.kind_of?(Exception))
|
|
617
|
+
message = error.to_str
|
|
618
|
+
error = EmissionFailed
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
failure_message =
|
|
622
|
+
if message then message
|
|
623
|
+
elsif error.respond_to?(:message) then error.message
|
|
624
|
+
else "failed to emit #{self}"
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
if Class === error
|
|
628
|
+
error = error.new(nil, self)
|
|
629
|
+
error.set_backtrace caller(1)
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
new_error = error.exception failure_message
|
|
633
|
+
new_error.set_backtrace error.backtrace
|
|
634
|
+
error = new_error
|
|
635
|
+
|
|
636
|
+
if !error.kind_of?(LocalizedError)
|
|
637
|
+
error = EmissionFailed.new(error, self)
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
execution_engine.log(:generator_emit_failed, self, error)
|
|
641
|
+
execution_engine.add_error(error)
|
|
642
|
+
error
|
|
643
|
+
ensure
|
|
644
|
+
clear_pending
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
# Emits the event regardless of wether we are in a propagation context
|
|
648
|
+
# or not. Returns true to match the behavior of #call_without_propagation
|
|
649
|
+
#
|
|
650
|
+
# This is used by event propagation. Do not call directly: use #call instead
|
|
651
|
+
def emit_without_propagation(context)
|
|
652
|
+
if error = check_emission_validity
|
|
653
|
+
execution_engine.add_error(error)
|
|
654
|
+
return
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
emitting(context)
|
|
658
|
+
|
|
659
|
+
# Create the event object
|
|
660
|
+
event = new(context)
|
|
661
|
+
if !event.respond_to?(:add_sources)
|
|
662
|
+
raise TypeError, "#{event} is not a valid event object in #{self}"
|
|
663
|
+
end
|
|
664
|
+
event.add_sources(execution_engine.propagation_source_events)
|
|
665
|
+
event.add_sources(@pending_sources)
|
|
666
|
+
fire(event)
|
|
667
|
+
event
|
|
668
|
+
ensure
|
|
669
|
+
clear_pending
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
# Emit the event with +context+ as the event context
|
|
673
|
+
def emit(*context)
|
|
674
|
+
engine = execution_engine
|
|
675
|
+
if engine && !engine.in_propagation_context?
|
|
676
|
+
Roby.warn_deprecated "calling EventGenerator#emit outside of propagation context is deprecated. In tests, use execute { } or expect_execution { }.to { }"
|
|
677
|
+
engine.process_events_synchronous { emit(*context) }
|
|
678
|
+
return
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
if error = check_emission_validity
|
|
682
|
+
clear_pending
|
|
683
|
+
raise error
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
# This test must not be done in #emit_without_propagation as the
|
|
687
|
+
# other ones: it is possible, using Distributed.update, to disable
|
|
688
|
+
# ownership tests, but that does not work if the test is in
|
|
689
|
+
# #emit_without_propagation
|
|
690
|
+
if !self_owned?
|
|
691
|
+
raise OwnershipError, "cannot emit an event we don't own. #{self} is owned by #{owners}"
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
if @calling_command
|
|
695
|
+
@command_emitted = true
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
engine.queue_forward(
|
|
699
|
+
engine.propagation_sources, self, context, nil)
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
# Set this generator up so that it "delegates" its emission to another
|
|
703
|
+
# event
|
|
704
|
+
#
|
|
705
|
+
# @overload achieve_with(generator)
|
|
706
|
+
# Emit self next time generator is emitted, and mark it as unreachable
|
|
707
|
+
# if generator is. The event context is propagated through.
|
|
708
|
+
#
|
|
709
|
+
# @param [EventGenerator] generator
|
|
710
|
+
#
|
|
711
|
+
# @overload achieve_with(generator) { |event| ... }
|
|
712
|
+
# Emit self next time generator is emitted, and mark it as unreachable
|
|
713
|
+
# if generator is. The value returned by the block is used as self's
|
|
714
|
+
# event context
|
|
715
|
+
#
|
|
716
|
+
# An exception raised by the filter will be localized on self.
|
|
717
|
+
#
|
|
718
|
+
# @param [EventGenerator] generator
|
|
719
|
+
# @yieldparam [Event] event the event emitted by 'generator'
|
|
720
|
+
# @yieldreturn [Object] the context to be used for self's event
|
|
721
|
+
def achieve_with(ev)
|
|
722
|
+
if block_given?
|
|
723
|
+
ev.add_causal_link self
|
|
724
|
+
ev.once do |event|
|
|
725
|
+
begin
|
|
726
|
+
context = yield(event)
|
|
727
|
+
do_emit = true
|
|
728
|
+
rescue Exception => e
|
|
729
|
+
emit_failed(e)
|
|
730
|
+
end
|
|
731
|
+
if do_emit
|
|
732
|
+
self.emit(context)
|
|
733
|
+
end
|
|
734
|
+
end
|
|
735
|
+
else
|
|
736
|
+
ev.forward_to_once self
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
ev.if_unreachable(cancel_at_emission: true) do |reason, event|
|
|
740
|
+
emit_failed(EmissionFailed.new(UnreachableEvent.new(ev, reason), self))
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
# For backwards compatibility. Use #achieve_with.
|
|
744
|
+
def realize_with(task); achieve_with(task) end
|
|
745
|
+
|
|
746
|
+
# Declares that the command of this event should be achieved by calling
|
|
747
|
+
# the provided block
|
|
748
|
+
#
|
|
749
|
+
# @param [Boolean] emit_on_success if true, the event will be emitted if
|
|
750
|
+
# the block got called successfully. Otherwise, nothing will be done.
|
|
751
|
+
# @param [Promise] a promise object that represents the work. Use
|
|
752
|
+
# {ExecutionEngine#promise} to create this promise.
|
|
753
|
+
# @param [Proc,nil] block a block from which the method will create a
|
|
754
|
+
# promise. This promise is *not* returned as it would give a false
|
|
755
|
+
# sense of security.
|
|
756
|
+
# @param [Symbol] on_failure controls what happens if the promise fails.
|
|
757
|
+
# With the default of :fail, the event generator's emit_failed is
|
|
758
|
+
# called. If it is :emit, it gets emitted. If it is :nothing,
|
|
759
|
+
# nothing's done
|
|
760
|
+
#
|
|
761
|
+
# @return [Promise] the promise. Do NOT chain work on this promise, as
|
|
762
|
+
# that work won't be automatically error-checked by Roby's mechanisms
|
|
763
|
+
def achieve_asynchronously(promise = nil, description: "#{self}#achieve_asynchronously", emit_on_success: true, on_failure: :fail, context: nil, &block)
|
|
764
|
+
if promise && block
|
|
765
|
+
raise ArgumentError, "cannot give both a promise and a block"
|
|
766
|
+
elsif ![:fail, :emit, :nothing].include?(on_failure)
|
|
767
|
+
raise ArgumentError, "expected on_failure to either be :fail or :emit"
|
|
768
|
+
elsif block
|
|
769
|
+
promise = execution_engine.promise(description: description, &block)
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
if promise.null?
|
|
773
|
+
emit(*context) if emit_on_success
|
|
774
|
+
return
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
if emit_on_success
|
|
778
|
+
promise.on_success(description: "#{self}.emit") { emit(*context) }
|
|
779
|
+
end
|
|
780
|
+
if on_failure != :nothing
|
|
781
|
+
promise.on_error(description: "#{self}#emit_failed") do |reason|
|
|
782
|
+
if on_failure == :fail
|
|
783
|
+
emit_failed(reason)
|
|
784
|
+
elsif on_failure == :emit
|
|
785
|
+
emit(*context)
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
promise.execute
|
|
790
|
+
promise
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
# A [time, event] array of past event emitted by this object
|
|
794
|
+
attr_reader :history
|
|
795
|
+
# True if this event has been emitted once.
|
|
796
|
+
attr_predicate :emitted?
|
|
797
|
+
# True if this event has been emitted once.
|
|
798
|
+
def happened?
|
|
799
|
+
Roby.warn_deprecated "#happened? is deprecated, use #emitted? instead"
|
|
800
|
+
emitted?
|
|
801
|
+
end
|
|
802
|
+
# Last event to have been emitted by this generator
|
|
803
|
+
def last; history.last end
|
|
804
|
+
|
|
805
|
+
# Defines a precondition handler for this event. Precondition handlers
|
|
806
|
+
# are blocks which are called just before the event command is called.
|
|
807
|
+
# If the handler returns false, the calling is aborted by a
|
|
808
|
+
# PreconditionFailed exception
|
|
809
|
+
def precondition(reason = nil, &block)
|
|
810
|
+
@preconditions << [reason, block]
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
# Yields all precondition handlers defined for this generator
|
|
814
|
+
def each_precondition # :yield:reason, block
|
|
815
|
+
@preconditions.each { |o| yield(o) }
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
# Call this method in the #calling hook to cancel calling the event
|
|
819
|
+
# command. This raises an EventCanceled exception with +reason+ for
|
|
820
|
+
# message
|
|
821
|
+
def cancel(reason = nil)
|
|
822
|
+
raise EventCanceled.new(self), (reason || "event canceled")
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
def pending(sources)
|
|
826
|
+
@pending = true
|
|
827
|
+
@pending_sources.concat(sources)
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
def clear_pending
|
|
831
|
+
@pending = false
|
|
832
|
+
@pending_sources = []
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
# Hook called when this event generator is called (i.e. the associated
|
|
836
|
+
# command is), before the command is actually called. Think of it as a
|
|
837
|
+
# pre-call hook.
|
|
838
|
+
def calling(context)
|
|
839
|
+
each_precondition do |reason, block|
|
|
840
|
+
result = begin
|
|
841
|
+
block.call(self, context)
|
|
842
|
+
rescue EventPreconditionFailed => e
|
|
843
|
+
e.generator = self
|
|
844
|
+
raise
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
if !result
|
|
848
|
+
raise EventPreconditionFailed.new(self), "precondition #{reason} failed"
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
# Hook called just after the event command has been called
|
|
854
|
+
def called(context)
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
# Hook called when this event will be emitted
|
|
858
|
+
def emitting(context)
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
# Hook called when this generator has been fired. +event+ is the Event object
|
|
862
|
+
# which has been created.
|
|
863
|
+
def fired(event)
|
|
864
|
+
unreachable_handlers.delete_if { |cancel, _| cancel }
|
|
865
|
+
history << event
|
|
866
|
+
execution_engine.log(:generator_fired, event)
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
# call-seq:
|
|
870
|
+
# filter(new_context) => filtering_event
|
|
871
|
+
# filter { |context| ... } => filtering_event
|
|
872
|
+
#
|
|
873
|
+
# Returns an event generator which forwards the events fired by this
|
|
874
|
+
# one, but by changing the context. In the first form, the new context
|
|
875
|
+
# is set to +new_context+. In the second form, to the value returned
|
|
876
|
+
# by the given block
|
|
877
|
+
#
|
|
878
|
+
# Example:
|
|
879
|
+
#
|
|
880
|
+
# base = task1.intermediate_event
|
|
881
|
+
# filtered = base.filter(10)
|
|
882
|
+
#
|
|
883
|
+
# base.on { |base_ev| ... }
|
|
884
|
+
# filtered.on { |filtered_ev| ... }
|
|
885
|
+
#
|
|
886
|
+
# base.emit(20)
|
|
887
|
+
# # base_ev.context is [20]
|
|
888
|
+
# # filtered_ev.context is [10]
|
|
889
|
+
#
|
|
890
|
+
# The returned value is a FilterGenerator instance which is the child of
|
|
891
|
+
# +self+ in the signalling relation
|
|
892
|
+
def filter(*new_context, &block)
|
|
893
|
+
filter = FilterGenerator.new(new_context, &block)
|
|
894
|
+
self.signals(filter)
|
|
895
|
+
filter
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
# Returns a new event generator which emits until the +limit+ event is
|
|
899
|
+
# sent
|
|
900
|
+
#
|
|
901
|
+
# source, target, limit = (1..3).map { EventGenerator.new(true) }
|
|
902
|
+
# until = target.until(limit).on { |ev| STDERR.puts "FIRED !!!" }
|
|
903
|
+
# source.signals target
|
|
904
|
+
#
|
|
905
|
+
# Will do
|
|
906
|
+
#
|
|
907
|
+
# source.call # => target is emitted
|
|
908
|
+
# limit.emit
|
|
909
|
+
# source.call # => target is not emitted anymore
|
|
910
|
+
#
|
|
911
|
+
# It returns an instance of UntilGenerator with +self+ as parent in the
|
|
912
|
+
# forwarding relation and +limit+ as parent in the signalling relation.
|
|
913
|
+
#
|
|
914
|
+
# Alternatively, the limitation can be triggered by calling the event's
|
|
915
|
+
# command explicitely:
|
|
916
|
+
#
|
|
917
|
+
# source.call # => target is emitted
|
|
918
|
+
# until.call
|
|
919
|
+
# source.call # => target is not emitted anymore
|
|
920
|
+
#
|
|
921
|
+
def until(limit); UntilGenerator.new(self, limit) end
|
|
922
|
+
|
|
923
|
+
# Checks that ownership allows to add the self => child relation
|
|
924
|
+
def add_child_object(child, type, info) # :nodoc:
|
|
925
|
+
if !child.read_write?
|
|
926
|
+
raise OwnershipError, "cannot add an event relation on a child we don't own. #{child} is owned by #{child.owners.to_a} (plan is owned by #{plan.owners.to_a if plan})"
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
super
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# Called when the object has been removed from its plan
|
|
933
|
+
def finalized!(timestamp = nil)
|
|
934
|
+
super
|
|
935
|
+
unreachable_handlers.clear
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
# True if this event is unreachable, i.e. if it will never be emitted
|
|
939
|
+
# anymore
|
|
940
|
+
attr_predicate :unreachable?
|
|
941
|
+
|
|
942
|
+
# If the event became unreachable, this holds the reason for its
|
|
943
|
+
# unreachability, if that reason is known.
|
|
944
|
+
attr_reader :unreachability_reason
|
|
945
|
+
|
|
946
|
+
# Internal helper for unreachable!
|
|
947
|
+
def call_unreachable_handlers(reason) # :nodoc:
|
|
948
|
+
unreachable_handlers.each do |_, handler|
|
|
949
|
+
begin
|
|
950
|
+
handler.call(reason, self)
|
|
951
|
+
rescue LocalizedError => e
|
|
952
|
+
execution_engine.add_error(e)
|
|
953
|
+
rescue Exception => e
|
|
954
|
+
execution_engine.add_error(EventHandlerError.new(e, self))
|
|
955
|
+
end
|
|
956
|
+
end
|
|
957
|
+
unreachable_handlers.clear
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
def unreachable_without_propagation(reason = nil, plan = self.plan)
|
|
961
|
+
return if @unreachable
|
|
962
|
+
mark_unreachable!(reason)
|
|
963
|
+
|
|
964
|
+
execution_engine.log(:generator_unreachable, self, reason)
|
|
965
|
+
if execution_engine
|
|
966
|
+
execution_engine.unreachable_event(self)
|
|
967
|
+
end
|
|
968
|
+
call_unreachable_handlers(reason)
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def mark_unreachable!(reason)
|
|
972
|
+
clear_pending
|
|
973
|
+
@unreachable = true
|
|
974
|
+
@unreachability_reason = reason
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
# @api private
|
|
978
|
+
#
|
|
979
|
+
# Called if the event has been garbage-collected, but cannot be
|
|
980
|
+
# finalized yet (possibly because {#can_finalize?} returns false)
|
|
981
|
+
def garbage!
|
|
982
|
+
super
|
|
983
|
+
unreachable!
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
# Called internally when the event becomes unreachable
|
|
987
|
+
def unreachable!(reason = nil, plan = self.plan)
|
|
988
|
+
engine = execution_engine
|
|
989
|
+
if engine && !engine.in_propagation_context?
|
|
990
|
+
Roby.warn_deprecated "calling EventGenerator#unreachable! outside of propagation context is deprecated. In tests, use execute { } or expect_execution { }.to { }"
|
|
991
|
+
execution_engine.process_events_synchronous do
|
|
992
|
+
unreachable!(reason, plan)
|
|
993
|
+
end
|
|
994
|
+
return
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
if !plan
|
|
998
|
+
raise FinalizedPlanObject, "#unreachable! called on #{self} but this is a finalized generator"
|
|
999
|
+
elsif !plan.executable?
|
|
1000
|
+
unreachable_without_propagation(reason)
|
|
1001
|
+
else
|
|
1002
|
+
unreachable_without_propagation(reason, plan)
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
def pretty_print(pp) # :nodoc:
|
|
1007
|
+
pp.text to_s
|
|
1008
|
+
pp.group(2, ' {', '}') do
|
|
1009
|
+
pp.breakable
|
|
1010
|
+
pp.text "owners: "
|
|
1011
|
+
pp.seplist(owners) { |r| pp.text r.to_s }
|
|
1012
|
+
end
|
|
1013
|
+
end
|
|
1014
|
+
|
|
1015
|
+
def to_execution_exception
|
|
1016
|
+
LocalizedError.new(self).to_execution_exception
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
def to_execution_exception_matcher
|
|
1020
|
+
LocalizedError.to_execution_exception_matcher.with_origin(self)
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
def self.match
|
|
1025
|
+
Queries::EventGeneratorMatcher.new.with_model(self)
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
def match
|
|
1029
|
+
Queries::EventGeneratorMatcher.new(self)
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
def replace_by(object)
|
|
1033
|
+
plan.replace_subplan(Hash.new, Hash[object => object])
|
|
1034
|
+
initialize_replacement(object)
|
|
1035
|
+
end
|
|
1036
|
+
|
|
1037
|
+
def create_transaction_proxy(transaction)
|
|
1038
|
+
transaction.create_and_register_proxy_event(self)
|
|
1039
|
+
end
|
|
1040
|
+
end
|
|
1041
|
+
|
|
1042
|
+
unless defined? EventStructure
|
|
1043
|
+
EventStructure = RelationSpace(EventGenerator)
|
|
1044
|
+
EventStructure.default_graph_class = Relations::EventRelationGraph
|
|
1045
|
+
end
|
|
1046
|
+
end
|
|
1047
|
+
|