ruote 2.1.10 → 2.1.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +51 -1
- data/CREDITS.txt +9 -0
- data/README.rdoc +13 -0
- data/Rakefile +50 -21
- data/TODO.txt +42 -4
- data/examples/pong.rb +37 -0
- data/lib/ruote/context.rb +19 -9
- data/lib/ruote/engine/process_error.rb +10 -0
- data/lib/ruote/engine/process_status.rb +140 -41
- data/lib/ruote/engine.rb +394 -27
- data/lib/ruote/exp/command.rb +2 -0
- data/lib/ruote/exp/fe_concurrence.rb +8 -0
- data/lib/ruote/exp/fe_concurrent_iterator.rb +3 -0
- data/lib/ruote/exp/fe_cursor.rb +48 -4
- data/lib/ruote/exp/fe_iterator.rb +40 -0
- data/lib/ruote/exp/fe_listen.rb +3 -3
- data/lib/ruote/exp/fe_participant.rb +30 -12
- data/lib/ruote/exp/fe_ref.rb +126 -0
- data/lib/ruote/exp/fe_subprocess.rb +20 -1
- data/lib/ruote/exp/fe_wait.rb +4 -1
- data/lib/ruote/exp/fe_when.rb +7 -10
- data/lib/ruote/exp/flowexpression.rb +23 -12
- data/lib/ruote/exp/ro_attributes.rb +5 -8
- data/lib/ruote/exp/ro_variables.rb +4 -2
- data/lib/ruote/fei.rb +2 -0
- data/lib/ruote/id/wfid_generator.rb +1 -1
- data/lib/ruote/log/pretty.rb +137 -0
- data/lib/ruote/log/storage_history.rb +1 -1
- data/lib/ruote/log/test_logger.rb +51 -126
- data/lib/ruote/log/wait_logger.rb +8 -13
- data/lib/ruote/parser/ruby_dsl.rb +4 -4
- data/lib/ruote/parser.rb +2 -2
- data/lib/ruote/part/block_participant.rb +1 -1
- data/lib/ruote/part/engine_participant.rb +1 -1
- data/lib/ruote/part/storage_participant.rb +27 -28
- data/lib/ruote/part/template.rb +8 -3
- data/lib/ruote/receiver/base.rb +24 -6
- data/lib/ruote/storage/base.rb +76 -11
- data/lib/ruote/storage/fs_storage.rb +10 -0
- data/lib/ruote/storage/hash_storage.rb +19 -8
- data/lib/ruote/{part → svc}/dispatch_pool.rb +3 -2
- data/lib/ruote/svc/dollar_sub.rb +265 -0
- data/lib/ruote/{error_handler.rb → svc/error_handler.rb} +6 -1
- data/lib/ruote/{exp → svc}/expression_map.rb +31 -37
- data/lib/ruote/{part → svc}/participant_list.rb +165 -25
- data/lib/ruote/{evt → svc}/tracker.rb +0 -0
- data/lib/ruote/{util → svc}/treechecker.rb +0 -0
- data/lib/ruote/util/look.rb +4 -1
- data/lib/ruote/util/ometa.rb +21 -5
- data/lib/ruote/{subprocess.rb → util/subprocess.rb} +0 -0
- data/lib/ruote/version.rb +1 -1
- data/lib/ruote/worker.rb +29 -69
- data/lib/ruote/workitem.rb +28 -1
- data/ruote.gemspec +26 -22
- data/test/functional/base.rb +3 -0
- data/test/functional/concurrent_base.rb +1 -0
- data/test/functional/crunner.sh +1 -1
- data/test/functional/ct_0_concurrence.rb +6 -0
- data/test/functional/ct_1_iterator.rb +3 -0
- data/test/functional/ct_2_cancel.rb +5 -0
- data/test/functional/eft_13_iterator.rb +39 -4
- data/test/functional/eft_14_cursor.rb +39 -0
- data/test/functional/eft_30_ref.rb +140 -0
- data/test/functional/eft_3_participant.rb +25 -23
- data/test/functional/ft_10_dollar.rb +17 -1
- data/test/functional/ft_14_re_apply.rb +76 -0
- data/test/functional/ft_1_process_status.rb +170 -29
- data/test/functional/ft_20_storage_participant.rb +14 -0
- data/test/functional/ft_24_block_participants.rb +1 -1
- data/test/functional/ft_26_participant_timeout.rb +93 -0
- data/test/functional/ft_2_errors.rb +24 -17
- data/test/functional/ft_30_smtp_participant.rb +7 -2
- data/test/functional/ft_38_participant_more.rb +15 -0
- data/test/functional/ft_39_wait_for.rb +34 -1
- data/test/functional/ft_3_participant_registration.rb +270 -2
- data/test/functional/ft_40_wait_logger.rb +61 -0
- data/test/functional/ft_42_storage_copy.rb +4 -0
- data/test/functional/{ft_40_participant_on_reply.rb → ft_43_participant_on_reply.rb} +17 -0
- data/test/functional/ft_44_var_participant.rb +35 -0
- data/test/functional/ft_45_participant_accept.rb +64 -0
- data/test/functional/ft_46_launch_single.rb +49 -0
- data/test/functional/ft_5_on_error.rb +39 -1
- data/test/functional/storage_helper.rb +7 -1
- data/test/test_helper.rb +1 -1
- data/test/unit/storage.rb +105 -32
- data/test/unit/ut_0_ruby_parser.rb +31 -1
- data/test/unit/ut_16_parser.rb +20 -0
- data/test/unit/ut_19_part_template.rb +11 -1
- data/test/unit/ut_20_composite_storage.rb +1 -1
- data/test/unit/ut_4_expmap.rb +1 -1
- data/test/unit/ut_6_condition.rb +2 -2
- metadata +112 -74
- data/lib/ruote/exp/raw.rb +0 -44
- data/lib/ruote/util/dollar.rb +0 -193
data/lib/ruote/storage/base.rb
CHANGED
@@ -95,7 +95,7 @@ module Ruote
|
|
95
95
|
|
96
96
|
def empty? (type)
|
97
97
|
|
98
|
-
(get_many(type) ==
|
98
|
+
(get_many(type, nil, :count => true) == 0)
|
99
99
|
end
|
100
100
|
|
101
101
|
#--
|
@@ -104,13 +104,34 @@ module Ruote
|
|
104
104
|
|
105
105
|
def find_root_expression (wfid)
|
106
106
|
|
107
|
-
get_many('expressions',
|
108
|
-
|
107
|
+
get_many('expressions', wfid).sort_by { |fexp|
|
108
|
+
fexp['fei']['expid']
|
109
109
|
}.select { |e|
|
110
110
|
e['parent_id'].nil?
|
111
111
|
}.first
|
112
112
|
end
|
113
113
|
|
114
|
+
# Given all the expressions stored here, returns a sorted list of unique
|
115
|
+
# wfids (this is used in Engine#processes(opts).
|
116
|
+
#
|
117
|
+
# Understands the :skip, :limit and :descending options.
|
118
|
+
#
|
119
|
+
# This is a base implementation, different storage implementations may
|
120
|
+
# come up with different implementations (think CouchDB, which could
|
121
|
+
# provide a view for it).
|
122
|
+
#
|
123
|
+
def expression_wfids (opts)
|
124
|
+
|
125
|
+
wfids = ids('expressions').collect { |fei| fei.split('!').last }.uniq.sort
|
126
|
+
|
127
|
+
wfids = wfids.reverse if opts[:descending]
|
128
|
+
|
129
|
+
skip = opts[:skip] || 0
|
130
|
+
limit = opts[:limit] || wfids.length
|
131
|
+
|
132
|
+
wfids[skip, limit]
|
133
|
+
end
|
134
|
+
|
114
135
|
#--
|
115
136
|
# trackers
|
116
137
|
#++
|
@@ -145,14 +166,20 @@ module Ruote
|
|
145
166
|
#end
|
146
167
|
end
|
147
168
|
|
169
|
+
# Places schedule in storage. Returns the id of the 'schedule' document.
|
170
|
+
# If the schedule got triggered immediately, nil is returned.
|
171
|
+
#
|
148
172
|
def put_schedule (flavour, owner_fei, s, msg)
|
149
173
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
174
|
+
doc = prepare_schedule_doc(flavour, owner_fei, s, msg)
|
175
|
+
|
176
|
+
return nil unless doc
|
154
177
|
|
155
|
-
|
178
|
+
r = put(doc)
|
179
|
+
|
180
|
+
raise "put_schedule failed" if r != nil
|
181
|
+
|
182
|
+
doc['_id']
|
156
183
|
end
|
157
184
|
|
158
185
|
def delete_schedule (schedule_id)
|
@@ -194,7 +221,9 @@ module Ruote
|
|
194
221
|
configurations errors expressions msgs schedules variables workitems
|
195
222
|
].each do |type|
|
196
223
|
|
197
|
-
|
224
|
+
ids(type).each do |id|
|
225
|
+
|
226
|
+
item = get(type, id)
|
198
227
|
|
199
228
|
item.delete('_rev')
|
200
229
|
target.put(item)
|
@@ -207,6 +236,18 @@ module Ruote
|
|
207
236
|
counter
|
208
237
|
end
|
209
238
|
|
239
|
+
# Used when doing integration tests, removes all
|
240
|
+
# msgs, schedules, errors, expressions and workitems.
|
241
|
+
#
|
242
|
+
# NOTE that it doesn't remove engine variables (danger)
|
243
|
+
#
|
244
|
+
def clear
|
245
|
+
|
246
|
+
%w[ msgs schedules errors expressions workitems ].each do |type|
|
247
|
+
purge_type!(type)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
210
251
|
protected
|
211
252
|
|
212
253
|
# Used by put_msg
|
@@ -272,11 +313,35 @@ module Ruote
|
|
272
313
|
|
273
314
|
# Returns all the ats whose due date arrived (now or earlier)
|
274
315
|
#
|
275
|
-
def filter_schedules (
|
316
|
+
def filter_schedules (schedules, now)
|
276
317
|
|
277
318
|
now = Ruote.time_to_utc_s(now)
|
278
319
|
|
279
|
-
|
320
|
+
schedules.select { |sch| sch['at'] <= now }
|
321
|
+
end
|
322
|
+
|
323
|
+
## Returns true if the doc wfid is included in the wfids passed.
|
324
|
+
##
|
325
|
+
#def wfid_match? (doc, wfids)
|
326
|
+
# wfids.find { |wfid| doc['_id'].index(wfid) } != nil
|
327
|
+
#end
|
328
|
+
|
329
|
+
# Used by #get_many. Returns true whenever one of the keys matches the
|
330
|
+
# doc['_id']. Works with strings (_id ends with key) or regexes (_id matches
|
331
|
+
# key).
|
332
|
+
#
|
333
|
+
# It's a class method meant to be used by the various storage
|
334
|
+
# implementations.
|
335
|
+
#
|
336
|
+
def self.key_match? (keys, doc)
|
337
|
+
|
338
|
+
_id = doc.is_a?(Hash) ? doc['_id'] : doc
|
339
|
+
|
340
|
+
if keys.first.is_a?(String)
|
341
|
+
keys.find { |key| _id[-key.length..-1] == key }
|
342
|
+
else # Regexp
|
343
|
+
keys.find { |key| key.match(_id) }
|
344
|
+
end
|
280
345
|
end
|
281
346
|
end
|
282
347
|
end
|
@@ -35,6 +35,8 @@ Rufus::Json.detect_backend
|
|
35
35
|
require 'rufus/cloche'
|
36
36
|
# gem install rufus-cloche
|
37
37
|
|
38
|
+
require 'ruote/storage/base'
|
39
|
+
|
38
40
|
|
39
41
|
module Ruote
|
40
42
|
|
@@ -84,6 +86,12 @@ module Ruote
|
|
84
86
|
|
85
87
|
def get_many (type, key=nil, opts={})
|
86
88
|
|
89
|
+
if key
|
90
|
+
key = Array(key)
|
91
|
+
key = key.map { |k| "!#{k}" } if key.first.is_a?(String)
|
92
|
+
end
|
93
|
+
# assuming /!#{wfid}$/...
|
94
|
+
|
87
95
|
@cloche.get_many(type, key, opts)
|
88
96
|
end
|
89
97
|
|
@@ -92,6 +100,8 @@ module Ruote
|
|
92
100
|
@cloche.ids(type)
|
93
101
|
end
|
94
102
|
|
103
|
+
# Purges the storage completely.
|
104
|
+
#
|
95
105
|
def purge!
|
96
106
|
|
97
107
|
FileUtils.rm_rf(@cloche.dir)
|
@@ -57,7 +57,6 @@ module Ruote
|
|
57
57
|
|
58
58
|
pre = get(doc['type'], doc['_id'])
|
59
59
|
|
60
|
-
#if pre && ( ! opts[:update_rev]) && pre['_rev'] != doc['_rev']
|
61
60
|
if pre && pre['_rev'] != doc['_rev']
|
62
61
|
return pre
|
63
62
|
end
|
@@ -122,15 +121,25 @@ module Ruote
|
|
122
121
|
|
123
122
|
synchronize do
|
124
123
|
|
125
|
-
|
126
|
-
|
124
|
+
keys = key ?
|
125
|
+
Array(key).map { |k| k.is_a?(String) ? "!#{k}" : k } : nil
|
126
|
+
|
127
|
+
docs = keys ?
|
128
|
+
@h[type].values.select { |doc|
|
129
|
+
Ruote::StorageBase.key_match?(keys, doc)
|
130
|
+
} :
|
127
131
|
@h[type].values
|
128
132
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
133
|
+
docs = docs.sort_by { |d| d['_id'] }
|
134
|
+
|
135
|
+
return docs.size if opts[:count]
|
136
|
+
|
137
|
+
docs = docs.reverse if opts[:descending]
|
138
|
+
|
139
|
+
skip = opts[:skip] || 0
|
140
|
+
limit = opts[:limit] || docs.size
|
141
|
+
|
142
|
+
docs[skip, limit]
|
134
143
|
end
|
135
144
|
end
|
136
145
|
|
@@ -141,6 +150,8 @@ module Ruote
|
|
141
150
|
@h[type].keys.sort
|
142
151
|
end
|
143
152
|
|
153
|
+
# Purges the storage completely.
|
154
|
+
#
|
144
155
|
def purge!
|
145
156
|
|
146
157
|
@h = %w[
|
@@ -57,7 +57,7 @@ module Ruote
|
|
57
57
|
|
58
58
|
flavour = msg['flavour']
|
59
59
|
|
60
|
-
participant = @context.plist.
|
60
|
+
participant = @context.plist.instantiate(msg['participant'])
|
61
61
|
|
62
62
|
begin
|
63
63
|
participant.cancel(Ruote::FlowExpressionId.new(msg['fei']), flavour)
|
@@ -73,7 +73,8 @@ module Ruote
|
|
73
73
|
|
74
74
|
def dispatch (msg)
|
75
75
|
|
76
|
-
participant = @context.plist.lookup(
|
76
|
+
participant = @context.plist.lookup(
|
77
|
+
msg['participant'] || msg['participant_name'], msg['workitem'])
|
77
78
|
|
78
79
|
if participant.respond_to?(:do_not_thread) && participant.do_not_thread
|
79
80
|
do_dispatch(participant, msg)
|
@@ -0,0 +1,265 @@
|
|
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
|
+
|
26
|
+
require 'rufus/dollar' # gem 'rufus-dollar'
|
27
|
+
require 'ruote/svc/treechecker'
|
28
|
+
require 'ruote/util/lookup'
|
29
|
+
|
30
|
+
|
31
|
+
module Ruote
|
32
|
+
|
33
|
+
#
|
34
|
+
# This service is in charge of extrapolating strings like
|
35
|
+
# "${f:nada} == ${f:y}".
|
36
|
+
#
|
37
|
+
# It relies on the rufus-dollar gem.
|
38
|
+
#
|
39
|
+
# It's OK to override this service with your own.
|
40
|
+
#
|
41
|
+
class DollarSubstitution
|
42
|
+
|
43
|
+
def initialize (context)
|
44
|
+
|
45
|
+
@context = context
|
46
|
+
end
|
47
|
+
|
48
|
+
# Performs 'dollar substitution' on a piece of text with as input
|
49
|
+
# a flow expression and a workitem (fields and variables).
|
50
|
+
#
|
51
|
+
# With help from Nick Petrella (2008/03/20)
|
52
|
+
#
|
53
|
+
def s (text, flow_expression, workitem)
|
54
|
+
|
55
|
+
if text.is_a?(String)
|
56
|
+
|
57
|
+
Rufus.dsub(text, dict_class.new(flow_expression, workitem))
|
58
|
+
|
59
|
+
elsif text.is_a?(Array)
|
60
|
+
|
61
|
+
text.collect { |e| s(e, flow_expression, workitem) }
|
62
|
+
|
63
|
+
elsif text.is_a?(Hash)
|
64
|
+
|
65
|
+
text.inject({}) { |h, (k, v)|
|
66
|
+
|
67
|
+
h[s(k, flow_expression, workitem)] = s(v, flow_expression, workitem)
|
68
|
+
h
|
69
|
+
}
|
70
|
+
|
71
|
+
else
|
72
|
+
|
73
|
+
text
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# This method is public, for easy overriding. This implementation returns
|
78
|
+
# Ruote::Dollar::Dict whose instances are used to extrapolate dollar
|
79
|
+
# strings like "${f:customer}" or "${r:Time.now.to_s}/${f:year_target}"
|
80
|
+
#
|
81
|
+
def dict_class
|
82
|
+
|
83
|
+
::Ruote::Dollar::Dict
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
#
|
89
|
+
# A mini-namespace Ruote::Dollar for Dict and RubyContext, just to separate
|
90
|
+
# them from the rest of Ruote.
|
91
|
+
#
|
92
|
+
module Dollar
|
93
|
+
|
94
|
+
#
|
95
|
+
# Wrapping a flow expression and the current workitem as a
|
96
|
+
# Hash-like object ready for lookup at substitution time.
|
97
|
+
#
|
98
|
+
class Dict
|
99
|
+
|
100
|
+
attr_reader :fexp
|
101
|
+
attr_reader :workitem
|
102
|
+
|
103
|
+
def initialize (flowexpression, workitem)
|
104
|
+
|
105
|
+
@fexp = flowexpression
|
106
|
+
@workitem = workitem
|
107
|
+
end
|
108
|
+
|
109
|
+
def [] (key)
|
110
|
+
|
111
|
+
return @fexp.fei.to_storage_id if key == 'fei'
|
112
|
+
return @fexp.fei.wfid if key == 'wfid'
|
113
|
+
return @fexp.fei.sub_wfid if key == 'sub_wfid'
|
114
|
+
return @fexp.fei.expid if key == 'expid'
|
115
|
+
|
116
|
+
pr, k = extract_prefix(key)
|
117
|
+
|
118
|
+
# stage 0
|
119
|
+
|
120
|
+
v = lookup(pr[0, 1], k)
|
121
|
+
|
122
|
+
return v if v != nil
|
123
|
+
|
124
|
+
# stage 1
|
125
|
+
|
126
|
+
return '' if pr.size < 2
|
127
|
+
|
128
|
+
lookup(pr[1, 1], k)
|
129
|
+
end
|
130
|
+
|
131
|
+
def []= (key, value)
|
132
|
+
|
133
|
+
pr, k = extract_prefix(key)
|
134
|
+
pr = pr[0, 1]
|
135
|
+
|
136
|
+
if pr == 'f'
|
137
|
+
|
138
|
+
@workitem.set_attribute(k, value)
|
139
|
+
|
140
|
+
elsif @fexp
|
141
|
+
|
142
|
+
@fexp.set_variable(k, value)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def has_key? (key)
|
147
|
+
|
148
|
+
pr, k = extract_prefix(key)
|
149
|
+
|
150
|
+
return true if pr == 'r'
|
151
|
+
|
152
|
+
(self[key] != nil)
|
153
|
+
end
|
154
|
+
|
155
|
+
protected
|
156
|
+
|
157
|
+
def lookup (pr, key)
|
158
|
+
|
159
|
+
case pr
|
160
|
+
when 'v' then @fexp.lookup_variable(key)
|
161
|
+
when 'f' then Ruote.lookup(@workitem['fields'], key)
|
162
|
+
when 'r' then ruby_eval(key)
|
163
|
+
else nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def extract_prefix (key)
|
168
|
+
|
169
|
+
i = key.index(':')
|
170
|
+
|
171
|
+
return [ 'f', key ] if not i
|
172
|
+
# 'f' is the default prefix (field, not variable)
|
173
|
+
|
174
|
+
pr = key[0..i-1] # until ':'
|
175
|
+
pr = pr[0, 2] # the first two chars
|
176
|
+
|
177
|
+
pr = pr[0, 1] unless (pr == 'vf') or (pr == 'fv')
|
178
|
+
|
179
|
+
[ pr, key[i+1..-1] ]
|
180
|
+
end
|
181
|
+
|
182
|
+
# TODO : rdoc me
|
183
|
+
#
|
184
|
+
def ruby_eval (ruby_code)
|
185
|
+
|
186
|
+
return '' if @fexp.context['ruby_eval_allowed'] != true
|
187
|
+
|
188
|
+
@fexp.context.treechecker.check(ruby_code)
|
189
|
+
|
190
|
+
RubyContext.new(self).instance_eval(ruby_code)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Dict uses this RubyContext class to evaluate ruby code. The method
|
195
|
+
# of this instance are directly visible to "${r:ruby_code}" ruby code.
|
196
|
+
#
|
197
|
+
class RubyContext < Ruote::BlankSlate
|
198
|
+
|
199
|
+
attr_reader :workitem
|
200
|
+
|
201
|
+
def initialize (dict)
|
202
|
+
|
203
|
+
@dict = dict
|
204
|
+
@workitem = Ruote::Workitem.new(@dict.workitem)
|
205
|
+
end
|
206
|
+
|
207
|
+
# The FlowExpression for which the rendering/substitution is occurring.
|
208
|
+
#
|
209
|
+
def flow_expression
|
210
|
+
@dict.fexp
|
211
|
+
end
|
212
|
+
alias fe flow_expression
|
213
|
+
alias fexp flow_expression
|
214
|
+
|
215
|
+
# The FlowExpressionId of the expression for which the
|
216
|
+
# rendering/substitution is occurring.
|
217
|
+
#
|
218
|
+
def fei
|
219
|
+
@dict.fexp.fei
|
220
|
+
end
|
221
|
+
|
222
|
+
alias wi workitem
|
223
|
+
|
224
|
+
# The engine_id, if any.
|
225
|
+
#
|
226
|
+
def engine_id
|
227
|
+
@dict.fexp.context.engine_id
|
228
|
+
end
|
229
|
+
|
230
|
+
# This 'd' function can be called from inside ${r:...} notations.
|
231
|
+
#
|
232
|
+
# pdef = Ruote.process_definition do
|
233
|
+
# sequence do
|
234
|
+
# set 'f:toto' => 'person'
|
235
|
+
# echo "${r:d('f:toto')}"
|
236
|
+
# end
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# will yield "person".
|
240
|
+
#
|
241
|
+
def d (s)
|
242
|
+
|
243
|
+
Rufus.dsub("${#{s}}", @dict)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Given a workitem with the field "newspaper" set to "NYT",
|
247
|
+
# "${r:newspaper}" will eval to "NYT".
|
248
|
+
#
|
249
|
+
# If the field "cars" hold the value [ "bmw", "volkswagen" ],
|
250
|
+
# "${r:cars[0]}" will eval to "bmw".
|
251
|
+
#
|
252
|
+
# Else the regular NoMethodError will be raised.
|
253
|
+
#
|
254
|
+
def method_missing (m, *args)
|
255
|
+
|
256
|
+
if args.length < 1 && v = @workitem.fields[m.to_s]
|
257
|
+
return v
|
258
|
+
end
|
259
|
+
|
260
|
+
super
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
@@ -45,7 +45,8 @@ module Ruote
|
|
45
45
|
def msg_handle (msg, exception)
|
46
46
|
|
47
47
|
fexp = Ruote::Exp::FlowExpression.fetch(
|
48
|
-
@context, msg['fei'] || msg['workitem']['fei']
|
48
|
+
@context, msg['fei'] || msg['workitem']['fei']
|
49
|
+
) rescue nil
|
49
50
|
|
50
51
|
handle(msg, fexp, exception)
|
51
52
|
end
|
@@ -102,6 +103,10 @@ module Ruote
|
|
102
103
|
|
103
104
|
@context.storage.put_msg(
|
104
105
|
'error_intercepted',
|
106
|
+
'error_class' => exception.class.name,
|
107
|
+
'error_message' => exception.message,
|
108
|
+
'error_backtrace' => exception.backtrace,
|
109
|
+
# for backward compatibility
|
105
110
|
'message' => exception.inspect,
|
106
111
|
'wfid' => wfid,
|
107
112
|
'msg' => msg)
|
@@ -30,16 +30,13 @@ end
|
|
30
30
|
end
|
31
31
|
|
32
32
|
require 'ruote/exp/flowexpression'
|
33
|
-
require 'ruote/exp/raw'
|
34
33
|
|
35
34
|
|
36
|
-
exppath = File.dirname(__FILE__)
|
35
|
+
exppath = File.join(File.dirname(__FILE__), '..', 'exp')
|
37
36
|
|
38
|
-
Dir.new(exppath).entries.
|
39
|
-
|
40
|
-
|
41
|
-
require exppath + '/' + p
|
42
|
-
}
|
37
|
+
Dir.new(exppath).entries.each do |pa|
|
38
|
+
require(File.join('ruote', 'exp', pa)) if pa.match(/^fe_.*\.rb$/)
|
39
|
+
end
|
43
40
|
|
44
41
|
|
45
42
|
module Ruote
|
@@ -48,41 +45,38 @@ module Ruote
|
|
48
45
|
# Mapping from expression names (sequence, concurrence, ...) to expression
|
49
46
|
# classes (Ruote::SequenceExpression, Ruote::ConcurrenceExpression, ...)
|
50
47
|
#
|
48
|
+
# Requiring this ruote/svc/expression_map.rb file will automatically load
|
49
|
+
# all the expressions in ruote/exp/fe_*.rb.
|
50
|
+
#
|
51
|
+
# When the ExpressionMap is
|
52
|
+
# instantiated by the engine, it will look at the Ruote::Exp namespace
|
53
|
+
# and register as expression any constant in there whose name ends with
|
54
|
+
# "Expression", like "SequenceExpression" or "ParticipantExpression".
|
55
|
+
#
|
56
|
+
# So adding expressions to ruote should be as simple as making sure the
|
57
|
+
# engine sees your classes under Ruote::Exp before it instantiates this
|
58
|
+
# expression map (so that the expression map will automatically register
|
59
|
+
# your expressions).
|
60
|
+
#
|
51
61
|
class ExpressionMap
|
52
62
|
|
63
|
+
# Will load any expression in the Ruote::Exp:: namespace and map
|
64
|
+
# its names to its class.
|
65
|
+
#
|
53
66
|
def initialize (worker)
|
54
67
|
|
55
68
|
@map = {}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
add(Ruote::Exp::RedoExpression)
|
68
|
-
add(Ruote::Exp::CancelProcessExpression)
|
69
|
-
add(Ruote::Exp::WaitExpression)
|
70
|
-
add(Ruote::Exp::ListenExpression)
|
71
|
-
add(Ruote::Exp::CommandExpression)
|
72
|
-
add(Ruote::Exp::IteratorExpression)
|
73
|
-
add(Ruote::Exp::CursorExpression)
|
74
|
-
add(Ruote::Exp::IfExpression)
|
75
|
-
add(Ruote::Exp::EqualsExpression)
|
76
|
-
add(Ruote::Exp::ReserveExpression)
|
77
|
-
add(Ruote::Exp::SaveExpression)
|
78
|
-
add(Ruote::Exp::RestoreExpression)
|
79
|
-
add(Ruote::Exp::NoOpExpression)
|
80
|
-
add(Ruote::Exp::ApplyExpression)
|
81
|
-
add(Ruote::Exp::AddBranchesExpression)
|
82
|
-
add(Ruote::Exp::ErrorExpression)
|
83
|
-
add(Ruote::Exp::IncExpression)
|
84
|
-
add(Ruote::Exp::WhenExpression)
|
85
|
-
add(Ruote::Exp::CronExpression)
|
69
|
+
|
70
|
+
Ruote::Exp.constants.each do |con|
|
71
|
+
|
72
|
+
con = con.to_s
|
73
|
+
next unless con.match(/Expression$/)
|
74
|
+
|
75
|
+
cla = Ruote::Exp.const_get(con)
|
76
|
+
next unless cla.respond_to?(:expression_names)
|
77
|
+
|
78
|
+
add(cla)
|
79
|
+
end
|
86
80
|
end
|
87
81
|
|
88
82
|
# Returns the expression class for the given expression name
|