ruote 0.9.20 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (397) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.txt +8 -0
  3. data/CREDITS.txt +65 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.rdoc +76 -0
  6. data/Rakefile +68 -0
  7. data/TODO.txt +287 -0
  8. data/examples/flickr_report.rb +108 -0
  9. data/examples/ruote_quickstart.rb +42 -0
  10. data/examples/web_first_page.rb +57 -0
  11. data/lib/ruote.rb +6 -0
  12. data/lib/ruote/context.rb +136 -0
  13. data/lib/ruote/engine.rb +339 -0
  14. data/lib/{openwfe/expressions/merge.rb → ruote/engine/process_error.rb} +35 -24
  15. data/lib/ruote/engine/process_status.rb +236 -0
  16. data/lib/ruote/evt/tracker.rb +110 -0
  17. data/lib/ruote/exp/command.rb +88 -0
  18. data/lib/ruote/exp/commanded.rb +69 -0
  19. data/lib/ruote/exp/condition.rb +120 -0
  20. data/lib/ruote/exp/expression_map.rb +103 -0
  21. data/lib/ruote/exp/fe_add_branches.rb +138 -0
  22. data/lib/ruote/exp/fe_apply.rb +85 -0
  23. data/lib/ruote/exp/fe_cancel_process.rb +74 -0
  24. data/lib/ruote/exp/fe_command.rb +163 -0
  25. data/lib/ruote/exp/fe_concurrence.rb +273 -0
  26. data/lib/ruote/exp/fe_concurrent_iterator.rb +204 -0
  27. data/lib/ruote/exp/fe_cron.rb +141 -0
  28. data/lib/ruote/exp/fe_cursor.rb +270 -0
  29. data/lib/ruote/exp/fe_define.rb +112 -0
  30. data/lib/{openwfe/engine/fs_engine.rb → ruote/exp/fe_echo.rb} +24 -18
  31. data/lib/ruote/exp/fe_equals.rb +115 -0
  32. data/lib/ruote/exp/fe_error.rb +90 -0
  33. data/lib/ruote/exp/fe_forget.rb +81 -0
  34. data/lib/ruote/exp/fe_if.rb +124 -0
  35. data/lib/ruote/exp/fe_inc.rb +205 -0
  36. data/lib/ruote/exp/fe_iterator.rb +193 -0
  37. data/lib/ruote/exp/fe_listen.rb +197 -0
  38. data/lib/{openwfe/engine.rb → ruote/exp/fe_noop.rb} +20 -3
  39. data/lib/ruote/exp/fe_participant.rb +202 -0
  40. data/lib/ruote/exp/fe_redo.rb +83 -0
  41. data/lib/ruote/exp/fe_reserve.rb +126 -0
  42. data/lib/ruote/exp/fe_restore.rb +102 -0
  43. data/lib/ruote/exp/fe_save.rb +79 -0
  44. data/lib/ruote/exp/fe_sequence.rb +60 -0
  45. data/lib/ruote/exp/fe_set.rb +160 -0
  46. data/lib/ruote/exp/fe_subprocess.rb +203 -0
  47. data/lib/{openwfe/expool/errors.rb → ruote/exp/fe_undo.rb} +28 -30
  48. data/lib/ruote/exp/fe_wait.rb +92 -0
  49. data/lib/ruote/exp/fe_when.rb +214 -0
  50. data/lib/ruote/exp/flowexpression.rb +624 -0
  51. data/lib/{openwfe/omixins.rb → ruote/exp/iterator.rb} +41 -23
  52. data/lib/ruote/exp/merge.rb +66 -0
  53. data/lib/{openwfe/util/ometa.rb → ruote/exp/raw.rb} +16 -16
  54. data/lib/ruote/exp/ro_attributes.rb +203 -0
  55. data/lib/ruote/exp/ro_persist.rb +139 -0
  56. data/lib/ruote/exp/ro_variables.rb +192 -0
  57. data/lib/ruote/fei.rb +131 -0
  58. data/lib/{openwfe/version.rb → ruote/id/mnemo_wfid_generator.rb} +17 -3
  59. data/lib/{openwfe/extras/engine/dm_engine.rb → ruote/id/wfid_generator.rb} +34 -22
  60. data/lib/ruote/log/fs_history.rb +181 -0
  61. data/lib/ruote/log/test_logger.rb +254 -0
  62. data/lib/ruote/log/wait_logger.rb +67 -0
  63. data/lib/ruote/parser.rb +205 -0
  64. data/lib/ruote/parser/ruby_dsl.rb +85 -0
  65. data/lib/ruote/parser/xml.rb +92 -0
  66. data/lib/ruote/part/block_participant.rb +101 -0
  67. data/lib/ruote/part/dispatch_pool.rb +84 -0
  68. data/lib/ruote/part/hash_participant.rb +91 -0
  69. data/lib/ruote/part/local_participant.rb +52 -0
  70. data/lib/{openwfe/engine/tc_engine.rb → ruote/part/no_op_participant.rb} +19 -14
  71. data/lib/{openwfe/engine/tt_engine.rb → ruote/part/null_participant.rb} +17 -18
  72. data/lib/ruote/part/participant_list.rb +201 -0
  73. data/lib/ruote/part/smtp_participant.rb +135 -0
  74. data/lib/ruote/part/storage_participant.rb +140 -0
  75. data/lib/{openwfe/util/irb.rb → ruote/part/template.rb} +23 -31
  76. data/lib/ruote/participant.rb +6 -0
  77. data/lib/ruote/receiver/base.rb +73 -0
  78. data/lib/ruote/storage/base.rb +210 -0
  79. data/lib/ruote/storage/fs_storage.rb +89 -0
  80. data/lib/ruote/storage/hash_storage.rb +171 -0
  81. data/lib/ruote/tree_dot.rb +85 -0
  82. data/lib/{openwfe → ruote}/util/dollar.rb +47 -63
  83. data/lib/{openwfe/extras/singlecon.rb → ruote/util/hashdot.rb} +40 -19
  84. data/lib/ruote/util/look.rb +129 -0
  85. data/lib/ruote/util/lookup.rb +92 -0
  86. data/lib/ruote/util/misc.rb +119 -0
  87. data/lib/ruote/util/ometa.rb +55 -0
  88. data/lib/ruote/util/serializer.rb +103 -0
  89. data/lib/ruote/util/time.rb +90 -0
  90. data/lib/ruote/util/tree.rb +58 -0
  91. data/lib/{openwfe → ruote}/util/treechecker.rb +10 -16
  92. data/lib/ruote/worker.rb +375 -0
  93. data/lib/ruote/workitem.rb +176 -0
  94. data/phil.txt +14 -0
  95. data/ruote.gemspec +278 -0
  96. data/test/README.rdoc +15 -0
  97. data/test/bm/ci.rb +55 -0
  98. data/test/bm/ici.rb +71 -0
  99. data/test/bm/juuman.rb +54 -0
  100. data/test/bm/load_26c.rb +25 -7
  101. data/test/bm/mega.rb +64 -0
  102. data/test/bm/seq_thousand.rb +31 -0
  103. data/test/bm/t.rb +35 -0
  104. data/test/functional/base.rb +88 -99
  105. data/test/functional/concurrent_base.rb +91 -0
  106. data/test/functional/crunner.rb +26 -0
  107. data/test/functional/ct_0_concurrence.rb +68 -0
  108. data/test/functional/ct_1_iterator.rb +61 -0
  109. data/test/functional/ct_2_cancel.rb +69 -0
  110. data/test/functional/eft_0_process_definition.rb +46 -15
  111. data/test/functional/eft_10_cancel_process.rb +46 -0
  112. data/test/functional/eft_11_wait.rb +97 -0
  113. data/test/functional/eft_12_listen.rb +271 -0
  114. data/test/functional/eft_13_iterator.rb +267 -0
  115. data/test/functional/eft_14_cursor.rb +278 -0
  116. data/test/functional/eft_15_loop.rb +67 -0
  117. data/test/functional/eft_16_if.rb +171 -0
  118. data/test/functional/eft_17_equals.rb +55 -0
  119. data/test/functional/eft_18_concurrent_iterator.rb +361 -0
  120. data/test/functional/eft_19_reserve.rb +136 -0
  121. data/test/functional/eft_1_echo.rb +59 -0
  122. data/test/functional/eft_20_save.rb +76 -0
  123. data/test/functional/eft_21_restore.rb +61 -0
  124. data/test/functional/eft_22_noop.rb +28 -0
  125. data/test/functional/eft_23_apply.rb +145 -0
  126. data/test/functional/eft_24_add_branches.rb +86 -0
  127. data/test/functional/eft_25_command.rb +28 -0
  128. data/test/functional/eft_26_error.rb +77 -0
  129. data/test/functional/eft_27_inc.rb +279 -0
  130. data/test/functional/eft_28_when.rb +109 -0
  131. data/test/functional/eft_29_cron.rb +64 -0
  132. data/test/functional/eft_2_sequence.rb +38 -27
  133. data/test/functional/eft_3_participant.rb +122 -0
  134. data/test/functional/eft_4_set.rb +230 -0
  135. data/test/functional/eft_5_subprocess.rb +164 -0
  136. data/test/functional/eft_6_concurrence.rb +279 -0
  137. data/test/functional/eft_7_forget.rb +61 -0
  138. data/test/functional/eft_8_undo.rb +78 -0
  139. data/test/functional/eft_9_redo.rb +46 -0
  140. data/test/functional/ft_0_worker.rb +46 -0
  141. data/test/functional/ft_10_dollar.rb +90 -0
  142. data/test/functional/ft_11_recursion.rb +111 -0
  143. data/test/functional/ft_12_launchitem.rb +37 -0
  144. data/test/functional/ft_13_variables.rb +131 -0
  145. data/test/functional/ft_14_re_apply.rb +133 -0
  146. data/test/functional/ft_15_timeout.rb +205 -0
  147. data/test/functional/ft_16_participant_params.rb +47 -0
  148. data/test/functional/ft_17_conditional.rb +76 -0
  149. data/test/functional/ft_18_kill.rb +85 -0
  150. data/test/functional/ft_19_alias.rb +33 -0
  151. data/test/functional/ft_1_process_status.rb +410 -20
  152. data/test/functional/ft_20_storage_participant.rb +46 -0
  153. data/test/functional/ft_21_forget.rb +42 -0
  154. data/test/functional/ft_22_process_definitions.rb +80 -0
  155. data/test/functional/ft_23_load_defs.rb +55 -0
  156. data/test/functional/ft_24_block_participants.rb +59 -0
  157. data/test/functional/ft_25_receiver.rb +87 -0
  158. data/test/functional/ft_26_participant_timeout.rb +49 -0
  159. data/test/functional/ft_27_var_indirection.rb +93 -0
  160. data/test/functional/ft_28_null_noop_participants.rb +51 -0
  161. data/test/functional/ft_29_part_template.rb +78 -0
  162. data/test/functional/ft_2_errors.rb +320 -0
  163. data/test/functional/ft_30_smtp_participant.rb +69 -0
  164. data/test/functional/ft_31_part_blocking.rb +70 -0
  165. data/test/functional/ft_32_history.rb +184 -0
  166. data/test/functional/ft_33_participant_subprocess_priority.rb +32 -0
  167. data/test/functional/ft_34_cursor_rewind.rb +98 -0
  168. data/test/functional/ft_35_add_service.rb +48 -0
  169. data/test/functional/ft_3_participant_registration.rb +107 -0
  170. data/test/functional/ft_4_cancel.rb +72 -0
  171. data/test/functional/ft_5_on_error.rb +155 -0
  172. data/test/functional/ft_6_on_cancel.rb +165 -0
  173. data/test/functional/ft_7_tags.rb +88 -0
  174. data/test/functional/ft_8_participant_consumption.rb +75 -0
  175. data/test/functional/ft_9_subprocesses.rb +145 -0
  176. data/test/functional/restart_base.rb +17 -26
  177. data/test/functional/rt_0_wait.rb +55 -0
  178. data/test/functional/rt_1_listen.rb +56 -0
  179. data/test/functional/rt_2_errors.rb +56 -0
  180. data/test/functional/rt_3_when.rb +70 -0
  181. data/test/functional/rt_4_cron.rb +63 -0
  182. data/test/functional/rt_5_timeout.rb +60 -0
  183. data/test/functional/rtest.rb +8 -0
  184. data/test/functional/storage_helper.rb +79 -0
  185. data/test/functional/test.rb +23 -11
  186. data/test/mpc_test.rb +29 -0
  187. data/test/path_helper.rb +4 -2
  188. data/test/pdef.xml +7 -0
  189. data/test/test_helper.rb +2 -30
  190. data/test/unit/storages.rb +13 -0
  191. data/test/unit/test.rb +2 -11
  192. data/test/unit/ut_0_ruby_parser.rb +120 -0
  193. data/test/unit/ut_11_lookup.rb +51 -0
  194. data/test/unit/ut_13_serializer.rb +65 -0
  195. data/test/unit/ut_14_is_uri.rb +28 -0
  196. data/test/unit/ut_15_util.rb +34 -0
  197. data/test/unit/ut_16_parser.rb +100 -0
  198. data/test/unit/ut_17_storage.rb +122 -0
  199. data/test/unit/ut_1_fei.rb +20 -0
  200. data/test/unit/ut_2_wfidgen.rb +21 -0
  201. data/test/unit/ut_3_wait_logger.rb +41 -0
  202. data/test/unit/ut_4_expmap.rb +20 -0
  203. data/test/unit/ut_5_tree.rb +54 -0
  204. data/test/unit/ut_6_condition.rb +138 -0
  205. data/test/unit/ut_7_workitem.rb +21 -0
  206. data/test/unit/ut_8_tree_to_dot.rb +72 -0
  207. data/test/unit/ut_9_xml_parser.rb +61 -0
  208. metadata +246 -253
  209. data/README.txt +0 -36
  210. data/bin/validate-workflow.rb +0 -89
  211. data/examples/about_state.rb +0 -81
  212. data/examples/bigflow.rb +0 -19
  213. data/examples/csv_weather.rb +0 -23
  214. data/examples/engine_template.rb +0 -222
  215. data/examples/flowtracing.rb +0 -24
  216. data/examples/homeworkreview.rb +0 -68
  217. data/examples/kotoba.rb +0 -22
  218. data/examples/mano_tracker.rb +0 -172
  219. data/examples/openwferu.rb +0 -60
  220. data/examples/quickstart.rb +0 -87
  221. data/examples/quotereporter.rb +0 -150
  222. data/examples/simple.rb +0 -56
  223. data/lib/openwfe.rb +0 -27
  224. data/lib/openwfe/contextual.rb +0 -120
  225. data/lib/openwfe/def.rb +0 -37
  226. data/lib/openwfe/engine/engine.rb +0 -455
  227. data/lib/openwfe/engine/expool_methods.rb +0 -113
  228. data/lib/openwfe/engine/file_persisted_engine.rb +0 -84
  229. data/lib/openwfe/engine/launch_methods.rb +0 -245
  230. data/lib/openwfe/engine/listener_methods.rb +0 -128
  231. data/lib/openwfe/engine/lookup_methods.rb +0 -156
  232. data/lib/openwfe/engine/participant_methods.rb +0 -141
  233. data/lib/openwfe/engine/status_methods.rb +0 -382
  234. data/lib/openwfe/engine/update_exp_methods.rb +0 -119
  235. data/lib/openwfe/expool/def_parser.rb +0 -196
  236. data/lib/openwfe/expool/errorjournal.rb +0 -294
  237. data/lib/openwfe/expool/expool_pause_methods.rb +0 -87
  238. data/lib/openwfe/expool/expressionpool.rb +0 -941
  239. data/lib/openwfe/expool/expstorage.rb +0 -370
  240. data/lib/openwfe/expool/fs_expstorage.rb +0 -302
  241. data/lib/openwfe/expool/history.rb +0 -278
  242. data/lib/openwfe/expool/journal.rb +0 -210
  243. data/lib/openwfe/expool/journal_replay.rb +0 -305
  244. data/lib/openwfe/expool/representation.rb +0 -105
  245. data/lib/openwfe/expool/tc_expstorage.rb +0 -239
  246. data/lib/openwfe/expool/threaded_expstorage.rb +0 -163
  247. data/lib/openwfe/expool/tt_expstorage.rb +0 -55
  248. data/lib/openwfe/expool/wfidgen.rb +0 -370
  249. data/lib/openwfe/expool/yaml_errorjournal.rb +0 -187
  250. data/lib/openwfe/expressions/condition.rb +0 -226
  251. data/lib/openwfe/expressions/environment.rb +0 -232
  252. data/lib/openwfe/expressions/expression_map.rb +0 -248
  253. data/lib/openwfe/expressions/expression_tree.rb +0 -265
  254. data/lib/openwfe/expressions/fe_cancel.rb +0 -89
  255. data/lib/openwfe/expressions/fe_command.rb +0 -237
  256. data/lib/openwfe/expressions/fe_concurrence.rb +0 -599
  257. data/lib/openwfe/expressions/fe_cron.rb +0 -197
  258. data/lib/openwfe/expressions/fe_cursor.rb +0 -200
  259. data/lib/openwfe/expressions/fe_define.rb +0 -146
  260. data/lib/openwfe/expressions/fe_do.rb +0 -181
  261. data/lib/openwfe/expressions/fe_equals.rb +0 -273
  262. data/lib/openwfe/expressions/fe_error.rb +0 -103
  263. data/lib/openwfe/expressions/fe_filter.rb +0 -112
  264. data/lib/openwfe/expressions/fe_filter_definition.rb +0 -151
  265. data/lib/openwfe/expressions/fe_fqv.rb +0 -231
  266. data/lib/openwfe/expressions/fe_http.rb +0 -198
  267. data/lib/openwfe/expressions/fe_if.rb +0 -287
  268. data/lib/openwfe/expressions/fe_iterator.rb +0 -128
  269. data/lib/openwfe/expressions/fe_listen.rb +0 -327
  270. data/lib/openwfe/expressions/fe_losfor.rb +0 -102
  271. data/lib/openwfe/expressions/fe_misc.rb +0 -374
  272. data/lib/openwfe/expressions/fe_participant.rb +0 -231
  273. data/lib/openwfe/expressions/fe_reserve.rb +0 -192
  274. data/lib/openwfe/expressions/fe_save.rb +0 -255
  275. data/lib/openwfe/expressions/fe_sequence.rb +0 -102
  276. data/lib/openwfe/expressions/fe_set.rb +0 -121
  277. data/lib/openwfe/expressions/fe_step.rb +0 -146
  278. data/lib/openwfe/expressions/fe_subprocess.rb +0 -150
  279. data/lib/openwfe/expressions/fe_timeout.rb +0 -107
  280. data/lib/openwfe/expressions/fe_wait.rb +0 -183
  281. data/lib/openwfe/expressions/fe_when.rb +0 -118
  282. data/lib/openwfe/expressions/filter.rb +0 -85
  283. data/lib/openwfe/expressions/flowexpression.rb +0 -872
  284. data/lib/openwfe/expressions/iterator.rb +0 -206
  285. data/lib/openwfe/expressions/raw.rb +0 -330
  286. data/lib/openwfe/expressions/rprocdef.rb +0 -373
  287. data/lib/openwfe/expressions/time.rb +0 -314
  288. data/lib/openwfe/expressions/timeout.rb +0 -184
  289. data/lib/openwfe/expressions/value.rb +0 -100
  290. data/lib/openwfe/extras/engine/ar_engine.rb +0 -58
  291. data/lib/openwfe/extras/engine/db_persisted_engine.rb +0 -74
  292. data/lib/openwfe/extras/expool/ar_expstorage.rb +0 -337
  293. data/lib/openwfe/extras/expool/db_errorjournal.rb +0 -165
  294. data/lib/openwfe/extras/expool/db_expstorage.rb +0 -73
  295. data/lib/openwfe/extras/expool/db_history.rb +0 -163
  296. data/lib/openwfe/extras/expool/dm_expstorage.rb +0 -327
  297. data/lib/openwfe/extras/listeners/jabber_listeners.rb +0 -102
  298. data/lib/openwfe/extras/listeners/jabberlisteners.rb +0 -26
  299. data/lib/openwfe/extras/listeners/sqs_listeners.rb +0 -128
  300. data/lib/openwfe/extras/misc/activityfeed.rb +0 -249
  301. data/lib/openwfe/extras/misc/basecamp.rb +0 -485
  302. data/lib/openwfe/extras/misc/jabber_common.rb +0 -122
  303. data/lib/openwfe/extras/participants/active_participants.rb +0 -724
  304. data/lib/openwfe/extras/participants/active_resource_participants.rb +0 -213
  305. data/lib/openwfe/extras/participants/activeparticipants.rb +0 -3
  306. data/lib/openwfe/extras/participants/ar_participants.rb +0 -285
  307. data/lib/openwfe/extras/participants/atomfeed_participants.rb +0 -158
  308. data/lib/openwfe/extras/participants/atompub_participants.rb +0 -252
  309. data/lib/openwfe/extras/participants/basecamp_participants.rb +0 -73
  310. data/lib/openwfe/extras/participants/decision_participants.rb +0 -113
  311. data/lib/openwfe/extras/participants/jabber_participants.rb +0 -147
  312. data/lib/openwfe/extras/participants/jabberparticipants.rb +0 -3
  313. data/lib/openwfe/extras/participants/sqs_participants.rb +0 -108
  314. data/lib/openwfe/extras/participants/twitter_participants.rb +0 -162
  315. data/lib/openwfe/filterdef.rb +0 -277
  316. data/lib/openwfe/flowexpressionid.rb +0 -396
  317. data/lib/openwfe/listeners/listener.rb +0 -86
  318. data/lib/openwfe/listeners/listeners.rb +0 -135
  319. data/lib/openwfe/logging.rb +0 -108
  320. data/lib/openwfe/participants.rb +0 -5
  321. data/lib/openwfe/participants/mail_participants.rb +0 -216
  322. data/lib/openwfe/participants/participant.rb +0 -142
  323. data/lib/openwfe/participants/participant_map.rb +0 -245
  324. data/lib/openwfe/participants/participants.rb +0 -381
  325. data/lib/openwfe/participants/soap_participants.rb +0 -121
  326. data/lib/openwfe/participants/store_participants.rb +0 -249
  327. data/lib/openwfe/participants/yaml_filestorage.rb +0 -216
  328. data/lib/openwfe/representations.rb +0 -770
  329. data/lib/openwfe/rexml.rb +0 -44
  330. data/lib/openwfe/rudefinitions.rb +0 -114
  331. data/lib/openwfe/service.rb +0 -92
  332. data/lib/openwfe/tools/flowtracer.rb +0 -63
  333. data/lib/openwfe/util/json.rb +0 -55
  334. data/lib/openwfe/util/observable.rb +0 -119
  335. data/lib/openwfe/util/workqueue.rb +0 -125
  336. data/lib/openwfe/util/xml.rb +0 -270
  337. data/lib/openwfe/utils.rb +0 -484
  338. data/lib/openwfe/workitem.rb +0 -541
  339. data/lib/openwfe/worklist/storelocks.rb +0 -277
  340. data/lib/openwfe/worklist/storeparticipant.rb +0 -6
  341. data/lib/openwfe/worklist/worklist.rb +0 -283
  342. data/lib/pooltool.ru +0 -311
  343. data/test/ar_test_connection.rb +0 -63
  344. data/test/bm/fatxml.rb +0 -70
  345. data/test/dm_test_connection.rb +0 -11
  346. data/test/extras/base.rb +0 -3
  347. data/test/extras/et_0_sqs.rb +0 -37
  348. data/test/extras/et_jabber_test.rb +0 -226
  349. data/test/extras/test.rb +0 -16
  350. data/test/functional/db_ft_0_ar_participants.rb +0 -136
  351. data/test/functional/eft_10_unset.rb +0 -60
  352. data/test/functional/eft_11_sleep.rb +0 -95
  353. data/test/functional/eft_12_wait.rb +0 -57
  354. data/test/functional/eft_13_cursor.rb +0 -139
  355. data/test/functional/eft_14_loop.rb +0 -36
  356. data/test/functional/eft_15_undo.rb +0 -77
  357. data/test/functional/eft_16_redo.rb +0 -88
  358. data/test/functional/eft_1_print.rb +0 -57
  359. data/test/functional/eft_3_equals.rb +0 -98
  360. data/test/functional/eft_4_if.rb +0 -96
  361. data/test/functional/eft_5_eval.rb +0 -89
  362. data/test/functional/eft_6_reval.rb +0 -101
  363. data/test/functional/eft_7_exp.rb +0 -47
  364. data/test/functional/eft_8_log.rb +0 -50
  365. data/test/functional/eft_9_set.rb +0 -132
  366. data/test/functional/engine_helper.rb +0 -122
  367. data/test/functional/ft_0_vars_at_launch.rb +0 -27
  368. data/test/functional/ft_2_file_listener.rb +0 -45
  369. data/test/functional/ft_3_on_cancel.rb +0 -171
  370. data/test/functional/ft_4_on_error.rb +0 -220
  371. data/test/functional/ft_5_process_uri.rb +0 -82
  372. data/test/functional/ft_6_process_status.rb +0 -62
  373. data/test/functional/ft_7_parameters.rb +0 -103
  374. data/test/functional/ft_8_dollar.rb +0 -53
  375. data/test/functional/ft_9_register_participants.rb +0 -119
  376. data/test/functional/rft_0_sleep.rb +0 -76
  377. data/test/unit/ut_0_fei.rb +0 -166
  378. data/test/unit/ut_10_lookup_attribute.rb +0 -86
  379. data/test/unit/ut_11_filter.rb +0 -124
  380. data/test/unit/ut_12_conditional.rb +0 -162
  381. data/test/unit/ut_13_xmlutil.rb +0 -57
  382. data/test/unit/ut_14_var_field_lookup.rb +0 -85
  383. data/test/unit/ut_15_fe_att_lookup.rb +0 -55
  384. data/test/unit/ut_16_expstorage_findexp.rb +0 -38
  385. data/test/unit/ut_17_representations.rb +0 -330
  386. data/test/unit/ut_17b_representations_hash.rb +0 -97
  387. data/test/unit/ut_18_store_lock.rb +0 -77
  388. data/test/unit/ut_1_wfid.rb +0 -104
  389. data/test/unit/ut_2_utils.rb +0 -53
  390. data/test/unit/ut_3_expmap.rb +0 -65
  391. data/test/unit/ut_4_fulldup.rb +0 -163
  392. data/test/unit/ut_5_observable.rb +0 -132
  393. data/test/unit/ut_6_treechecker.rb +0 -101
  394. data/test/unit/ut_7_parser_ruby.rb +0 -344
  395. data/test/unit/ut_7b_parser_ruby.rb +0 -56
  396. data/test/unit/ut_8_parser_description.rb +0 -77
  397. data/test/unit/ut_9_workitem.rb +0 -72
@@ -0,0 +1,108 @@
1
+
2
+ $:.unshift('lib')
3
+
4
+ require 'rubygems'
5
+ require 'ruote/engine' # sudo gem install ruote
6
+ require 'atom/feed' # sudo gem install atom-tools
7
+ require 'prawn' # sudo gem install prawn
8
+
9
+ #
10
+ # starting a transient engine (no need to make it persistent)
11
+
12
+ engine = Ruote::Engine.new(:definition_in_launchitem_allowed => true)
13
+
14
+ #
15
+ # a process that fetches the latest pictures from flickr.com and submits
16
+ # them concurrently to three users for review
17
+
18
+ pdef = Ruote.process_definition :name => 'picture_acquisition' do
19
+ sequence do
20
+
21
+ get_pictures
22
+
23
+ concurrence :merge_type => 'mix' do
24
+ # pass the picture list to three users concurrently
25
+ # make sure to let their choice appear in the final workitem
26
+ # at the end of the concurrence
27
+
28
+ user_alice
29
+ user_bob
30
+ user_charly
31
+ user_doug
32
+ end
33
+
34
+ generate_result_pdf
35
+ end
36
+ end
37
+
38
+ #
39
+ # fetching the flickr.com pictures via Atom
40
+
41
+ engine.register_participant :get_pictures do |workitem|
42
+
43
+ feed = Atom::Feed.new(
44
+ "http://api.flickr.com/services/feeds/photos_public.gne"+
45
+ "?tags=#{workitem.fields['tags'].join(',')}&format=atom")
46
+ feed.update!
47
+
48
+ workitem.fields['pictures'] = feed.entries.inject([]) do |a, entry|
49
+ a << [
50
+ entry.title,
51
+ entry.authors.first.name,
52
+ entry.links.last.href
53
+ ]
54
+ end
55
+ end
56
+
57
+ #
58
+ # the users (well, here, just randomly picking a picture)
59
+
60
+ engine.register_participant 'user_.*' do |workitem|
61
+
62
+ workitem.fields[workitem.participant_name] =
63
+ workitem.fields['pictures'][(rand * workitem.fields['pictures'].length).to_i]
64
+ end
65
+
66
+ #
67
+ # the final participant, generates an "out.pdf" file in the current dir
68
+
69
+ engine.register_participant :generate_result_pdf do |workitem|
70
+
71
+ entries = workitem.fields.inject([]) do |a, (k, v)|
72
+ a << [ k, v.last ] if k.match(/^user\_.+$/)
73
+ a
74
+ end
75
+
76
+ entries.each_with_index do |entry, i|
77
+ entry << "pic#{i}.jpg"
78
+ `curl #{entry[1]} > #{entry[2]}`
79
+ puts "..got #{entry[0]} / #{entry[2]}"
80
+ end
81
+
82
+ Prawn::Document.generate('out.pdf') do
83
+ font 'Helvetica'
84
+ entries.each do |entry|
85
+ text entry[0]
86
+ image entry[2], :width => 200
87
+ end
88
+ end
89
+ puts ".generated out.pdf"
90
+
91
+ `rm pic*.jpg`
92
+ end
93
+
94
+ #
95
+ # launching the process, requesting pictures tagged 'cat' and 'fish'
96
+
97
+ li = Ruote::Launchitem.new(pdef)
98
+ li.fields['tags'] = [ 'cat', 'fish' ]
99
+
100
+ fei = engine.launch(li)
101
+
102
+ #
103
+ # workflow engines are asynchronous beasts, have to wait for them
104
+ # (here we wait for a particular process)
105
+
106
+ outcome = engine.wait_for(fei)
107
+ #p outcome
108
+
@@ -0,0 +1,42 @@
1
+
2
+ $:.unshift('lib') # running from ruote/ probably
3
+
4
+ require 'rubygems'
5
+ require 'ruote'
6
+ require 'ruote/storage/fs_storage'
7
+
8
+ # preparing the engine
9
+
10
+ engine = Ruote::Engine.new(
11
+ Ruote::Worker.new(
12
+ Ruote::FsStorage.new("ruote_work")))
13
+ #Ruote::HashStorage.new))
14
+
15
+ # registering participants
16
+
17
+ engine.register_participant :alpha do |workitem|
18
+ workitem.fields['message'] = { 'text' => 'hello !', 'author' => 'Alice' }
19
+ end
20
+
21
+ engine.register_participant :bravo do |workitem|
22
+ puts "I received a message from #{workitem.fields['message']['author']}"
23
+ end
24
+
25
+ # defining a process
26
+
27
+ pdef = Ruote.process_definition :name => 'test' do
28
+ sequence do
29
+ participant :alpha
30
+ participant :bravo
31
+ end
32
+ end
33
+
34
+ # launching, creating a process instance
35
+
36
+ wfid = engine.launch(pdef)
37
+
38
+ engine.wait_for(wfid)
39
+ # blocks current thread until our process instance terminates
40
+
41
+ # => 'I received a message from Alice'
42
+
@@ -0,0 +1,57 @@
1
+
2
+ require 'ruote'
3
+
4
+ pdef = Ruote.process_definition :name => 'work' do
5
+ cursor do
6
+ concurrence do
7
+ reviewer1
8
+ reviewer2
9
+ end
10
+ editor
11
+ rewind :if => '${not_ok}' # back to the reviewers if editor not happy
12
+ publish # the document
13
+ end
14
+ end
15
+
16
+ # engine
17
+
18
+ require 'ruote/storage/fs_storage'
19
+
20
+ engine = Ruote::Engine.new(Ruote::Worker.new(Ruote::FsStorage.new('work')))
21
+
22
+ # participants
23
+
24
+ engine.register_participant 'reviewer.+' do |workitem|
25
+ puts "reviewing document #{workitem.fields['doc_url']}"
26
+ print "approve ?"
27
+ workitem.fields["#{workitem.participant_name}_reply"] = gets
28
+ end
29
+
30
+ engine.register_participant 'editor' do |workitem|
31
+ puts "doc : #{workitem.fields['doc_url']}"
32
+ puts "reviewers approval :"
33
+ workitem.fields.entries.each do |k, v|
34
+ puts "#{k} : #{v}" if k.match(/\_reply$/)
35
+ end
36
+ print "should we publish ?"
37
+ workitem.fields['not_ok'] = (gets.strip == 'no')
38
+ end
39
+
40
+ engine.register_participant 'publish' do |workitem|
41
+ PublicationService.post(workitem.fields['doc_url'])
42
+ end
43
+
44
+ wfid0 = engine.launch(pdef, 'doc_url' => 'http://en.wikipedia.org/wiki/File:Bundesbrief.jpg')
45
+ wfid1 = engine.launch(pdef, 'doc_url' => 'http://en.wikipedia.org/wiki/File:Constitution_Pg1of4_AC.jpg')
46
+
47
+ # querying
48
+
49
+ [ wfid0, wfid1 ].each do |wfid|
50
+ ps = engine.process(wfid)
51
+ puts "errors for #{wfid} ? #{ps.errors.size > 0}"
52
+ end
53
+
54
+ # cancelling a process instance
55
+
56
+ engine.cancel_process(wfid1)
57
+
@@ -0,0 +1,6 @@
1
+
2
+ require 'ruote/storage/hash_storage'
3
+ require 'ruote/worker'
4
+ require 'ruote/engine'
5
+ require 'ruote/parser/ruby_dsl'
6
+
@@ -0,0 +1,136 @@
1
+ #--
2
+ # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'ruote/util/misc'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # A sort of internal registry, via a shared instance of this class, the worker
32
+ # and the engine can access subservices like parser, treechecker,
33
+ # wfid_generator and so on.
34
+ #
35
+ class Context
36
+
37
+ attr_reader :storage
38
+ attr_accessor :worker
39
+ attr_accessor :engine
40
+
41
+ def initialize (storage, worker_or_engine)
42
+
43
+ @storage = storage
44
+ @conf = default_conf.merge(@storage.get_configuration('engine') || {})
45
+
46
+ @worker, @engine = if worker_or_engine.kind_of?(Ruote::Engine)
47
+ [ worker_or_engine.worker, worker_or_engine ]
48
+ else
49
+ [ worker_or_engine, nil ]
50
+ end
51
+
52
+ initialize_services
53
+ end
54
+
55
+ def [] (key)
56
+
57
+ @conf[key]
58
+ end
59
+
60
+ def []= (key, value)
61
+
62
+ @conf[key] = value
63
+ end
64
+
65
+ def keys
66
+
67
+ @conf.keys
68
+ end
69
+
70
+ def add_service (key, *args)
71
+
72
+ path, klass, opts = args
73
+
74
+ key = "s_#{key}" unless key.match(/^s\_/)
75
+
76
+ if klass
77
+
78
+ require(path)
79
+
80
+ aa = [ self ]
81
+ aa << opts if opts
82
+
83
+ @conf[key] = Ruote.constantize(klass).new(*aa)
84
+ else
85
+
86
+ @conf[key] = path
87
+ end
88
+
89
+ self.class.class_eval %{ def #{key[2..-1]}; @conf['#{key}']; end }
90
+ end
91
+
92
+ def shutdown
93
+
94
+ @storage.shutdown if @storage.respond_to?(:shutdown)
95
+ @worker.shutdown if @worker
96
+
97
+ @conf.values.each do |s|
98
+
99
+ s.shutdown if s.respond_to?(:shutdown)
100
+ end
101
+ end
102
+
103
+ protected
104
+
105
+ def initialize_services
106
+
107
+ @conf.keys.each do |key|
108
+
109
+ next unless key.match(/^s\_/)
110
+
111
+ add_service(key, *@conf[key])
112
+ end
113
+ end
114
+
115
+ def default_conf
116
+
117
+ { 's_wfidgen' => [
118
+ 'ruote/id/mnemo_wfid_generator', 'Ruote::MnemoWfidGenerator' ],
119
+ 's_parser' => [
120
+ 'ruote/parser', 'Ruote::Parser' ],
121
+ 's_treechecker' => [
122
+ 'ruote/util/treechecker', 'Ruote::TreeChecker' ],
123
+ 's_expmap' => [
124
+ 'ruote/exp/expression_map', 'Ruote::ExpressionMap' ],
125
+ 's_tracker' => [
126
+ 'ruote/evt/tracker', 'Ruote::Tracker' ],
127
+ 's_plist' => [
128
+ 'ruote/part/participant_list', 'Ruote::ParticipantList' ],
129
+ 's_dispatch_pool' => [
130
+ 'ruote/part/dispatch_pool', 'Ruote::DispatchPool' ],
131
+ 's_logger' => [
132
+ 'ruote/log/wait_logger', 'Ruote::WaitLogger' ] }
133
+ end
134
+ end
135
+ end
136
+
@@ -0,0 +1,339 @@
1
+ #--
2
+ # Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'ruote/context'
26
+ require 'ruote/engine/process_status'
27
+ require 'ruote/receiver/base'
28
+
29
+
30
+ module Ruote
31
+
32
+ class Engine
33
+
34
+ include ReceiverMixin
35
+
36
+ attr_reader :storage
37
+ attr_reader :worker
38
+ attr_reader :context
39
+ attr_reader :variables
40
+
41
+ def initialize (worker_or_storage, run=true)
42
+
43
+ if worker_or_storage.respond_to?(:context)
44
+
45
+ @worker = worker_or_storage
46
+ @storage = @worker.storage
47
+ @context = @worker.context
48
+ @context.engine = self
49
+ else
50
+
51
+ @worker = nil
52
+ @storage = worker_or_storage
53
+ @context = Ruote::Context.new(self)
54
+ end
55
+
56
+ @variables = EngineVariables.new(@storage)
57
+
58
+ @worker.run_in_thread if @worker && run
59
+ end
60
+
61
+ def launch (process_definition, fields={}, variables={})
62
+
63
+ wfid = @context.wfidgen.generate
64
+
65
+ @storage.put_msg(
66
+ 'launch',
67
+ 'wfid' => wfid,
68
+ 'tree' => @context.parser.parse(process_definition),
69
+ 'workitem' => { 'fields' => fields },
70
+ 'variables' => variables)
71
+
72
+ wfid
73
+ end
74
+
75
+ def cancel_process (wfid)
76
+
77
+ @storage.put_msg('cancel_process', 'wfid' => wfid)
78
+ end
79
+
80
+ def kill_process (wfid)
81
+
82
+ @storage.put_msg('kill_process', 'wfid' => wfid)
83
+ end
84
+
85
+ def cancel_expression (fei)
86
+
87
+ fei = fei.to_h if fei.respond_to?(:to_h)
88
+ @storage.put_msg('cancel', 'fei' => fei)
89
+ end
90
+
91
+ def kill_expression (fei)
92
+
93
+ fei = fei.to_h if fei.respond_to?(:to_h)
94
+ @storage.put_msg('cancel', 'fei' => fei, 'flavour' => 'kill')
95
+ end
96
+
97
+ # Replays at a given error (hopefully you fixed the cause of the error
98
+ # before replaying...)
99
+ #
100
+ def replay_at_error (err)
101
+
102
+ msg = err.msg.dup
103
+ action = msg.delete('action')
104
+
105
+ msg['replay_at_error'] = true
106
+ # just an indication
107
+
108
+ if msg['tree'] && fei = msg['fei']
109
+ #
110
+ # nukes the expression in case of [re]apply
111
+ #
112
+ exp = Ruote::Exp::FlowExpression.fetch(@context, fei)
113
+ exp.unpersist_or_raise if exp
114
+ end
115
+
116
+ #@storage.delete(err.to_h) # remove error
117
+ #
118
+ # done when the expression gets deleted
119
+ #
120
+ # but
121
+ #
122
+ # is there a case, 5 lines above, where there is no expression
123
+ # to delete ?
124
+
125
+ @storage.put_msg(action, msg) # trigger replay
126
+ end
127
+
128
+ # Re-applies an expression (given via its FlowExpressionId).
129
+ #
130
+ # That will cancel the expression and, once the cancel operation is over
131
+ # (all the children have been cancelled), the expression will get
132
+ # re-applied.
133
+ #
134
+ def re_apply (fei)
135
+
136
+ @context.storage.put_msg('cancel', 'fei' => fei.to_h, 're_apply' => true)
137
+ end
138
+
139
+ # Returns a ProcessStatus instance describing the current status of
140
+ # a process instance.
141
+ #
142
+ def process (wfid)
143
+
144
+ exps = @storage.get_many('expressions', /#{wfid}$/)
145
+
146
+ return nil if exps.size < 1
147
+
148
+ ProcessStatus.new(
149
+ @context, exps, @storage.get_many('errors', /#{wfid}$/))
150
+ end
151
+
152
+ # Returns an array of ProcessStatus instances.
153
+ #
154
+ # WARNING : this is an expensive operation.
155
+ #
156
+ def processes
157
+
158
+ exps = @storage.get_many('expressions')
159
+ errs = @storage.get_many('errors')
160
+
161
+ by_wfid = {}
162
+
163
+ exps.each do |exp|
164
+ (by_wfid[exp['fei']['wfid']] ||= [ [], [] ]).first << exp
165
+ end
166
+ errs.each do |err|
167
+ (by_wfid[err['msg']['fei']['wfid']] ||= [ [], [] ]).last << err
168
+ end
169
+
170
+ by_wfid.values.collect { |xs, rs| ProcessStatus.new(@context, xs, rs) }
171
+ end
172
+
173
+ def shutdown
174
+
175
+ @context.shutdown
176
+ end
177
+
178
+ # This method expects there is a logger with a wait_for method in the
179
+ # context, else it will raise an exception.
180
+ #
181
+ # This method is only useful for test/quickstart/examples environments.
182
+ #
183
+ # engine.wait_for(:alpha)
184
+ # # will make the current thread block until a workitem is delivered
185
+ # # to the participant named 'alpha'
186
+ #
187
+ # engine.wait_for('123432123-9043')
188
+ # # will make the current thread block until the processed whose
189
+ # # wfid is given (String) terminates or produces an error.
190
+ #
191
+ # engine.wait_for(5)
192
+ # # will make the current thread block until 5 messages have been
193
+ # # processed on the workqueue...
194
+ #
195
+ def wait_for (item)
196
+
197
+ logger = @context['s_logger']
198
+
199
+ raise(
200
+ "can't wait_for, there is no logger that responds to that call"
201
+ ) unless logger.respond_to?(:wait_for)
202
+
203
+ logger.wait_for(item)
204
+ end
205
+
206
+ # Loads and parses the process definition at the given path.
207
+ #
208
+ def load_definition (path)
209
+
210
+ @context.parser.parse(path)
211
+ end
212
+
213
+ # Registers a participant in the engine. Returns the participant instance.
214
+ #
215
+ # Some examples :
216
+ #
217
+ # require 'ruote/part/hash_participant'
218
+ # alice = engine.register_participant 'alice', Ruote::HashParticipant
219
+ # # register an in-memory (hash) store for Alice's workitems
220
+ #
221
+ # engine.register_participant 'compute_sum' do |wi|
222
+ # wi.fields['sum'] = wi.fields['articles'].inject(0) do |s, (c, v)|
223
+ # s + c * v # sum + count * value
224
+ # end
225
+ # # a block participant implicitely replies to the engine immediately
226
+ # end
227
+ #
228
+ # class MyParticipant
229
+ # def initialize (name)
230
+ # @name = name
231
+ # end
232
+ # def consume (workitem)
233
+ # workitem.fields['rocket_name'] = @name
234
+ # send_to_the_moon(workitem)
235
+ # end
236
+ # def cancel (fei, flavour)
237
+ # # do nothing
238
+ # end
239
+ # end
240
+ # engine.register_participant /^moon-.+/, MyParticipant.new('Saturn-V')
241
+ #
242
+ #
243
+ # == passing a block to a participant
244
+ #
245
+ # Usually only the BlockParticipant cares about being passed a block :
246
+ #
247
+ # engine.register_participant 'compute_sum' do |workitem|
248
+ # workitem.fields['kilroy'] = 'was here'
249
+ # end
250
+ #
251
+ # But it's OK to pass a block to a custom participant :
252
+ #
253
+ # require 'ruote/part/local_participant'
254
+ #
255
+ # class MyParticipant
256
+ # include Ruote::LocalParticipant
257
+ # def initialize (opts)
258
+ # @name = opts[:name]
259
+ # @block = opts[:block]
260
+ # end
261
+ # def consume (workitem)
262
+ # workitem.fields['prestamp'] = Time.now
263
+ # workitem.fields['author'] = @name
264
+ # @block.call(workitem)
265
+ # reply_to_engine(workitem)
266
+ # end
267
+ # end
268
+ #
269
+ # engine.register_participant 'al', MyParticipant, :name => 'toto' do |wi|
270
+ # wi.fields['nada'] = surf
271
+ # end
272
+ #
273
+ # The block is available under the :block option.
274
+ #
275
+ def register_participant (regex, participant=nil, opts={}, &block)
276
+
277
+ pa = @context.plist.register(regex, participant, opts, block)
278
+
279
+ @context.storage.put_msg(
280
+ 'participant_registered',
281
+ 'regex' => regex.to_s,
282
+ 'engine_worker_only' => (pa != nil))
283
+
284
+ pa
285
+ end
286
+
287
+ # Removes/unregisters a participant from the engine.
288
+ #
289
+ def unregister_participant (name_or_participant)
290
+
291
+ re = @context.plist.unregister(name_or_participant)
292
+
293
+ raise(ArgumentError.new('participant not found')) unless re
294
+
295
+ @context.storage.put_msg(
296
+ 'participant_unregistered',
297
+ 'regex' => re.to_s)
298
+ end
299
+
300
+ # Adds a service locally (will not get propagated to other workers).
301
+ #
302
+ # tracer = Tracer.new
303
+ # @engine.add_service('tracer', tracer)
304
+ #
305
+ # or
306
+ #
307
+ # @engine.add_service('tracer', 'ruote/exp/tracer', 'Ruote::Exp::Tracer')
308
+ #
309
+ def add_service (name, path_or_instance, classname=nil, opts=nil)
310
+
311
+ @context.add_service(name, path_or_instance, classname, opts)
312
+ end
313
+ end
314
+
315
+ #
316
+ # A wrapper class giving easy access to engine variables.
317
+ #
318
+ # There is one instance of this class for an Engine instance. It is
319
+ # returned when calling Engine#variables.
320
+ #
321
+ class EngineVariables
322
+
323
+ def initialize (storage)
324
+
325
+ @storage = storage
326
+ end
327
+
328
+ def [] (k)
329
+
330
+ @storage.get_engine_variable(k)
331
+ end
332
+
333
+ def []= (k, v)
334
+
335
+ @storage.put_engine_variable(k, v)
336
+ end
337
+ end
338
+ end
339
+