roby 0.8.0 → 3.0.0

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