ruote 2.1.11 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +60 -0
- data/CREDITS.txt +22 -4
- data/LICENSE.txt +1 -1
- data/README.rdoc +6 -7
- data/Rakefile +58 -59
- data/TODO.txt +137 -65
- data/couch_url.txt +1 -0
- data/jruby_issue.txt +32 -0
- data/lib/ruote.rb +1 -1
- data/lib/ruote/context.rb +12 -10
- data/lib/ruote/engine.rb +280 -145
- data/lib/ruote/engine/process_error.rb +5 -5
- data/lib/ruote/engine/process_status.rb +47 -28
- data/lib/ruote/exp/command.rb +7 -10
- data/lib/ruote/exp/commanded.rb +2 -2
- data/lib/ruote/exp/condition.rb +130 -43
- data/lib/ruote/exp/fe_add_branches.rb +2 -2
- data/lib/ruote/exp/fe_apply.rb +1 -1
- data/lib/ruote/exp/fe_cancel_process.rb +3 -3
- data/lib/ruote/exp/fe_command.rb +3 -3
- data/lib/ruote/exp/fe_concurrence.rb +4 -4
- data/lib/ruote/exp/fe_concurrent_iterator.rb +17 -5
- data/lib/ruote/exp/fe_cron.rb +3 -3
- data/lib/ruote/exp/fe_cursor.rb +5 -5
- data/lib/ruote/exp/fe_define.rb +3 -3
- data/lib/ruote/exp/fe_echo.rb +3 -3
- data/lib/ruote/exp/fe_equals.rb +2 -2
- data/lib/ruote/exp/fe_error.rb +2 -2
- data/lib/ruote/exp/fe_filter.rb +519 -0
- data/lib/ruote/exp/fe_forget.rb +9 -2
- data/lib/ruote/exp/fe_given.rb +154 -0
- data/lib/ruote/exp/fe_if.rb +16 -13
- data/lib/ruote/exp/fe_inc.rb +3 -3
- data/lib/ruote/exp/fe_iterator.rb +4 -4
- data/lib/ruote/exp/fe_let.rb +75 -0
- data/lib/ruote/exp/fe_listen.rb +68 -12
- data/lib/ruote/exp/fe_lose.rb +110 -0
- data/lib/ruote/exp/fe_noop.rb +1 -1
- data/lib/ruote/exp/{fe_when.rb → fe_once.rb} +25 -21
- data/lib/ruote/exp/fe_participant.rb +14 -17
- data/lib/ruote/exp/fe_redo.rb +10 -6
- data/lib/ruote/exp/fe_ref.rb +1 -1
- data/lib/ruote/exp/fe_registerp.rb +112 -0
- data/lib/ruote/exp/fe_reserve.rb +3 -3
- data/lib/ruote/exp/fe_restore.rb +2 -2
- data/lib/ruote/exp/fe_save.rb +2 -2
- data/lib/ruote/exp/fe_sequence.rb +3 -4
- data/lib/ruote/exp/fe_set.rb +16 -7
- data/lib/ruote/exp/fe_subprocess.rb +23 -1
- data/lib/ruote/exp/fe_that.rb +92 -0
- data/lib/ruote/exp/fe_undo.rb +3 -3
- data/lib/ruote/exp/fe_unregisterp.rb +71 -0
- data/lib/ruote/exp/fe_wait.rb +2 -2
- data/lib/ruote/exp/flowexpression.rb +153 -78
- data/lib/ruote/exp/iterator.rb +2 -2
- data/lib/ruote/exp/merge.rb +2 -2
- data/lib/ruote/exp/ro_attributes.rb +14 -12
- data/lib/ruote/exp/ro_filters.rb +136 -0
- data/lib/ruote/exp/ro_persist.rb +51 -35
- data/lib/ruote/exp/ro_variables.rb +18 -27
- data/lib/ruote/fei.rb +73 -33
- data/lib/ruote/id/mnemo_wfid_generator.rb +1 -1
- data/lib/ruote/id/wfid_generator.rb +11 -4
- data/lib/ruote/log/default_history.rb +122 -0
- data/lib/ruote/log/pretty.rb +36 -8
- data/lib/ruote/log/storage_history.rb +37 -5
- data/lib/ruote/log/test_logger.rb +26 -24
- data/lib/ruote/log/wait_logger.rb +5 -3
- data/lib/ruote/part/block_participant.rb +22 -11
- data/lib/ruote/part/engine_participant.rb +6 -7
- data/lib/ruote/part/local_participant.rb +6 -12
- data/lib/ruote/part/no_op_participant.rb +4 -4
- data/lib/ruote/part/null_participant.rb +4 -4
- data/lib/ruote/part/smtp_participant.rb +4 -4
- data/lib/ruote/part/storage_participant.rb +40 -20
- data/lib/ruote/part/template.rb +4 -4
- data/lib/ruote/participant.rb +0 -1
- data/lib/ruote/{parser.rb → reader.rb} +30 -25
- data/lib/ruote/{parser → reader}/ruby_dsl.rb +28 -11
- data/lib/ruote/{parser → reader}/xml.rb +6 -5
- data/lib/ruote/receiver/base.rb +35 -13
- data/lib/ruote/storage/base.rb +20 -18
- data/lib/ruote/storage/composite_storage.rb +10 -10
- data/lib/ruote/storage/fs_storage.rb +17 -10
- data/lib/ruote/storage/hash_storage.rb +29 -18
- data/lib/ruote/svc/dispatch_pool.rb +41 -14
- data/lib/ruote/svc/dollar_sub.rb +50 -17
- data/lib/ruote/svc/error_handler.rb +19 -11
- data/lib/ruote/svc/expression_map.rb +4 -4
- data/lib/ruote/svc/participant_list.rb +105 -100
- data/lib/ruote/svc/tracker.rb +58 -18
- data/lib/ruote/svc/treechecker.rb +51 -24
- data/lib/ruote/tree_dot.rb +4 -4
- data/lib/ruote/util/filter.rb +440 -0
- data/lib/ruote/util/hashdot.rb +4 -4
- data/lib/ruote/util/look.rb +2 -6
- data/lib/ruote/util/lookup.rb +9 -7
- data/lib/ruote/util/misc.rb +40 -8
- data/lib/ruote/util/ometa.rb +1 -1
- data/lib/ruote/util/serializer.rb +4 -4
- data/lib/ruote/util/subprocess.rb +29 -9
- data/lib/ruote/util/time.rb +4 -4
- data/lib/ruote/util/tree.rb +3 -3
- data/lib/ruote/version.rb +2 -2
- data/lib/ruote/worker.rb +55 -32
- data/lib/ruote/workitem.rb +64 -11
- data/ruote.gemspec +31 -302
- data/test/bm/launch_bench.rb +37 -0
- data/test/functional/base.rb +60 -18
- data/test/functional/concurrent_base.rb +2 -2
- data/test/functional/ct_0_concurrence.rb +1 -1
- data/test/functional/ct_1_iterator.rb +1 -1
- data/test/functional/ct_2_cancel.rb +1 -1
- data/test/functional/eft_0_process_definition.rb +2 -2
- data/test/functional/eft_10_cancel_process.rb +1 -1
- data/test/functional/eft_11_wait.rb +19 -11
- data/test/functional/eft_12_listen.rb +79 -13
- data/test/functional/eft_13_iterator.rb +13 -10
- data/test/functional/eft_14_cursor.rb +98 -9
- data/test/functional/eft_15_loop.rb +6 -4
- data/test/functional/eft_16_if.rb +12 -0
- data/test/functional/eft_18_concurrent_iterator.rb +31 -32
- data/test/functional/eft_19_reserve.rb +4 -4
- data/test/functional/eft_1_echo.rb +9 -0
- data/test/functional/eft_20_save.rb +4 -4
- data/test/functional/{eft_28_when.rb → eft_28_once.rb} +33 -7
- data/test/functional/eft_30_ref.rb +17 -2
- data/test/functional/eft_31_registerp.rb +130 -0
- data/test/functional/eft_32_lose.rb +93 -0
- data/test/functional/eft_33_let.rb +31 -0
- data/test/functional/eft_34_given.rb +123 -0
- data/test/functional/eft_35_filter.rb +269 -0
- data/test/functional/eft_3_participant.rb +4 -6
- data/test/functional/eft_4_set.rb +16 -2
- data/test/functional/eft_5_subprocess.rb +2 -4
- data/test/functional/eft_6_concurrence.rb +29 -29
- data/test/functional/eft_8_undo.rb +39 -3
- data/test/functional/eft_9_redo.rb +94 -2
- data/test/functional/ft_10_dollar.rb +81 -2
- data/test/functional/ft_11_recursion.rb +13 -17
- data/test/functional/ft_12_launchitem.rb +9 -5
- data/test/functional/ft_13_variables.rb +7 -9
- data/test/functional/ft_14_re_apply.rb +6 -9
- data/test/functional/ft_15_timeout.rb +18 -18
- data/test/functional/ft_16_participant_params.rb +1 -3
- data/test/functional/ft_17_conditional.rb +25 -2
- data/test/functional/ft_18_kill.rb +65 -12
- data/test/functional/ft_1_process_status.rb +147 -71
- data/test/functional/ft_20_storage_participant.rb +0 -1
- data/test/functional/ft_21_forget.rb +82 -1
- data/test/functional/{ft_24_block_participants.rb → ft_24_block_participant.rb} +42 -11
- data/test/functional/ft_25_receiver.rb +47 -17
- data/test/functional/{ft_26_participant_timeout.rb → ft_26_participant_rtimeout.rb} +56 -19
- data/test/functional/ft_29_part_template.rb +6 -5
- data/test/functional/ft_2_errors.rb +21 -37
- data/test/functional/ft_30_smtp_participant.rb +1 -1
- data/test/functional/ft_31_part_blocking.rb +8 -6
- data/test/functional/ft_34_cursor_rewind.rb +13 -10
- data/test/functional/ft_35_add_service.rb +1 -1
- data/test/functional/ft_36_storage_history.rb +24 -1
- data/test/functional/ft_37_default_history.rb +109 -0
- data/test/functional/ft_38_participant_more.rb +10 -10
- data/test/functional/ft_39_wait_for.rb +12 -9
- data/test/functional/ft_3_participant_registration.rb +111 -32
- data/test/functional/ft_40_wait_logger.rb +2 -1
- data/test/functional/ft_41_participants.rb +30 -4
- data/test/functional/ft_43_participant_on_reply.rb +6 -23
- data/test/functional/ft_45_participant_accept.rb +4 -4
- data/test/functional/ft_46_launch_single.rb +36 -2
- data/test/functional/ft_47_wfid_generator.rb +54 -0
- data/test/functional/ft_48_lose.rb +112 -0
- data/test/functional/ft_49_engine_on_error.rb +201 -0
- data/test/functional/ft_4_cancel.rb +66 -6
- data/test/functional/ft_50_engine_config.rb +22 -0
- data/test/functional/ft_51_misc.rb +67 -0
- data/test/functional/ft_52_case.rb +134 -0
- data/test/functional/ft_53_engine_on_terminate.rb +95 -0
- data/test/functional/ft_54_patterns.rb +104 -0
- data/test/functional/{ft_37_engine_participant.rb → ft_55_engine_participant.rb} +4 -5
- data/test/functional/ft_56_filter_attribute.rb +259 -0
- data/test/functional/ft_5_on_error.rb +77 -30
- data/test/functional/ft_6_on_cancel.rb +66 -11
- data/test/functional/ft_7_tags.rb +94 -5
- data/test/functional/ft_8_participant_consumption.rb +36 -5
- data/test/functional/ft_9_subprocesses.rb +10 -10
- data/test/functional/rt_1_listen.rb +3 -3
- data/test/functional/{rt_3_when.rb → rt_3_once.rb} +4 -4
- data/test/functional/storage_helper.rb +15 -13
- data/test/functional/test.rb +1 -3
- data/test/test_helper.rb +0 -8
- data/test/unit/storage.rb +154 -10
- data/test/unit/{ut_0_ruby_parser.rb → ut_0_ruby_reader.rb} +61 -11
- data/test/unit/ut_11_lookup.rb +7 -0
- data/test/unit/ut_13_serializer.rb +1 -1
- data/test/unit/ut_15_util.rb +23 -0
- data/test/unit/{ut_16_parser.rb → ut_16_reader.rb} +11 -13
- data/test/unit/ut_1_fei.rb +57 -10
- data/test/unit/ut_20_composite_storage.rb +25 -11
- data/test/unit/ut_21_participant_list.rb +47 -0
- data/test/unit/ut_22_filter.rb +903 -0
- data/test/unit/ut_3_wait_logger.rb +2 -6
- data/test/unit/ut_6_condition.rb +164 -17
- data/test/unit/ut_7_workitem.rb +28 -0
- data/test/unit/ut_8_tree_to_dot.rb +1 -1
- data/test/unit/{ut_9_xml_parser.rb → ut_9_xml_reader.rb} +5 -5
- metadata +108 -84
- data/.gitignore +0 -4
- data/examples/barley.rb +0 -391
- data/examples/flickr_report.rb +0 -107
- data/examples/pong.rb +0 -37
- data/examples/ruote_quickstart.rb +0 -43
- data/examples/web_first_page.rb +0 -68
- data/lib/ruote/part/hash_participant.rb +0 -91
- data/test/README.rdoc +0 -15
- data/test/functional/crunner.sh +0 -19
- data/test/pdef.xml +0 -7
- data/test/unit/ut_2_wfidgen.rb +0 -21
data/.gitignore
DELETED
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(' » ')}
|
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
|
-
|
data/examples/flickr_report.rb
DELETED
@@ -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
|
-
|