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,44 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module DRoby
|
|
3
|
+
module V5
|
|
4
|
+
# These objects are used in distributed Roby to identify objects across
|
|
5
|
+
# the various Roby instances
|
|
6
|
+
class DRobyID
|
|
7
|
+
# The object ID
|
|
8
|
+
attr_reader :id
|
|
9
|
+
|
|
10
|
+
def initialize(id)
|
|
11
|
+
@id = id
|
|
12
|
+
@hash = id.hash
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other) # :nodoc:
|
|
16
|
+
other.kind_of?(DRobyID) && other.id == id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias :eql? :==
|
|
20
|
+
attr_reader :hash
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
"#<DRobyID:#{id}>"
|
|
24
|
+
end
|
|
25
|
+
def inspect
|
|
26
|
+
to_s
|
|
27
|
+
end
|
|
28
|
+
def pretty_print(pp)
|
|
29
|
+
pp.text to_s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.droby_id_allocator
|
|
33
|
+
@droby_id_allocator
|
|
34
|
+
end
|
|
35
|
+
@droby_id_allocator = Concurrent::AtomicFixnum.new
|
|
36
|
+
|
|
37
|
+
def self.allocate
|
|
38
|
+
DRobyID.new(droby_id_allocator.increment)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module DRoby
|
|
3
|
+
module V5
|
|
4
|
+
class DRobyModel
|
|
5
|
+
attr_reader :name
|
|
6
|
+
attr_reader :remote_siblings
|
|
7
|
+
attr_reader :supermodel
|
|
8
|
+
attr_reader :provided_models
|
|
9
|
+
|
|
10
|
+
def initialize(name, remote_siblings, supermodel, provided_models)
|
|
11
|
+
@name, @remote_siblings, @supermodel, @provided_models =
|
|
12
|
+
name, remote_siblings, supermodel, provided_models
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def proxy(peer)
|
|
16
|
+
unmarshal_dependent_models(peer)
|
|
17
|
+
if local_m = peer.find_local_model(self)
|
|
18
|
+
# Ensures that the supermodel(s) are registered
|
|
19
|
+
return local_m
|
|
20
|
+
elsif !supermodel
|
|
21
|
+
raise NoLocalObject, "#{name}, at the root of a model hierarchy, was expected to be explicitely registered but is not"
|
|
22
|
+
else
|
|
23
|
+
create_new_proxy_model(peer)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create_new_proxy_model(peer)
|
|
28
|
+
local_model = @unmarshalled_supermodel.
|
|
29
|
+
new_submodel(name: name || "#{@unmarshalled_supermodel.name}#")
|
|
30
|
+
peer.register_model(local_model, remote_siblings)
|
|
31
|
+
local_model
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def unmarshal_dependent_models(peer)
|
|
35
|
+
# Ensure that the peer-local info of related models gets
|
|
36
|
+
# registered, no matter what.
|
|
37
|
+
if supermodel
|
|
38
|
+
@unmarshalled_supermodel = peer.local_model(supermodel)
|
|
39
|
+
end
|
|
40
|
+
@unmarshalled_provided_models = @provided_models.map { |m| peer.local_model(m) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def update(peer, local_object, fresh_proxy: false)
|
|
44
|
+
@unmarshalled_provided_models ||= @provided_models.map { |m| peer.local_model(m) }
|
|
45
|
+
@unmarshalled_provided_models.each do |local_m|
|
|
46
|
+
if !(local_object <= local_m)
|
|
47
|
+
local_object.provides local_m
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.dump_supermodel(peer, model)
|
|
53
|
+
s = model.supermodel
|
|
54
|
+
if s.kind_of?(ModelDumper)
|
|
55
|
+
peer.dump_model(s)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.dump_provided_models_of(peer, model)
|
|
60
|
+
provided_models_of(model).map do |m|
|
|
61
|
+
peer.dump_model(m)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.provided_models_of(model)
|
|
66
|
+
super_m = model.supermodel
|
|
67
|
+
provided_m = Array.new
|
|
68
|
+
model.ancestors.each do |m|
|
|
69
|
+
if m == super_m
|
|
70
|
+
break
|
|
71
|
+
elsif (m != model) && m.kind_of?(ModelDumper)
|
|
72
|
+
provided_m << m
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
provided_m
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module DRoby
|
|
3
|
+
module V5
|
|
4
|
+
# Cross-instance identification of an object
|
|
5
|
+
class RemoteDRobyID
|
|
6
|
+
# The peer on which the object is known as {#droby_id}
|
|
7
|
+
#
|
|
8
|
+
# @return [PeerID]
|
|
9
|
+
attr_reader :peer_id
|
|
10
|
+
|
|
11
|
+
# The object ID
|
|
12
|
+
#
|
|
13
|
+
# @return [DRobyID]
|
|
14
|
+
attr_reader :droby_id
|
|
15
|
+
|
|
16
|
+
# The ID hash value
|
|
17
|
+
#
|
|
18
|
+
# The values are immutable, so the hash value is computed once
|
|
19
|
+
# and cached here
|
|
20
|
+
attr_reader :hash
|
|
21
|
+
|
|
22
|
+
def initialize(peer_id, droby_id)
|
|
23
|
+
@peer_id = peer_id
|
|
24
|
+
@droby_id = droby_id
|
|
25
|
+
|
|
26
|
+
@hash = [@peer_id, @droby_id].hash
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def eql?(obj)
|
|
30
|
+
obj.kind_of?(RemoteDRobyID) &&
|
|
31
|
+
obj.peer_id == peer_id && obj.droby_id == droby_id
|
|
32
|
+
end
|
|
33
|
+
def ==(obj); eql?(obj) end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
"#<RemoteDRobyID #{peer_id}@#{droby_id}>"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
data/lib/roby/event.rb
CHANGED
|
@@ -5,17 +5,19 @@ module Roby
|
|
|
5
5
|
# functionalities related to propagation as well.
|
|
6
6
|
class Event
|
|
7
7
|
# The generator which emitted this event
|
|
8
|
-
|
|
8
|
+
attr_reader :generator
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
def initialize(generator, propagation_id, context, time = Time.now)
|
|
11
|
+
@generator, @propagation_id, @context, @time = generator, propagation_id, context.freeze, time
|
|
12
|
+
@sources = Set.new
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
def plan
|
|
16
|
+
generator.plan
|
|
17
|
+
end
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
attr_accessor :propagation_id, :context, :time
|
|
20
|
+
protected :propagation_id=, :context=, :time=
|
|
19
21
|
|
|
20
22
|
# The events whose emission directly triggered this event during the
|
|
21
23
|
# propagation. The events in this set are subject to Ruby's own
|
|
@@ -23,992 +25,112 @@ def initialize(generator, propagation_id, context, time = Time.now)
|
|
|
23
25
|
# collected (i.e. if all references to the associated task/event
|
|
24
26
|
# generator are removed), it will be removed from this set as well.
|
|
25
27
|
def sources
|
|
26
|
-
result =
|
|
28
|
+
result = Set.new
|
|
27
29
|
@sources.delete_if do |ref|
|
|
28
30
|
begin
|
|
29
|
-
result << ref.
|
|
31
|
+
result << ref.__getobj__
|
|
30
32
|
false
|
|
31
|
-
rescue
|
|
33
|
+
rescue WeakRef::RefError
|
|
32
34
|
true
|
|
33
35
|
end
|
|
34
36
|
end
|
|
35
37
|
result
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
# Recursively computes the source event that led to the emission of
|
|
41
|
+
# +self+
|
|
42
|
+
def all_sources
|
|
43
|
+
result = Set.new
|
|
44
|
+
sources.each do |ev|
|
|
45
|
+
result << ev
|
|
46
|
+
result.merge(ev.all_sources)
|
|
43
47
|
end
|
|
48
|
+
result
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
new_event = self.dup
|
|
51
|
-
new_event.propagation_id = new_id
|
|
52
|
-
new_event.context = new_context
|
|
53
|
-
new_event.time = Time.now
|
|
54
|
-
new_event
|
|
55
|
-
else
|
|
56
|
-
self
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def name; model.name end
|
|
61
|
-
def model; self.class end
|
|
62
|
-
def inspect # :nodoc:
|
|
63
|
-
"#<#{model.to_s}:0x#{address.to_s(16)} generator=#{generator} model=#{model}"
|
|
51
|
+
# Call to protect this event's source from Ruby's garbage collection.
|
|
52
|
+
# Call this if you want to store the propagation history for this event
|
|
53
|
+
def protect_sources
|
|
54
|
+
@protected_sources = sources
|
|
64
55
|
end
|
|
65
56
|
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
# Call to recursively protect this event's sources from Ruby's garbage
|
|
58
|
+
# collection. Call this if you want to store the propagation history for
|
|
59
|
+
# this event
|
|
60
|
+
def protect_all_sources
|
|
61
|
+
@protected_all_sources = all_sources
|
|
70
62
|
end
|
|
71
63
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
# Sets the sources. See #sources
|
|
65
|
+
def sources=(new_sources) # :nodoc:
|
|
66
|
+
@sources = Set.new
|
|
67
|
+
add_sources(new_sources)
|
|
68
|
+
end
|
|
75
69
|
|
|
76
|
-
def
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
pp.breakable
|
|
80
|
-
pp.nest(2) do
|
|
81
|
-
pp.text " "
|
|
82
|
-
pp.seplist(context) { |v| v.pretty_print(pp) }
|
|
83
|
-
end
|
|
70
|
+
def add_sources(new_sources)
|
|
71
|
+
for new_s in new_sources
|
|
72
|
+
@sources << WeakRef.new(new_s)
|
|
84
73
|
end
|
|
85
74
|
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# EventGenerator objects are the objects which manage the event generation
|
|
89
|
-
# process (propagation, event creation, ...). They can be combined
|
|
90
|
-
# logically using & and |.
|
|
91
|
-
#
|
|
92
|
-
# === Standard relations
|
|
93
|
-
# - signals: calls the *command* of an event when this generator emits
|
|
94
|
-
# - forwardings: *emits* another event when this generator emits
|
|
95
|
-
#
|
|
96
|
-
# === Hooks
|
|
97
|
-
# The following hooks are defined:
|
|
98
|
-
# * #postponed
|
|
99
|
-
# * #calling
|
|
100
|
-
# * #called
|
|
101
|
-
# * #fired
|
|
102
|
-
# * #signalling
|
|
103
|
-
# * #forwarding
|
|
104
|
-
#
|
|
105
|
-
class EventGenerator < PlanObject
|
|
106
|
-
# Creates a new Event generator which is emitted as soon as one of this
|
|
107
|
-
# object and +generator+ is emitted
|
|
108
|
-
def |(generator)
|
|
109
|
-
OrGenerator.new << self << generator
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Creates a AndGenerator object which is emitted when both this object
|
|
113
|
-
# and +generator+ are emitted
|
|
114
|
-
def &(generator)
|
|
115
|
-
AndGenerator.new << self << generator
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
attr_enumerable(:handler, :handlers) { Array.new }
|
|
119
|
-
attr_enumerable(:once_handler, :once_handlers) { Array.new }
|
|
120
|
-
|
|
121
|
-
def initialize_copy(old) # :nodoc:
|
|
122
|
-
super
|
|
123
|
-
|
|
124
|
-
@history = old.history.dup
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def model; self.class end
|
|
128
|
-
# The model name
|
|
129
|
-
def name; model.name end
|
|
130
|
-
# The count of command calls that have not a corresponding emission
|
|
131
|
-
attr_reader :pending
|
|
132
|
-
# True if this event has been called but is not emitted yet
|
|
133
|
-
def pending?; pending end
|
|
134
|
-
|
|
135
|
-
# call-seq:
|
|
136
|
-
# EventGenerator.new
|
|
137
|
-
# EventGenerator.new(false)
|
|
138
|
-
# EventGenerator.new(true)
|
|
139
|
-
# EventGenerator.new { |event| ... }
|
|
140
|
-
#
|
|
141
|
-
# Create a new event generator. If a block is given, the event is
|
|
142
|
-
# controlable and the block is its command. If a +true+ argument is
|
|
143
|
-
# given, the event is controlable and is 'pass-through': it is emitted
|
|
144
|
-
# as soon as its command is called. If no argument is given (or a
|
|
145
|
-
# +false+ argument), then it is not controlable
|
|
146
|
-
def initialize(command_object = nil, &command_block)
|
|
147
|
-
@preconditions = []
|
|
148
|
-
@handlers = []
|
|
149
|
-
@pending = false
|
|
150
|
-
@unreachable = false
|
|
151
|
-
@unreachable_handlers = []
|
|
152
|
-
|
|
153
|
-
if command_object || command_block
|
|
154
|
-
self.command = if command_object.respond_to?(:call)
|
|
155
|
-
command_object
|
|
156
|
-
elsif command_block
|
|
157
|
-
command_block
|
|
158
|
-
else
|
|
159
|
-
method(:default_command)
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
super() if defined? super
|
|
163
|
-
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def default_command(context)
|
|
167
|
-
emit(*context)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# The current command block
|
|
171
|
-
attr_accessor :command
|
|
172
|
-
|
|
173
|
-
# True if this event is controlable
|
|
174
|
-
def controlable?; !!@command end
|
|
175
|
-
|
|
176
|
-
# Checks that the event can be called. Raises various exception
|
|
177
|
-
# when it is not the case.
|
|
178
|
-
def check_call_validity
|
|
179
|
-
if !plan
|
|
180
|
-
raise EventNotExecutable.new(self), "#emit called on #{self} which is in no plan"
|
|
181
|
-
elsif !engine
|
|
182
|
-
raise EventNotExecutable.new(self), "#emit called on #{self} which is has no associated execution engine"
|
|
183
|
-
elsif !engine.allow_propagation?
|
|
184
|
-
raise PhaseMismatch, "call to #emit is not allowed in this context"
|
|
185
|
-
elsif !controlable?
|
|
186
|
-
raise EventNotControlable.new(self), "#call called on a non-controlable event"
|
|
187
|
-
elsif !engine.inside_control?
|
|
188
|
-
raise ThreadMismatch, "#call called while not in control thread"
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Checks that the event can be emitted. Raises various exception
|
|
193
|
-
# when it is not the case.
|
|
194
|
-
def check_emission_validity
|
|
195
|
-
if !executable?
|
|
196
|
-
raise EventNotExecutable.new(self), "#emit called on #{self} which is a non-executable event"
|
|
197
|
-
elsif !engine.allow_propagation?
|
|
198
|
-
raise PhaseMismatch, "call to #emit is not allowed in this context"
|
|
199
|
-
elsif !engine.inside_control?
|
|
200
|
-
raise ThreadMismatch, "#emit called while not in control thread"
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# Returns true if the command has been called and false otherwise
|
|
205
|
-
# The command won't be called if #postpone() is called within the
|
|
206
|
-
# #calling hook, in which case the method returns false.
|
|
207
|
-
#
|
|
208
|
-
# This is used by propagation code, and should never be called directly
|
|
209
|
-
def call_without_propagation(context)
|
|
210
|
-
check_call_validity
|
|
211
|
-
|
|
212
|
-
if !controlable?
|
|
213
|
-
raise EventNotControlable.new(self), "#call called on a non-controlable event"
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
postponed = catch :postponed do
|
|
217
|
-
calling(context)
|
|
218
|
-
@pending = true
|
|
219
|
-
|
|
220
|
-
if !executable?
|
|
221
|
-
raise EventNotExecutable.new(self), "#call called on #{self} which is a non-executable event"
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
plan.engine.propagation_context([self]) do
|
|
225
|
-
command[context]
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
false
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
if postponed
|
|
232
|
-
@pending = false
|
|
233
|
-
postponed(context, *postponed)
|
|
234
|
-
false
|
|
235
|
-
else
|
|
236
|
-
called(context)
|
|
237
|
-
true
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
rescue Exception
|
|
241
|
-
@pending = false
|
|
242
|
-
raise
|
|
243
|
-
end
|
|
244
75
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
check_call_validity
|
|
250
|
-
|
|
251
|
-
# This test must not be done in #emit_without_propagation as the
|
|
252
|
-
# other ones: it is possible, using Distributed.update, to disable
|
|
253
|
-
# ownership tests, but that does not work if the test is in
|
|
254
|
-
# #emit_without_propagation
|
|
255
|
-
if !self_owned?
|
|
256
|
-
raise OwnershipError, "not owner"
|
|
76
|
+
def root_sources
|
|
77
|
+
all = all_sources
|
|
78
|
+
all.find_all do |event|
|
|
79
|
+
all.none? { |ev| ev.generator.child_object?(event.generator, Roby::EventStructure::Forwarding) }
|
|
257
80
|
end
|
|
258
|
-
|
|
259
|
-
context.compact!
|
|
260
|
-
engine = plan.engine
|
|
261
|
-
if engine.gathering?
|
|
262
|
-
engine.add_event_propagation(false, engine.propagation_sources, self, (context unless context.empty?), nil)
|
|
263
|
-
else
|
|
264
|
-
Roby.synchronize do
|
|
265
|
-
errors = engine.propagate_events do |initial_set|
|
|
266
|
-
engine.add_event_propagation(false, nil, self, (context unless context.empty?), nil)
|
|
267
|
-
end
|
|
268
|
-
if errors.size == 1
|
|
269
|
-
e = errors.first.exception
|
|
270
|
-
raise e.dup, e.message, Roby.filter_backtrace(e.backtrace)
|
|
271
|
-
elsif !errors.empty?
|
|
272
|
-
for e in errors
|
|
273
|
-
pp e.exception
|
|
274
|
-
end
|
|
275
|
-
raise "multiple exceptions"
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
# call-seq:
|
|
282
|
-
# on { |event| ... }
|
|
283
|
-
#
|
|
284
|
-
# Adds an event handler on this generator. The block gets an Event
|
|
285
|
-
# object which describes the parameters of the emission (context value,
|
|
286
|
-
# time, ...). See Event for details.
|
|
287
|
-
def on(signal = nil, time = nil, &handler)
|
|
288
|
-
if signal
|
|
289
|
-
Roby.warn_deprecated "EventGenerator#on only accepts event handlers now. Use #signals to establish signalling"
|
|
290
|
-
self.signals(signal, time)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
if handler
|
|
294
|
-
check_arity(handler, 1)
|
|
295
|
-
self.handlers << handler
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
self
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
# Adds a signal from this event to +generator+. +generator+ must be
|
|
302
|
-
# controlable.
|
|
303
|
-
#
|
|
304
|
-
# If +time+ is given it is either a :delay => time association, or a
|
|
305
|
-
# :at => time association. In the first case, +time+ is a floating-point
|
|
306
|
-
# delay in seconds and in the second case it is a Time object which is
|
|
307
|
-
# the absolute point in time at which this propagation must happen.
|
|
308
|
-
def signals(generator, timespec = nil)
|
|
309
|
-
if !generator.controlable?
|
|
310
|
-
raise EventNotControlable.new(self), "trying to establish a signal from #{self} to #{generator} which is not controllable"
|
|
311
|
-
end
|
|
312
|
-
timespec = ExecutionEngine.validate_timespec(timespec)
|
|
313
|
-
|
|
314
|
-
add_signal generator, timespec
|
|
315
|
-
self
|
|
316
81
|
end
|
|
317
82
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
block.object_id
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
# Returns an event which will be emitted when this event becones
|
|
333
|
-
# unreachable
|
|
334
|
-
def when_unreachable
|
|
335
|
-
# NOTE: the unreachable event is not directly tied to this one from
|
|
336
|
-
# a GC point of view (being able to do this would be useful, but
|
|
337
|
-
# anyway). So, it is possible that it is GCed because the event
|
|
338
|
-
# user did not take care to use it.
|
|
339
|
-
if !@unreachable_event || !@unreachable_event.plan
|
|
340
|
-
result = EventGenerator.new(true)
|
|
341
|
-
if_unreachable(false) do
|
|
342
|
-
if result.plan
|
|
343
|
-
result.emit
|
|
344
|
-
end
|
|
345
|
-
end
|
|
346
|
-
add_causal_link result
|
|
347
|
-
@unreachable_event = result
|
|
83
|
+
# To be used in the event generators ::new methods, when we need to reemit
|
|
84
|
+
# an event while changing its
|
|
85
|
+
def reemit(new_id, new_context = nil)
|
|
86
|
+
if propagation_id != new_id || (new_context && new_context != context)
|
|
87
|
+
new_event = self.dup
|
|
88
|
+
new_event.propagation_id = new_id
|
|
89
|
+
new_event.context = new_context
|
|
90
|
+
new_event.time = Time.now
|
|
91
|
+
new_event
|
|
92
|
+
else
|
|
93
|
+
self
|
|
348
94
|
end
|
|
349
|
-
@unreachable_event
|
|
350
95
|
end
|
|
351
96
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
# Emit +generator+ when +self+ is fired, without calling the command of
|
|
358
|
-
# +generator+, if any.
|
|
359
|
-
#
|
|
360
|
-
# If +timespec+ is given it is either a :delay => time association, or a
|
|
361
|
-
# :at => time association. In the first case, +time+ is a floating-point
|
|
362
|
-
# delay in seconds and in the second case it is a Time object which is
|
|
363
|
-
# the absolute point in time at which this propagation must happen.
|
|
364
|
-
def forward_to(generator, timespec = nil)
|
|
365
|
-
timespec = ExecutionEngine.validate_timespec(timespec)
|
|
366
|
-
add_forwarding generator, timespec
|
|
367
|
-
self
|
|
97
|
+
def name; model.name end
|
|
98
|
+
def model; self.class end
|
|
99
|
+
def inspect # :nodoc:
|
|
100
|
+
"#<#{model.to_s}:0x#{address.to_s(16)} generator=#{generator} model=#{model}"
|
|
368
101
|
end
|
|
369
102
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
ev = EventGenerator.new
|
|
375
|
-
forward_to(ev, :delay => seconds)
|
|
376
|
-
ev
|
|
377
|
-
end
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
# Signals the given target event only once
|
|
381
|
-
def signals_once(signal, delay = nil)
|
|
382
|
-
signals(signal, delay)
|
|
383
|
-
once do |context|
|
|
384
|
-
remove_signal signal
|
|
385
|
-
end
|
|
386
|
-
self
|
|
103
|
+
# Returns an event generator which will be emitted once +time+ seconds
|
|
104
|
+
# after this event has been emitted.
|
|
105
|
+
def after(time)
|
|
106
|
+
State.at t: (self.time + time)
|
|
387
107
|
end
|
|
388
108
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
#
|
|
392
|
-
# Calls the provided event handler only once
|
|
393
|
-
def once(signal = nil, time = nil, &block)
|
|
394
|
-
if signal
|
|
395
|
-
Roby.warn_deprecated "the once(event_name) form has been replaced by #signal_once"
|
|
396
|
-
signal_once(signal, time)
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
once_handlers << block
|
|
400
|
-
self
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
def forward_once(ev, delay = nil)
|
|
404
|
-
Roby.warn_deprecated "#forward_once has been renamed into #forward_to_once"
|
|
405
|
-
forward_to_once(ev)
|
|
109
|
+
def to_s # :nodoc:
|
|
110
|
+
"[#{Roby.format_time(time)} @#{propagation_id}] #{self.class.to_s}: #{context}"
|
|
406
111
|
end
|
|
407
112
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
# Returns the set of events directly related to this one
|
|
420
|
-
def related_events(result = nil); related_objects(nil, result) end
|
|
421
|
-
# Returns the set of tasks directly related to this event
|
|
422
|
-
def related_tasks(result = nil)
|
|
423
|
-
result ||= ValueSet.new
|
|
424
|
-
for ev in related_events
|
|
425
|
-
if ev.respond_to?(:task)
|
|
426
|
-
result << ev.task
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
result
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
# Create a new event object for +context+
|
|
433
|
-
def new(context); Event.new(self, plan.engine.propagation_id, context, Time.now) end
|
|
434
|
-
|
|
435
|
-
# Adds a propagation originating from this event to event propagation
|
|
436
|
-
def add_propagation(only_forward, event, signalled, context, timespec) # :nodoc:
|
|
437
|
-
if self == signalled
|
|
438
|
-
raise PropagationError, "#{self} is trying to signal itself"
|
|
439
|
-
elsif !only_forward && !signalled.controlable?
|
|
440
|
-
raise PropagationError, "trying to signal #{signalled} from #{self}"
|
|
441
|
-
end
|
|
442
|
-
|
|
443
|
-
plan.engine.add_event_propagation(only_forward, [event], signalled, context, timespec)
|
|
444
|
-
end
|
|
445
|
-
private :add_propagation
|
|
446
|
-
|
|
447
|
-
# Do fire this event. It gathers the list of signals that are to
|
|
448
|
-
# be propagated in the next step and calls fired()
|
|
449
|
-
#
|
|
450
|
-
# This method is always called in a propagation context
|
|
451
|
-
def fire(event)
|
|
452
|
-
plan.engine.propagation_context([event]) do |result|
|
|
453
|
-
each_signal do |signalled|
|
|
454
|
-
add_propagation(false, event, signalled, event.context, self[signalled, EventStructure::Signal])
|
|
455
|
-
end
|
|
456
|
-
each_forwarding do |signalled|
|
|
457
|
-
add_propagation(true, event, signalled, event.context, self[signalled, EventStructure::Forwarding])
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
@happened = true
|
|
461
|
-
fired(event)
|
|
462
|
-
|
|
463
|
-
call_handlers(event)
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
private :fire
|
|
468
|
-
|
|
469
|
-
# Call the event handlers defined for this event generator
|
|
470
|
-
def call_handlers(event)
|
|
471
|
-
# Since we are in a gathering context, call
|
|
472
|
-
# to other objects are not done, but gathered in the
|
|
473
|
-
# :propagation TLS
|
|
474
|
-
each_handler do |h|
|
|
475
|
-
begin
|
|
476
|
-
h.call(event)
|
|
477
|
-
rescue Exception => e
|
|
478
|
-
plan.engine.add_error( EventHandlerError.new(e, event) )
|
|
479
|
-
end
|
|
480
|
-
end
|
|
481
|
-
each_once_handler do |h|
|
|
482
|
-
begin
|
|
483
|
-
h.call(event)
|
|
484
|
-
rescue Exception => e
|
|
485
|
-
plan.engine_add_error( EventHandlerError.new(e, event) )
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
once_handlers.clear
|
|
489
|
-
end
|
|
490
|
-
|
|
491
|
-
# Raises an exception object when an event whose command has been
|
|
492
|
-
# called won't be emitted (ever)
|
|
493
|
-
def emit_failed(*what)
|
|
494
|
-
what, message = *what
|
|
495
|
-
what ||= EmissionFailed
|
|
496
|
-
|
|
497
|
-
if !message && !(what.kind_of?(Class) || what.kind_of?(Exception))
|
|
498
|
-
message = what.to_str
|
|
499
|
-
what = EmissionFailed
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
failure_message =
|
|
503
|
-
if message then "failed to emit #{self}: #{message}"
|
|
504
|
-
elsif what.respond_to?(:message) then "failed to emit #{self}: #{what.message}"
|
|
505
|
-
else "failed to emit #{self}: #{message}"
|
|
113
|
+
def pretty_print(pp, with_context = true) # :nodoc:
|
|
114
|
+
pp.text "[#{Roby.format_time(time)} @#{propagation_id}] #{self.class}"
|
|
115
|
+
if with_context && context
|
|
116
|
+
pp.breakable
|
|
117
|
+
pp.text "with context"
|
|
118
|
+
pp.nest(2) do
|
|
119
|
+
pp.text " "
|
|
120
|
+
pp.seplist(context) do |v|
|
|
121
|
+
v.pretty_print(pp)
|
|
122
|
+
end
|
|
506
123
|
end
|
|
507
|
-
|
|
508
|
-
error = if Class === what then what.new(nil, self)
|
|
509
|
-
else what
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
new_error = error.exception failure_message
|
|
513
|
-
new_error.set_backtrace error.backtrace
|
|
514
|
-
error = new_error
|
|
515
|
-
|
|
516
|
-
if !error.kind_of?(LocalizedError)
|
|
517
|
-
error = EmissionFailed.new(error, self)
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
plan.engine.add_error(error)
|
|
521
|
-
ensure
|
|
522
|
-
@pending = false
|
|
523
|
-
end
|
|
524
|
-
|
|
525
|
-
# Emits the event regardless of wether we are in a propagation context
|
|
526
|
-
# or not. Returns true to match the behavior of #call_without_propagation
|
|
527
|
-
#
|
|
528
|
-
# This is used by event propagation. Do not call directly: use #call instead
|
|
529
|
-
def emit_without_propagation(context)
|
|
530
|
-
check_emission_validity
|
|
531
|
-
|
|
532
|
-
if !executable?
|
|
533
|
-
raise EventNotExecutable.new(self), "#emit called on #{self} which is not executable"
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
emitting(context)
|
|
537
|
-
|
|
538
|
-
# Create the event object
|
|
539
|
-
event = new(context)
|
|
540
|
-
unless event.respond_to?(:context)
|
|
541
|
-
raise TypeError, "#{event} is not a valid event object in #{self}"
|
|
542
|
-
end
|
|
543
|
-
event.sources = plan.engine.propagation_source_events
|
|
544
|
-
fire(event)
|
|
545
|
-
|
|
546
|
-
true
|
|
547
|
-
|
|
548
|
-
ensure
|
|
549
|
-
@pending = false
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
# Emit the event with +context+ as the event context
|
|
553
|
-
def emit(*context)
|
|
554
|
-
check_emission_validity
|
|
555
|
-
|
|
556
|
-
# This test must not be done in #emit_without_propagation as the
|
|
557
|
-
# other ones: it is possible, using Distributed.update, to disable
|
|
558
|
-
# ownership tests, but that does not work if the test is in
|
|
559
|
-
# #emit_without_propagation
|
|
560
|
-
if !self_owned?
|
|
561
|
-
raise OwnershipError, "cannot emit an event we don't own. #{self} is owned by #{owners}"
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
context.compact!
|
|
565
|
-
engine = plan.engine
|
|
566
|
-
if engine.gathering?
|
|
567
|
-
engine.add_event_propagation(true, engine.propagation_sources, self, (context unless context.empty?), nil)
|
|
568
|
-
else
|
|
569
|
-
Roby.synchronize do
|
|
570
|
-
errors = engine.propagate_events do |initial_set|
|
|
571
|
-
engine.add_event_propagation(true, engine.propagation_sources, self, (context unless context.empty?), nil)
|
|
572
|
-
end
|
|
573
|
-
if errors.size == 1
|
|
574
|
-
e = errors.first.exception
|
|
575
|
-
raise e.dup, e.message, Roby.filter_backtrace(e.backtrace)
|
|
576
|
-
elsif !errors.empty?
|
|
577
|
-
for e in errors
|
|
578
|
-
pp e.exception
|
|
579
|
-
end
|
|
580
|
-
raise "multiple exceptions"
|
|
581
|
-
end
|
|
582
|
-
end
|
|
583
|
-
end
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
# Deprecated. Instead of using
|
|
587
|
-
# dest.emit_on(source)
|
|
588
|
-
# now use
|
|
589
|
-
# source.forward_to(dest)
|
|
590
|
-
def emit_on(generator, timespec = nil)
|
|
591
|
-
Roby.warn_deprecated "a.emit_on(b) has been replaced by b.forward_to(a)"
|
|
592
|
-
generator.forward(self, timespec)
|
|
593
|
-
self
|
|
594
|
-
end
|
|
595
|
-
|
|
596
|
-
# Sets up +ev+ and +self+ to represent that the command of +self+ is to
|
|
597
|
-
# be achieved by the emission of +ev+. It is to be used in a command
|
|
598
|
-
# handler:
|
|
599
|
-
#
|
|
600
|
-
# event :start do |context|
|
|
601
|
-
# init = <create an initialization event>
|
|
602
|
-
# event(:start).achieve_with(init)
|
|
603
|
-
# end
|
|
604
|
-
#
|
|
605
|
-
# If +ev+ becomes unreachable, an EmissionFailed exception will be
|
|
606
|
-
# raised. If a block is given, it is supposed to return the context of
|
|
607
|
-
# the event emitted by +self+, given the context of the event emitted
|
|
608
|
-
# by +ev+.
|
|
609
|
-
#
|
|
610
|
-
# From an event propagation point of view, it looks like:
|
|
611
|
-
# TODO: add a figure
|
|
612
|
-
def achieve_with(ev)
|
|
613
|
-
stack = caller(1)
|
|
614
|
-
if block_given?
|
|
615
|
-
ev.add_causal_link self
|
|
616
|
-
ev.once do |context|
|
|
617
|
-
self.emit(yield(context))
|
|
618
|
-
end
|
|
619
|
-
else
|
|
620
|
-
ev.forward_to_once self
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
ev.if_unreachable(true) do |reason|
|
|
624
|
-
emit_failed(UnreachableEvent.new(self, reason))
|
|
625
|
-
end
|
|
626
|
-
end
|
|
627
|
-
# For backwards compatibility. Use #achieve_with.
|
|
628
|
-
def realize_with(task); achieve_with(task) end
|
|
629
|
-
|
|
630
|
-
# A [time, event] array of past event emitted by this object
|
|
631
|
-
attribute(:history) { Array.new }
|
|
632
|
-
# True if this event has been emitted once.
|
|
633
|
-
attr_predicate :happened
|
|
634
|
-
# Last event to have been emitted by this generator
|
|
635
|
-
def last; history.last end
|
|
636
|
-
|
|
637
|
-
# Defines a precondition handler for this event. Precondition handlers
|
|
638
|
-
# are blocks which are called just before the event command is called.
|
|
639
|
-
# If the handler returns false, the calling is aborted by a
|
|
640
|
-
# PreconditionFailed exception
|
|
641
|
-
def precondition(reason = nil, &block)
|
|
642
|
-
@preconditions << [reason, block]
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
# Yields all precondition handlers defined for this generator
|
|
646
|
-
def each_precondition # :yield:reason, block
|
|
647
|
-
@preconditions.each { |o| yield(o) }
|
|
648
|
-
end
|
|
649
|
-
|
|
650
|
-
# Call #postpone in #calling to announce that the event should not be
|
|
651
|
-
# called now, but should be called back when +generator+ is emitted
|
|
652
|
-
#
|
|
653
|
-
# A reason string can be provided for debugging purposes
|
|
654
|
-
def postpone(generator, reason = nil)
|
|
655
|
-
generator.signals self
|
|
656
|
-
yield if block_given?
|
|
657
|
-
throw :postponed, [generator, reason]
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
# Hook called when the event has been postponed. See #postpone
|
|
661
|
-
def postponed(context, generator, reason); super if defined? super end
|
|
662
|
-
|
|
663
|
-
# Call this method in the #calling hook to cancel calling the event
|
|
664
|
-
# command. This raises an EventCanceled exception with +reason+ for
|
|
665
|
-
# message
|
|
666
|
-
def cancel(reason = nil)
|
|
667
|
-
raise EventCanceled.new(self), (reason || "event canceled")
|
|
668
|
-
end
|
|
669
|
-
|
|
670
|
-
# Hook called when this event generator is called (i.e. the associated
|
|
671
|
-
# command is), before the command is actually called. Think of it as a
|
|
672
|
-
# pre-call hook.
|
|
673
|
-
#
|
|
674
|
-
# The #postpone method can be called in this hook
|
|
675
|
-
def calling(context)
|
|
676
|
-
super if defined? super
|
|
677
|
-
each_precondition do |reason, block|
|
|
678
|
-
result = begin
|
|
679
|
-
block.call(self, context)
|
|
680
|
-
rescue EventPreconditionFailed => e
|
|
681
|
-
e.generator = self
|
|
682
|
-
raise
|
|
683
|
-
end
|
|
684
|
-
|
|
685
|
-
if !result
|
|
686
|
-
raise EventPreconditionFailed.new(self), "precondition #{reason} failed"
|
|
687
|
-
end
|
|
688
|
-
end
|
|
689
|
-
end
|
|
690
|
-
|
|
691
|
-
# Hook called just after the event command has been called
|
|
692
|
-
def called(context); super if defined? super end
|
|
693
|
-
|
|
694
|
-
# Hook called when this generator has been fired. +event+ is the Event object
|
|
695
|
-
# which has been created.
|
|
696
|
-
def fired(event)
|
|
697
|
-
unreachable_handlers.delete_if { |cancel, _| cancel }
|
|
698
|
-
|
|
699
|
-
history << event
|
|
700
|
-
if EventGenerator.event_gathering.has_key?(event.generator)
|
|
701
|
-
for c in EventGenerator.event_gathering[event.generator]
|
|
702
|
-
c << event
|
|
703
|
-
end
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
super if defined? super
|
|
707
|
-
end
|
|
708
|
-
|
|
709
|
-
# Hook called just before the +to+ generator is signalled by this
|
|
710
|
-
# generator. +event+ is the Event object which has been generated by
|
|
711
|
-
# this model
|
|
712
|
-
def signalling(event, to); super if defined? super end
|
|
713
|
-
|
|
714
|
-
# Hook called just before the propagation forwards +self+ to +to+.
|
|
715
|
-
# +event+ is the Event object which has been generated by this model
|
|
716
|
-
def forwarding(event, to); super if defined? super end
|
|
717
|
-
|
|
718
|
-
# Hook called when this event will be emitted
|
|
719
|
-
def emitting(context); super if defined? super end
|
|
720
|
-
|
|
721
|
-
# call-seq:
|
|
722
|
-
# filter(new_context) => filtering_event
|
|
723
|
-
# filter { |context| ... } => filtering_event
|
|
724
|
-
#
|
|
725
|
-
# Returns an event generator which forwards the events fired by this
|
|
726
|
-
# one, but by changing the context. In the first form, the new context
|
|
727
|
-
# is set to +new_context+. In the second form, to the value returned
|
|
728
|
-
# by the given block
|
|
729
|
-
def filter(*new_context, &block)
|
|
730
|
-
filter = FilterGenerator.new(new_context, &block)
|
|
731
|
-
self.signals(filter)
|
|
732
|
-
filter
|
|
733
|
-
end
|
|
734
|
-
|
|
735
|
-
# Returns a new event generator which emits until the +limit+ event is
|
|
736
|
-
# sent
|
|
737
|
-
#
|
|
738
|
-
# source, ev, limit = (1..3).map { EventGenerator.new(true) }
|
|
739
|
-
# ev.until(limit).on { STDERR.puts "FIRED !!!" }
|
|
740
|
-
# source.signals ev
|
|
741
|
-
#
|
|
742
|
-
# Will do
|
|
743
|
-
#
|
|
744
|
-
# source.call # => FIRED !!!
|
|
745
|
-
# limit.emit
|
|
746
|
-
# source.call # =>
|
|
747
|
-
#
|
|
748
|
-
# See also UntilGenerator
|
|
749
|
-
def until(limit); UntilGenerator.new(self, limit) end
|
|
750
|
-
|
|
751
|
-
# Checks that ownership allows to add the self => child relation
|
|
752
|
-
def add_child_object(child, type, info) # :nodoc:
|
|
753
|
-
unless child.read_write?
|
|
754
|
-
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})"
|
|
755
|
-
end
|
|
756
|
-
|
|
757
|
-
super
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
def added_child_object(child, relations, info) # :nodoc:
|
|
761
|
-
super if defined? super
|
|
762
|
-
if relations.include?(Roby::EventStructure::Precedence) && plan && plan.engine
|
|
763
|
-
plan.engine.event_ordering.clear
|
|
764
|
-
end
|
|
765
|
-
end
|
|
766
|
-
def removed_child_object(child, relations) # :nodoc:
|
|
767
|
-
super if defined? super
|
|
768
|
-
if relations.include?(Roby::EventStructure::Precedence) && plan && plan.engine
|
|
769
|
-
plan.engine.event_ordering.clear
|
|
770
124
|
end
|
|
771
125
|
end
|
|
772
126
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
for ev in events
|
|
777
|
-
event_gathering[ev] << collection
|
|
778
|
-
end
|
|
779
|
-
end
|
|
780
|
-
# Remove the notifications that have been registered for +collection+
|
|
781
|
-
def self.remove_event_gathering(collection)
|
|
782
|
-
@@event_gathering.delete_if do |_, collections|
|
|
783
|
-
collections.delete(collection)
|
|
784
|
-
collections.empty?
|
|
785
|
-
end
|
|
786
|
-
end
|
|
787
|
-
# An array of [collection, events] elements, collection being the
|
|
788
|
-
# object in which we must add the fired events, and events the set of
|
|
789
|
-
# event generators +collection+ is listening for.
|
|
790
|
-
def self.event_gathering; @@event_gathering end
|
|
791
|
-
|
|
792
|
-
attr_predicate :unreachable?
|
|
793
|
-
# If the event became unreachable, this holds the reason for its
|
|
794
|
-
# unreachability, if that reason is known. This reason is always an
|
|
795
|
-
# Event instance which represents the emission that triggered this
|
|
796
|
-
# unreachability.
|
|
797
|
-
attr_reader :unreachability_reason
|
|
798
|
-
|
|
799
|
-
# Called internally when the event becomes unreachable
|
|
800
|
-
def unreachable!(reason = nil, plan = self.plan)
|
|
801
|
-
return if @unreachable
|
|
802
|
-
@unreachable = true
|
|
803
|
-
@unreachability_reason = reason
|
|
804
|
-
|
|
805
|
-
EventGenerator.event_gathering.delete(self)
|
|
806
|
-
|
|
807
|
-
unreachable_handlers.each do |_, block|
|
|
808
|
-
begin
|
|
809
|
-
block.call(reason)
|
|
810
|
-
rescue LocalizedError => e
|
|
811
|
-
plan.engine.add_error(e)
|
|
812
|
-
rescue Exception => e
|
|
813
|
-
plan.engine.add_error(EventHandlerError.new(e, self))
|
|
814
|
-
end
|
|
815
|
-
end
|
|
816
|
-
unreachable_handlers.clear
|
|
817
|
-
end
|
|
818
|
-
|
|
819
|
-
def pretty_print(pp) # :nodoc:
|
|
820
|
-
pp.text to_s
|
|
821
|
-
pp.group(2, ' {', '}') do
|
|
822
|
-
pp.breakable
|
|
823
|
-
pp.text "owners: "
|
|
824
|
-
pp.seplist(owners) { |r| pp.text r.to_s }
|
|
825
|
-
|
|
826
|
-
pp.breakable
|
|
827
|
-
pp.text "relations: "
|
|
828
|
-
pp.seplist(relations) { |r| pp.text r.name }
|
|
829
|
-
end
|
|
830
|
-
end
|
|
831
|
-
end
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
# This generator reemits an event after having changed its context. See
|
|
835
|
-
# EventGenerator#filter for a more complete explanation
|
|
836
|
-
class FilterGenerator < EventGenerator
|
|
837
|
-
def initialize(user_context, &block)
|
|
838
|
-
if block && !user_context.empty?
|
|
839
|
-
raise ArgumentError, "you must set either the filter or the value, not both"
|
|
840
|
-
end
|
|
841
|
-
|
|
842
|
-
if block
|
|
843
|
-
super() do |context|
|
|
844
|
-
context = context.map do |val|
|
|
845
|
-
block.call(val)
|
|
846
|
-
end
|
|
847
|
-
emit(*context)
|
|
848
|
-
end
|
|
849
|
-
else
|
|
850
|
-
super() do
|
|
851
|
-
emit(*user_context)
|
|
852
|
-
end
|
|
853
|
-
end
|
|
854
|
-
end
|
|
855
|
-
end
|
|
856
|
-
|
|
857
|
-
# Event generator which fires when all its source events have fired
|
|
858
|
-
# See EventGenerator#& for a more complete description
|
|
859
|
-
class AndGenerator < EventGenerator
|
|
860
|
-
def initialize
|
|
861
|
-
super do |context|
|
|
862
|
-
emit_if_achieved(context)
|
|
863
|
-
end
|
|
864
|
-
|
|
865
|
-
# This hash is a event_generator => event mapping of the last
|
|
866
|
-
# events of each event generator. We compare the event stored in
|
|
867
|
-
# this hash with the last events of each source to know if the
|
|
868
|
-
# source fired since it has been added to this AndGenerator
|
|
869
|
-
@events = Hash.new
|
|
870
|
-
|
|
871
|
-
# This flag is true unless we are not waiting for the emission
|
|
872
|
-
# anymore.
|
|
873
|
-
@active = true
|
|
874
|
-
end
|
|
875
|
-
|
|
876
|
-
# Resets the waiting. If the event has already been emitted, it re-arms
|
|
877
|
-
# it.
|
|
878
|
-
def reset
|
|
879
|
-
@active = true
|
|
880
|
-
each_parent_object(EventStructure::Signal) do |source|
|
|
881
|
-
@events[source] = source.last
|
|
882
|
-
if source.respond_to?(:reset)
|
|
883
|
-
source.reset
|
|
884
|
-
end
|
|
885
|
-
end
|
|
886
|
-
end
|
|
887
|
-
|
|
888
|
-
def emit_if_achieved(context) # :nodoc:
|
|
889
|
-
return unless @active
|
|
890
|
-
each_parent_object(EventStructure::Signal) do |source|
|
|
891
|
-
return if @events[source] == source.last
|
|
892
|
-
end
|
|
893
|
-
@active = false
|
|
894
|
-
emit(nil)
|
|
895
|
-
end
|
|
896
|
-
|
|
897
|
-
def empty?; events.empty? end
|
|
898
|
-
|
|
899
|
-
# Adds a new source to +events+ when a source event is added
|
|
900
|
-
def added_parent_object(parent, relations, info) # :nodoc:
|
|
901
|
-
super if defined? super
|
|
902
|
-
return unless relations.include?(EventStructure::Signal)
|
|
903
|
-
@events[parent] = parent.last
|
|
904
|
-
|
|
905
|
-
# If the parent is unreachable, check that it has neither been
|
|
906
|
-
# removed, nor it has been emitted
|
|
907
|
-
parent.if_unreachable(true) do |reason|
|
|
908
|
-
if @events[parent] == parent.last
|
|
909
|
-
unreachable!(reason || parent)
|
|
910
|
-
end
|
|
911
|
-
end
|
|
912
|
-
end
|
|
913
|
-
|
|
914
|
-
# Removes a source from +events+ when the source is removed
|
|
915
|
-
def removed_parent_object(parent, relations) # :nodoc:
|
|
916
|
-
super if defined? super
|
|
917
|
-
return unless relations.include?(EventStructure::Signal)
|
|
918
|
-
@events.delete(parent)
|
|
919
|
-
end
|
|
920
|
-
|
|
921
|
-
# The set of source events
|
|
922
|
-
def events; parent_objects(EventStructure::Signal) end
|
|
923
|
-
# The set of events which we are waiting for
|
|
924
|
-
def waiting; parent_objects(EventStructure::Signal).find_all { |ev| @events[ev] == ev.last } end
|
|
925
|
-
|
|
926
|
-
# Add a new source to this generator
|
|
927
|
-
def << (generator)
|
|
928
|
-
generator.add_signal self
|
|
929
|
-
self
|
|
930
|
-
end
|
|
931
|
-
end
|
|
932
|
-
|
|
933
|
-
# Event generator which fires when the first of its source events fires.
|
|
934
|
-
# All event generators which signal this one are considered as sources.
|
|
935
|
-
#
|
|
936
|
-
# See also EventGenerator#| and #<<
|
|
937
|
-
class OrGenerator < EventGenerator
|
|
938
|
-
# Creates a new OrGenerator without any sources.
|
|
939
|
-
def initialize
|
|
940
|
-
super do |context|
|
|
941
|
-
emit_if_first(context)
|
|
942
|
-
end
|
|
943
|
-
@active = true
|
|
944
|
-
end
|
|
945
|
-
|
|
946
|
-
# True if there is no source event for this combinator.
|
|
947
|
-
def empty?; parent_objects(EventStructure::Signal).empty? end
|
|
948
|
-
|
|
949
|
-
# Reset its state, so as to behave as if no source has ever
|
|
950
|
-
# been emitted.
|
|
951
|
-
def reset
|
|
952
|
-
@active = true
|
|
953
|
-
each_parent_object(EventStructure::Signal) do |source|
|
|
954
|
-
if source.respond_to?(:reset)
|
|
955
|
-
source.reset
|
|
956
|
-
end
|
|
957
|
-
end
|
|
958
|
-
end
|
|
959
|
-
|
|
960
|
-
def emit_if_first(context) # :nodoc:
|
|
961
|
-
return unless @active
|
|
962
|
-
@active = false
|
|
963
|
-
emit(context)
|
|
964
|
-
end
|
|
965
|
-
|
|
966
|
-
def added_parent_object(parent, relations, info) # :nodoc:
|
|
967
|
-
super if defined? super
|
|
968
|
-
return unless relations.include?(EventStructure::Signal)
|
|
969
|
-
|
|
970
|
-
parent.if_unreachable(true) do |reason|
|
|
971
|
-
if !happened? && parent_objects(EventStructure::Signal).all? { |ev| ev.unreachable? }
|
|
972
|
-
unreachable!(reason || parent)
|
|
973
|
-
end
|
|
974
|
-
end
|
|
975
|
-
end
|
|
976
|
-
|
|
977
|
-
# Adds +generator+ to the sources of this event
|
|
978
|
-
def << (generator)
|
|
979
|
-
generator.add_signal self
|
|
980
|
-
self
|
|
981
|
-
end
|
|
982
|
-
end
|
|
983
|
-
|
|
984
|
-
# This event generator combines a source and a limit in a temporal pattern.
|
|
985
|
-
# The generator acts as a pass-through for the source, until the limit is
|
|
986
|
-
# itself emitted. It means that:
|
|
987
|
-
#
|
|
988
|
-
# * before the limit is emitted, the generator will emit each time its
|
|
989
|
-
# source emits
|
|
990
|
-
# * since the point where the limit is emitted, the generator
|
|
991
|
-
# does not emit anymore
|
|
992
|
-
#
|
|
993
|
-
# See also EventGenerator#until
|
|
994
|
-
class UntilGenerator < Roby::EventGenerator
|
|
995
|
-
# Creates a until generator for the given source and limit event
|
|
996
|
-
# generators
|
|
997
|
-
def initialize(source = nil, limit = nil)
|
|
998
|
-
super() do |context|
|
|
999
|
-
plan.remove_object(self) if plan
|
|
1000
|
-
clear_relations
|
|
1001
|
-
end
|
|
1002
|
-
|
|
1003
|
-
if source && limit
|
|
1004
|
-
source.forward_to(self)
|
|
1005
|
-
limit.signals(self)
|
|
1006
|
-
end
|
|
1007
|
-
end
|
|
1008
|
-
end
|
|
127
|
+
def to_execution_exception
|
|
128
|
+
generator.to_execution_exception
|
|
129
|
+
end
|
|
1009
130
|
|
|
1010
|
-
|
|
1011
|
-
|
|
131
|
+
def to_execution_exception_matcher
|
|
132
|
+
generator.to_execution_exception_matcher
|
|
133
|
+
end
|
|
1012
134
|
end
|
|
1013
135
|
end
|
|
1014
136
|
|