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.
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
+