ruote 2.1.11 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (217) hide show
  1. data/CHANGELOG.txt +60 -0
  2. data/CREDITS.txt +22 -4
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +6 -7
  5. data/Rakefile +58 -59
  6. data/TODO.txt +137 -65
  7. data/couch_url.txt +1 -0
  8. data/jruby_issue.txt +32 -0
  9. data/lib/ruote.rb +1 -1
  10. data/lib/ruote/context.rb +12 -10
  11. data/lib/ruote/engine.rb +280 -145
  12. data/lib/ruote/engine/process_error.rb +5 -5
  13. data/lib/ruote/engine/process_status.rb +47 -28
  14. data/lib/ruote/exp/command.rb +7 -10
  15. data/lib/ruote/exp/commanded.rb +2 -2
  16. data/lib/ruote/exp/condition.rb +130 -43
  17. data/lib/ruote/exp/fe_add_branches.rb +2 -2
  18. data/lib/ruote/exp/fe_apply.rb +1 -1
  19. data/lib/ruote/exp/fe_cancel_process.rb +3 -3
  20. data/lib/ruote/exp/fe_command.rb +3 -3
  21. data/lib/ruote/exp/fe_concurrence.rb +4 -4
  22. data/lib/ruote/exp/fe_concurrent_iterator.rb +17 -5
  23. data/lib/ruote/exp/fe_cron.rb +3 -3
  24. data/lib/ruote/exp/fe_cursor.rb +5 -5
  25. data/lib/ruote/exp/fe_define.rb +3 -3
  26. data/lib/ruote/exp/fe_echo.rb +3 -3
  27. data/lib/ruote/exp/fe_equals.rb +2 -2
  28. data/lib/ruote/exp/fe_error.rb +2 -2
  29. data/lib/ruote/exp/fe_filter.rb +519 -0
  30. data/lib/ruote/exp/fe_forget.rb +9 -2
  31. data/lib/ruote/exp/fe_given.rb +154 -0
  32. data/lib/ruote/exp/fe_if.rb +16 -13
  33. data/lib/ruote/exp/fe_inc.rb +3 -3
  34. data/lib/ruote/exp/fe_iterator.rb +4 -4
  35. data/lib/ruote/exp/fe_let.rb +75 -0
  36. data/lib/ruote/exp/fe_listen.rb +68 -12
  37. data/lib/ruote/exp/fe_lose.rb +110 -0
  38. data/lib/ruote/exp/fe_noop.rb +1 -1
  39. data/lib/ruote/exp/{fe_when.rb → fe_once.rb} +25 -21
  40. data/lib/ruote/exp/fe_participant.rb +14 -17
  41. data/lib/ruote/exp/fe_redo.rb +10 -6
  42. data/lib/ruote/exp/fe_ref.rb +1 -1
  43. data/lib/ruote/exp/fe_registerp.rb +112 -0
  44. data/lib/ruote/exp/fe_reserve.rb +3 -3
  45. data/lib/ruote/exp/fe_restore.rb +2 -2
  46. data/lib/ruote/exp/fe_save.rb +2 -2
  47. data/lib/ruote/exp/fe_sequence.rb +3 -4
  48. data/lib/ruote/exp/fe_set.rb +16 -7
  49. data/lib/ruote/exp/fe_subprocess.rb +23 -1
  50. data/lib/ruote/exp/fe_that.rb +92 -0
  51. data/lib/ruote/exp/fe_undo.rb +3 -3
  52. data/lib/ruote/exp/fe_unregisterp.rb +71 -0
  53. data/lib/ruote/exp/fe_wait.rb +2 -2
  54. data/lib/ruote/exp/flowexpression.rb +153 -78
  55. data/lib/ruote/exp/iterator.rb +2 -2
  56. data/lib/ruote/exp/merge.rb +2 -2
  57. data/lib/ruote/exp/ro_attributes.rb +14 -12
  58. data/lib/ruote/exp/ro_filters.rb +136 -0
  59. data/lib/ruote/exp/ro_persist.rb +51 -35
  60. data/lib/ruote/exp/ro_variables.rb +18 -27
  61. data/lib/ruote/fei.rb +73 -33
  62. data/lib/ruote/id/mnemo_wfid_generator.rb +1 -1
  63. data/lib/ruote/id/wfid_generator.rb +11 -4
  64. data/lib/ruote/log/default_history.rb +122 -0
  65. data/lib/ruote/log/pretty.rb +36 -8
  66. data/lib/ruote/log/storage_history.rb +37 -5
  67. data/lib/ruote/log/test_logger.rb +26 -24
  68. data/lib/ruote/log/wait_logger.rb +5 -3
  69. data/lib/ruote/part/block_participant.rb +22 -11
  70. data/lib/ruote/part/engine_participant.rb +6 -7
  71. data/lib/ruote/part/local_participant.rb +6 -12
  72. data/lib/ruote/part/no_op_participant.rb +4 -4
  73. data/lib/ruote/part/null_participant.rb +4 -4
  74. data/lib/ruote/part/smtp_participant.rb +4 -4
  75. data/lib/ruote/part/storage_participant.rb +40 -20
  76. data/lib/ruote/part/template.rb +4 -4
  77. data/lib/ruote/participant.rb +0 -1
  78. data/lib/ruote/{parser.rb → reader.rb} +30 -25
  79. data/lib/ruote/{parser → reader}/ruby_dsl.rb +28 -11
  80. data/lib/ruote/{parser → reader}/xml.rb +6 -5
  81. data/lib/ruote/receiver/base.rb +35 -13
  82. data/lib/ruote/storage/base.rb +20 -18
  83. data/lib/ruote/storage/composite_storage.rb +10 -10
  84. data/lib/ruote/storage/fs_storage.rb +17 -10
  85. data/lib/ruote/storage/hash_storage.rb +29 -18
  86. data/lib/ruote/svc/dispatch_pool.rb +41 -14
  87. data/lib/ruote/svc/dollar_sub.rb +50 -17
  88. data/lib/ruote/svc/error_handler.rb +19 -11
  89. data/lib/ruote/svc/expression_map.rb +4 -4
  90. data/lib/ruote/svc/participant_list.rb +105 -100
  91. data/lib/ruote/svc/tracker.rb +58 -18
  92. data/lib/ruote/svc/treechecker.rb +51 -24
  93. data/lib/ruote/tree_dot.rb +4 -4
  94. data/lib/ruote/util/filter.rb +440 -0
  95. data/lib/ruote/util/hashdot.rb +4 -4
  96. data/lib/ruote/util/look.rb +2 -6
  97. data/lib/ruote/util/lookup.rb +9 -7
  98. data/lib/ruote/util/misc.rb +40 -8
  99. data/lib/ruote/util/ometa.rb +1 -1
  100. data/lib/ruote/util/serializer.rb +4 -4
  101. data/lib/ruote/util/subprocess.rb +29 -9
  102. data/lib/ruote/util/time.rb +4 -4
  103. data/lib/ruote/util/tree.rb +3 -3
  104. data/lib/ruote/version.rb +2 -2
  105. data/lib/ruote/worker.rb +55 -32
  106. data/lib/ruote/workitem.rb +64 -11
  107. data/ruote.gemspec +31 -302
  108. data/test/bm/launch_bench.rb +37 -0
  109. data/test/functional/base.rb +60 -18
  110. data/test/functional/concurrent_base.rb +2 -2
  111. data/test/functional/ct_0_concurrence.rb +1 -1
  112. data/test/functional/ct_1_iterator.rb +1 -1
  113. data/test/functional/ct_2_cancel.rb +1 -1
  114. data/test/functional/eft_0_process_definition.rb +2 -2
  115. data/test/functional/eft_10_cancel_process.rb +1 -1
  116. data/test/functional/eft_11_wait.rb +19 -11
  117. data/test/functional/eft_12_listen.rb +79 -13
  118. data/test/functional/eft_13_iterator.rb +13 -10
  119. data/test/functional/eft_14_cursor.rb +98 -9
  120. data/test/functional/eft_15_loop.rb +6 -4
  121. data/test/functional/eft_16_if.rb +12 -0
  122. data/test/functional/eft_18_concurrent_iterator.rb +31 -32
  123. data/test/functional/eft_19_reserve.rb +4 -4
  124. data/test/functional/eft_1_echo.rb +9 -0
  125. data/test/functional/eft_20_save.rb +4 -4
  126. data/test/functional/{eft_28_when.rb → eft_28_once.rb} +33 -7
  127. data/test/functional/eft_30_ref.rb +17 -2
  128. data/test/functional/eft_31_registerp.rb +130 -0
  129. data/test/functional/eft_32_lose.rb +93 -0
  130. data/test/functional/eft_33_let.rb +31 -0
  131. data/test/functional/eft_34_given.rb +123 -0
  132. data/test/functional/eft_35_filter.rb +269 -0
  133. data/test/functional/eft_3_participant.rb +4 -6
  134. data/test/functional/eft_4_set.rb +16 -2
  135. data/test/functional/eft_5_subprocess.rb +2 -4
  136. data/test/functional/eft_6_concurrence.rb +29 -29
  137. data/test/functional/eft_8_undo.rb +39 -3
  138. data/test/functional/eft_9_redo.rb +94 -2
  139. data/test/functional/ft_10_dollar.rb +81 -2
  140. data/test/functional/ft_11_recursion.rb +13 -17
  141. data/test/functional/ft_12_launchitem.rb +9 -5
  142. data/test/functional/ft_13_variables.rb +7 -9
  143. data/test/functional/ft_14_re_apply.rb +6 -9
  144. data/test/functional/ft_15_timeout.rb +18 -18
  145. data/test/functional/ft_16_participant_params.rb +1 -3
  146. data/test/functional/ft_17_conditional.rb +25 -2
  147. data/test/functional/ft_18_kill.rb +65 -12
  148. data/test/functional/ft_1_process_status.rb +147 -71
  149. data/test/functional/ft_20_storage_participant.rb +0 -1
  150. data/test/functional/ft_21_forget.rb +82 -1
  151. data/test/functional/{ft_24_block_participants.rb → ft_24_block_participant.rb} +42 -11
  152. data/test/functional/ft_25_receiver.rb +47 -17
  153. data/test/functional/{ft_26_participant_timeout.rb → ft_26_participant_rtimeout.rb} +56 -19
  154. data/test/functional/ft_29_part_template.rb +6 -5
  155. data/test/functional/ft_2_errors.rb +21 -37
  156. data/test/functional/ft_30_smtp_participant.rb +1 -1
  157. data/test/functional/ft_31_part_blocking.rb +8 -6
  158. data/test/functional/ft_34_cursor_rewind.rb +13 -10
  159. data/test/functional/ft_35_add_service.rb +1 -1
  160. data/test/functional/ft_36_storage_history.rb +24 -1
  161. data/test/functional/ft_37_default_history.rb +109 -0
  162. data/test/functional/ft_38_participant_more.rb +10 -10
  163. data/test/functional/ft_39_wait_for.rb +12 -9
  164. data/test/functional/ft_3_participant_registration.rb +111 -32
  165. data/test/functional/ft_40_wait_logger.rb +2 -1
  166. data/test/functional/ft_41_participants.rb +30 -4
  167. data/test/functional/ft_43_participant_on_reply.rb +6 -23
  168. data/test/functional/ft_45_participant_accept.rb +4 -4
  169. data/test/functional/ft_46_launch_single.rb +36 -2
  170. data/test/functional/ft_47_wfid_generator.rb +54 -0
  171. data/test/functional/ft_48_lose.rb +112 -0
  172. data/test/functional/ft_49_engine_on_error.rb +201 -0
  173. data/test/functional/ft_4_cancel.rb +66 -6
  174. data/test/functional/ft_50_engine_config.rb +22 -0
  175. data/test/functional/ft_51_misc.rb +67 -0
  176. data/test/functional/ft_52_case.rb +134 -0
  177. data/test/functional/ft_53_engine_on_terminate.rb +95 -0
  178. data/test/functional/ft_54_patterns.rb +104 -0
  179. data/test/functional/{ft_37_engine_participant.rb → ft_55_engine_participant.rb} +4 -5
  180. data/test/functional/ft_56_filter_attribute.rb +259 -0
  181. data/test/functional/ft_5_on_error.rb +77 -30
  182. data/test/functional/ft_6_on_cancel.rb +66 -11
  183. data/test/functional/ft_7_tags.rb +94 -5
  184. data/test/functional/ft_8_participant_consumption.rb +36 -5
  185. data/test/functional/ft_9_subprocesses.rb +10 -10
  186. data/test/functional/rt_1_listen.rb +3 -3
  187. data/test/functional/{rt_3_when.rb → rt_3_once.rb} +4 -4
  188. data/test/functional/storage_helper.rb +15 -13
  189. data/test/functional/test.rb +1 -3
  190. data/test/test_helper.rb +0 -8
  191. data/test/unit/storage.rb +154 -10
  192. data/test/unit/{ut_0_ruby_parser.rb → ut_0_ruby_reader.rb} +61 -11
  193. data/test/unit/ut_11_lookup.rb +7 -0
  194. data/test/unit/ut_13_serializer.rb +1 -1
  195. data/test/unit/ut_15_util.rb +23 -0
  196. data/test/unit/{ut_16_parser.rb → ut_16_reader.rb} +11 -13
  197. data/test/unit/ut_1_fei.rb +57 -10
  198. data/test/unit/ut_20_composite_storage.rb +25 -11
  199. data/test/unit/ut_21_participant_list.rb +47 -0
  200. data/test/unit/ut_22_filter.rb +903 -0
  201. data/test/unit/ut_3_wait_logger.rb +2 -6
  202. data/test/unit/ut_6_condition.rb +164 -17
  203. data/test/unit/ut_7_workitem.rb +28 -0
  204. data/test/unit/ut_8_tree_to_dot.rb +1 -1
  205. data/test/unit/{ut_9_xml_parser.rb → ut_9_xml_reader.rb} +5 -5
  206. metadata +108 -84
  207. data/.gitignore +0 -4
  208. data/examples/barley.rb +0 -391
  209. data/examples/flickr_report.rb +0 -107
  210. data/examples/pong.rb +0 -37
  211. data/examples/ruote_quickstart.rb +0 -43
  212. data/examples/web_first_page.rb +0 -68
  213. data/lib/ruote/part/hash_participant.rb +0 -91
  214. data/test/README.rdoc +0 -15
  215. data/test/functional/crunner.sh +0 -19
  216. data/test/pdef.xml +0 -7
  217. data/test/unit/ut_2_wfidgen.rb +0 -21
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- .yardoc
2
- ruote_rdoc/
3
- work/
4
- *.swp
data/examples/barley.rb DELETED
@@ -1,391 +0,0 @@
1
-
2
- #--
3
- # Copyright (c) 2010, John Mettraux, jmettraux@gmail.com
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
- #++
23
-
24
- # featured in
25
- # http://jmettraux.wordpress.com/2010/01/29/barley/
26
-
27
-
28
- require 'rubygems'
29
-
30
- #
31
- # the users
32
- #
33
-
34
- USERS = {
35
- '_none_' => 'http://s.twimg.com/a/1264550348/images/default_profile_0_normal.png',
36
- 'john' => 'http://www.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f',
37
- 'kenneth' => 'http://www.gravatar.com/avatar/8e033d0007374b14f6c213ede64d470b',
38
- 'torsten' => 'http://www.gravatar.com/avatar/3fa5d7edd1f21da184964146e062c8da',
39
- 'postmodern' => 'http://a3.twimg.com/profile_images/261097869/postmodern_bigger.jpg',
40
- 'amedeo' => 'http://a1.twimg.com/profile_images/99817242/me_bigger.png',
41
- 'radlepunktde' => 'http://a1.twimg.com/profile_images/303265014/radlepunktde_bigger.jpg'
42
- }
43
-
44
-
45
- #
46
- # the workflow engine
47
- #
48
-
49
- require 'ruote'
50
- require 'ruote/part/storage_participant'
51
- require 'ruote/storage/fs_storage'
52
-
53
- ENGINE = Ruote::Engine.new(
54
- Ruote::Worker.new(Ruote::FsStorage.new('ruote_data')))
55
-
56
-
57
- #
58
- # the workflow participants
59
- #
60
-
61
- ENGINE.register_participant('trace') do |workitem|
62
- (workitem.fields['trace'] ||= []) << [
63
- Time.now.strftime('%Y-%m-%d %H:%M:%S'),
64
- workitem.fields['next'],
65
- workitem.fields['task'] ]
66
- end
67
-
68
- ENGINE.register_participant('.+', Ruote::StorageParticipant)
69
-
70
- PART = Ruote::StorageParticipant.new(ENGINE)
71
- # a handy pointer into the workitems
72
-
73
-
74
- #
75
- # the (only) process definition
76
- #
77
-
78
- PDEF = Ruote.process_definition :name => 'barely' do
79
- cursor do
80
- trace
81
- participant '${f:next}'
82
- rewind :if => '${f:next}'
83
- end
84
- end
85
-
86
- #
87
- # web resources (thanks to Sinatra)
88
- #
89
-
90
- require 'cgi'
91
- require 'sinatra'
92
- require 'haml'
93
-
94
- #use_in_file_templates! # sinatra 0.9.x
95
- enable :inline_templates # sinatra 1.0
96
-
97
- def h (s)
98
- Rack::Utils.escape_html(s)
99
- end
100
-
101
- def sort (workitems)
102
- workitems.sort! do |wi0, wi1|
103
- (wi0.fields['last'] || '') <=> (wi1.fields['last'] || '')
104
- end
105
- end
106
-
107
- set :haml, { :format => :html5 }
108
-
109
- get '/' do
110
- redirect '/work'
111
- end
112
-
113
- get '/work' do
114
-
115
- @workitems = PART.all
116
- sort(@workitems)
117
-
118
- haml :work
119
- end
120
-
121
- get '/work/:thing' do
122
-
123
- t = params[:thing]
124
-
125
- @workitems = if USERS[t]
126
- PART.by_participant(t)
127
- else
128
- PART.by_field('subject', t)
129
- end
130
- sort(@workitems)
131
-
132
- haml :work
133
- end
134
-
135
- post '/new' do
136
-
137
- if n = params['next']
138
- wfid = ENGINE.launch(
139
- PDEF,
140
- 'next' => n,
141
- 'subject' => params['subject'],
142
- 'task' => params['task'],
143
- 'last' => Ruote.now_to_utc_s)
144
- end
145
-
146
- sleep 0.5
147
-
148
- redirect '/work'
149
- end
150
-
151
- post '/work' do
152
-
153
- fei = params['fei']
154
- fei = Ruote::FlowExpressionId.from_id(fei, ENGINE.context.engine_id)
155
-
156
- workitem = PART[fei]
157
- # fetch workitem from storage
158
-
159
- if params['action'] == 'resume'
160
- workitem.fields['next'] = params['next']
161
- workitem.fields['task'] = params['task']
162
- workitem.fields['last'] = Ruote.now_to_utc_s
163
- PART.reply(workitem)
164
- else # params['action'] == 'terminate'
165
- workitem.fields.delete('next')
166
- PART.reply(workitem)
167
- end
168
-
169
- sleep 0.5
170
-
171
- redirect '/work'
172
- end
173
-
174
- __END__
175
-
176
- @@work
177
-
178
- %html
179
- %head
180
- %title barley
181
-
182
- %script( src='http://code.jquery.com/jquery-1.4.1.min.js' )
183
-
184
- %link( href='http://barley.s3.amazonaws.com/reset.css' type='text/css' rel='stylesheet' )
185
- %link( href='http://ruote.rubyforge.org/images/ruote.png' type='image/png' rel='icon' )
186
-
187
- %style
188
- :sass
189
- body
190
- font-family: "helvetica neue", helvetica
191
- font-size: 14pt
192
- margin-left: 20%
193
- margin-right: 20%
194
- margin-top: 20pt
195
-
196
- background: #C0DEED url('http://a3.twimg.com/a/1264550348/images/bg-clouds.png') repeat-x
197
- p
198
- margin-bottom: 5pt
199
- input[type='text']
200
- width: 100%
201
- img
202
- width: 38px
203
- a
204
- color: black
205
- text-decoration: none
206
- a:visited
207
- color: black
208
- text-decoration: none
209
- a:active
210
- color: black
211
- text-decoration: none
212
- #barley
213
- font-size: 350%
214
- font-weight: lighter
215
- color: white
216
- padding-left: 2pt
217
- padding-bottom: 7pt
218
- #buttons
219
- font-size: 90%
220
- color: white
221
- margin-bottom: 14pt
222
- #buttons a
223
- color: white
224
- #buttons a:visited
225
- color: white
226
- .workitem
227
- margin-bottom: 7pt
228
- .workitem > *
229
- float: left
230
- .workitem:after
231
- display: block
232
- clear: both
233
- visibility: hidden
234
- content: ''
235
- .wi_info
236
- margin-left: 3pt
237
- .wi_user
238
- font-weight: bold
239
- .wi_task
240
- opacity: 0.37
241
- cursor: pointer
242
- .wi_wfid
243
- font-size: 70%
244
- vertical-align: middle
245
- font-weight: lighter
246
- table
247
- width: 100%
248
- tr.buttons > td
249
- text-align: center
250
- padding-top: 4pt
251
- td
252
- vertical-align: middle
253
- td.constrained
254
- width: 1%
255
- padding-right: 1em
256
- td.label
257
- font-weight: lighter
258
- .trace
259
- opacity: 0.37
260
- margin-bottom: 4pt
261
- cursor: pointer
262
- .trace_detail
263
- padding-left: 2pt
264
- border-left: 2.5pt solid #8EC1DA
265
- .trace_step
266
- width: 100%
267
- .trace_step_time
268
- font-size: 70%
269
- .trace_step_user
270
- font-weight: bold
271
- opacity: 0.6
272
- .trace_step_task
273
- opacity: 0.37
274
-
275
- %body
276
-
277
- #barley
278
- %span{ :onclick => "document.location.href = '/work';", :style => 'cursor: pointer;' } barley
279
-
280
- #message
281
- #{@message}
282
-
283
- #buttons
284
-
285
- %a{ :href => '', :onclick => "$('#new_form').slideToggle(); $('#new_next').focus(); return false;" } new
286
- |
287
- %a{ :href => '/work' } all
288
-
289
- #new_form{ :style => 'display: none;' }
290
- %form{ :action => '/new', :method => 'POST' }
291
- %table
292
- %tr
293
- %td.constrained{ :rowspan => 2 }
294
- %select#new_next{ :name => 'next', :onchange => "this.options[selectedIndex].select();" }
295
- - USERS.keys.sort.each do |uname|
296
- - uavatar = USERS[uname]
297
- %option{ :id => "new_#{uname}" } #{uname}
298
- :javascript
299
- document.getElementById('new_#{uname}').select = function () {
300
- $('#new_avatar').get(0).src = '#{uavatar}';
301
- $('#new_subject').focus();
302
- }
303
- :javascript
304
- $('#new_next').get(0).value = '_none_';
305
- %td.constrained{ :rowspan => 2 }
306
- %img#new_avatar{ :src => USERS['_none_'] }
307
- %td.constrained.label
308
- subject
309
- %td
310
- %input{ :id => 'new_subject', :type => 'text', :name => 'subject', :value => '' }
311
- %tr
312
- %td.constrained.label
313
- task
314
- %td
315
- %input{ :type => 'text', :name => 'task', :value => '' }
316
- %tr.buttons
317
- %td{ :colspan => 4 }
318
- %input{ :type => 'submit', :value => 'launch' }
319
-
320
- #work
321
- - @workitems.each do |workitem|
322
-
323
- - wid = "workitem#{workitem.fei.hash.to_s}"
324
-
325
- .workitem
326
- .wi_user_image
327
- %img{ :src => USERS[workitem.participant_name], :class => 'wi_user' }
328
- .wi_info
329
- .wi_first_line
330
- %span.wi_user
331
- %a{ :href => "/work/#{h workitem.participant_name}" } #{h workitem.participant_name}
332
- %span.wi_subject
333
- %a{ :href => "/work/#{CGI.escape(workitem.fields['subject'])}" } #{h workitem.fields['subject']}
334
- %span.wi_task{ :onclick => "$('##{wid}').slideToggle(); $('#next_#{wid}').focus();" }
335
- #{h workitem.fields['task']}
336
- .wi_second_line
337
- %span.wi_wfid
338
- #{workitem.fei.wfid}
339
- - t = Rufus.to_ruby_time(workitem.fields['last'])
340
- - ago = Rufus.to_duration_string(Time.now - t.to_time, :drop_seconds => true)
341
- - ago = (ago.strip == '') ? 'a few seconds' : ago
342
- (#{ago} ago)
343
-
344
- .workitem_form{ :style => 'display: none;', :id => wid }
345
-
346
- .trace{ :onclick => "$('#trace#{wid}').slideToggle();" }
347
- - names = workitem.fields['trace'].collect { |e| e[1] }
348
- #{names.join(' &#187; ')}
349
-
350
- .trace_detail{ :id => "trace#{wid}", :style => 'display: none;' }
351
- - workitem.fields['trace'].each do |time, user, task|
352
- - t = Rufus.to_ruby_time(time)
353
- - ago = Rufus.to_duration_string(Time.now - t.to_time, :drop_seconds => true)
354
- %p.trace_step
355
- %span.trace_step_time #{h time} (#{ago} ago)
356
- %span.trace_step_user #{h user}
357
- %span.trace_step_task #{h task}
358
-
359
- %form{ :action => '/work', :method => 'POST' }
360
- %input{ :type => 'hidden', :name => 'fei', :value => workitem.fei.to_storage_id }
361
- %table
362
- %tr
363
- %td.constrained{ :rowspan => 2 }
364
- %select{ :id => "next_#{wid}", :name => 'next', :onchange => "this.options[selectedIndex].select();" }
365
- - USERS.keys.sort.each do |uname|
366
- - uavatar = USERS[uname]
367
- %option{ :id => "#{uname}_#{wid}" } #{uname}
368
- :javascript
369
- document.getElementById('#{uname}_#{wid}').select = function () {
370
- $('#avatar_#{wid}').get(0).src = '#{uavatar}';
371
- $('#task_#{wid}').focus();
372
- }
373
- :javascript
374
- $('#next_#{wid}').get(0).value = '#{workitem.participant_name}';
375
- %td.constrained{ :rowspan => 2 }
376
- %img{ :src => USERS[workitem.participant_name], :id => "avatar_#{wid}" }
377
- %td.constrained.label
378
- subject
379
- %td
380
- #{h workitem.fields['subject']}
381
- %tr
382
- %td.constrained.label
383
- task
384
- %td
385
- %input{ :id => "task_#{wid}", :type => 'text', :name => 'task', :value => workitem.fields['task'] }
386
- %tr.buttons
387
- %td{ :colspan => 4 }
388
- %input{ :type => 'submit', :name => 'action', :value => 'resume' }
389
- or
390
- %input{ :type => 'submit', :name => 'action', :value => 'terminate' }
391
-
@@ -1,107 +0,0 @@
1
-
2
- $:.unshift('lib')
3
-
4
- require 'rubygems'
5
- require 'ruote' # sudo gem install ruote
6
- require 'atom/feed' # sudo gem install atom-tools
7
- require 'prawn' # sudo gem install prawn
8
-
9
- #
10
- # starting a transient engine (no need to make it persistent)
11
-
12
- engine = Ruote::Engine.new(Ruote::Worker.new(Ruote::HashStorage.new()))
13
-
14
- #
15
- # a process that fetches the latest pictures from flickr.com and submits
16
- # them concurrently to three users for review
17
-
18
- pdef = Ruote.process_definition :name => 'picture_acquisition' do
19
- sequence do
20
-
21
- get_pictures
22
-
23
- concurrence :merge_type => 'mix' do
24
- # pass the picture list to three users concurrently
25
- # make sure to let their choice appear in the final workitem
26
- # at the end of the concurrence
27
-
28
- user_alice
29
- user_bob
30
- user_charly
31
- user_doug
32
- end
33
-
34
- generate_result_pdf
35
- end
36
- end
37
-
38
- #
39
- # fetching the flickr.com pictures via Atom
40
-
41
- engine.register_participant :get_pictures do |workitem|
42
-
43
- feed = Atom::Feed.new(
44
- "http://api.flickr.com/services/feeds/photos_public.gne"+
45
- "?tags=#{workitem.fields['tags'].join(',')}&format=atom")
46
- feed.update!
47
-
48
- workitem.fields['pictures'] = feed.entries.inject([]) do |a, entry|
49
- a << [
50
- entry.title.to_s,
51
- entry.authors.first.name,
52
- entry.links.last.href
53
- ]
54
- end
55
- end
56
-
57
- #
58
- # the users (well, here, just randomly picking a picture)
59
-
60
- engine.register_participant 'user_.*' do |workitem|
61
-
62
- workitem.fields[workitem.participant_name] =
63
- workitem.fields['pictures'][(rand * workitem.fields['pictures'].length).to_i]
64
- end
65
-
66
- #
67
- # the final participant, generates an "out.pdf" file in the current dir
68
-
69
- engine.register_participant :generate_result_pdf do |workitem|
70
-
71
- entries = workitem.fields.inject([]) do |a, (k, v)|
72
- a << [ k, v.last ] if k.match(/^user\_.+$/)
73
- a
74
- end
75
-
76
- entries.each_with_index do |entry, i|
77
- entry << "pic#{i}.jpg"
78
- `curl #{entry[1]} > #{entry[2]}`
79
- puts "..got #{entry[0]} / #{entry[2]}"
80
- end
81
-
82
- Prawn::Document.generate('out.pdf') do
83
- font 'Helvetica'
84
- entries.each do |entry|
85
- text entry[0]
86
- image entry[2], :width => 200
87
- end
88
- end
89
- puts ".generated out.pdf"
90
-
91
- `rm pic*.jpg`
92
- end
93
-
94
- #
95
- # launching the process, requesting pictures tagged 'cat' and 'fish'
96
-
97
- initial_workitem_fields = { 'tags' => [ 'cat', 'fish' ] }
98
-
99
- fei = engine.launch(pdef, initial_workitem_fields)
100
-
101
- #
102
- # workflow engines are asynchronous beasts, have to wait for them
103
- # (here we wait for a particular process)
104
-
105
- outcome = engine.wait_for(fei)
106
- #p outcome
107
-