ruote 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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