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,591 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
# This module defines functionality that can be mixed-in other objects to
|
|
3
|
+
# have an 'automatically extensible struct' behaviour, i.e.
|
|
4
|
+
#
|
|
5
|
+
# Roby::OpenStruct objects are OpenStructs where attributes have a default
|
|
6
|
+
# class. They are used to build hierarchical data structure on-the-fly.
|
|
7
|
+
# Additionally, they may have a model which constrains what can be created
|
|
8
|
+
# on them
|
|
9
|
+
#
|
|
10
|
+
# For instance
|
|
11
|
+
#
|
|
12
|
+
# @example create an openstruct and assign a value in the hierarchy
|
|
13
|
+
# root = Roby::OpenStruct.new
|
|
14
|
+
# root.child.value = 42
|
|
15
|
+
#
|
|
16
|
+
# However, you *cannot* check if a value is defined or not with
|
|
17
|
+
#
|
|
18
|
+
# if (root.child)
|
|
19
|
+
# <do something>
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# You'll have to test with respond_to? or field_name?. The second one will
|
|
23
|
+
# return true only if the attribute is defined <b>and</b> it is not false
|
|
24
|
+
#
|
|
25
|
+
# @example test for the presence of a value in the hierarchy
|
|
26
|
+
# if root.respond_to?(:child)
|
|
27
|
+
# <do something if child has been set>
|
|
28
|
+
# end
|
|
29
|
+
# if root.child?
|
|
30
|
+
# <do something if child has been set and is non-nil>
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# == Handling of methods defined on parents
|
|
34
|
+
#
|
|
35
|
+
# Methods defined in Object or Kernel are automatically overriden if needed.
|
|
36
|
+
# For instance, if you're managing a (x, y, z) position using OpenStruct,
|
|
37
|
+
# you will want YAML#y to *not* get in the way. The exceptions are the methods
|
|
38
|
+
# listed in NOT_OVERRIDABLE
|
|
39
|
+
#
|
|
40
|
+
class OpenStruct
|
|
41
|
+
attr_reader :model
|
|
42
|
+
|
|
43
|
+
# +attach_to+ and +attach_name+
|
|
44
|
+
# are used so that
|
|
45
|
+
# root = OpenStruct.new
|
|
46
|
+
# root.bla
|
|
47
|
+
# does *not* add a +bla+ attribute to root, while the following constructs
|
|
48
|
+
# root.bla.test = 20
|
|
49
|
+
# bla = root.bla
|
|
50
|
+
# bla.test = 20
|
|
51
|
+
# does
|
|
52
|
+
#
|
|
53
|
+
# Note, however that
|
|
54
|
+
# bla = root.bla
|
|
55
|
+
# root.bla = 10
|
|
56
|
+
# bla.test = 20
|
|
57
|
+
#
|
|
58
|
+
# will *not* make root.bla be the +bla+ object. And that
|
|
59
|
+
#
|
|
60
|
+
# bla = root.bla
|
|
61
|
+
# root.stable!
|
|
62
|
+
# bla.test = 20
|
|
63
|
+
#
|
|
64
|
+
# will not fail
|
|
65
|
+
def initialize(model = nil, attach_to = nil, attach_name = nil) # :nodoc
|
|
66
|
+
clear
|
|
67
|
+
|
|
68
|
+
@model = model
|
|
69
|
+
@observers = Hash.new { |h, k| h[k] = [] }
|
|
70
|
+
@filters = Hash.new
|
|
71
|
+
|
|
72
|
+
if attach_to
|
|
73
|
+
link_to(attach_to, attach_name)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if model
|
|
77
|
+
attach_model
|
|
78
|
+
attach
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def clear
|
|
83
|
+
@attach_as = nil
|
|
84
|
+
@stable = false
|
|
85
|
+
@members = Hash.new
|
|
86
|
+
@pending = Hash.new
|
|
87
|
+
@aliases = Hash.new
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def clear_model
|
|
91
|
+
@model = nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def pretty_print(pp)
|
|
95
|
+
pp.seplist(@members) do |child|
|
|
96
|
+
child_name, child_obj = *child
|
|
97
|
+
if child_obj.kind_of?(OpenStruct)
|
|
98
|
+
pp.text "#{child_name} >"
|
|
99
|
+
else
|
|
100
|
+
pp.text "#{child_name}"
|
|
101
|
+
end
|
|
102
|
+
pp.breakable
|
|
103
|
+
child_obj.pretty_print(pp)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self._load(io)
|
|
108
|
+
marshalled_members, aliases = Marshal.load(io)
|
|
109
|
+
|
|
110
|
+
result = new
|
|
111
|
+
marshalled_members.each do |name, marshalled_field|
|
|
112
|
+
begin
|
|
113
|
+
value = Marshal.load(marshalled_field)
|
|
114
|
+
if value.kind_of?(OpenStruct)
|
|
115
|
+
value.attach_to(result, name)
|
|
116
|
+
else
|
|
117
|
+
result.set(name, value)
|
|
118
|
+
end
|
|
119
|
+
rescue Exception
|
|
120
|
+
Roby::DRoby.warn "cannot load #{name} #{marshalled_field}: #{$!.message}"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
result.instance_variable_set("@aliases", aliases)
|
|
125
|
+
result
|
|
126
|
+
|
|
127
|
+
rescue Exception
|
|
128
|
+
Roby::DRoby.warn "cannot load #{marshalled_members} #{io}: #{$!.message}"
|
|
129
|
+
raise
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def _dump(lvl = -1)
|
|
133
|
+
marshalled_members = @members.map do |name, value|
|
|
134
|
+
[name, Marshal.dump(value)] rescue nil
|
|
135
|
+
end
|
|
136
|
+
marshalled_members.compact!
|
|
137
|
+
Marshal.dump([marshalled_members, @aliases])
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
attr_reader :attach_as, :__parent_struct, :__parent_name
|
|
141
|
+
|
|
142
|
+
# Create a model structure and associate it with this openstruct
|
|
143
|
+
def new_model
|
|
144
|
+
if !@model
|
|
145
|
+
@model = create_model
|
|
146
|
+
attach_model
|
|
147
|
+
end
|
|
148
|
+
@model
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def create_model
|
|
152
|
+
OpenStructModel.new
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Do the necessary initialization after having added a model to this
|
|
156
|
+
# task
|
|
157
|
+
def attach_model
|
|
158
|
+
model.each_member do |name, field|
|
|
159
|
+
case field
|
|
160
|
+
when OpenStructModel
|
|
161
|
+
@members[name] ||= create_subfield(name)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Trigger updating the structure whenever the state model is
|
|
166
|
+
# changed
|
|
167
|
+
model.on_change(nil, false) do |name, value|
|
|
168
|
+
if value.kind_of?(OpenStructModel)
|
|
169
|
+
@members[name] ||= create_subfield(name)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def link_to(parent, name)
|
|
175
|
+
@attach_as = [parent, name]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def attach_to(parent, name)
|
|
179
|
+
link_to(parent, name)
|
|
180
|
+
attach
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# When a field is dynamically created by #method_missing, it is created
|
|
184
|
+
# in a pending state, in which it is not yet attached to its parent
|
|
185
|
+
# structure
|
|
186
|
+
#
|
|
187
|
+
# This method does the attachment. It calls #attach_child on the parent
|
|
188
|
+
# to notify it
|
|
189
|
+
def attach
|
|
190
|
+
if @attach_as
|
|
191
|
+
@__parent_struct, @__parent_name = @attach_as
|
|
192
|
+
@attach_as = nil
|
|
193
|
+
__parent_struct.attach_child(__parent_name, self)
|
|
194
|
+
if @model
|
|
195
|
+
@model.attach
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# When a field is dynamically created by #method_missing, it is created
|
|
201
|
+
# in a pending state, in which it is not yet attached to its parent
|
|
202
|
+
# structure
|
|
203
|
+
#
|
|
204
|
+
# This method makes sure that the field will never be attached to the
|
|
205
|
+
# parent. It has no effect once #attach has been called
|
|
206
|
+
def detach
|
|
207
|
+
@attach_as = nil
|
|
208
|
+
end
|
|
209
|
+
# Called by a child when #attach is called
|
|
210
|
+
def attach_child(name, obj)
|
|
211
|
+
@members[name.to_s] = obj
|
|
212
|
+
updated(name, obj)
|
|
213
|
+
end
|
|
214
|
+
protected :detach, :attach_as
|
|
215
|
+
|
|
216
|
+
def __root?
|
|
217
|
+
!__parent
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def __parent
|
|
221
|
+
@__parent_struct ||
|
|
222
|
+
(@attach_as[0] if @attach_as)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def __root
|
|
226
|
+
if p = __parent
|
|
227
|
+
return p.__root
|
|
228
|
+
else self
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# If true, this field is attached to a parent structure
|
|
233
|
+
def attached?
|
|
234
|
+
!!@__parent_struct
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Internal data structure used to register the observers defined with
|
|
238
|
+
# #on_change
|
|
239
|
+
class Observer
|
|
240
|
+
def recursive?; !!@recursive end
|
|
241
|
+
def initialize(recursive, block)
|
|
242
|
+
@recursive, @block = recursive, block
|
|
243
|
+
end
|
|
244
|
+
def call(name, value)
|
|
245
|
+
@block.call(name, value)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Call +block+ with the new value if +name+ changes
|
|
250
|
+
#
|
|
251
|
+
# If name is not given, it will be called for any change
|
|
252
|
+
def on_change(name = nil, recursive = false, &block)
|
|
253
|
+
attach
|
|
254
|
+
name = name.to_s if name
|
|
255
|
+
@observers[name] << Observer.new(recursive, block)
|
|
256
|
+
self
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Converts this OpenStruct into a corresponding hash, where all
|
|
260
|
+
# keys are symbols. If +recursive+ is true, any member which responds
|
|
261
|
+
# to #to_hash will be converted as well
|
|
262
|
+
def to_hash(recursive = true)
|
|
263
|
+
result = Hash.new
|
|
264
|
+
@members.each do |k, v|
|
|
265
|
+
result[k.to_sym] = if recursive && v.respond_to?(:to_hash)
|
|
266
|
+
v.to_hash
|
|
267
|
+
else v
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
result
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Iterates on all defined members of this object
|
|
274
|
+
def each_member(&block)
|
|
275
|
+
@members.each(&block)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Update a set of values on this struct
|
|
279
|
+
# If a hash is given, it is an name => value hash of attribute
|
|
280
|
+
# values. A given block is yield with self, so that the construct
|
|
281
|
+
#
|
|
282
|
+
# my.extendable.struct.very.deep.update do |deep|
|
|
283
|
+
# <update deep>
|
|
284
|
+
# end
|
|
285
|
+
#
|
|
286
|
+
# can be used
|
|
287
|
+
def update(hash = nil)
|
|
288
|
+
attach
|
|
289
|
+
hash.each { |k, v| send("#{k}=", v) } if hash
|
|
290
|
+
yield(self) if block_given?
|
|
291
|
+
self
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def delete(name = nil)
|
|
295
|
+
raise TypeError, "#{self} is stable" if stable?
|
|
296
|
+
if name
|
|
297
|
+
name = name.to_s
|
|
298
|
+
child = @members.delete(name) ||
|
|
299
|
+
@pending.delete(name)
|
|
300
|
+
if child && child.respond_to?(:detached!)
|
|
301
|
+
child.detached!
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# We don't detach aliases
|
|
305
|
+
if !child && !@aliases.delete(name)
|
|
306
|
+
raise ArgumentError, "no such child #{name}"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# and remove aliases that point to +name+
|
|
310
|
+
@aliases.delete_if { |_, pointed_to| pointed_to == name }
|
|
311
|
+
else
|
|
312
|
+
if __parent_struct
|
|
313
|
+
__parent_struct.delete(__parent_name)
|
|
314
|
+
elsif @attach_as
|
|
315
|
+
@attach_as.first.delete(@attach_as.last)
|
|
316
|
+
else
|
|
317
|
+
raise ArgumentError, "#{self} is attached to nothing"
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def detached!
|
|
323
|
+
@__parent_struct, @__parent_name, @attach_as = nil
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Define a filter for the +name+ attribute on self. The given block is
|
|
327
|
+
# called when the attribute is written with both the attribute name and
|
|
328
|
+
# value. It should return the value that should actually be written, and
|
|
329
|
+
# raise an exception if the new value is invalid.
|
|
330
|
+
def filter(name, &block)
|
|
331
|
+
@filters[name.to_s] = block
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Define a filter for the +name+ attribute on self. The given block is
|
|
335
|
+
# called when the attribute is written with both the attribute name and
|
|
336
|
+
# value. It should return the value that should actually be written, and
|
|
337
|
+
# raise an exception if the new value is invalid.
|
|
338
|
+
def global_filter(&block)
|
|
339
|
+
@filters[nil] = block
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# If self is stable, it cannot be updated. That is, calling a setter method
|
|
343
|
+
# raises NoMethodError
|
|
344
|
+
def stable?; @stable end
|
|
345
|
+
|
|
346
|
+
def freeze
|
|
347
|
+
freeze
|
|
348
|
+
each_member do |name, field|
|
|
349
|
+
field.freeze
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Sets the stable attribute of +self+ to +is_stable+. If +recursive+ is true,
|
|
354
|
+
# set it on the child struct as well.
|
|
355
|
+
#
|
|
356
|
+
def stable!(recursive = false, is_stable = true)
|
|
357
|
+
@stable = is_stable
|
|
358
|
+
if recursive
|
|
359
|
+
@members.each { |name, object| object.stable!(recursive, is_stable) if object.respond_to?(:stable!) }
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def updated(name, value, recursive = false)
|
|
364
|
+
if @observers.has_key?(name)
|
|
365
|
+
@observers[name].each do |ob|
|
|
366
|
+
if ob.recursive? || !recursive
|
|
367
|
+
ob.call(name, value)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
@observers[nil].each do |ob|
|
|
373
|
+
if ob.recursive? || !recursive
|
|
374
|
+
ob.call(name, value)
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
if __parent_struct
|
|
379
|
+
__parent_struct.updated(__parent_name, self, true)
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Returns true if this object has no member
|
|
384
|
+
def empty?; @members.empty? end
|
|
385
|
+
|
|
386
|
+
if RUBY_VERSION >= "1.8.7"
|
|
387
|
+
# has_method? will be used to know if a given method is already defined
|
|
388
|
+
# on the OpenStruct object, without taking into account the members
|
|
389
|
+
# and aliases.
|
|
390
|
+
def has_method?(name)
|
|
391
|
+
Object.instance_method(:respond_to?).bind(self).call(name, true)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def respond_to?(name, include_private = false) # :nodoc:
|
|
395
|
+
return true if super
|
|
396
|
+
return __respond_to__(name)
|
|
397
|
+
end
|
|
398
|
+
else
|
|
399
|
+
# has_method? will be used to know if a given method is already defined
|
|
400
|
+
# on the OpenStruct object, without taking into account the members
|
|
401
|
+
# and aliases.
|
|
402
|
+
def has_method?(name)
|
|
403
|
+
Object.instance_method(:respond_to?).bind(self).call(name)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def respond_to?(name) # :nodoc:
|
|
407
|
+
return true if super
|
|
408
|
+
return __respond_to__(name)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
# 1.8.7's #respond_to? takes two arguments, 1.8.6 only one. This is the
|
|
414
|
+
# common implementation for both version. #respond_to? is adapted (see
|
|
415
|
+
# above)
|
|
416
|
+
def __respond_to__(name) # :nodoc:
|
|
417
|
+
name = name.to_s
|
|
418
|
+
return false if name =~ FORBIDDEN_NAMES_RX
|
|
419
|
+
|
|
420
|
+
if name =~ /=$/
|
|
421
|
+
!@stable
|
|
422
|
+
else
|
|
423
|
+
if @members.has_key?(name)
|
|
424
|
+
true
|
|
425
|
+
else
|
|
426
|
+
(alias_to = @aliases[name]) && respond_to?(alias_to)
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Returns the value of the given field
|
|
432
|
+
#
|
|
433
|
+
# Unlike #method_missing, it will return nil if the field is not set
|
|
434
|
+
def get(name)
|
|
435
|
+
__get(name, false)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# Returns the path to root, i.e. the list of field names from the root
|
|
439
|
+
# of the extended struct tree
|
|
440
|
+
def path
|
|
441
|
+
result = []
|
|
442
|
+
obj = self
|
|
443
|
+
while obj
|
|
444
|
+
result.unshift(obj.__parent_name)
|
|
445
|
+
obj = obj.__parent_struct
|
|
446
|
+
end
|
|
447
|
+
result.shift # we alwas add a nil for one-after-the-root
|
|
448
|
+
result
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def __get(name, create_substruct = true, &update)
|
|
452
|
+
name = name.to_s
|
|
453
|
+
|
|
454
|
+
if model
|
|
455
|
+
# We never automatically create levels as the model should tell us
|
|
456
|
+
# what we want
|
|
457
|
+
create_substruct = false
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
if @members.has_key?(name)
|
|
461
|
+
member = @members[name]
|
|
462
|
+
else
|
|
463
|
+
if alias_to = @aliases[name]
|
|
464
|
+
return send(alias_to)
|
|
465
|
+
elsif stable?
|
|
466
|
+
raise NoMethodError, "no such attribute #{name} (#{self} is stable)"
|
|
467
|
+
elsif create_substruct
|
|
468
|
+
attach
|
|
469
|
+
member = @pending[name] = create_subfield(name)
|
|
470
|
+
else return
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
if update
|
|
475
|
+
member.update(&update)
|
|
476
|
+
else
|
|
477
|
+
member
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# Called by #method_missing to create a subfield when needed.
|
|
482
|
+
#
|
|
483
|
+
# The default is to create a subfield of the same class than +self+
|
|
484
|
+
def create_subfield(name)
|
|
485
|
+
model = if self.model then self.model.get(name) end
|
|
486
|
+
self.class.new(model, self, name)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def set(name, *args)
|
|
490
|
+
name = name.to_s
|
|
491
|
+
name = @aliases[name] || name
|
|
492
|
+
|
|
493
|
+
if model && !model.get(name).kind_of?(OpenStructModel::Variable)
|
|
494
|
+
raise ArgumentError, "#{name} is not a state variable on #{self}"
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
value = args.first
|
|
498
|
+
|
|
499
|
+
if stable?
|
|
500
|
+
raise NoMethodError, "#{self} is stable"
|
|
501
|
+
elsif @filters.has_key?(name)
|
|
502
|
+
value = @filters[name].call(value)
|
|
503
|
+
elsif @filters.has_key?(nil)
|
|
504
|
+
value = @filters[nil].call(name, value)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
if has_method?(name)
|
|
508
|
+
if NOT_OVERRIDABLE_RX =~ name
|
|
509
|
+
raise ArgumentError, "#{name} is already defined an cannot be overriden"
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# Override it
|
|
513
|
+
singleton_class.class_eval do
|
|
514
|
+
define_method(name) do
|
|
515
|
+
method_missing(name)
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
attach
|
|
521
|
+
|
|
522
|
+
@aliases.delete(name)
|
|
523
|
+
pending = @pending.delete(name)
|
|
524
|
+
|
|
525
|
+
if pending && pending != value
|
|
526
|
+
pending.detach
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
@members[name] = value
|
|
530
|
+
updated(name, value)
|
|
531
|
+
return value
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def method_missing(name, *args, &update) # :nodoc:
|
|
535
|
+
if name !~ /^\w+(?:\?|=|!)?$/
|
|
536
|
+
if name[-1, 1] == '?'
|
|
537
|
+
return false
|
|
538
|
+
else
|
|
539
|
+
super
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
name = name.to_s
|
|
544
|
+
|
|
545
|
+
if name =~ FORBIDDEN_NAMES_RX
|
|
546
|
+
super(name.to_sym, *args, &update)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
if name =~ /^(\w+)=$/
|
|
550
|
+
ret = set($1, *args)
|
|
551
|
+
return ret
|
|
552
|
+
|
|
553
|
+
elsif name =~ /^(\w+)\?$/
|
|
554
|
+
# Test
|
|
555
|
+
name = @aliases[$1] || $1
|
|
556
|
+
respond_to?(name) && get(name) && send(name)
|
|
557
|
+
|
|
558
|
+
elsif args.empty? # getter
|
|
559
|
+
attach
|
|
560
|
+
return __get(name, &update)
|
|
561
|
+
|
|
562
|
+
else
|
|
563
|
+
super(name.to_sym, *args, &update)
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
def alias(from, to)
|
|
568
|
+
@aliases[to.to_s] = from.to_s
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
FORBIDDEN_NAMES=%w{marshal each enum to}.map { |str| "^#{str}_" }
|
|
572
|
+
FORBIDDEN_NAMES_RX = /(?:#{FORBIDDEN_NAMES.join("|")})/
|
|
573
|
+
|
|
574
|
+
NOT_OVERRIDABLE = %w{class} + instance_methods(false)
|
|
575
|
+
NOT_OVERRIDABLE_RX = /(?:#{NOT_OVERRIDABLE.join("|")})/
|
|
576
|
+
|
|
577
|
+
def __merge(other)
|
|
578
|
+
@members.merge(other) do |k, v1, v2|
|
|
579
|
+
if v1.kind_of?(OpenStruct) && v2.kind_of?(OpenStruct)
|
|
580
|
+
if v1.class != v2.class
|
|
581
|
+
raise ArgumentError, "#{k} is a #{v1.class} in self and #{v2.class} in other, I don't know what to do"
|
|
582
|
+
end
|
|
583
|
+
v1.__merge(v2)
|
|
584
|
+
else
|
|
585
|
+
v2
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|