ruote 2.1.5 → 2.1.6

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.
@@ -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