ruote 2.1.6 → 2.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +14 -0
- data/CREDITS.txt +4 -3
- data/Rakefile +4 -3
- data/TODO.txt +9 -6
- data/lib/ruote/context.rb +29 -13
- data/lib/ruote/engine.rb +14 -0
- data/lib/ruote/exp/flowexpression.rb +7 -0
- data/lib/ruote/fei.rb +15 -7
- data/lib/ruote/id/wfid_generator.rb +3 -0
- data/lib/ruote/log/fs_history.rb +3 -3
- data/lib/ruote/log/storage_history.rb +13 -7
- data/lib/ruote/log/test_logger.rb +6 -0
- data/lib/ruote/parser.rb +12 -3
- data/lib/ruote/parser/ruby_dsl.rb +53 -0
- data/lib/ruote/part/participant_list.rb +10 -0
- data/lib/ruote/part/storage_participant.rb +74 -3
- data/lib/ruote/storage/base.rb +9 -6
- data/lib/ruote/storage/hash_storage.rb +7 -2
- data/lib/ruote/util/misc.rb +4 -0
- data/lib/ruote/version.rb +1 -1
- data/lib/ruote/workitem.rb +35 -48
- data/ruote.gemspec +12 -9
- data/test/README.rdoc +3 -3
- data/test/functional/eft_18_concurrent_iterator.rb +8 -11
- data/test/functional/eft_24_add_branches.rb +18 -6
- data/test/functional/eft_27_inc.rb +2 -1
- data/test/functional/eft_6_concurrence.rb +9 -4
- data/test/functional/ft_20_storage_participant.rb +63 -29
- data/test/functional/ft_24_block_participants.rb +6 -0
- data/test/functional/ft_30_smtp_participant.rb +2 -2
- data/test/functional/ft_32_fs_history.rb +15 -10
- data/test/functional/ft_36_storage_history.rb +3 -3
- data/test/functional/ft_3_participant_registration.rb +8 -0
- data/test/functional/storage_helper.rb +2 -0
- data/test/functional/test.rb +9 -2
- data/test/unit/storage.rb +2 -1
- data/test/unit/test.rb +18 -2
- data/test/unit/ut_0_ruby_parser.rb +7 -0
- data/test/unit/ut_16_parser.rb +1 -1
- data/test/unit/ut_1_fei.rb +60 -2
- data/test/unit/ut_3_wait_logger.rb +2 -0
- data/test/unit/ut_7_workitem.rb +29 -2
- metadata +15 -4
@@ -27,16 +27,69 @@ module Ruote
|
|
27
27
|
|
28
28
|
# Not really a parser, more an AST builder.
|
29
29
|
#
|
30
|
+
# pdef = Ruote.define :name => 'take_out_garbage' do
|
31
|
+
# sequence do
|
32
|
+
# take_out_regular_garbage
|
33
|
+
# take_out_glass
|
34
|
+
# take_out_paper
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# engine.launch(pdef)
|
39
|
+
#
|
30
40
|
def self.define (*attributes, &block)
|
31
41
|
|
32
42
|
RubyDsl.create_branch('define', attributes, &block)
|
33
43
|
end
|
34
44
|
|
45
|
+
# Same as Ruote.define()
|
46
|
+
#
|
47
|
+
# pdef = Ruote.process_definition :name => 'take_out_garbage' do
|
48
|
+
# sequence do
|
49
|
+
# take_out_regular_garbage
|
50
|
+
# take_out_paper
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# engine.launch(pdef)
|
55
|
+
#
|
35
56
|
def self.process_definition (*attributes, &block)
|
36
57
|
|
37
58
|
define(*attributes, &block)
|
38
59
|
end
|
39
60
|
|
61
|
+
# Similar in purpose to Ruote.define and Ruote.process_definition but
|
62
|
+
# instead of returning a [process] definition, returns the tree.
|
63
|
+
#
|
64
|
+
# tree = Ruote.process_definition :name => 'take_out_garbage' do
|
65
|
+
# sequence do
|
66
|
+
# take_out_regular_garbage
|
67
|
+
# take_out_paper
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# p tree
|
72
|
+
# # => [ 'sequence', {}, [ [ 'take_out_regular_garbage', {}, [] ], [ 'take_out_paper', {}, [] ] ] ],
|
73
|
+
#
|
74
|
+
# This is useful when modifying a process instance via methods like re_apply :
|
75
|
+
#
|
76
|
+
# engine.re_apply(
|
77
|
+
# fei,
|
78
|
+
# :tree => Ruote.to_tree {
|
79
|
+
# sequence do
|
80
|
+
# participant 'alfred'
|
81
|
+
# participant 'bob'
|
82
|
+
# end
|
83
|
+
# })
|
84
|
+
# #
|
85
|
+
# # cancels the segment of process at fei and replaces it with
|
86
|
+
# # a simple alfred-bob sequence.
|
87
|
+
#
|
88
|
+
def self.to_tree (&block)
|
89
|
+
|
90
|
+
RubyDsl.create_branch('x', {}, &block).last.first
|
91
|
+
end
|
92
|
+
|
40
93
|
# :nodoc:
|
41
94
|
#
|
42
95
|
module RubyDsl
|
@@ -93,6 +93,9 @@ module Ruote
|
|
93
93
|
|
94
94
|
else
|
95
95
|
|
96
|
+
return Ruote::StorageParticipant.new(@context) \
|
97
|
+
if entry.last.first == 'Ruote::StorageParticipant'
|
98
|
+
|
96
99
|
nil
|
97
100
|
end
|
98
101
|
end
|
@@ -177,6 +180,13 @@ module Ruote
|
|
177
180
|
pa
|
178
181
|
end
|
179
182
|
|
183
|
+
# Return a list of names (regex) for the registered participants
|
184
|
+
#
|
185
|
+
def names
|
186
|
+
|
187
|
+
get_list['list'].map { |re, pa| re }
|
188
|
+
end
|
189
|
+
|
180
190
|
# Shuts down the 'instantiated participants' (engine worker participants)
|
181
191
|
# if they respond to #shutdown.
|
182
192
|
#
|
@@ -146,16 +146,17 @@ module Ruote
|
|
146
146
|
|
147
147
|
# Return all workitems for the specified wfid
|
148
148
|
#
|
149
|
-
def by_wfid(
|
149
|
+
def by_wfid (wfid)
|
150
150
|
|
151
|
-
@context.storage.get_many('workitems', /!#{wfid}$/).map { |hwi|
|
151
|
+
@context.storage.get_many('workitems', /!#{wfid}$/).map { |hwi|
|
152
|
+
Ruote::Workitem.new(hwi)
|
153
|
+
}
|
152
154
|
end
|
153
155
|
|
154
156
|
# Returns all workitems for the specified participant name
|
155
157
|
#
|
156
158
|
def by_participant (participant_name)
|
157
159
|
|
158
|
-
|
159
160
|
hwis = if @context.storage.respond_to?(:by_participant)
|
160
161
|
|
161
162
|
@context.storage.by_participant('workitems', participant_name)
|
@@ -194,6 +195,56 @@ module Ruote
|
|
194
195
|
hwis.collect { |hwi| Ruote::Workitem.new(hwi) }
|
195
196
|
end
|
196
197
|
|
198
|
+
# Queries the store participant for workitems.
|
199
|
+
#
|
200
|
+
# Some examples :
|
201
|
+
#
|
202
|
+
# part.query(:wfid => @wfid).size
|
203
|
+
# part.query('place' => 'nara').size
|
204
|
+
# part.query('place' => 'heiankyou').size
|
205
|
+
# part.query(:wfid => @wfid, :place => 'heiankyou').size
|
206
|
+
#
|
207
|
+
# There are two 'reserved' criterion : 'wfid' and 'participant'
|
208
|
+
# ('participant_name' as well). The rest of the criteria are considered
|
209
|
+
# constraints for fields.
|
210
|
+
#
|
211
|
+
# 'offset' and 'limit' are reserved as well. They should prove useful
|
212
|
+
# for pagination.
|
213
|
+
#
|
214
|
+
# Note : the criteria is AND only, you'll have to do ORs (aggregation)
|
215
|
+
# by yourself.
|
216
|
+
#
|
217
|
+
def query (criteria)
|
218
|
+
|
219
|
+
cr = criteria.inject({}) { |h, (k, v)| h[k.to_s] = v; h }
|
220
|
+
|
221
|
+
return @context.storage.query_workitems(cr) \
|
222
|
+
if @context.storage.respond_to?(:query_workitems)
|
223
|
+
|
224
|
+
offset = cr.delete('offset')
|
225
|
+
limit = cr.delete('limit')
|
226
|
+
|
227
|
+
wfid = cr.delete('wfid')
|
228
|
+
pname = cr.delete('participant_name') || cr.delete('participant')
|
229
|
+
|
230
|
+
hwis = if wfid
|
231
|
+
@context.storage.get_many('workitems', /!#{wfid}$/)
|
232
|
+
else
|
233
|
+
fetch_all
|
234
|
+
end
|
235
|
+
|
236
|
+
hwis = hwis.select { |hwi|
|
237
|
+
Ruote::StorageParticipant.matches?(hwi, pname, cr)
|
238
|
+
}.collect { |hwi|
|
239
|
+
Ruote::Workitem.new(hwi)
|
240
|
+
}
|
241
|
+
|
242
|
+
offset = offset || 0
|
243
|
+
limit = limit || hwis.length
|
244
|
+
|
245
|
+
hwis[offset, limit]
|
246
|
+
end
|
247
|
+
|
197
248
|
# Cleans this participant out completely
|
198
249
|
#
|
199
250
|
def purge!
|
@@ -201,8 +252,26 @@ module Ruote
|
|
201
252
|
fetch_all.each { |hwi| @context.storage.delete( hwi ) }
|
202
253
|
end
|
203
254
|
|
255
|
+
# Used by #query when filtering workitems.
|
256
|
+
#
|
257
|
+
def self.matches? (hwi, pname, criteria)
|
258
|
+
|
259
|
+
return false if pname && hwi['participant_name'] != pname
|
260
|
+
|
261
|
+
fields = hwi['fields']
|
262
|
+
|
263
|
+
criteria.each do |fname, fvalue|
|
264
|
+
return false if fields[fname] != fvalue
|
265
|
+
end
|
266
|
+
|
267
|
+
true
|
268
|
+
end
|
269
|
+
|
204
270
|
protected
|
205
271
|
|
272
|
+
# Fetches all the workitems. If there is a @store_name, will only fetch
|
273
|
+
# the workitems in that store.
|
274
|
+
#
|
206
275
|
def fetch_all
|
207
276
|
|
208
277
|
key = @store_name ? /^wi!#{@store_name}::/ : nil
|
@@ -210,6 +279,8 @@ module Ruote
|
|
210
279
|
@context.storage.get_many('workitems', key)
|
211
280
|
end
|
212
281
|
|
282
|
+
# Computes the id for the document representing the document in the storage.
|
283
|
+
#
|
213
284
|
def to_id (fei)
|
214
285
|
|
215
286
|
a = [ Ruote.to_storage_id(fei) ]
|
data/lib/ruote/storage/base.rb
CHANGED
@@ -55,13 +55,16 @@ module Ruote
|
|
55
55
|
|
56
56
|
# merge! is way faster than merge (no object creation probably)
|
57
57
|
|
58
|
-
|
59
|
-
t = "#{t.to_i}.#{"%06d" % t.usec}"
|
58
|
+
@counter ||= 0
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
t = Time.now.utc
|
61
|
+
ts = "#{t.strftime('%Y-%m-%d')}!#{t.to_i}.#{'%06d' % t.usec}"
|
62
|
+
_id = "#{$$}!#{Thread.current.object_id}!#{ts}!#{'%03d' % @counter}"
|
63
|
+
|
64
|
+
@counter = (@counter + 1) % 1000
|
65
|
+
# some platforms (windows) have shallow usecs, so adding that counter...
|
66
|
+
|
67
|
+
msg = options.merge!('type' => 'msgs', '_id' => _id, 'action' => action)
|
65
68
|
|
66
69
|
msg.delete('_rev')
|
67
70
|
# in case of message replay
|
@@ -30,6 +30,8 @@ require 'monitor'
|
|
30
30
|
|
31
31
|
module Ruote
|
32
32
|
|
33
|
+
# An in-memory storage.
|
34
|
+
#
|
33
35
|
class HashStorage
|
34
36
|
|
35
37
|
include StorageBase
|
@@ -40,14 +42,17 @@ module Ruote
|
|
40
42
|
def initialize (options={})
|
41
43
|
|
42
44
|
super()
|
43
|
-
|
44
|
-
@options = options
|
45
|
+
# since were including MonitorMixin, this super() is necessary
|
45
46
|
|
46
47
|
purge!
|
48
|
+
|
49
|
+
put(options.merge('type' => 'configurations', '_id' => 'engine'))
|
47
50
|
end
|
48
51
|
|
49
52
|
def put (doc, opts={})
|
50
53
|
|
54
|
+
i = @h.size
|
55
|
+
|
51
56
|
synchronize do
|
52
57
|
|
53
58
|
pre = get(doc['type'], doc['_id'])
|
data/lib/ruote/util/misc.rb
CHANGED
data/lib/ruote/version.rb
CHANGED
data/lib/ruote/workitem.rb
CHANGED
@@ -29,6 +29,12 @@ require 'ruote/util/hashdot'
|
|
29
29
|
|
30
30
|
module Ruote
|
31
31
|
|
32
|
+
#
|
33
|
+
# A workitem can be thought of an "execution token", but with a payload
|
34
|
+
# (fields).
|
35
|
+
#
|
36
|
+
# The payload/fields MUST be JSONifiable.
|
37
|
+
#
|
32
38
|
class Workitem
|
33
39
|
|
34
40
|
attr_reader :h
|
@@ -44,27 +50,41 @@ module Ruote
|
|
44
50
|
@h
|
45
51
|
end
|
46
52
|
|
53
|
+
# Returns a Ruote::FlowExpressionId instance.
|
54
|
+
#
|
47
55
|
def fei
|
48
56
|
|
49
57
|
FlowExpressionId.new(h.fei)
|
50
58
|
end
|
51
59
|
|
60
|
+
# Returns a complete copy of this workitem.
|
61
|
+
#
|
52
62
|
def dup
|
53
63
|
|
54
|
-
|
64
|
+
Workitem.new(Rufus::Json.dup(@h))
|
55
65
|
end
|
56
66
|
|
67
|
+
# The participant for which this item is destined. Will be nil when
|
68
|
+
# the workitem is transiting inside of its process instance (as opposed
|
69
|
+
# to when it's being delivered outside of the engine).
|
70
|
+
#
|
57
71
|
def participant_name
|
58
72
|
|
59
73
|
@h['participant_name']
|
60
74
|
end
|
61
75
|
|
76
|
+
# Returns the payload, ie the fields hash.
|
77
|
+
#
|
62
78
|
def fields
|
63
79
|
|
64
80
|
@h['fields']
|
65
81
|
end
|
66
82
|
|
67
|
-
|
83
|
+
# Sets all the fields in one sweep.
|
84
|
+
#
|
85
|
+
# Remember : the fields must be a JSONifiable hash.
|
86
|
+
#
|
87
|
+
def fields= (fields)
|
68
88
|
|
69
89
|
@h['fields'] = fields
|
70
90
|
end
|
@@ -87,25 +107,22 @@ module Ruote
|
|
87
107
|
|
88
108
|
fields['__result__'] = r
|
89
109
|
end
|
90
|
-
end
|
91
110
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
class BakWorkitem
|
111
|
+
# Warning : equality is based on fei and not on payload !
|
112
|
+
#
|
113
|
+
def == (other)
|
96
114
|
|
97
|
-
|
98
|
-
|
99
|
-
|
115
|
+
return false if other.class != self.class
|
116
|
+
self.h['fei'] == other.h['fei']
|
117
|
+
end
|
100
118
|
|
101
|
-
alias
|
102
|
-
alias :attributes :fields
|
103
|
-
alias :attributes= :fields=
|
119
|
+
alias eql? ==
|
104
120
|
|
105
|
-
|
121
|
+
# Warning : hash is fei's hash.
|
122
|
+
#
|
123
|
+
def hash
|
106
124
|
|
107
|
-
|
108
|
-
@fields = fields
|
125
|
+
self.h['fei'].hash
|
109
126
|
end
|
110
127
|
|
111
128
|
# For a simple key
|
@@ -126,7 +143,7 @@ module Ruote
|
|
126
143
|
#
|
127
144
|
def lookup (key, container_lookup=false)
|
128
145
|
|
129
|
-
Ruote.lookup(@fields, key, container_lookup)
|
146
|
+
Ruote.lookup(@h['fields'], key, container_lookup)
|
130
147
|
end
|
131
148
|
|
132
149
|
# 'lf' for 'lookup field'
|
@@ -144,37 +161,7 @@ module Ruote
|
|
144
161
|
#
|
145
162
|
def set_field (key, value)
|
146
163
|
|
147
|
-
Ruote.set(@fields, key, value)
|
148
|
-
end
|
149
|
-
|
150
|
-
# Returns a deep copy of this workitem instance.
|
151
|
-
#
|
152
|
-
def dup
|
153
|
-
|
154
|
-
Ruote.fulldup(self)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Turns a workitem into a Ruby Hash (useful for JSON serializations)
|
158
|
-
#
|
159
|
-
def to_h
|
160
|
-
|
161
|
-
h = {}
|
162
|
-
h['fei'] = @fei.to_h
|
163
|
-
h['participant_name'] = @participant_name
|
164
|
-
h['fields'] = @fields
|
165
|
-
|
166
|
-
h
|
167
|
-
end
|
168
|
-
|
169
|
-
# Turns back a Ruby Hash into a workitem (well, attempts to)
|
170
|
-
#
|
171
|
-
def self.from_h (h)
|
172
|
-
|
173
|
-
wi = Workitem.new(h['fields'])
|
174
|
-
wi.fei = FlowExpressionId.from_h(h['fei'])
|
175
|
-
wi.participant_name = h['participant_name']
|
176
|
-
|
177
|
-
wi
|
164
|
+
Ruote.set(@h['fields'], key, value)
|
178
165
|
end
|
179
166
|
end
|
180
167
|
end
|
data/ruote.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ruote}
|
8
|
-
s.version = "2.1.
|
8
|
+
s.version = "2.1.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["John Mettraux", "Kenneth Kalmer"]
|
12
|
-
s.date = %q{2010-02-
|
11
|
+
s.authors = ["John Mettraux", "Kenneth Kalmer", "Torsten Schoenebaum"]
|
12
|
+
s.date = %q{2010-02-15}
|
13
13
|
s.description = %q{
|
14
14
|
ruote is an open source ruby workflow engine.
|
15
15
|
}
|
@@ -251,8 +251,8 @@ ruote is an open source ruby workflow engine.
|
|
251
251
|
s.specification_version = 3
|
252
252
|
|
253
253
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
254
|
-
s.add_runtime_dependency(%q<rufus-json>, [">= 0"])
|
255
|
-
s.add_runtime_dependency(%q<rufus-cloche>, [">= 0.1.
|
254
|
+
s.add_runtime_dependency(%q<rufus-json>, [">= 0.2.0"])
|
255
|
+
s.add_runtime_dependency(%q<rufus-cloche>, [">= 0.1.14"])
|
256
256
|
s.add_runtime_dependency(%q<rufus-dollar>, [">= 0"])
|
257
257
|
s.add_runtime_dependency(%q<rufus-lru>, [">= 0"])
|
258
258
|
s.add_runtime_dependency(%q<rufus-mnemo>, [">= 1.1.0"])
|
@@ -262,9 +262,10 @@ ruote is an open source ruby workflow engine.
|
|
262
262
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
263
263
|
s.add_development_dependency(%q<builder>, [">= 0"])
|
264
264
|
s.add_development_dependency(%q<mailtrap>, [">= 0"])
|
265
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
265
266
|
else
|
266
|
-
s.add_dependency(%q<rufus-json>, [">= 0"])
|
267
|
-
s.add_dependency(%q<rufus-cloche>, [">= 0.1.
|
267
|
+
s.add_dependency(%q<rufus-json>, [">= 0.2.0"])
|
268
|
+
s.add_dependency(%q<rufus-cloche>, [">= 0.1.14"])
|
268
269
|
s.add_dependency(%q<rufus-dollar>, [">= 0"])
|
269
270
|
s.add_dependency(%q<rufus-lru>, [">= 0"])
|
270
271
|
s.add_dependency(%q<rufus-mnemo>, [">= 1.1.0"])
|
@@ -274,10 +275,11 @@ ruote is an open source ruby workflow engine.
|
|
274
275
|
s.add_dependency(%q<yard>, [">= 0"])
|
275
276
|
s.add_dependency(%q<builder>, [">= 0"])
|
276
277
|
s.add_dependency(%q<mailtrap>, [">= 0"])
|
278
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
277
279
|
end
|
278
280
|
else
|
279
|
-
s.add_dependency(%q<rufus-json>, [">= 0"])
|
280
|
-
s.add_dependency(%q<rufus-cloche>, [">= 0.1.
|
281
|
+
s.add_dependency(%q<rufus-json>, [">= 0.2.0"])
|
282
|
+
s.add_dependency(%q<rufus-cloche>, [">= 0.1.14"])
|
281
283
|
s.add_dependency(%q<rufus-dollar>, [">= 0"])
|
282
284
|
s.add_dependency(%q<rufus-lru>, [">= 0"])
|
283
285
|
s.add_dependency(%q<rufus-mnemo>, [">= 1.1.0"])
|
@@ -287,6 +289,7 @@ ruote is an open source ruby workflow engine.
|
|
287
289
|
s.add_dependency(%q<yard>, [">= 0"])
|
288
290
|
s.add_dependency(%q<builder>, [">= 0"])
|
289
291
|
s.add_dependency(%q<mailtrap>, [">= 0"])
|
292
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
290
293
|
end
|
291
294
|
end
|
292
295
|
|