ruote-maestrodev 2.2.1

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 (265) hide show
  1. data/CHANGELOG.txt +290 -0
  2. data/CREDITS.txt +99 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.rdoc +88 -0
  5. data/Rakefile +108 -0
  6. data/TODO.txt +488 -0
  7. data/lib/ruote.rb +7 -0
  8. data/lib/ruote/context.rb +194 -0
  9. data/lib/ruote/engine.rb +1062 -0
  10. data/lib/ruote/engine/process_error.rb +122 -0
  11. data/lib/ruote/engine/process_status.rb +448 -0
  12. data/lib/ruote/exp/command.rb +87 -0
  13. data/lib/ruote/exp/commanded.rb +69 -0
  14. data/lib/ruote/exp/condition.rb +227 -0
  15. data/lib/ruote/exp/fe_add_branches.rb +138 -0
  16. data/lib/ruote/exp/fe_apply.rb +154 -0
  17. data/lib/ruote/exp/fe_cancel_process.rb +78 -0
  18. data/lib/ruote/exp/fe_command.rb +156 -0
  19. data/lib/ruote/exp/fe_concurrence.rb +321 -0
  20. data/lib/ruote/exp/fe_concurrent_iterator.rb +219 -0
  21. data/lib/ruote/exp/fe_cron.rb +141 -0
  22. data/lib/ruote/exp/fe_cursor.rb +324 -0
  23. data/lib/ruote/exp/fe_define.rb +112 -0
  24. data/lib/ruote/exp/fe_echo.rb +60 -0
  25. data/lib/ruote/exp/fe_equals.rb +115 -0
  26. data/lib/ruote/exp/fe_error.rb +82 -0
  27. data/lib/ruote/exp/fe_filter.rb +648 -0
  28. data/lib/ruote/exp/fe_forget.rb +88 -0
  29. data/lib/ruote/exp/fe_given.rb +154 -0
  30. data/lib/ruote/exp/fe_if.rb +127 -0
  31. data/lib/ruote/exp/fe_inc.rb +205 -0
  32. data/lib/ruote/exp/fe_iterator.rb +234 -0
  33. data/lib/ruote/exp/fe_let.rb +75 -0
  34. data/lib/ruote/exp/fe_listen.rb +304 -0
  35. data/lib/ruote/exp/fe_lose.rb +110 -0
  36. data/lib/ruote/exp/fe_noop.rb +45 -0
  37. data/lib/ruote/exp/fe_once.rb +215 -0
  38. data/lib/ruote/exp/fe_participant.rb +287 -0
  39. data/lib/ruote/exp/fe_read.rb +69 -0
  40. data/lib/ruote/exp/fe_redo.rb +82 -0
  41. data/lib/ruote/exp/fe_ref.rb +152 -0
  42. data/lib/ruote/exp/fe_registerp.rb +110 -0
  43. data/lib/ruote/exp/fe_reserve.rb +126 -0
  44. data/lib/ruote/exp/fe_restore.rb +102 -0
  45. data/lib/ruote/exp/fe_save.rb +72 -0
  46. data/lib/ruote/exp/fe_sequence.rb +59 -0
  47. data/lib/ruote/exp/fe_set.rb +154 -0
  48. data/lib/ruote/exp/fe_subprocess.rb +211 -0
  49. data/lib/ruote/exp/fe_that.rb +92 -0
  50. data/lib/ruote/exp/fe_undo.rb +67 -0
  51. data/lib/ruote/exp/fe_unregisterp.rb +69 -0
  52. data/lib/ruote/exp/fe_wait.rb +95 -0
  53. data/lib/ruote/exp/flowexpression.rb +886 -0
  54. data/lib/ruote/exp/iterator.rb +81 -0
  55. data/lib/ruote/exp/merge.rb +118 -0
  56. data/lib/ruote/exp/ro_attributes.rb +212 -0
  57. data/lib/ruote/exp/ro_filters.rb +136 -0
  58. data/lib/ruote/exp/ro_persist.rb +154 -0
  59. data/lib/ruote/exp/ro_variables.rb +189 -0
  60. data/lib/ruote/exp/ro_vf.rb +68 -0
  61. data/lib/ruote/fei.rb +260 -0
  62. data/lib/ruote/id/mnemo_wfid_generator.rb +43 -0
  63. data/lib/ruote/id/wfid_generator.rb +81 -0
  64. data/lib/ruote/log/default_history.rb +122 -0
  65. data/lib/ruote/log/pretty.rb +176 -0
  66. data/lib/ruote/log/storage_history.rb +159 -0
  67. data/lib/ruote/log/test_logger.rb +208 -0
  68. data/lib/ruote/log/wait_logger.rb +64 -0
  69. data/lib/ruote/part/block_participant.rb +137 -0
  70. data/lib/ruote/part/code_participant.rb +81 -0
  71. data/lib/ruote/part/engine_participant.rb +189 -0
  72. data/lib/ruote/part/local_participant.rb +138 -0
  73. data/lib/ruote/part/no_op_participant.rb +60 -0
  74. data/lib/ruote/part/null_participant.rb +54 -0
  75. data/lib/ruote/part/rev_participant.rb +169 -0
  76. data/lib/ruote/part/smtp_participant.rb +116 -0
  77. data/lib/ruote/part/storage_participant.rb +392 -0
  78. data/lib/ruote/part/template.rb +84 -0
  79. data/lib/ruote/participant.rb +7 -0
  80. data/lib/ruote/reader.rb +278 -0
  81. data/lib/ruote/reader/json.rb +49 -0
  82. data/lib/ruote/reader/radial.rb +290 -0
  83. data/lib/ruote/reader/ruby_dsl.rb +186 -0
  84. data/lib/ruote/reader/xml.rb +99 -0
  85. data/lib/ruote/receiver/base.rb +212 -0
  86. data/lib/ruote/storage/base.rb +364 -0
  87. data/lib/ruote/storage/composite_storage.rb +121 -0
  88. data/lib/ruote/storage/fs_storage.rb +139 -0
  89. data/lib/ruote/storage/hash_storage.rb +211 -0
  90. data/lib/ruote/svc/dispatch_pool.rb +158 -0
  91. data/lib/ruote/svc/dollar_sub.rb +298 -0
  92. data/lib/ruote/svc/error_handler.rb +138 -0
  93. data/lib/ruote/svc/expression_map.rb +97 -0
  94. data/lib/ruote/svc/participant_list.rb +397 -0
  95. data/lib/ruote/svc/tracker.rb +172 -0
  96. data/lib/ruote/svc/treechecker.rb +141 -0
  97. data/lib/ruote/tree_dot.rb +85 -0
  98. data/lib/ruote/util/filter.rb +525 -0
  99. data/lib/ruote/util/hashdot.rb +79 -0
  100. data/lib/ruote/util/look.rb +128 -0
  101. data/lib/ruote/util/lookup.rb +127 -0
  102. data/lib/ruote/util/misc.rb +167 -0
  103. data/lib/ruote/util/ometa.rb +71 -0
  104. data/lib/ruote/util/serializer.rb +103 -0
  105. data/lib/ruote/util/subprocess.rb +88 -0
  106. data/lib/ruote/util/time.rb +100 -0
  107. data/lib/ruote/util/tree.rb +58 -0
  108. data/lib/ruote/version.rb +29 -0
  109. data/lib/ruote/worker.rb +386 -0
  110. data/lib/ruote/workitem.rb +394 -0
  111. data/phil.txt +14 -0
  112. data/ruote.gemspec +44 -0
  113. data/test/bm/ci.rb +55 -0
  114. data/test/bm/ici.rb +71 -0
  115. data/test/bm/juuman.rb +54 -0
  116. data/test/bm/launch_bench.rb +37 -0
  117. data/test/bm/load_26c.rb +97 -0
  118. data/test/bm/mega.rb +64 -0
  119. data/test/bm/seq_thousand.rb +31 -0
  120. data/test/bm/t.rb +35 -0
  121. data/test/functional/base.rb +247 -0
  122. data/test/functional/concurrent_base.rb +98 -0
  123. data/test/functional/crunner.rb +31 -0
  124. data/test/functional/ct_0_concurrence.rb +65 -0
  125. data/test/functional/ct_1_iterator.rb +67 -0
  126. data/test/functional/ct_2_cancel.rb +81 -0
  127. data/test/functional/eft_0_process_definition.rb +65 -0
  128. data/test/functional/eft_10_cancel_process.rb +46 -0
  129. data/test/functional/eft_11_wait.rb +109 -0
  130. data/test/functional/eft_12_listen.rb +500 -0
  131. data/test/functional/eft_13_iterator.rb +342 -0
  132. data/test/functional/eft_14_cursor.rb +456 -0
  133. data/test/functional/eft_15_loop.rb +69 -0
  134. data/test/functional/eft_16_if.rb +183 -0
  135. data/test/functional/eft_17_equals.rb +55 -0
  136. data/test/functional/eft_18_concurrent_iterator.rb +410 -0
  137. data/test/functional/eft_19_reserve.rb +136 -0
  138. data/test/functional/eft_1_echo.rb +68 -0
  139. data/test/functional/eft_20_save.rb +116 -0
  140. data/test/functional/eft_21_restore.rb +61 -0
  141. data/test/functional/eft_22_noop.rb +28 -0
  142. data/test/functional/eft_23_apply.rb +168 -0
  143. data/test/functional/eft_24_add_branches.rb +98 -0
  144. data/test/functional/eft_25_command.rb +28 -0
  145. data/test/functional/eft_26_error.rb +77 -0
  146. data/test/functional/eft_27_inc.rb +280 -0
  147. data/test/functional/eft_28_once.rb +135 -0
  148. data/test/functional/eft_29_cron.rb +64 -0
  149. data/test/functional/eft_2_sequence.rb +58 -0
  150. data/test/functional/eft_30_ref.rb +155 -0
  151. data/test/functional/eft_31_registerp.rb +130 -0
  152. data/test/functional/eft_32_lose.rb +93 -0
  153. data/test/functional/eft_33_let.rb +31 -0
  154. data/test/functional/eft_34_given.rb +123 -0
  155. data/test/functional/eft_35_filter.rb +375 -0
  156. data/test/functional/eft_36_read.rb +95 -0
  157. data/test/functional/eft_3_participant.rb +149 -0
  158. data/test/functional/eft_4_set.rb +296 -0
  159. data/test/functional/eft_5_subprocess.rb +163 -0
  160. data/test/functional/eft_6_concurrence.rb +304 -0
  161. data/test/functional/eft_7_forget.rb +61 -0
  162. data/test/functional/eft_8_undo.rb +114 -0
  163. data/test/functional/eft_9_redo.rb +138 -0
  164. data/test/functional/ft_0_worker.rb +65 -0
  165. data/test/functional/ft_10_dollar.rb +304 -0
  166. data/test/functional/ft_11_recursion.rb +109 -0
  167. data/test/functional/ft_12_launchitem.rb +43 -0
  168. data/test/functional/ft_13_variables.rb +151 -0
  169. data/test/functional/ft_14_re_apply.rb +324 -0
  170. data/test/functional/ft_15_timeout.rb +226 -0
  171. data/test/functional/ft_16_participant_params.rb +98 -0
  172. data/test/functional/ft_17_conditional.rb +102 -0
  173. data/test/functional/ft_18_kill.rb +138 -0
  174. data/test/functional/ft_19_participant_code.rb +67 -0
  175. data/test/functional/ft_1_process_status.rb +796 -0
  176. data/test/functional/ft_20_storage_participant.rb +543 -0
  177. data/test/functional/ft_21_forget.rb +153 -0
  178. data/test/functional/ft_22_process_definitions.rb +90 -0
  179. data/test/functional/ft_23_load_defs.rb +79 -0
  180. data/test/functional/ft_24_block_participant.rb +235 -0
  181. data/test/functional/ft_25_receiver.rb +207 -0
  182. data/test/functional/ft_26_participant_rtimeout.rb +179 -0
  183. data/test/functional/ft_27_var_indirection.rb +128 -0
  184. data/test/functional/ft_28_null_noop_participants.rb +51 -0
  185. data/test/functional/ft_29_part_template.rb +60 -0
  186. data/test/functional/ft_2_errors.rb +380 -0
  187. data/test/functional/ft_30_smtp_participant.rb +122 -0
  188. data/test/functional/ft_31_part_blocking.rb +72 -0
  189. data/test/functional/ft_33_participant_subprocess_priority.rb +32 -0
  190. data/test/functional/ft_34_cursor_rewind.rb +101 -0
  191. data/test/functional/ft_35_add_service.rb +56 -0
  192. data/test/functional/ft_36_storage_history.rb +150 -0
  193. data/test/functional/ft_37_default_history.rb +109 -0
  194. data/test/functional/ft_38_participant_more.rb +193 -0
  195. data/test/functional/ft_39_wait_for.rb +136 -0
  196. data/test/functional/ft_3_participant_registration.rb +574 -0
  197. data/test/functional/ft_40_wait_logger.rb +62 -0
  198. data/test/functional/ft_41_participants.rb +91 -0
  199. data/test/functional/ft_42_storage_copy.rb +71 -0
  200. data/test/functional/ft_43_participant_on_reply.rb +87 -0
  201. data/test/functional/ft_44_var_participant.rb +35 -0
  202. data/test/functional/ft_45_participant_accept.rb +64 -0
  203. data/test/functional/ft_46_launch_single.rb +83 -0
  204. data/test/functional/ft_47_wfid_generator.rb +54 -0
  205. data/test/functional/ft_48_lose.rb +112 -0
  206. data/test/functional/ft_49_engine_on_error.rb +201 -0
  207. data/test/functional/ft_4_cancel.rb +132 -0
  208. data/test/functional/ft_50_engine_config.rb +22 -0
  209. data/test/functional/ft_51_misc.rb +67 -0
  210. data/test/functional/ft_52_case.rb +134 -0
  211. data/test/functional/ft_53_engine_on_terminate.rb +95 -0
  212. data/test/functional/ft_54_patterns.rb +104 -0
  213. data/test/functional/ft_55_engine_participant.rb +303 -0
  214. data/test/functional/ft_56_filter_attribute.rb +259 -0
  215. data/test/functional/ft_57_rev_participant.rb +252 -0
  216. data/test/functional/ft_58_workitem.rb +69 -0
  217. data/test/functional/ft_59_pause.rb +343 -0
  218. data/test/functional/ft_5_on_error.rb +384 -0
  219. data/test/functional/ft_60_code_participant.rb +45 -0
  220. data/test/functional/ft_61_trailing_fields.rb +34 -0
  221. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  222. data/test/functional/ft_6_on_cancel.rb +221 -0
  223. data/test/functional/ft_7_tags.rb +177 -0
  224. data/test/functional/ft_8_participant_consumption.rb +124 -0
  225. data/test/functional/ft_9_subprocesses.rb +146 -0
  226. data/test/functional/restart_base.rb +34 -0
  227. data/test/functional/rt_0_wait.rb +55 -0
  228. data/test/functional/rt_1_listen.rb +56 -0
  229. data/test/functional/rt_2_errors.rb +56 -0
  230. data/test/functional/rt_3_once.rb +70 -0
  231. data/test/functional/rt_4_cron.rb +64 -0
  232. data/test/functional/rt_5_timeout.rb +60 -0
  233. data/test/functional/rtest.rb +8 -0
  234. data/test/functional/storage_helper.rb +93 -0
  235. data/test/functional/test.rb +44 -0
  236. data/test/functional/vertical.rb +46 -0
  237. data/test/path_helper.rb +15 -0
  238. data/test/test.rb +13 -0
  239. data/test/test_helper.rb +28 -0
  240. data/test/unit/storage.rb +428 -0
  241. data/test/unit/storages.rb +37 -0
  242. data/test/unit/test.rb +28 -0
  243. data/test/unit/ut_0_ruby_reader.rb +223 -0
  244. data/test/unit/ut_11_lookup.rb +122 -0
  245. data/test/unit/ut_13_serializer.rb +65 -0
  246. data/test/unit/ut_14_is_uri.rb +28 -0
  247. data/test/unit/ut_15_util.rb +57 -0
  248. data/test/unit/ut_16_reader.rb +225 -0
  249. data/test/unit/ut_18_engine.rb +47 -0
  250. data/test/unit/ut_19_part_template.rb +86 -0
  251. data/test/unit/ut_1_fei.rb +165 -0
  252. data/test/unit/ut_20_composite_storage.rb +74 -0
  253. data/test/unit/ut_21_svc_participant_list.rb +46 -0
  254. data/test/unit/ut_22_filter.rb +1094 -0
  255. data/test/unit/ut_23_svc_tracker.rb +48 -0
  256. data/test/unit/ut_24_radial_reader.rb +332 -0
  257. data/test/unit/ut_25_merge.rb +113 -0
  258. data/test/unit/ut_3_wait_logger.rb +39 -0
  259. data/test/unit/ut_4_expmap.rb +20 -0
  260. data/test/unit/ut_5_tree.rb +54 -0
  261. data/test/unit/ut_6_condition.rb +303 -0
  262. data/test/unit/ut_7_workitem.rb +99 -0
  263. data/test/unit/ut_8_tree_to_dot.rb +72 -0
  264. data/test/unit/ut_9_xml_reader.rb +61 -0
  265. metadata +504 -0
@@ -0,0 +1,234 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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
+
26
+ require 'ruote/exp/commanded'
27
+ require 'ruote/exp/iterator'
28
+
29
+
30
+ module Ruote::Exp
31
+
32
+ #
33
+ # Iterating on a list of values
34
+ #
35
+ # pdef = Ruote.process_definition :name => 'test' do
36
+ # iterator :on_val => 'alice, bob, charly', :to_var => 'v' do
37
+ # participant '${v:v}'
38
+ # end
39
+ # end
40
+ #
41
+ # This expression expects at list an 'on' attribute, which can be :on,
42
+ # :on_val, :on_value for a value (usually a comma separated list), :on_v,
43
+ # :on_var, :on_variable for a list contained in the designated variable and
44
+ # :on_f, :on_fld, :on_field for a list contained in the designated workitem
45
+ # field.
46
+ #
47
+ # The 'on' attribute is used to instruct the expression on which list/array
48
+ # it should iterate.
49
+ #
50
+ # The 'to' attribute takes two forms, :to_v, :to_var, :to_variable or
51
+ # :to_f, :to_fld, :to_field. Finally, you can write :to => 'field_name',
52
+ # :to => 'f:field_name' or :to => 'v:variable_name'.
53
+ #
54
+ # The 'to' attribute instructs the iterator into which variable or field
55
+ # it should place the current value (the value being iterated over).
56
+ #
57
+ # If there is no 'to' specified, the current value is placed in the variable
58
+ # named 'i'.
59
+ #
60
+ # The variables 'ii' contains the index (from 0 to ...) of the current value
61
+ # (think Ruby's #each_with_index).
62
+ #
63
+ # The 'on' attribute can be replaced by a :time or a :branches attribute.
64
+ #
65
+ # pdef = Ruote.process_definition :name => 'test' do
66
+ # iterator :times => '3'
67
+ # participant 'accounting'
68
+ # end
69
+ # end
70
+ #
71
+ # will be equivalent to
72
+ #
73
+ # pdef = Ruote.process_definition :name => 'test' do
74
+ # sequence do
75
+ # participant 'accounting'
76
+ # participant 'accounting'
77
+ # participant 'accounting'
78
+ # end
79
+ # end
80
+ #
81
+ #
82
+ # == the classical case
83
+ #
84
+ # Iterating over a workitem field :
85
+ #
86
+ # pdef = Ruote.process_definition :name => 'test' do
87
+ # iterator :on_field => 'customers', :to_f => 'customer'
88
+ # participant '${f:customer}'
89
+ # end
90
+ # end
91
+ #
92
+ #
93
+ # == break/rewind/continue/skip/jump
94
+ #
95
+ # The 'iterator' expression understands a certain the following commands :
96
+ #
97
+ # * break (_break) : exits the iteration
98
+ # * rewind : places the iteration back at the first iterated value
99
+ # * continue : same as 'rewind'
100
+ # * skip : skips a certain number of steps (relative)
101
+ # * jump : jump to certain step (absolute)
102
+ #
103
+ # pdef = Ruote.process_definition :name => 'test' do
104
+ # iterator :times => '3'
105
+ # sequence do
106
+ # participant 'accounting', :review => '${v:i}'
107
+ # rewind :if => '${f:redo_everything} == true'
108
+ # end
109
+ # end
110
+ # end
111
+ #
112
+ # == iterator command in the workitem
113
+ #
114
+ # It's OK to issue a command to the iterator from a participant via the
115
+ # workitem.
116
+ #
117
+ # pdef = Ruote.process_definition do
118
+ # iterator :times => 10
119
+ # sequence do
120
+ # participant 'accounting'
121
+ # participant 'adjust'
122
+ # end
123
+ # end
124
+ # end
125
+ #
126
+ # where
127
+ #
128
+ # class Adjust
129
+ # include Ruote::LocalParticipant
130
+ # def consume(workitem)
131
+ # workitem.command = 'break' if workitem.fields['amount'] > 10_000
132
+ # reply_to_engine(workitem)
133
+ # end
134
+ # def cancel(fei, flavour)
135
+ # end
136
+ # end
137
+ #
138
+ # A completely stupid example... The adjust participant will make the
139
+ # loop break if the amount reaches 10_000 (euros?).
140
+ #
141
+ #
142
+ # == break/rewind/continue/skip/jump with :ref
143
+ #
144
+ # An iterator can be tagged (with the :tag attribute) and directly referenced
145
+ # from a break/rewind/continue/skip/jump command.
146
+ #
147
+ # It's very useful when iterators (and cursors/loops) are nested within each
148
+ # other or when one has to act on an iterator from outside of it.
149
+ #
150
+ # concurrence do
151
+ #
152
+ # iterator :on => 'alpha, bravo, charly', :tag => 'review' do
153
+ # participant '${v:i}'
154
+ # end
155
+ #
156
+ # # meanwhile ...
157
+ #
158
+ # sequence do
159
+ # participant 'main control program'
160
+ # _break :ref => 'review', :if => '${f:cancel_review} == yes'
161
+ # end
162
+ # end
163
+ #
164
+ # in this example, the participant 'main control program' may cancel the
165
+ # review.
166
+ #
167
+ # iterator :on => 'c1, c2, c3', :to_f => 'client', :tag => 'main' do
168
+ # cursor do
169
+ # participant :ref => '${f:client}'
170
+ # _break :ref => 'main', :if => '${f:cancel_everything}'
171
+ # participant :ref => 'salesclerk'
172
+ # participant :ref => 'salesclerk'
173
+ # end
174
+ # end
175
+ #
176
+ # in this weird process, if one customer says "cancel everything" (set the
177
+ # workitem field "cancel_everything" to true), then the whole iterator
178
+ # gets 'broken' out of.
179
+ #
180
+ class IteratorExpression < CommandedExpression
181
+
182
+ include IteratorMixin
183
+
184
+ names :iterator
185
+
186
+ def apply
187
+
188
+ return reply_to_parent(h.applied_workitem) if tree_children.size < 1
189
+
190
+ h.list = determine_list
191
+ h.to_v, h.to_f = determine_tos
192
+ h.position = -1
193
+
194
+ h.to_v = 'i' if h.to_v == nil && h.to_f == nil
195
+
196
+ move_on
197
+ end
198
+
199
+ protected
200
+
201
+ def move_on(workitem=h.applied_workitem)
202
+
203
+ h.position += 1
204
+
205
+ com, arg = get_command(workitem)
206
+
207
+ return reply_to_parent(workitem) if com == 'break'
208
+
209
+ case com
210
+ when 'rewind', 'continue' then h.position = 0
211
+ when 'skip' then h.position += arg
212
+ when 'jump' then h.position = arg
213
+ end
214
+
215
+ h.position = h.list.length + h.position if h.position < 0
216
+
217
+ val = h.list[h.position]
218
+
219
+ return reply_to_parent(workitem) if val == nil
220
+
221
+ (h.variables ||= {})['ii'] = h.position
222
+
223
+ if h.to_v
224
+ h.variables[h.to_v] = val
225
+ else #if h.to_f
226
+ workitem['fields'][h.to_f] = val
227
+ end
228
+
229
+ apply_child(0, workitem)
230
+ # persist is done in there
231
+ end
232
+ end
233
+ end
234
+
@@ -0,0 +1,75 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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/exp/fe_sequence'
26
+
27
+
28
+ module Ruote::Exp
29
+
30
+ #
31
+ # Behaves like a sequence, but the children have their own variable
32
+ # scope.
33
+ #
34
+ # pdef = Ruote.process_definition do
35
+ # set 'v:var' => 'val'
36
+ # echo "out:${v:var}"
37
+ # let do
38
+ # set 'v:var' => 'val1'
39
+ # echo "in:${v:var}"
40
+ # end
41
+ # echo "out:${v:var}"
42
+ # end
43
+ #
44
+ # # => out:val, in:val1, out:val
45
+ #
46
+ #
47
+ # == as a 'case' statement
48
+ #
49
+ # let do
50
+ # define 'published' do
51
+ # do_this
52
+ # end
53
+ # define 'reviewed' do
54
+ # do_that
55
+ # end
56
+ # subprocess '${case}'
57
+ # end
58
+ #
59
+ # Subprocesses 'published' and 'reviewed' are bound in a local scope,
60
+ # that gets discarded when the let exits.
61
+ #
62
+ class LetExpression < SequenceExpression
63
+
64
+ names :let
65
+
66
+ def apply
67
+
68
+ h.variables = {}
69
+ # the blank local scope
70
+
71
+ reply(h.applied_workitem)
72
+ end
73
+ end
74
+ end
75
+
@@ -0,0 +1,304 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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
+
26
+ require 'ruote/exp/condition'
27
+
28
+
29
+ module Ruote::Exp
30
+
31
+ #
32
+ # Listens for activity (incoming or outgoing workitems) on a (set of)
33
+ # participant(s).
34
+ #
35
+ # This expression is an advanced one. It allows for cross process instance
36
+ # communication or at least cross branch communication within the same
37
+ # process instance.
38
+ #
39
+ # DO NOT confuse the listen expression with the 'listener' concept. They are
40
+ # not directly related. The listen expression listens to workitem activity
41
+ # inside of the engine, while a listener listens for workitems or launchitems
42
+ # from sources external to the ruote workflow engine.
43
+ #
44
+ # It can be used in two ways : 'blocking' or 'triggering'. In both cases
45
+ # the listen expression 'reacts' upon activity (incoming or outgoing workitem)
46
+ # happening on a channel (a participant name or a tag name).
47
+ #
48
+ # == blocking
49
+ #
50
+ # A blocking example :
51
+ #
52
+ # sequence do
53
+ # participant 'alice'
54
+ # listen :to => 'bob'
55
+ # participant 'charly'
56
+ # end
57
+ #
58
+ # Once the listen expression got applied, this process will block until a
59
+ # workitem (in any other process instance in the same engine) is dispatched
60
+ # to participant 'bob'. It then proceeds to charly.
61
+ #
62
+ # == triggering
63
+ #
64
+ # This way of using 'listen' is useful for launching processes that "stalk"
65
+ # other processes :
66
+ #
67
+ # Ruote.process_definition :name => 'stalker' do
68
+ # listen :to => 'bob' do
69
+ # participant :ref => 'charly'
70
+ # end
71
+ # end
72
+ #
73
+ # This small process will never exits and will send a workitem to charly
74
+ # each time the ruote engine sends a workitem to bob.
75
+ #
76
+ # The workitems passed to charly will be copies of the workitem initially
77
+ # applied to the 'listen' expression, but with a copy of the fields of the
78
+ # workitem passed to bob, merged in.
79
+ #
80
+ # Note : for now, the triggered segments of processes are 'forgotten'. The
81
+ # 'listen' expression doesn't keep track of them. This also means that in
82
+ # case of cancel, the triggered segments will not get cancelled.
83
+ #
84
+ # == :merge
85
+ #
86
+ # By default, :merge is set to true, the listened for workitems see their
87
+ # values merged into a copy of the workitem held in the listen expression
88
+ # and this copy is delivered to the expressions that are client to the
89
+ # 'listen'.
90
+ #
91
+ # == :upon
92
+ #
93
+ # There are two kinds of main events in ruote, apply and reply. Thus,
94
+ # a listen expression may listen to 'apply' and to 'reply' and this is
95
+ # defined by the :upon attribute.
96
+ #
97
+ # By default, listens upon 'apply' (engine handing workitem to participant).
98
+ #
99
+ # Can be set to 'reply', to react on workitems being handed back to the
100
+ # engine by the participant.
101
+ #
102
+ # Setting :upon to 'entering' or 'leaving' tells the listen to focus on
103
+ # tag events.
104
+ #
105
+ # sequence do
106
+ # sequence :tag => 'phase_one' do
107
+ # alpha
108
+ # end
109
+ # sequence :tag => 'phase_two' do
110
+ # bravo
111
+ # end
112
+ # end
113
+ #
114
+ # In this dummy process definition, there are four tag events :
115
+ #
116
+ # * 'entering' 'phase_one'
117
+ # * 'leaving' 'phase_one'
118
+ # * 'entering' 'phase_two'
119
+ # * 'leaving' 'phase_two'
120
+ #
121
+ #
122
+ # == :to and :on
123
+ #
124
+ # The :to attribute has already been seen, it can be replaced by the :on one.
125
+ #
126
+ # listen :to => 'alpha'
127
+ #
128
+ # is equivalent to
129
+ #
130
+ # listen :on => 'alpha'
131
+ #
132
+ #
133
+ # == :to (:on) and regular expressions
134
+ #
135
+ # It's OK to write things like :
136
+ #
137
+ # listen :to => "/^user\_.+/"
138
+ #
139
+ # or
140
+ #
141
+ # listen :to => /^user\_.+/
142
+ #
143
+ # To listen for workitems for all the participant whose name start with
144
+ # "user_".
145
+ #
146
+ #
147
+ # == :wfid
148
+ #
149
+ # By default, a listen expression listens for any workitem/participant event
150
+ # in the engine. Setting the :wfid attribute to 'true' or 'same' or 'current'
151
+ # will make the listen expression only care for events belonging to the
152
+ # same process instance (same wfid).
153
+ #
154
+ #
155
+ # == :where
156
+ #
157
+ # The :wfid can be considered a 'guard'. Another tool for guarding listen
158
+ # is to use the :where attribute.
159
+ #
160
+ # listen :to => 'alpha', :where => '${customer.state} == CA'
161
+ #
162
+ # The listen will trigger only if the workitem has a customer field with
163
+ # a subfield state containing the value "CA".
164
+ #
165
+ # The documentation about the dollar notation and the one about common
166
+ # attributes :if and :unless applies for the :where attribute.
167
+ #
168
+ #
169
+ # == listen :to => :errors
170
+ #
171
+ # The listen expression can be made to listen to errors.
172
+ #
173
+ # listen :to => errors do
174
+ # participant 'supervisor_sms', :task => 'verify system'
175
+ # end
176
+ #
177
+ # Whenever an error happens in the process with this listen stance,
178
+ # the listen will trigger.
179
+ #
180
+ # "listen :to => :errors" only works with errors in the same process instance
181
+ # (same wfid).
182
+ #
183
+ # "listen :to => :errors" doesn't trigger when the error is caught (via
184
+ # :on_error).
185
+ #
186
+ # === listen :to => :errors, :class => 'ArgumentError'
187
+ #
188
+ # One can restrict the listen to certain classes of errors.
189
+ # Passing a list of error classes separated by a comma is OK.
190
+ #
191
+ # === listen :to => :errors, :message => /x/
192
+ #
193
+ # One can restrict the error listening to errors matching a certain regex
194
+ # or equal to a certain string. The attribute is :message or :msg. The
195
+ # value is a String (strict equality) or a Regex (matching).
196
+ #
197
+ class ListenExpression < FlowExpression
198
+
199
+ names :listen, :receive, :intercept
200
+
201
+ UPONS = {
202
+ 'apply' => 'dispatch', 'reply' => 'receive',
203
+ 'entering' => 'entered_tag', 'leaving' => 'left_tag'
204
+ }
205
+
206
+ def apply
207
+
208
+ # gathering info
209
+
210
+ h.to = attribute(:to) || attribute(:on)
211
+
212
+ h.upon = UPONS[attribute(:upon) || 'apply']
213
+ h.upon = 'error_intercepted' if h.to == 'errors'
214
+
215
+ h.lmerge = attribute(:merge).to_s
216
+ h.lmerge = 'true' if h.lmerge == ''
217
+
218
+ h.lwfid = attribute(:wfid).to_s
219
+ h.lwfid = %w[ same current true ].include?(h.lwfid)
220
+
221
+ h.lwfid = true if h.to == 'errors'
222
+ # can only listen to errors in the same process instance
223
+
224
+ persist_or_raise
225
+
226
+ # adding a new tracker
227
+
228
+ @context.tracker.add_tracker(
229
+ h.lwfid ? h.fei['wfid'] : nil,
230
+ h.upon,
231
+ Ruote.to_storage_id(h.fei),
232
+ determine_condition,
233
+ { 'action' => 'reply',
234
+ 'fei' => h.fei,
235
+ 'workitem' => 'replace',
236
+ 'flavour' => 'listen' })
237
+ end
238
+
239
+ def reply(workitem)
240
+
241
+ #
242
+ # :where guard
243
+
244
+ where = attribute(:where, workitem)
245
+ return if where && ( ! Condition.true?(where))
246
+
247
+ #
248
+ # green for trigger
249
+
250
+ wi = h.applied_workitem.dup
251
+
252
+ if h.lmerge == 'true'
253
+ wi['fields'].merge!(workitem['fields'])
254
+ elsif h.lmerge == 'override'
255
+ wi['fields'] = workitem['fields']
256
+ #else don't touch
257
+ end
258
+
259
+ if tree_children.size > 0
260
+
261
+ launch_sub(
262
+ "#{h.fei['expid']}_0", tree[2][0], :forget => true, :workitem => wi)
263
+ else
264
+
265
+ reply_to_parent(wi)
266
+ end
267
+ end
268
+
269
+ protected
270
+
271
+ # Overriding the parent's #reply_to_parent to make sure the tracker is
272
+ # removed before (expression terminating, no need for it to track anything
273
+ # anymore).
274
+ #
275
+ def reply_to_parent(workitem)
276
+
277
+ @context.tracker.remove_tracker(h.fei)
278
+
279
+ super(workitem)
280
+ end
281
+
282
+ def determine_condition
283
+
284
+ if h.upon == 'dispatch' || h.upon == 'receive'
285
+
286
+ { 'participant_name' => h.to }
287
+
288
+ elsif h.upon == 'error_intercepted'
289
+
290
+ {
291
+ 'class' => (attribute(:class) || '').split(/, */),
292
+ 'message' => attribute(:message) || attribute(:msg)
293
+ }.delete_if { |k, v|
294
+ v == nil or v == []
295
+ }
296
+
297
+ else
298
+
299
+ { 'tag' => h.to }
300
+ end
301
+ end
302
+ end
303
+ end
304
+