ruote 2.1.5 → 2.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,13 @@
2
2
  = ruote - CHANGELOG.txt
3
3
 
4
4
 
5
+ == ruote - 2.1.6 released 2010/02/08
6
+
7
+ - welcoming ruote-dm (datamapper persistency)
8
+ - Engine#re_apply(fei, opts) where opts in [ :tree, :fields, :merge_in_fields ]
9
+ - fixed issue about StorageParticipant#update, thanks Torsten
10
+
11
+
5
12
  == ruote - 2.1.5 released 2010/01/28
6
13
 
7
14
  - fixed StorageParticipant a to b flow, fix by Torsten
data/Rakefile CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
+ require 'lib/ruote/version.rb'
3
+
2
4
  require 'rubygems'
3
5
  require 'rake'
4
6
 
5
- $:.unshift( File.join(File.dirname(__FILE__), 'lib') )
6
- require File.join(File.dirname(__FILE__), %w[ lib ruote worker.rb ])
7
7
 
8
8
  begin
9
9
 
@@ -60,7 +60,7 @@ CLEAN.include('pkg', 'rdoc', 'work', 'logs')
60
60
  task :default => [ :clean ]
61
61
 
62
62
  desc 'Upload the documentation to rubyforge'
63
- task :upload_rdoc => :rdoc do
63
+ task :upload_rdoc => :yard do
64
64
  sh %{
65
65
  rsync -azv -e ssh \
66
66
  ruote_rdoc \
data/TODO.txt CHANGED
@@ -300,3 +300,7 @@
300
300
 
301
301
  [ ] engine.on_error = 'participant_name'
302
302
 
303
+ [ ] "open days" plugin / service / lambda ? is_open_day?(d)
304
+
305
+ [ ] engine.re_apply(fei, wi) (thanks Torsten)... :wi => x, :tree => y...
306
+
@@ -0,0 +1,390 @@
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!
95
+
96
+ def h (s)
97
+ Rack::Utils.escape_html(s)
98
+ end
99
+
100
+ def sort (workitems)
101
+ workitems.sort! do |wi0, wi1|
102
+ (wi0.fields['last'] || '') <=> (wi1.fields['last'] || '')
103
+ end
104
+ end
105
+
106
+ set :haml, { :format => :html5 }
107
+
108
+ get '/' do
109
+ redirect '/work'
110
+ end
111
+
112
+ get '/work' do
113
+
114
+ @workitems = PART.all
115
+ sort(@workitems)
116
+
117
+ haml :work
118
+ end
119
+
120
+ get '/work/:thing' do
121
+
122
+ t = params[:thing]
123
+
124
+ @workitems = if USERS[t]
125
+ PART.by_participant(t)
126
+ else
127
+ PART.by_field('subject', t)
128
+ end
129
+ sort(@workitems)
130
+
131
+ haml :work
132
+ end
133
+
134
+ post '/new' do
135
+
136
+ if n = params['next']
137
+ wfid = ENGINE.launch(
138
+ PDEF,
139
+ 'next' => n,
140
+ 'subject' => params['subject'],
141
+ 'task' => params['task'],
142
+ 'last' => Ruote.now_to_utc_s)
143
+ end
144
+
145
+ sleep 0.5
146
+
147
+ redirect '/work'
148
+ end
149
+
150
+ post '/work' do
151
+
152
+ fei = params['fei']
153
+ fei = Ruote::FlowExpressionId.from_id(fei, ENGINE.context.engine_id)
154
+
155
+ workitem = PART[fei]
156
+ # fetch workitem from storage
157
+
158
+ if params['action'] == 'resume'
159
+ workitem.fields['next'] = params['next']
160
+ workitem.fields['task'] = params['task']
161
+ workitem.fields['last'] = Ruote.now_to_utc_s
162
+ PART.reply(workitem)
163
+ else # params['action'] == 'terminate'
164
+ workitem.fields.delete('next')
165
+ PART.reply(workitem)
166
+ end
167
+
168
+ sleep 0.5
169
+
170
+ redirect '/work'
171
+ end
172
+
173
+ __END__
174
+
175
+ @@work
176
+
177
+ %html
178
+ %head
179
+ %title barley
180
+
181
+ %script( src='http://code.jquery.com/jquery-1.4.1.min.js' )
182
+
183
+ %link( href='http://barley.s3.amazonaws.com/reset.css' type='text/css' rel='stylesheet' )
184
+ %link( href='http://ruote.rubyforge.org/images/ruote.png' type='image/png' rel='icon' )
185
+
186
+ %style
187
+ :sass
188
+ body
189
+ font-family: "helvetica neue", helvetica
190
+ font-size: 14pt
191
+ margin-left: 20%
192
+ margin-right: 20%
193
+ margin-top: 20pt
194
+
195
+ background: #C0DEED url('http://a3.twimg.com/a/1264550348/images/bg-clouds.png') repeat-x
196
+ p
197
+ margin-bottom: 5pt
198
+ input[type='text']
199
+ width: 100%
200
+ img
201
+ width: 38px
202
+ a
203
+ color: black
204
+ text-decoration: none
205
+ a:visited
206
+ color: black
207
+ text-decoration: none
208
+ a:active
209
+ color: black
210
+ text-decoration: none
211
+ #barley
212
+ font-size: 350%
213
+ font-weight: lighter
214
+ color: white
215
+ padding-left: 2pt
216
+ padding-bottom: 7pt
217
+ #buttons
218
+ font-size: 90%
219
+ color: white
220
+ margin-bottom: 14pt
221
+ #buttons a
222
+ color: white
223
+ #buttons a:visited
224
+ color: white
225
+ .workitem
226
+ margin-bottom: 7pt
227
+ .workitem > *
228
+ float: left
229
+ .workitem:after
230
+ display: block
231
+ clear: both
232
+ visibility: hidden
233
+ content: ''
234
+ .wi_info
235
+ margin-left: 3pt
236
+ .wi_user
237
+ font-weight: bold
238
+ .wi_task
239
+ opacity: 0.37
240
+ cursor: pointer
241
+ .wi_wfid
242
+ font-size: 70%
243
+ vertical-align: middle
244
+ font-weight: lighter
245
+ table
246
+ width: 100%
247
+ tr.buttons > td
248
+ text-align: center
249
+ padding-top: 4pt
250
+ td
251
+ vertical-align: middle
252
+ td.constrained
253
+ width: 1%
254
+ padding-right: 1em
255
+ td.label
256
+ font-weight: lighter
257
+ .trace
258
+ opacity: 0.37
259
+ margin-bottom: 4pt
260
+ cursor: pointer
261
+ .trace_detail
262
+ padding-left: 2pt
263
+ border-left: 2.5pt solid #8EC1DA
264
+ .trace_step
265
+ width: 100%
266
+ .trace_step_time
267
+ font-size: 70%
268
+ .trace_step_user
269
+ font-weight: bold
270
+ opacity: 0.6
271
+ .trace_step_task
272
+ opacity: 0.37
273
+
274
+ %body
275
+
276
+ #barley
277
+ %span{ :onclick => "document.location.href = '/work';", :style => 'cursor: pointer;' } barley
278
+
279
+ #message
280
+ #{@message}
281
+
282
+ #buttons
283
+
284
+ %a{ :href => '', :onclick => "$('#new_form').slideToggle(); $('#new_next').focus(); return false;" } new
285
+ |
286
+ %a{ :href => '/work' } all
287
+
288
+ #new_form{ :style => 'display: none;' }
289
+ %form{ :action => '/new', :method => 'POST' }
290
+ %table
291
+ %tr
292
+ %td.constrained{ :rowspan => 2 }
293
+ %select#new_next{ :name => 'next', :onchange => "this.options[selectedIndex].select();" }
294
+ - USERS.keys.sort.each do |uname|
295
+ - uavatar = USERS[uname]
296
+ %option{ :id => "new_#{uname}" } #{uname}
297
+ :javascript
298
+ document.getElementById('new_#{uname}').select = function () {
299
+ $('#new_avatar').get(0).src = '#{uavatar}';
300
+ $('#new_subject').focus();
301
+ }
302
+ :javascript
303
+ $('#new_next').get(0).value = '_none_';
304
+ %td.constrained{ :rowspan => 2 }
305
+ %img#new_avatar{ :src => USERS['_none_'] }
306
+ %td.constrained.label
307
+ subject
308
+ %td
309
+ %input{ :id => 'new_subject', :type => 'text', :name => 'subject', :value => '' }
310
+ %tr
311
+ %td.constrained.label
312
+ task
313
+ %td
314
+ %input{ :type => 'text', :name => 'task', :value => '' }
315
+ %tr.buttons
316
+ %td{ :colspan => 4 }
317
+ %input{ :type => 'submit', :value => 'launch' }
318
+
319
+ #work
320
+ - @workitems.each do |workitem|
321
+
322
+ - wid = "workitem#{workitem.fei.hash.to_s}"
323
+
324
+ .workitem
325
+ .wi_user_image
326
+ %img{ :src => USERS[workitem.participant_name], :class => 'wi_user' }
327
+ .wi_info
328
+ .wi_first_line
329
+ %span.wi_user
330
+ %a{ :href => "/work/#{h workitem.participant_name}" } #{h workitem.participant_name}
331
+ %span.wi_subject
332
+ %a{ :href => "/work/#{CGI.escape(workitem.fields['subject'])}" } #{h workitem.fields['subject']}
333
+ %span.wi_task{ :onclick => "$('##{wid}').slideToggle(); $('#next_#{wid}').focus();" }
334
+ #{h workitem.fields['task']}
335
+ .wi_second_line
336
+ %span.wi_wfid
337
+ #{workitem.fei.wfid}
338
+ - t = Rufus.to_ruby_time(workitem.fields['last'])
339
+ - ago = Rufus.to_duration_string(Time.now - t.to_time, :drop_seconds => true)
340
+ - ago = (ago.strip == '') ? 'a few seconds' : ago
341
+ (#{ago} ago)
342
+
343
+ .workitem_form{ :style => 'display: none;', :id => wid }
344
+
345
+ .trace{ :onclick => "$('#trace#{wid}').slideToggle();" }
346
+ - names = workitem.fields['trace'].collect { |e| e[1] }
347
+ #{names.join(' &#187; ')}
348
+
349
+ .trace_detail{ :id => "trace#{wid}", :style => 'display: none;' }
350
+ - workitem.fields['trace'].each do |time, user, task|
351
+ - t = Rufus.to_ruby_time(time)
352
+ - ago = Rufus.to_duration_string(Time.now - t.to_time, :drop_seconds => true)
353
+ %p.trace_step
354
+ %span.trace_step_time #{h time} (#{ago} ago)
355
+ %span.trace_step_user #{h user}
356
+ %span.trace_step_task #{h task}
357
+
358
+ %form{ :action => '/work', :method => 'POST' }
359
+ %input{ :type => 'hidden', :name => 'fei', :value => workitem.fei.to_storage_id }
360
+ %table
361
+ %tr
362
+ %td.constrained{ :rowspan => 2 }
363
+ %select{ :id => "next_#{wid}", :name => 'next', :onchange => "this.options[selectedIndex].select();" }
364
+ - USERS.keys.sort.each do |uname|
365
+ - uavatar = USERS[uname]
366
+ %option{ :id => "#{uname}_#{wid}" } #{uname}
367
+ :javascript
368
+ document.getElementById('#{uname}_#{wid}').select = function () {
369
+ $('#avatar_#{wid}').get(0).src = '#{uavatar}';
370
+ $('#task_#{wid}').focus();
371
+ }
372
+ :javascript
373
+ $('#next_#{wid}').get(0).value = '#{workitem.participant_name}';
374
+ %td.constrained{ :rowspan => 2 }
375
+ %img{ :src => USERS[workitem.participant_name], :id => "avatar_#{wid}" }
376
+ %td.constrained.label
377
+ subject
378
+ %td
379
+ #{h workitem.fields['subject']}
380
+ %tr
381
+ %td.constrained.label
382
+ task
383
+ %td
384
+ %input{ :id => "task_#{wid}", :type => 'text', :name => 'task', :value => workitem.fields['task'] }
385
+ %tr.buttons
386
+ %td{ :colspan => 4 }
387
+ %input{ :type => 'submit', :name => 'action', :value => 'resume' }
388
+ or
389
+ %input{ :type => 'submit', :name => 'action', :value => 'terminate' }
390
+
@@ -124,9 +124,23 @@ module Ruote
124
124
  # (all the children have been cancelled), the expression will get
125
125
  # re-applied.
126
126
  #
127
- def re_apply (fei)
127
+ # == options
128
+ #
129
+ # :tree is used to completely change the tree of the expression at re_apply
130
+ #
131
+ # engine.re_apply(fei, :tree => [ 'participant', { 'ref' => 'bob' }, [] ])
132
+ #
133
+ # :fields is used to replace the fields of the workitem at re_apply
134
+ #
135
+ # engine.re_apply(fei, :fields => { 'customer' => 'bob' })
136
+ #
137
+ # :merge_in_fields is used to add / override fields
138
+ #
139
+ # engine.re_apply(fei, :merge_in_fields => { 'customer' => 'bob' })
140
+ #
141
+ def re_apply (fei, opts={})
128
142
 
129
- @context.storage.put_msg('cancel', 'fei' => fei.to_h, 're_apply' => true)
143
+ @context.storage.put_msg('cancel', 'fei' => fei.to_h, 're_apply' => opts)
130
144
  end
131
145
 
132
146
  # Returns a ProcessStatus instance describing the current status of
@@ -318,10 +318,21 @@ module Ruote::Exp
318
318
  ] if h.state == 'timing_out'
319
319
 
320
320
  if h.state == 'cancelling'
321
+
321
322
  if t = msg['on_cancel']
323
+
322
324
  h.on_cancel = t
323
- elsif msg['re_apply']
324
- h.on_cancel = tree
325
+
326
+ elsif hra = msg['re_apply']
327
+
328
+ hra = {} if hra == true
329
+ h.on_cancel = hra['tree'] || tree
330
+ if fs = hra['fields']
331
+ h.applied_workitem['fields'] = fs
332
+ end
333
+ if mfs = hra['merge_in_fields']
334
+ h.applied_workitem['fields'].merge!(mfs)
335
+ end
325
336
  end
326
337
  end
327
338
 
@@ -22,7 +22,7 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
-
25
+ require 'ruote/version'
26
26
  require 'ruote/util/misc'
27
27
  require 'ruote/util/hashdot'
28
28
 
@@ -87,7 +87,10 @@ module Ruote
87
87
  workitem, Ruote::Exp::FlowExpression.fetch(@context, workitem.h.fei))
88
88
  end
89
89
 
90
- workitem.result = r if r != nil && r != workitem
90
+ if r != nil && r != workitem
91
+ #workitem.result = r
92
+ workitem.result = (Rufus::Json.dup(r) rescue nil)
93
+ end
91
94
 
92
95
  reply_to_engine(workitem)
93
96
  end
@@ -37,25 +37,25 @@ module Ruote
37
37
  #
38
38
  # For instance :
39
39
  #
40
- # engine0 =
41
- # Ruote::Engine.new(
42
- # Ruote::Worker.new(
43
- # Ruote::FsStorage.new('work0', 'engine_id' => 'engine0')))
44
- # engine1 =
45
- # Ruote::Engine.new(
46
- # Ruote::Worker.new(
47
- # Ruote::FsStorage.new('work1', 'engine_id' => 'engine1')))
48
- #
49
- # engine0.register_participant('engine1',
50
- # Ruote::EngineParticipant,
51
- # 'storage_class' => Ruote::FsStorage,
52
- # 'storage_path' => 'ruote/storage/fs_storage',
53
- # 'storage_args' => 'work1')
54
- # engine1.register_participant('engine0',
55
- # Ruote::EngineParticipant,
56
- # 'storage_class' => Ruote::FsStorage,
57
- # 'storage_path' => 'ruote/storage/fs_storage',
58
- # 'storage_args' => 'work0')
40
+ # engine0 =
41
+ # Ruote::Engine.new(
42
+ # Ruote::Worker.new(
43
+ # Ruote::FsStorage.new('work0', 'engine_id' => 'engine0')))
44
+ # engine1 =
45
+ # Ruote::Engine.new(
46
+ # Ruote::Worker.new(
47
+ # Ruote::FsStorage.new('work1', 'engine_id' => 'engine1')))
48
+ #
49
+ # engine0.register_participant('engine1',
50
+ # Ruote::EngineParticipant,
51
+ # 'storage_class' => Ruote::FsStorage,
52
+ # 'storage_path' => 'ruote/storage/fs_storage',
53
+ # 'storage_args' => 'work1')
54
+ # engine1.register_participant('engine0',
55
+ # Ruote::EngineParticipant,
56
+ # 'storage_class' => Ruote::FsStorage,
57
+ # 'storage_path' => 'ruote/storage/fs_storage',
58
+ # 'storage_args' => 'work0')
59
59
  #
60
60
  # In this example, two engines are created (note that their 'engine_id' is
61
61
  # explicitely set (else it would default to 'engine')). Each engine is then
@@ -61,8 +61,6 @@ module Ruote
61
61
 
62
62
  doc = workitem.to_h
63
63
 
64
- doc.delete('_rev')
65
-
66
64
  doc.merge!(
67
65
  'type' => 'workitems',
68
66
  '_id' => to_id(doc['fei']),
@@ -110,6 +108,8 @@ module Ruote
110
108
 
111
109
  return reply(workitem) if r != nil
112
110
 
111
+ workitem.h.delete('_rev')
112
+
113
113
  reply_to_engine(workitem)
114
114
  end
115
115
 
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Copyright (c) 2005-2010, 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
+ module Ruote
26
+ VERSION = '2.1.6'
27
+ end
28
+
@@ -27,8 +27,6 @@ require 'ruote/fei'
27
27
 
28
28
  module Ruote
29
29
 
30
- VERSION = '2.1.5'
31
-
32
30
  class Worker
33
31
 
34
32
  EXP_ACTIONS = %w[ reply cancel fail receive ]
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruote}
8
- s.version = "2.1.5"
8
+ s.version = "2.1.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Mettraux", "Kenneth Kalmer"]
12
- s.date = %q{2010-01-28}
12
+ s.date = %q{2010-02-08}
13
13
  s.description = %q{
14
14
  ruote is an open source ruby workflow engine.
15
15
  }
@@ -26,6 +26,7 @@ ruote is an open source ruby workflow engine.
26
26
  "README.rdoc",
27
27
  "Rakefile",
28
28
  "TODO.txt",
29
+ "examples/barley.rb",
29
30
  "examples/flickr_report.rb",
30
31
  "examples/ruote_quickstart.rb",
31
32
  "examples/web_first_page.rb",
@@ -113,6 +114,7 @@ ruote is an open source ruby workflow engine.
113
114
  "lib/ruote/util/time.rb",
114
115
  "lib/ruote/util/tree.rb",
115
116
  "lib/ruote/util/treechecker.rb",
117
+ "lib/ruote/version.rb",
116
118
  "lib/ruote/worker.rb",
117
119
  "lib/ruote/workitem.rb",
118
120
  "phil.txt",
@@ -214,6 +216,7 @@ ruote is an open source ruby workflow engine.
214
216
  "test/pdef.xml",
215
217
  "test/test.rb",
216
218
  "test/test_helper.rb",
219
+ "test/unit/storage.rb",
217
220
  "test/unit/storages.rb",
218
221
  "test/unit/test.rb",
219
222
  "test/unit/ut_0_ruby_parser.rb",
@@ -222,7 +225,6 @@ ruote is an open source ruby workflow engine.
222
225
  "test/unit/ut_14_is_uri.rb",
223
226
  "test/unit/ut_15_util.rb",
224
227
  "test/unit/ut_16_parser.rb",
225
- "test/unit/ut_17_storage.rb",
226
228
  "test/unit/ut_18_engine.rb",
227
229
  "test/unit/ut_1_fei.rb",
228
230
  "test/unit/ut_2_wfidgen.rb",
@@ -29,6 +29,8 @@ module FunctionalBase
29
29
  determine_storage(
30
30
  's_logger' => [ 'ruote/log/test_logger', 'Ruote::TestLogger' ])))
31
31
 
32
+ #p @engine.storage.class
33
+
32
34
  @tracer = Tracer.new
33
35
 
34
36
  @engine.add_service('tracer', @tracer)
@@ -50,9 +50,9 @@ class CtConcurrenceTest < Test::Unit::TestCase
50
50
  msgs.each do |m|
51
51
 
52
52
  fei = m['fei'] ?
53
- Ruote::FlowExpressionId.to_s_id(m['fei']) : ''
53
+ Ruote::FlowExpressionId.to_storage_id(m['fei']) : ''
54
54
  wi_fei = m['workitem'] ?
55
- Ruote::FlowExpressionId.to_s_id(m['workitem']['fei']) : ''
55
+ Ruote::FlowExpressionId.to_storage_id(m['workitem']['fei']) : ''
56
56
 
57
57
  p [ m['action'], fei, wi_fei ]
58
58
  end
@@ -13,20 +13,21 @@ require 'ruote/part/hash_participant'
13
13
  class FtReApplyTest < Test::Unit::TestCase
14
14
  include FunctionalBase
15
15
 
16
+ PDEF = Ruote.process_definition do
17
+ sequence do
18
+ alpha
19
+ echo 'done.'
20
+ end
21
+ end
22
+
16
23
  def test_re_apply
17
24
 
18
- pdef = Ruote.process_definition do
19
- sequence do
20
- alpha
21
- echo 'done.'
22
- end
23
- end
24
25
 
25
26
  alpha = @engine.register_participant :alpha, Ruote::HashParticipant.new
26
27
 
27
28
  #noisy
28
29
 
29
- wfid = @engine.launch(pdef)
30
+ wfid = @engine.launch(PDEF)
30
31
  wait_for(:alpha)
31
32
 
32
33
  id0 = alpha.first.object_id
@@ -53,10 +54,75 @@ class FtReApplyTest < Test::Unit::TestCase
53
54
 
54
55
  def test_cancel_and_re_apply
55
56
 
57
+ alpha = @engine.register_participant :alpha, Ruote::HashParticipant.new
58
+
59
+ #noisy
60
+
61
+ wfid = @engine.launch(PDEF)
62
+ wait_for(:alpha)
63
+
64
+ id0 = alpha.first.object_id
65
+
66
+ # ... flow stalled ...
67
+
68
+ ps = @engine.process(wfid)
69
+
70
+ stalled_exp = ps.expressions.find { |fexp| fexp.fei.expid == '0_0_0' }
71
+
72
+ @engine.re_apply(stalled_exp.fei)
73
+
74
+ wait_for(:alpha)
75
+
76
+ assert_equal 1, alpha.size
77
+ assert_not_equal id0, alpha.first.object_id
78
+
79
+ alpha.reply(alpha.first)
80
+
81
+ wait_for(wfid)
82
+
83
+ assert_equal 'done.', @tracer.to_s
84
+ end
85
+
86
+ def test_update_expression_and_re_apply
87
+
88
+ alpha = @engine.register_participant :alpha, Ruote::HashParticipant.new
89
+
90
+ #noisy
91
+
92
+ wfid = @engine.launch(PDEF)
93
+ wait_for(:alpha)
94
+
95
+ id0 = alpha.first.object_id
96
+
97
+ # ... flow stalled ...
98
+
99
+ ps = @engine.process(wfid)
100
+
101
+ stalled_exp = ps.expressions.find { |fexp| fexp.fei.expid == '0_0_0' }
102
+
103
+ stalled_exp.update_tree([
104
+ 'participant', { 'ref' => 'alpha', 'activity' => 'mow lawn' }, [] ])
105
+ stalled_exp.persist
106
+
107
+ @engine.re_apply(stalled_exp.fei)
108
+
109
+ wait_for(:alpha)
110
+
111
+ assert_equal 'mow lawn', alpha.first.fields['params']['activity']
112
+
113
+ alpha.reply(alpha.first)
114
+
115
+ wait_for(wfid)
116
+
117
+ assert_equal 'done.', @tracer.to_s
118
+ end
119
+
120
+ def test_re_apply_with_new_workitem_fields
121
+
56
122
  pdef = Ruote.process_definition do
57
123
  sequence do
58
124
  alpha
59
- echo 'done.'
125
+ echo 'done for ${f:x}.'
60
126
  end
61
127
  end
62
128
 
@@ -75,7 +141,7 @@ class FtReApplyTest < Test::Unit::TestCase
75
141
 
76
142
  stalled_exp = ps.expressions.find { |fexp| fexp.fei.expid == '0_0_0' }
77
143
 
78
- @engine.re_apply(stalled_exp.fei)
144
+ @engine.re_apply(stalled_exp.fei, :fields => { 'x' => 'nada' })
79
145
 
80
146
  wait_for(:alpha)
81
147
 
@@ -86,15 +152,15 @@ class FtReApplyTest < Test::Unit::TestCase
86
152
 
87
153
  wait_for(wfid)
88
154
 
89
- assert_equal 'done.', @tracer.to_s
155
+ assert_equal 'done for nada.', @tracer.to_s
90
156
  end
91
157
 
92
- def test_update_expression_and_re_apply
158
+ def test_re_apply_with_merged_workitem_fields
93
159
 
94
160
  pdef = Ruote.process_definition do
95
161
  sequence do
96
162
  alpha
97
- echo 'done.'
163
+ echo 'done for ${f:x} and ${f:y}.'
98
164
  end
99
165
  end
100
166
 
@@ -102,7 +168,7 @@ class FtReApplyTest < Test::Unit::TestCase
102
168
 
103
169
  #noisy
104
170
 
105
- wfid = @engine.launch(pdef)
171
+ wfid = @engine.launch(pdef, { 'y' => 'nemo' })
106
172
  wait_for(:alpha)
107
173
 
108
174
  id0 = alpha.first.object_id
@@ -113,21 +179,43 @@ class FtReApplyTest < Test::Unit::TestCase
113
179
 
114
180
  stalled_exp = ps.expressions.find { |fexp| fexp.fei.expid == '0_0_0' }
115
181
 
116
- stalled_exp.update_tree([
117
- 'participant', { 'ref' => 'alpha', 'activity' => 'mow lawn' }, [] ])
118
- stalled_exp.persist
119
-
120
- @engine.re_apply(stalled_exp.fei)
182
+ @engine.re_apply(stalled_exp.fei, :merge_in_fields => { 'x' => 'nada' })
121
183
 
122
184
  wait_for(:alpha)
123
185
 
124
- assert_equal 'mow lawn', alpha.first.fields['params']['activity']
186
+ assert_equal 1, alpha.size
187
+ assert_not_equal id0, alpha.first.object_id
125
188
 
126
189
  alpha.reply(alpha.first)
127
190
 
128
191
  wait_for(wfid)
129
192
 
130
- assert_equal 'done.', @tracer.to_s
193
+ assert_equal 'done for nada and nemo.', @tracer.to_s
194
+ end
195
+
196
+ def test_re_apply_with_new_tree
197
+
198
+ alpha = @engine.register_participant :alpha, Ruote::HashParticipant.new
199
+
200
+ #noisy
201
+
202
+ wfid = @engine.launch(PDEF)
203
+ wait_for(:alpha)
204
+
205
+ id0 = alpha.first.object_id
206
+
207
+ # ... flow stalled ...
208
+
209
+ ps = @engine.process(wfid)
210
+
211
+ stalled_exp = ps.expressions.find { |fexp| fexp.fei.expid == '0_0_0' }
212
+
213
+ @engine.re_apply(
214
+ stalled_exp.fei, :tree => [ 'echo', { 're_applied' => nil }, [] ])
215
+
216
+ wait_for(wfid)
217
+
218
+ assert_equal "re_applied\ndone.", @tracer.to_s
131
219
  end
132
220
  end
133
221
 
@@ -112,7 +112,7 @@ class FtStorageParticipantTest < Test::Unit::TestCase
112
112
  end
113
113
  end
114
114
 
115
- def test_find_by_participant
115
+ def test_by_participant
116
116
 
117
117
  @engine.register_participant :alpha, Ruote::StorageParticipant
118
118
  @engine.register_participant :bravo, Ruote::StorageParticipant
@@ -125,6 +125,7 @@ class FtStorageParticipantTest < Test::Unit::TestCase
125
125
  part.context = @engine.context
126
126
 
127
127
  assert_equal 2, part.size
128
+ #part.by_participant('alpha').each { |wi| p wi }
128
129
  assert_equal 1, part.by_participant('alpha').size
129
130
  assert_equal 1, part.by_participant('bravo').size
130
131
  end
@@ -235,5 +236,24 @@ class FtStorageParticipantTest < Test::Unit::TestCase
235
236
 
236
237
  assert_nil @engine.process(wfid)
237
238
  end
239
+
240
+ def test_update_workitem
241
+
242
+ @engine.register_participant 'alpha', Ruote::StorageParticipant
243
+
244
+ wfid = @engine.launch(Ruote.process_definition { alpha })
245
+
246
+ alpha = Ruote::StorageParticipant.new(@engine)
247
+
248
+ wait_for(:alpha)
249
+
250
+ wi = alpha.first
251
+
252
+ wi.fields['jidai'] = 'heian'
253
+
254
+ alpha.update(wi)
255
+
256
+ assert_equal 'heian', alpha.first.fields['jidai']
257
+ end
238
258
  end
239
259
 
@@ -38,22 +38,36 @@ class FtBlockParticipantTest < Test::Unit::TestCase
38
38
  assert_trace pdef, "a\nb:f0:f0val\nc:f0:f0val:v0val"
39
39
  end
40
40
 
41
+ TEST_BLOCK = Ruote.process_definition do
42
+ sequence do
43
+ alpha
44
+ echo '${f:__result__}'
45
+ end
46
+ end
47
+
41
48
  def test_block_result
42
49
 
43
- pdef = Ruote.process_definition do
44
- sequence do
45
- alpha
46
- echo '${f:__result__}'
47
- end
50
+ @engine.register_participant :alpha do |workitem|
51
+ 'seen'
48
52
  end
49
53
 
54
+ #noisy
55
+
56
+ assert_trace TEST_BLOCK, 'seen'
57
+ end
58
+
59
+ def test_non_jsonfiable_result
60
+
61
+ t = Time.now
62
+
50
63
  @engine.register_participant :alpha do |workitem|
51
- 'seen'
64
+ t
52
65
  end
53
66
 
54
67
  #noisy
55
68
 
56
- assert_trace pdef, 'seen'
69
+ #assert_trace TEST_BLOCK, Ruote.time_to_utc_s(t)
70
+ assert_trace TEST_BLOCK, defined?(DataMapper) ? '' : t.to_s
57
71
  end
58
72
  end
59
73
 
@@ -13,7 +13,7 @@ def l (t)
13
13
 
14
14
  puts
15
15
  puts "=== #{t} :"
16
- puts `ruby#{_v} #{t}`
16
+ puts `ruby#{_v} #{t} #{ARGV.join(' ')}`
17
17
 
18
18
  exit $?.exitstatus if $?.exitstatus != 0
19
19
  else
@@ -61,6 +61,7 @@ class UtStorage < Test::Unit::TestCase
61
61
  h = @s.get('dogfood', 'nada')
62
62
 
63
63
  assert_not_nil h['_rev']
64
+ assert_not_nil h['put_at']
64
65
  end
65
66
 
66
67
  def test_put_fail
@@ -80,6 +81,24 @@ class UtStorage < Test::Unit::TestCase
80
81
  assert_not_nil doc['_rev']
81
82
  end
82
83
 
84
+ def test_put_put_and_put
85
+
86
+ doc = { '_id' => 'whiskas', 'type' => 'dogfood', 'message' => 'miam' }
87
+
88
+ r = @s.put(doc)
89
+ doc = @s.get('dogfood', 'whiskas')
90
+
91
+ r = @s.put(doc)
92
+ assert_nil r
93
+
94
+ doc = @s.get('dogfood', 'whiskas')
95
+
96
+ assert_not_nil doc['put_at']
97
+
98
+ r = @s.put(doc)
99
+ assert_nil r
100
+ end
101
+
83
102
  def test_delete_fail
84
103
 
85
104
  assert_raise(ArgumentError) do
@@ -150,5 +169,16 @@ class UtStorage < Test::Unit::TestCase
150
169
 
151
170
  assert_equal %w[ estereo nada ouinouin toto ], @s.ids('dogfood')
152
171
  end
172
+
173
+ def test_get_many
174
+
175
+ 30.times do |i|
176
+ @s.put('_id' => "xx!#{i}", 'type' => 'dogfood', 'msg' => "whatever #{i}")
177
+ end
178
+
179
+ assert_equal 31, @s.get_many('dogfood').size
180
+ assert_equal 10, @s.get_many('dogfood', nil, :limit => 10).size
181
+ assert_equal 1, @s.get_many('dogfood', /!7$/).size
182
+ end
153
183
  end
154
184
 
@@ -1,13 +1,17 @@
1
1
 
2
2
  puts "\n\n\n== in memory"
3
3
  puts
4
- puts `ruby test/unit/ut_17_storage.rb`
4
+ puts `ruby test/unit/storage.rb`
5
5
 
6
6
  puts "\n\n\n== fs_storage"
7
7
  puts
8
- puts `ruby test/unit/ut_17_storage.rb --fs`
8
+ puts `ruby test/unit/storage.rb --fs`
9
9
 
10
10
  puts "\n\n\n== couch_storage"
11
11
  puts
12
- puts `ruby -r patron -r yajl test/unit/ut_17_storage.rb --couch`
12
+ puts `ruby -r patron -r yajl test/unit/storage.rb --couch`
13
+
14
+ puts "\n\n\n== dm_storage"
15
+ puts
16
+ puts `ruby -r yajl test/unit/storage.rb --dm`
13
17
 
@@ -5,6 +5,8 @@
5
5
  # since Mon Oct 9 22:19:44 JST 2006
6
6
  #
7
7
 
8
+ load File.join(File.dirname(__FILE__), 'storage.rb')
9
+
8
10
  Dir.glob(File.join(File.dirname(__FILE__), 'ut_*.rb')).sort.each { |t| load(t) }
9
11
  Dir.glob(File.join(File.dirname(__FILE__), 'hut_*.rb')).sort.each { |t| load(t) }
10
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruote
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.5
4
+ version: 2.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-01-28 00:00:00 +09:00
13
+ date: 2010-02-08 00:00:00 +09:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -141,6 +141,7 @@ files:
141
141
  - README.rdoc
142
142
  - Rakefile
143
143
  - TODO.txt
144
+ - examples/barley.rb
144
145
  - examples/flickr_report.rb
145
146
  - examples/ruote_quickstart.rb
146
147
  - examples/web_first_page.rb
@@ -228,6 +229,7 @@ files:
228
229
  - lib/ruote/util/time.rb
229
230
  - lib/ruote/util/tree.rb
230
231
  - lib/ruote/util/treechecker.rb
232
+ - lib/ruote/version.rb
231
233
  - lib/ruote/worker.rb
232
234
  - lib/ruote/workitem.rb
233
235
  - phil.txt
@@ -329,6 +331,7 @@ files:
329
331
  - test/pdef.xml
330
332
  - test/test.rb
331
333
  - test/test_helper.rb
334
+ - test/unit/storage.rb
332
335
  - test/unit/storages.rb
333
336
  - test/unit/test.rb
334
337
  - test/unit/ut_0_ruby_parser.rb
@@ -337,7 +340,6 @@ files:
337
340
  - test/unit/ut_14_is_uri.rb
338
341
  - test/unit/ut_15_util.rb
339
342
  - test/unit/ut_16_parser.rb
340
- - test/unit/ut_17_storage.rb
341
343
  - test/unit/ut_18_engine.rb
342
344
  - test/unit/ut_1_fei.rb
343
345
  - test/unit/ut_2_wfidgen.rb