ruote 2.2.0 → 2.3.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 (305) hide show
  1. data/CHANGELOG.txt +166 -1
  2. data/CREDITS.txt +36 -17
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +1 -7
  5. data/Rakefile +38 -29
  6. data/TODO.txt +93 -52
  7. data/lib/ruote-fs.rb +3 -0
  8. data/lib/ruote.rb +5 -1
  9. data/lib/ruote/context.rb +140 -35
  10. data/lib/ruote/dashboard.rb +1247 -0
  11. data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
  12. data/lib/ruote/dboard/process_status.rb +587 -0
  13. data/lib/ruote/engine.rb +6 -871
  14. data/lib/ruote/exp/command.rb +7 -2
  15. data/lib/ruote/exp/commanded.rb +2 -2
  16. data/lib/ruote/exp/condition.rb +38 -13
  17. data/lib/ruote/exp/fe_add_branches.rb +1 -1
  18. data/lib/ruote/exp/fe_apply.rb +1 -1
  19. data/lib/ruote/exp/fe_await.rb +357 -0
  20. data/lib/ruote/exp/fe_cancel_process.rb +17 -3
  21. data/lib/ruote/exp/fe_command.rb +8 -4
  22. data/lib/ruote/exp/fe_concurrence.rb +218 -18
  23. data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
  24. data/lib/ruote/exp/fe_cron.rb +3 -10
  25. data/lib/ruote/exp/fe_cursor.rb +14 -4
  26. data/lib/ruote/exp/fe_define.rb +3 -1
  27. data/lib/ruote/exp/fe_echo.rb +1 -1
  28. data/lib/ruote/exp/fe_equals.rb +1 -1
  29. data/lib/ruote/exp/fe_error.rb +1 -1
  30. data/lib/ruote/exp/fe_filter.rb +163 -4
  31. data/lib/ruote/exp/fe_forget.rb +21 -4
  32. data/lib/ruote/exp/fe_given.rb +1 -1
  33. data/lib/ruote/exp/fe_if.rb +1 -1
  34. data/lib/ruote/exp/fe_inc.rb +102 -35
  35. data/lib/ruote/exp/fe_iterator.rb +47 -12
  36. data/lib/ruote/exp/fe_listen.rb +96 -11
  37. data/lib/ruote/exp/fe_lose.rb +31 -4
  38. data/lib/ruote/exp/fe_noop.rb +1 -1
  39. data/lib/ruote/exp/fe_on_error.rb +109 -0
  40. data/lib/ruote/exp/fe_once.rb +10 -19
  41. data/lib/ruote/exp/fe_participant.rb +90 -28
  42. data/lib/ruote/exp/fe_read.rb +69 -0
  43. data/lib/ruote/exp/fe_redo.rb +3 -2
  44. data/lib/ruote/exp/fe_ref.rb +57 -27
  45. data/lib/ruote/exp/fe_registerp.rb +1 -3
  46. data/lib/ruote/exp/fe_reserve.rb +1 -1
  47. data/lib/ruote/exp/fe_restore.rb +6 -6
  48. data/lib/ruote/exp/fe_save.rb +12 -19
  49. data/lib/ruote/exp/fe_sequence.rb +38 -2
  50. data/lib/ruote/exp/fe_set.rb +143 -40
  51. data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
  52. data/lib/ruote/exp/fe_subprocess.rb +8 -2
  53. data/lib/ruote/exp/fe_that.rb +1 -1
  54. data/lib/ruote/exp/fe_undo.rb +40 -4
  55. data/lib/ruote/exp/fe_unregisterp.rb +1 -3
  56. data/lib/ruote/exp/fe_wait.rb +12 -25
  57. data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
  58. data/lib/ruote/exp/iterator.rb +2 -2
  59. data/lib/ruote/exp/merge.rb +78 -17
  60. data/lib/ruote/exp/ro_attributes.rb +46 -36
  61. data/lib/ruote/exp/ro_filters.rb +34 -8
  62. data/lib/ruote/exp/ro_on_x.rb +431 -0
  63. data/lib/ruote/exp/ro_persist.rb +19 -7
  64. data/lib/ruote/exp/ro_timers.rb +123 -0
  65. data/lib/ruote/exp/ro_variables.rb +90 -29
  66. data/lib/ruote/fei.rb +57 -3
  67. data/lib/ruote/fs.rb +3 -0
  68. data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
  69. data/lib/ruote/id/wfid_generator.rb +17 -38
  70. data/lib/ruote/log/default_history.rb +23 -9
  71. data/lib/ruote/log/fancy_printing.rb +265 -0
  72. data/lib/ruote/log/storage_history.rb +23 -13
  73. data/lib/ruote/log/wait_logger.rb +224 -17
  74. data/lib/ruote/observer.rb +82 -0
  75. data/lib/ruote/part/block_participant.rb +65 -28
  76. data/lib/ruote/part/code_participant.rb +81 -0
  77. data/lib/ruote/part/engine_participant.rb +7 -2
  78. data/lib/ruote/part/local_participant.rb +221 -21
  79. data/lib/ruote/part/no_op_participant.rb +1 -1
  80. data/lib/ruote/part/null_participant.rb +1 -1
  81. data/lib/ruote/part/participant.rb +50 -0
  82. data/lib/ruote/part/rev_participant.rb +178 -0
  83. data/lib/ruote/part/smtp_participant.rb +2 -2
  84. data/lib/ruote/part/storage_participant.rb +228 -60
  85. data/lib/ruote/part/template.rb +1 -1
  86. data/lib/ruote/participant.rb +2 -0
  87. data/lib/ruote/reader.rb +205 -68
  88. data/lib/ruote/reader/json.rb +49 -0
  89. data/lib/ruote/reader/radial.rb +303 -0
  90. data/lib/ruote/reader/ruby_dsl.rb +44 -9
  91. data/lib/ruote/reader/xml.rb +11 -8
  92. data/lib/ruote/receiver/base.rb +98 -45
  93. data/lib/ruote/storage/base.rb +104 -35
  94. data/lib/ruote/storage/composite_storage.rb +50 -60
  95. data/lib/ruote/storage/fs_storage.rb +25 -34
  96. data/lib/ruote/storage/hash_storage.rb +38 -36
  97. data/lib/ruote/svc/dispatch_pool.rb +104 -35
  98. data/lib/ruote/svc/dollar_sub.rb +10 -8
  99. data/lib/ruote/svc/error_handler.rb +108 -52
  100. data/lib/ruote/svc/expression_map.rb +3 -3
  101. data/lib/ruote/svc/participant_list.rb +160 -55
  102. data/lib/ruote/svc/tracker.rb +31 -31
  103. data/lib/ruote/svc/treechecker.rb +28 -16
  104. data/lib/ruote/tree_dot.rb +1 -1
  105. data/lib/ruote/util/deep.rb +143 -0
  106. data/lib/ruote/util/filter.rb +125 -18
  107. data/lib/ruote/util/hashdot.rb +15 -13
  108. data/lib/ruote/util/look.rb +1 -1
  109. data/lib/ruote/util/lookup.rb +60 -22
  110. data/lib/ruote/util/misc.rb +63 -18
  111. data/lib/ruote/util/mpatch.rb +53 -0
  112. data/lib/ruote/util/ometa.rb +1 -2
  113. data/lib/ruote/util/process_observer.rb +177 -0
  114. data/lib/ruote/util/subprocess.rb +1 -1
  115. data/lib/ruote/util/time.rb +2 -2
  116. data/lib/ruote/util/tree.rb +64 -2
  117. data/lib/ruote/version.rb +3 -2
  118. data/lib/ruote/worker.rb +421 -92
  119. data/lib/ruote/workitem.rb +157 -22
  120. data/ruote.gemspec +15 -9
  121. data/test/bm/ci.rb +0 -2
  122. data/test/bm/ici.rb +0 -2
  123. data/test/bm/load_26c.rb +0 -3
  124. data/test/bm/mega.rb +0 -2
  125. data/test/functional/base.rb +57 -43
  126. data/test/functional/concurrent_base.rb +16 -13
  127. data/test/functional/ct_0_concurrence.rb +7 -11
  128. data/test/functional/ct_1_iterator.rb +9 -11
  129. data/test/functional/ct_2_cancel.rb +28 -17
  130. data/test/functional/eft_0_flow_expression.rb +35 -0
  131. data/test/functional/eft_10_cancel_process.rb +1 -1
  132. data/test/functional/eft_11_wait.rb +13 -13
  133. data/test/functional/eft_12_listen.rb +199 -66
  134. data/test/functional/eft_13_iterator.rb +95 -29
  135. data/test/functional/eft_14_cursor.rb +74 -24
  136. data/test/functional/eft_15_loop.rb +7 -7
  137. data/test/functional/eft_16_if.rb +1 -1
  138. data/test/functional/eft_17_equals.rb +1 -1
  139. data/test/functional/eft_18_concurrent_iterator.rb +156 -68
  140. data/test/functional/eft_19_reserve.rb +15 -15
  141. data/test/functional/eft_1_echo.rb +1 -1
  142. data/test/functional/eft_20_save.rb +51 -9
  143. data/test/functional/eft_21_restore.rb +1 -1
  144. data/test/functional/eft_22_noop.rb +1 -1
  145. data/test/functional/eft_23_apply.rb +1 -1
  146. data/test/functional/eft_24_add_branches.rb +7 -8
  147. data/test/functional/eft_25_command.rb +1 -1
  148. data/test/functional/eft_26_error.rb +11 -11
  149. data/test/functional/eft_27_inc.rb +111 -67
  150. data/test/functional/eft_28_once.rb +16 -16
  151. data/test/functional/eft_29_cron.rb +9 -9
  152. data/test/functional/eft_2_sequence.rb +23 -4
  153. data/test/functional/eft_30_ref.rb +36 -24
  154. data/test/functional/eft_31_registerp.rb +24 -24
  155. data/test/functional/eft_32_lose.rb +46 -20
  156. data/test/functional/eft_34_given.rb +1 -1
  157. data/test/functional/eft_35_filter.rb +161 -7
  158. data/test/functional/eft_36_read.rb +97 -0
  159. data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
  160. data/test/functional/eft_38_on_error.rb +195 -0
  161. data/test/functional/eft_39_stall.rb +35 -0
  162. data/test/functional/eft_3_participant.rb +77 -22
  163. data/test/functional/eft_40_await.rb +297 -0
  164. data/test/functional/eft_4_set.rb +110 -11
  165. data/test/functional/eft_5_subprocess.rb +27 -5
  166. data/test/functional/eft_6_concurrence.rb +299 -60
  167. data/test/functional/eft_7_forget.rb +24 -22
  168. data/test/functional/eft_8_undo.rb +52 -15
  169. data/test/functional/eft_9_redo.rb +18 -20
  170. data/test/functional/ft_0_worker.rb +122 -13
  171. data/test/functional/ft_10_dollar.rb +77 -16
  172. data/test/functional/ft_11_recursion.rb +9 -9
  173. data/test/functional/ft_12_launchitem.rb +7 -9
  174. data/test/functional/ft_13_variables.rb +125 -22
  175. data/test/functional/ft_14_re_apply.rb +112 -56
  176. data/test/functional/ft_15_timeout.rb +64 -33
  177. data/test/functional/ft_16_participant_params.rb +59 -6
  178. data/test/functional/ft_17_conditional.rb +68 -2
  179. data/test/functional/ft_18_kill.rb +48 -30
  180. data/test/functional/ft_19_participant_code.rb +67 -0
  181. data/test/functional/ft_1_process_status.rb +222 -150
  182. data/test/functional/ft_20_storage_participant.rb +445 -44
  183. data/test/functional/ft_21_forget.rb +21 -26
  184. data/test/functional/ft_22_process_definitions.rb +8 -6
  185. data/test/functional/ft_23_load_defs.rb +29 -5
  186. data/test/functional/ft_24_block_participant.rb +199 -20
  187. data/test/functional/ft_25_receiver.rb +98 -46
  188. data/test/functional/ft_26_participant_rtimeout.rb +34 -26
  189. data/test/functional/ft_27_var_indirection.rb +40 -5
  190. data/test/functional/ft_28_null_noop_participants.rb +5 -5
  191. data/test/functional/ft_29_part_template.rb +2 -2
  192. data/test/functional/ft_2_errors.rb +106 -74
  193. data/test/functional/ft_30_smtp_participant.rb +7 -7
  194. data/test/functional/ft_31_part_blocking.rb +11 -11
  195. data/test/functional/ft_32_scope.rb +50 -0
  196. data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
  197. data/test/functional/ft_34_cursor_rewind.rb +14 -14
  198. data/test/functional/ft_35_add_service.rb +67 -9
  199. data/test/functional/ft_36_storage_history.rb +92 -24
  200. data/test/functional/ft_37_default_history.rb +35 -23
  201. data/test/functional/ft_38_participant_more.rb +189 -32
  202. data/test/functional/ft_39_wait_for.rb +25 -25
  203. data/test/functional/ft_3_participant_registration.rb +235 -107
  204. data/test/functional/ft_40_wait_logger.rb +105 -18
  205. data/test/functional/ft_41_participants.rb +13 -12
  206. data/test/functional/ft_42_storage_copy.rb +12 -12
  207. data/test/functional/ft_43_participant_on_reply.rb +85 -11
  208. data/test/functional/ft_44_var_participant.rb +5 -5
  209. data/test/functional/ft_45_participant_accept.rb +3 -3
  210. data/test/functional/ft_46_launch_single.rb +17 -17
  211. data/test/functional/ft_47_wfids.rb +41 -0
  212. data/test/functional/ft_48_lose.rb +19 -25
  213. data/test/functional/ft_49_engine_on_error.rb +54 -70
  214. data/test/functional/ft_4_cancel.rb +84 -26
  215. data/test/functional/ft_50_engine_config.rb +4 -4
  216. data/test/functional/ft_51_misc.rb +12 -12
  217. data/test/functional/ft_52_case.rb +17 -17
  218. data/test/functional/ft_53_engine_on_terminate.rb +18 -21
  219. data/test/functional/ft_54_patterns.rb +18 -16
  220. data/test/functional/ft_55_engine_participant.rb +55 -55
  221. data/test/functional/ft_56_filter_attribute.rb +90 -52
  222. data/test/functional/ft_57_rev_participant.rb +252 -0
  223. data/test/functional/ft_58_workitem.rb +150 -0
  224. data/test/functional/ft_59_pause.rb +329 -0
  225. data/test/functional/ft_5_on_error.rb +430 -77
  226. data/test/functional/ft_60_code_participant.rb +65 -0
  227. data/test/functional/ft_61_trailing_fields.rb +34 -0
  228. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  229. data/test/functional/ft_63_participants_221.rb +458 -0
  230. data/test/functional/ft_64_stash.rb +41 -0
  231. data/test/functional/ft_65_timers.rb +313 -0
  232. data/test/functional/ft_66_flank.rb +133 -0
  233. data/test/functional/ft_67_radial_misc.rb +34 -0
  234. data/test/functional/ft_68_reput.rb +72 -0
  235. data/test/functional/ft_69_worker_info.rb +56 -0
  236. data/test/functional/ft_6_on_cancel.rb +189 -36
  237. data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
  238. data/test/functional/ft_71_retries.rb +144 -0
  239. data/test/functional/ft_72_on_terminate.rb +60 -0
  240. data/test/functional/ft_73_raise_msg.rb +107 -0
  241. data/test/functional/ft_74_respark.rb +106 -0
  242. data/test/functional/ft_75_context.rb +66 -0
  243. data/test/functional/ft_76_observer.rb +53 -0
  244. data/test/functional/ft_77_process_observer.rb +157 -0
  245. data/test/functional/ft_78_part_participant.rb +37 -0
  246. data/test/functional/ft_7_tags.rb +238 -50
  247. data/test/functional/ft_8_participant_consumption.rb +27 -21
  248. data/test/functional/ft_9_subprocesses.rb +48 -18
  249. data/test/functional/restart_base.rb +4 -6
  250. data/test/functional/rt_0_wait.rb +10 -10
  251. data/test/functional/rt_1_listen.rb +6 -6
  252. data/test/functional/rt_2_errors.rb +12 -12
  253. data/test/functional/rt_3_once.rb +17 -12
  254. data/test/functional/rt_4_cron.rb +17 -17
  255. data/test/functional/rt_5_timeout.rb +13 -13
  256. data/test/functional/signals.rb +103 -0
  257. data/test/functional/storage.rb +730 -0
  258. data/test/functional/storage_helper.rb +48 -35
  259. data/test/functional/test.rb +6 -2
  260. data/test/misc/idle.rb +21 -0
  261. data/test/misc/light.rb +29 -0
  262. data/test/path_helper.rb +1 -1
  263. data/test/test.rb +2 -5
  264. data/test/test_helper.rb +13 -0
  265. data/test/unit/test.rb +1 -4
  266. data/test/unit/ut_0_ruby_reader.rb +25 -9
  267. data/test/unit/ut_10_participants.rb +47 -0
  268. data/test/unit/ut_11_lookup.rb +59 -2
  269. data/test/unit/ut_12_wait_logger.rb +123 -0
  270. data/test/unit/ut_14_is_uri.rb +1 -1
  271. data/test/unit/ut_15_util.rb +1 -1
  272. data/test/unit/ut_16_reader.rb +136 -14
  273. data/test/unit/ut_17_merge.rb +155 -0
  274. data/test/unit/ut_19_part_template.rb +1 -1
  275. data/test/unit/ut_1_fei.rb +11 -2
  276. data/test/unit/ut_20_composite_storage.rb +27 -1
  277. data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
  278. data/test/unit/ut_22_filter.rb +231 -10
  279. data/test/unit/ut_23_svc_tracker.rb +48 -0
  280. data/test/unit/ut_24_radial_reader.rb +458 -0
  281. data/test/unit/ut_25_process_status.rb +143 -0
  282. data/test/unit/ut_26_deep.rb +131 -0
  283. data/test/unit/ut_2_dashboard.rb +114 -0
  284. data/test/unit/ut_3_worker.rb +54 -0
  285. data/test/unit/ut_4_expmap.rb +1 -1
  286. data/test/unit/ut_5_tree.rb +23 -23
  287. data/test/unit/ut_6_condition.rb +71 -29
  288. data/test/unit/ut_7_workitem.rb +18 -4
  289. data/test/unit/ut_8_tree_to_dot.rb +1 -1
  290. data/test/unit/ut_9_xml_reader.rb +1 -1
  291. metadata +142 -63
  292. data/jruby_issue.txt +0 -32
  293. data/lib/ruote/engine/process_status.rb +0 -403
  294. data/lib/ruote/log/pretty.rb +0 -165
  295. data/lib/ruote/log/test_logger.rb +0 -204
  296. data/lib/ruote/util/serializer.rb +0 -103
  297. data/phil.txt +0 -14
  298. data/test/functional/eft_33_let.rb +0 -31
  299. data/test/functional/ft_19_alias.rb +0 -33
  300. data/test/functional/ft_47_wfid_generator.rb +0 -54
  301. data/test/unit/storage.rb +0 -403
  302. data/test/unit/storages.rb +0 -37
  303. data/test/unit/ut_13_serializer.rb +0 -65
  304. data/test/unit/ut_18_engine.rb +0 -47
  305. data/test/unit/ut_3_wait_logger.rb +0 -39
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -94,7 +94,6 @@ module Ruote::Exp
94
94
  def apply
95
95
 
96
96
  h.schedule = attribute(:tab) || attribute(:interval) || attribute_text
97
- h.job_id = nil
98
97
 
99
98
  reschedule
100
99
  end
@@ -110,17 +109,11 @@ module Ruote::Exp
110
109
  reschedule
111
110
  end
112
111
 
113
- def cancel(flavour)
114
-
115
- @context.storage.delete_schedule(h.job_id)
116
- reply_to_parent(h.applied_workitem)
117
- end
118
-
119
112
  # Note : this method has to be public.
120
113
  #
121
114
  def reschedule
122
115
 
123
- h.job_id = @context.storage.put_schedule(
116
+ h.schedule_id = @context.storage.put_schedule(
124
117
  'cron',
125
118
  h.fei,
126
119
  h.schedule,
@@ -128,7 +121,7 @@ module Ruote::Exp
128
121
  'fei' => h.fei,
129
122
  'workitem' => h.applied_workitem)
130
123
 
131
- @context.storage.delete_schedule(h.job_id) if try_persist
124
+ @context.storage.delete_schedule(h.schedule_id) if try_persist
132
125
  #
133
126
  # if the persist failed, immediately unschedule
134
127
  # the just scheduled job
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -66,6 +66,12 @@ module Ruote::Exp
66
66
  # publisher
67
67
  # end
68
68
  #
69
+ # === reset
70
+ #
71
+ # Whereas 'rewind' places the cursor back to the initial step with the current
72
+ # workitem, 'reset' will rewind it and start again but with the workitem
73
+ # as it was when it reached the cursor/repeat.
74
+ #
69
75
  # === stop, over & break
70
76
  #
71
77
  # Exits the cursor.
@@ -262,7 +268,7 @@ module Ruote::Exp
262
268
  return reply_to_parent(workitem) if com == 'break'
263
269
 
264
270
  case com
265
- when 'rewind', 'continue' then position = 0
271
+ when 'rewind', 'continue', 'reset' then position = 0
266
272
  when 'skip' then position += arg
267
273
  when 'jump' then position = jump_to(workitem, position, arg)
268
274
  end
@@ -270,8 +276,12 @@ module Ruote::Exp
270
276
  position = 0 if position >= tree_children.size && is_loop?
271
277
 
272
278
  if position < tree_children.size
279
+
280
+ workitem = h.applied_workitem if com == 'reset'
273
281
  apply_child(position, workitem)
282
+
274
283
  else
284
+
275
285
  reply_to_parent(workitem)
276
286
  end
277
287
  end
@@ -298,8 +308,8 @@ module Ruote::Exp
298
308
  ref = c[1]['ref']
299
309
  tag = c[1]['tag']
300
310
 
301
- ref = @context.dollar_sub.s(ref, self, workitem) if ref
302
- tag = @context.dollar_sub.s(tag, self, workitem) if tag
311
+ ref = dsub(ref, workitem) if ref
312
+ tag = dsub(tag, workitem) if tag
303
313
 
304
314
  next if exp_name != arg && ref != arg && tag != arg
305
315
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -105,6 +105,8 @@ module Ruote::Exp
105
105
  definitions, bodies = tree[2].partition { |b| is_definition?(b) }
106
106
  name = tree[1]['name'] || tree[1].keys.find { |k| tree[1][k] == nil }
107
107
 
108
+ definitions = definitions.collect { |d| reorganize(d)[1] }
109
+
108
110
  [ name, [ 'define', tree[1], definitions + bodies ] ]
109
111
  end
110
112
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -80,6 +80,12 @@ module Ruote::Exp
80
80
  #
81
81
  # Note the "!" used as a shortcut for "\." in the second line.
82
82
  #
83
+ # Passing a | separated list of field also works :
84
+ #
85
+ # filter 'city|region|country', :type => 'string'
86
+ # # will make sure that at least of one those field is present
87
+ # # any of the three that is present must hold a string
88
+ #
83
89
  #
84
90
  # == validations
85
91
  #
@@ -162,6 +168,13 @@ module Ruote::Exp
162
168
  #
163
169
  # filter 'x', :empty => true
164
170
  #
171
+ # === 'is'
172
+ #
173
+ # Checks if a field holds the given value.
174
+ #
175
+ # filter 'x', :is => true
176
+ # filter 'x', :is => [ 'a', 2, 3 ]
177
+ #
165
178
  # === 'in'
166
179
  #
167
180
  # Checks if a value is in a given set of values.
@@ -183,6 +196,15 @@ module Ruote::Exp
183
196
  # filter 'x', :has => "x"
184
197
  # filter 'x', :has => "abraham, bob, charly"
185
198
  #
199
+ # === 'includes'
200
+ #
201
+ # Checks if an array includes a given value. Works with Hash values as well.
202
+ #
203
+ # filter 'x', :includes => 1
204
+ #
205
+ # Whereas 'has' accepts multiple values, 'includes' only accepts one (like
206
+ # Ruby's Array#include?).
207
+ #
186
208
  # === 'valid'
187
209
  #
188
210
  # Sometimes, it's better to immediately say 'true' or 'false'.
@@ -398,6 +420,34 @@ module Ruote::Exp
398
420
  # { 'field' => 'A', 'delete' => true } ]
399
421
  # # out : { 'x' => 'a', 'y' => 'a' })
400
422
  #
423
+ # === 'take' and 'discard'
424
+ #
425
+ # (doesn't work well with the filter expression, it works better with
426
+ # filter as an attribute)
427
+ #
428
+ # Those two only make sense in out filters. One should use one or the other in
429
+ # a filter, but not both. It's probably better to use them at the bottom of
430
+ # the filters (last positions), because they switch the applied workitem
431
+ # (apply time) with the current workitem (reply time).
432
+ #
433
+ # 'take' means "the fields to consider are the one in the applied workitem
434
+ # plus the ones from the new workitem listed here".
435
+ #
436
+ # 'discard' means "the fields to consider are the the ones of the applied
437
+ # workitem plus all the ones from the new workitem except those listed here".
438
+ #
439
+ # subprocess 'list_products', :filter => { :out => [
440
+ # { 'field' => 'products', 'take' => true },
441
+ # { 'field' => 'point_of_contact', 'take' => true }
442
+ # ] }
443
+ # # whatever the fields set by 'list_products', only 'products' and
444
+ # # 'point_of_contact' make it through
445
+ #
446
+ # Saying :discard => true means "completely ignore any workitem field set
447
+ # by this expression".
448
+ #
449
+ # subprocess 'review_document', :discard => true
450
+ #
401
451
  #
402
452
  # == short forms
403
453
  #
@@ -421,6 +471,23 @@ module Ruote::Exp
421
471
  # * 'restore', 'restore_from', 'rs'
422
472
  #
423
473
  #
474
+ # == top-level 'or'
475
+ #
476
+ # Filters may be used to transform hashes or to validate them. In both cases
477
+ # the filters seen until now were like chained by a big AND.
478
+ #
479
+ # It's OK to write
480
+ #
481
+ # filter :in => [
482
+ # { 'field' => 'server_href', 'smatch' => '^https?:\/\/' },
483
+ # 'or',
484
+ # { 'field' => 'nickname', 'type' => 'string' } ]
485
+ #
486
+ # Granted, this is mostly for validation purposes, but it also works
487
+ # with transformations (as soon as an 'or' child succeeds it's returned
488
+ # and the other children are not evaluated).
489
+ #
490
+ #
424
491
  # == compared to the :filter attribute
425
492
  #
426
493
  # The :filter attribute accepts participant names, but for this filter
@@ -430,13 +497,42 @@ module Ruote::Exp
430
497
  # The 'restore' operation makes lots of sense for the :filter attribute
431
498
  # though.
432
499
  #
500
+ #
501
+ # == filtering with rules in a block
502
+ #
503
+ # This filter
504
+ #
505
+ # filter :in => [
506
+ # { :field => 'x', :type => 'string' },
507
+ # { :field => 'y', :type => 'number' }
508
+ # ]
509
+ #
510
+ # can be rewritten as
511
+ #
512
+ # filter do
513
+ # field 'x', :type => 'string'
514
+ # field 'y', :type => 'number'
515
+ # end
516
+ #
517
+ # The field names can be passed directly as head of each rule :
518
+ #
519
+ # filter do
520
+ # x :type => 'string'
521
+ # y :type => 'number'
522
+ # end
523
+ #
433
524
  class FilterExpression < FlowExpression
434
525
 
435
526
  names :filter
436
527
 
437
528
  def apply
438
529
 
439
- filter = referenced_filter || complete_filter || one_line_filter
530
+ h.applied_workitem['fields'].delete('__result__')
531
+ #
532
+ # get rid of __result__
533
+
534
+ filter =
535
+ referenced_filter || complete_filter || one_line_filter || block_filter
440
536
 
441
537
  record = filter.first.delete('record') rescue nil
442
538
  flush = filter.first.delete('flush') rescue nil
@@ -480,6 +576,50 @@ module Ruote::Exp
480
576
 
481
577
  protected
482
578
 
579
+ # Filter is passed in a block (which is not evaluted as a ruote branch
580
+ # but immediately translated into a filter.
581
+ #
582
+ # pdef = Ruote.process_definition do
583
+ # filter do
584
+ # field 'x', :type => 'string'
585
+ # field 'y', :type => 'number'
586
+ # end
587
+ # end
588
+ #
589
+ # Note : 'or' is OK
590
+ #
591
+ # pdef = Ruote.process_definition do
592
+ # filter do
593
+ # field 'x', :type => 'string'
594
+ # _or
595
+ # field 'y', :type => 'number'
596
+ # end
597
+ # end
598
+ #
599
+ def block_filter
600
+
601
+ return nil if tree.last.empty?
602
+
603
+ tree.last.collect { |line|
604
+
605
+ next 'or' if line.first == 'or'
606
+
607
+ rule = line[1].remap { |(k, v), h|
608
+ if v == nil
609
+ h['field'] = k
610
+ else
611
+ h[k] = v
612
+ end
613
+ }
614
+
615
+ rule['field'] ||= line.first
616
+
617
+ rule
618
+ }
619
+ end
620
+
621
+ # Filter is somewhere else (process variable or workitem field)
622
+ #
483
623
  def referenced_filter
484
624
 
485
625
  prefix, key = attribute_text.split(':')
@@ -496,6 +636,15 @@ module Ruote::Exp
496
636
  filter
497
637
  end
498
638
 
639
+ # Filter is passed with an :in attribute.
640
+ #
641
+ # Ruote.process_definition do
642
+ # filter :in => [
643
+ # { :field => 'x', :type => 'string' },
644
+ # { :field => 'y', :type => 'number' }
645
+ # ]
646
+ # end
647
+ #
499
648
  def complete_filter
500
649
 
501
650
  return nil if attribute_text != ''
@@ -503,15 +652,25 @@ module Ruote::Exp
503
652
  attribute(:in)
504
653
  end
505
654
 
655
+ # Filter thanks to the attributes of the expression.
656
+ #
657
+ # pdef = Ruote.process_definition do
658
+ # filter 'x', :type => 'string', :record => true
659
+ # filter 'y', :type => 'number', :record => true
660
+ # end
661
+ #
506
662
  def one_line_filter
507
663
 
508
- [ attributes.inject({}) { |h, (k, v)|
664
+ if (attributes.keys - COMMON_ATT_KEYS - %w[ ref original_ref ]).empty?
665
+ return nil
666
+ end
667
+
668
+ [ attributes.remap { |(k, v), h|
509
669
  if v.nil?
510
670
  h['field'] = k
511
671
  else
512
672
  h[k] = v
513
673
  end
514
- h
515
674
  } ]
516
675
  end
517
676
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -57,14 +57,31 @@ module Ruote::Exp
57
57
  # participant 'delta'
58
58
  # end
59
59
  #
60
- # This expression can be useful for fire-and-forget parallelism in processes.
60
+ # This expression can be useful for fire-and-forget 'parallelism'
61
+ # in processes.
61
62
  #
62
- # == forget vs lose
63
+ #
64
+ # == multi forget
65
+ #
66
+ # Forget multiple children at once.
67
+ #
68
+ # forget do
69
+ # alice :task => 'take out garbage'
70
+ # bob :task => 'clean living room'
71
+ # end
72
+ #
73
+ # The forget expression will reply immediately to its parent expression, it
74
+ # will thus not be cancellable (neither the children will be cancellable).
75
+ #
76
+ #
77
+ # == forget vs lose vs flank
63
78
  #
64
79
  # forget : replies to parent expression immediately, is not cancellable
65
80
  # (not reachable).
66
81
  #
67
- # lose : never replies to parent expression, is cancellable.
82
+ # lose : never replies to the parent expression, is cancellable.
83
+ #
84
+ # flank : immediately replies to the parent expression, is cancellable.
68
85
  #
69
86
  class ForgetExpression < FlowExpression
70
87
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,6 @@
23
23
  #++
24
24
 
25
25
 
26
- require 'ruote/exp/fe_set'
27
-
28
-
29
26
  module Ruote::Exp
30
27
 
31
28
  #
@@ -75,8 +72,8 @@ module Ruote::Exp
75
72
  # set 'v:x' => %w[ a b c d ]
76
73
  # repeat do
77
74
  # dec 'v:x', :pos => 'head'
78
- # _break :unless => '${v:d}'
79
- # participant '${v:d}'
75
+ # _break :unless => '${__result__}'
76
+ # participant '${__result__}'
80
77
  # end
81
78
  # end
82
79
  #
@@ -108,7 +105,7 @@ module Ruote::Exp
108
105
  # dec 'v:x', :val => 'bryan'
109
106
  # # the variable 'x' now holds [ 'alfred', 'carl' ]
110
107
  #
111
- # 'dec' places the removed value in the local variable named 'd'. This trick
108
+ # 'dec' places the removed value in workitem field '__result__'. This trick
112
109
  # was used in the above iterator example.
113
110
  #
114
111
  # A specific variable or field can be specified via the :to_var / :to_field
@@ -117,65 +114,137 @@ module Ruote::Exp
117
114
  # dec 'v:x', :to_v => 'a'
118
115
  # participant :ref => '${v:a}'
119
116
  #
120
- class IncExpression < SetExpression
117
+ #
118
+ # == nested value
119
+ #
120
+ # (Since ruote 2.3.0)
121
+ #
122
+ # If nested expressions are provided the __result__ workitem field is
123
+ # used for inc.
124
+ #
125
+ # inc 'v:x' do
126
+ # set '__result__' => 3
127
+ # end
128
+ #
129
+ # will increase the value of the variable x by 3.
130
+ #
131
+ #
132
+ # == push and pop
133
+ #
134
+ # push and pop are aliases for inc and dec respectively. There is a major
135
+ # difference though: they'll force the target value into an array.
136
+ #
137
+ # sequence do
138
+ # set 'v:x' => 2
139
+ # push 'v:x' => 3
140
+ # end
141
+ #
142
+ # will result in a variable x holding [ 2, 3 ] as value.
143
+ #
144
+ # Likewise,
145
+ #
146
+ # pop 'v:x'
147
+ #
148
+ # will force a value of [] into the variable x if it wasn't previously set
149
+ # or its value was not an array with more than one element.
150
+ #
151
+ class IncExpression < SequenceExpression
121
152
 
122
- names :inc, :dec, :increment, :decrement
153
+ names :inc, :dec, :increment, :decrement, :push, :pop
123
154
 
124
155
  def apply
125
156
 
126
- if var_key = has_attribute(:v, :var, :variable)
157
+ h.variables ||= {} # ensures a local scope
158
+
159
+ reply(h.applied_workitem)
160
+ end
161
+
162
+ def reply_to_parent(workitem)
163
+
164
+ h.applied_workitem['fields'] = workitem['fields']
165
+
166
+ key, value = if var_key = has_attribute(:v, :var, :variable)
127
167
 
128
168
  var = attribute(var_key)
129
- set_v(var, new_value(:var, var))
169
+
170
+ [ "v:#{var}", new_value(:var, var, nil) ]
130
171
 
131
172
  elsif field_key = has_attribute(:f, :fld, :field)
132
173
 
133
174
  field = attribute(field_key)
134
- set_f(field, new_value(:field, field))
135
175
 
136
- else
176
+ [ field, new_value(:field, field, nil) ]
177
+
178
+ elsif k = att_text
179
+
180
+ [ k, new_value(nil, k, nil) ]
137
181
 
138
- k = attribute_text
182
+ elsif kv = find_kv
139
183
 
140
- raise(
141
- ArgumentError.new('no variable or field to increment/decrement')
142
- ) if k.length < 1
184
+ k, v = kv
143
185
 
144
- set_vf(k, new_value(nil, k))
186
+ [ k, new_value(nil, k, v) ]
145
187
 
146
- #else
147
- # raise ArgumentError.new(
148
- # "missing a variable or field target in #{tree.inspect}")
188
+ else
189
+
190
+ raise(ArgumentError.new('no variable or field to increment/decrement'))
149
191
  end
150
192
 
151
- reply_to_parent(h.applied_workitem)
152
- end
193
+ h.variables = nil
194
+ # the local scope is over,
195
+ # variables set here will be set in the parent scope
196
+
197
+ if dec? && value.is_a?(Array)
198
+ k, car, value = value
199
+ set_vf(k || '__result__', car)
200
+ end
153
201
 
154
- def reply(workitem)
202
+ set_vf(key, value)
155
203
 
156
- # never called
204
+ super(h.applied_workitem)
157
205
  end
158
206
 
159
207
  protected
160
208
 
161
- def new_value(type, key)
209
+ def find_kv
162
210
 
163
- dec = name.match(/^dec/)
211
+ compile_atts.reject { |k, v|
212
+ COMMON_ATT_KEYS.include?(k) ||
213
+ k.match(/^to_/)
214
+ }.first
215
+ end
216
+
217
+ def dec?
218
+
219
+ @dec ||= !!(name.match(/^dec/) or name == 'pop')
220
+ end
221
+
222
+ def new_value(type, key, increment)
164
223
 
165
224
  if type == nil && m = PREFIX_REGEX.match(key)
166
225
  type = (m[1][0, 1] == 'f' ? :field : :var)
167
226
  key = m[2]
168
227
  end
169
228
 
170
- delta = lookup_val
229
+ delta = increment.nil? ? lookup_val : increment
230
+
231
+ if delta.nil? && @msg && @msg['action'] == 'reply'
232
+ delta = h.applied_workitem['fields']['__result__']
233
+ end
171
234
 
172
235
  ndelta = Ruote.narrow_to_number(delta || 1)
173
- ndelta = -ndelta if dec && ndelta
236
+ ndelta = -ndelta if dec? && ndelta
174
237
 
175
238
  value = type == :var ?
176
239
  lookup_variable(key) :
177
240
  Ruote.lookup(h.applied_workitem['fields'], key)
178
241
 
242
+ value = case value
243
+ when NilClass then []
244
+ when Array then value
245
+ else [ value ]
246
+ end if (name == 'push' || name == 'pop')
247
+
179
248
  pos = attribute(:position) || attribute(:pos)
180
249
 
181
250
  return ((value || 0) + ndelta) if ndelta && (not value.is_a?(Array))
@@ -183,10 +252,7 @@ module Ruote::Exp
183
252
  pos ||= 'tail'
184
253
  value ||= []
185
254
 
186
- return (pos == 'tail' ? value + [ delta ] : [ delta ] + value) unless dec
187
-
188
- to_v, to_f = determine_tos
189
- to_v = 'd' if to_v.nil? && to_f.nil?
255
+ return (pos == 'tail' ? value + [ delta ] : [ delta ] + value) unless dec?
190
256
 
191
257
  car, cdr = if delta != nil
192
258
  (value.delete(delta) != nil ) ? [ delta, value ] : [ nil, value ]
@@ -196,9 +262,10 @@ module Ruote::Exp
196
262
  [ value[0], value[1..-1] ]
197
263
  end
198
264
 
199
- to_v ? set_v(to_v, car) : set_f(to_f, car)
265
+ to_v, to_f = determine_tos
266
+ key = to_v ? "v:#{to_v}" : to_f
200
267
 
201
- cdr
268
+ [ key, car, cdr ]
202
269
  end
203
270
  end
204
271
  end