ruote 2.1.6 → 2.1.7
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.
- 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
|
|