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
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
= ruote - CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== ruote - 2.1.7 released 2010/02/15
|
6
|
+
|
7
|
+
- now works on WinXP, Ruby 1.8.7
|
8
|
+
- reformed msgs ids and adapted Ruote::StorageHistory
|
9
|
+
- engine.register_participant(x, Ruote::StorageParticipant) now returning
|
10
|
+
a instance of the participant, for easy query
|
11
|
+
- StorageParticipant, added #query(criteria), thanks Torsten and Brett
|
12
|
+
- Ruote::Workitem #lookup('deep.field') and #set_field('deep.field') are back
|
13
|
+
- Ruote::Workitem added == and hash (list.uniq friendly), thanks Brett
|
14
|
+
- Engine#configure(key, value), thanks Torsten
|
15
|
+
- Ruote.to_tree (lightweight version of Ruote.process_definition)
|
16
|
+
- ParticipantList#names, thanks Kenneth
|
17
|
+
|
18
|
+
|
5
19
|
== ruote - 2.1.6 released 2010/02/08
|
6
20
|
|
7
21
|
- welcoming ruote-dm (datamapper persistency)
|
data/CREDITS.txt
CHANGED
@@ -8,14 +8,15 @@ Ruote (OpenWFEru) is an open source Ruby workflow (and sometimes BPM) engine.
|
|
8
8
|
The main project team
|
9
9
|
---------------------
|
10
10
|
|
11
|
-
John Mettraux
|
12
|
-
Kenneth Kalmer
|
11
|
+
John Mettraux - http://jmettraux.wordpress.com
|
12
|
+
Kenneth Kalmer - http://www.opensourcery.co.za
|
13
|
+
Torsten Schoenebaum - http://github.com/tosch
|
13
14
|
|
14
15
|
|
15
16
|
Contributors
|
16
17
|
------------
|
17
18
|
|
18
|
-
|
19
|
+
Brett Anthoine - http://github.com/anb
|
19
20
|
Matt Nichols - http://github.com/mattnichols
|
20
21
|
Nicholas Faiz - http://github.com/biv
|
21
22
|
Chris Beer - http://github.com/cbeer
|
data/Rakefile
CHANGED
@@ -19,12 +19,12 @@ ruote is an open source ruby workflow engine.
|
|
19
19
|
}
|
20
20
|
gem.email = 'jmettraux@gmail.com'
|
21
21
|
gem.homepage = 'http://ruote.rubyforge.org'
|
22
|
-
gem.authors = [ 'John Mettraux', 'Kenneth Kalmer' ]
|
22
|
+
gem.authors = [ 'John Mettraux', 'Kenneth Kalmer', 'Torsten Schoenebaum' ]
|
23
23
|
gem.rubyforge_project = 'ruote'
|
24
24
|
gem.test_file = 'test/test.rb'
|
25
25
|
|
26
|
-
gem.add_dependency 'rufus-json'
|
27
|
-
gem.add_dependency 'rufus-cloche', '>= 0.1.
|
26
|
+
gem.add_dependency 'rufus-json', '>= 0.2.0'
|
27
|
+
gem.add_dependency 'rufus-cloche', '>= 0.1.14'
|
28
28
|
gem.add_dependency 'rufus-dollar'
|
29
29
|
gem.add_dependency 'rufus-lru'
|
30
30
|
gem.add_dependency 'rufus-mnemo', '>= 1.1.0'
|
@@ -35,6 +35,7 @@ ruote is an open source ruby workflow engine.
|
|
35
35
|
gem.add_development_dependency 'yard'
|
36
36
|
gem.add_development_dependency 'builder'
|
37
37
|
gem.add_development_dependency 'mailtrap'
|
38
|
+
gem.add_development_dependency 'jeweler'
|
38
39
|
|
39
40
|
# Gem::Specification http://www.rubygems.org/read/chapter/20
|
40
41
|
end
|
data/TODO.txt
CHANGED
@@ -184,6 +184,13 @@
|
|
184
184
|
[o] process_status.to_dot
|
185
185
|
[o] EngineParticipant : don't wait in case of forget (reply could NEVER come !)
|
186
186
|
[x] align :forget behaviour on EngineParticipant forget... OK as it is
|
187
|
+
[o] engine.re_apply(fei, wi) (thanks Torsten)... :wi => x, :tree => y...
|
188
|
+
[o] ruote-dm 2.1
|
189
|
+
[o] :tree => Ruote.to_tree { participant 'alpha' }
|
190
|
+
[o] implement == eql? hash for workitem
|
191
|
+
[o] StorageParticipant#query(wfid, participant_name, {fields})
|
192
|
+
[x] break fs_history, prepare for dm_history
|
193
|
+
[o] part = engine.register_participant :alpha, StorageParticipant should work...
|
187
194
|
|
188
195
|
[ ] exp : exp (restricted form of eval ?)
|
189
196
|
[ ] exp : case (is it necessary ?)
|
@@ -264,8 +271,6 @@
|
|
264
271
|
|
265
272
|
[ ] engine.force_reply_to_parent(fei) ?
|
266
273
|
|
267
|
-
[ ] break fs_history, prepare for dm_history
|
268
|
-
|
269
274
|
[ ] :on_timeout => :rewind (break, jump to x)...
|
270
275
|
[ ] rewind 'x' where x is a tagname (command x)
|
271
276
|
|
@@ -293,14 +298,12 @@
|
|
293
298
|
[ ] shell ? irb ? Shell.new(storage)
|
294
299
|
[ ] focus on fulldup or json.dup (via fulldup ?)
|
295
300
|
|
296
|
-
[ ] ruote-dm 2.1
|
297
|
-
|
298
301
|
[ ] implement pause engine
|
299
302
|
[ ] implement pause process
|
300
303
|
|
301
304
|
[ ] engine.on_error = 'participant_name'
|
302
305
|
|
303
|
-
[ ] "
|
306
|
+
[ ] "business days" plugin
|
304
307
|
|
305
|
-
[ ]
|
308
|
+
[ ] issue with ruote-kit and inpa participants...
|
306
309
|
|
data/lib/ruote/context.rb
CHANGED
@@ -34,6 +34,8 @@ module Ruote
|
|
34
34
|
#
|
35
35
|
class Context
|
36
36
|
|
37
|
+
SERVICE_PREFIX = /^s\_/
|
38
|
+
|
37
39
|
attr_reader :storage
|
38
40
|
attr_accessor :worker
|
39
41
|
attr_accessor :engine
|
@@ -41,7 +43,6 @@ module Ruote
|
|
41
43
|
def initialize (storage, worker_or_engine)
|
42
44
|
|
43
45
|
@storage = storage
|
44
|
-
@conf = default_conf.merge(@storage.get_configuration('engine') || {})
|
45
46
|
|
46
47
|
@worker, @engine = if worker_or_engine.kind_of?(Ruote::Engine)
|
47
48
|
[ worker_or_engine.worker, worker_or_engine ]
|
@@ -54,29 +55,37 @@ module Ruote
|
|
54
55
|
|
55
56
|
def engine_id
|
56
57
|
|
57
|
-
|
58
|
+
get_conf['engine_id'] || 'engine'
|
58
59
|
end
|
59
60
|
|
60
61
|
def [] (key)
|
61
62
|
|
62
|
-
@
|
63
|
+
SERVICE_PREFIX.match(key) ? @services[key] : get_conf[key]
|
63
64
|
end
|
64
65
|
|
65
66
|
def []= (key, value)
|
66
67
|
|
67
|
-
|
68
|
+
raise(
|
69
|
+
ArgumentError.new('use context#add_service to register services')
|
70
|
+
) if SERVICE_PREFIX.match(key)
|
71
|
+
|
72
|
+
cf = get_conf
|
73
|
+
cf[key] = value
|
74
|
+
@storage.put(cf)
|
75
|
+
|
76
|
+
value
|
68
77
|
end
|
69
78
|
|
70
79
|
def keys
|
71
80
|
|
72
|
-
|
81
|
+
get_conf.keys
|
73
82
|
end
|
74
83
|
|
75
84
|
def add_service (key, *args)
|
76
85
|
|
77
86
|
path, klass, opts = args
|
78
87
|
|
79
|
-
key = "s_#{key}" unless
|
88
|
+
key = "s_#{key}" unless SERVICE_PREFIX.match(key)
|
80
89
|
|
81
90
|
service = if klass
|
82
91
|
|
@@ -85,13 +94,13 @@ module Ruote
|
|
85
94
|
aa = [ self ]
|
86
95
|
aa << opts if opts
|
87
96
|
|
88
|
-
@
|
97
|
+
@services[key] = Ruote.constantize(klass).new(*aa)
|
89
98
|
else
|
90
99
|
|
91
|
-
@
|
100
|
+
@services[key] = path
|
92
101
|
end
|
93
102
|
|
94
|
-
self.class.class_eval %{ def #{key[2..-1]}; @
|
103
|
+
self.class.class_eval %{ def #{key[2..-1]}; @services['#{key}']; end }
|
95
104
|
|
96
105
|
service
|
97
106
|
end
|
@@ -101,7 +110,7 @@ module Ruote
|
|
101
110
|
@storage.shutdown if @storage.respond_to?(:shutdown)
|
102
111
|
@worker.shutdown if @worker
|
103
112
|
|
104
|
-
@
|
113
|
+
@services.values.each do |s|
|
105
114
|
|
106
115
|
s.shutdown if s.respond_to?(:shutdown)
|
107
116
|
end
|
@@ -109,13 +118,20 @@ module Ruote
|
|
109
118
|
|
110
119
|
protected
|
111
120
|
|
121
|
+
def get_conf
|
122
|
+
|
123
|
+
@storage.get_configuration('engine') || {}
|
124
|
+
end
|
125
|
+
|
112
126
|
def initialize_services
|
113
127
|
|
114
|
-
@
|
128
|
+
@services = {}
|
129
|
+
|
130
|
+
default_conf.merge(get_conf).each do |key, value|
|
115
131
|
|
116
|
-
next unless
|
132
|
+
next unless SERVICE_PREFIX.match(key)
|
117
133
|
|
118
|
-
add_service(key,
|
134
|
+
add_service(key, *value)
|
119
135
|
end
|
120
136
|
end
|
121
137
|
|
data/lib/ruote/engine.rb
CHANGED
@@ -319,6 +319,20 @@ module Ruote
|
|
319
319
|
|
320
320
|
@context.add_service(name, path_or_instance, classname, opts)
|
321
321
|
end
|
322
|
+
|
323
|
+
# Sets a configuration option. Examples:
|
324
|
+
#
|
325
|
+
# # allow remote workflow definitions (for subprocesses or when launching
|
326
|
+
# # processes)
|
327
|
+
# @engine.configure('remote_definition_allowed', true)
|
328
|
+
#
|
329
|
+
# # allow ruby_eval
|
330
|
+
# @engine.configure('ruby_eval_allowed', true)
|
331
|
+
#
|
332
|
+
def configure (config_key, value)
|
333
|
+
|
334
|
+
@context[config_key] = value
|
335
|
+
end
|
322
336
|
end
|
323
337
|
|
324
338
|
#
|
@@ -507,6 +507,10 @@ module Ruote::Exp
|
|
507
507
|
tree[2]
|
508
508
|
end
|
509
509
|
|
510
|
+
# A tiny class-bound counter used when generating subprocesses ids.
|
511
|
+
#
|
512
|
+
@@sub_wfid_counter = -1
|
513
|
+
|
510
514
|
# Generates a sub_wfid, without hitting storage.
|
511
515
|
#
|
512
516
|
# There's a better implementation for sure...
|
@@ -517,6 +521,9 @@ module Ruote::Exp
|
|
517
521
|
$$, Time.now.to_f.to_s, self.hash.to_s, @h['fei'].inspect
|
518
522
|
].join('-').hash
|
519
523
|
|
524
|
+
@@sub_wfid_counter = (@@sub_wfid_counter + 1) % 1000
|
525
|
+
i = i * 1000 + (@@sub_wfid_counter)
|
526
|
+
|
520
527
|
(i < 0 ? "1#{i * -1}" : "0#{i}").to_s
|
521
528
|
end
|
522
529
|
|
data/lib/ruote/fei.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c)
|
2
|
+
# Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -39,7 +39,20 @@ module Ruote
|
|
39
39
|
end
|
40
40
|
|
41
41
|
#
|
42
|
-
#
|
42
|
+
# The FlowExpressionId (fei for short) is an process expression identifier.
|
43
|
+
# Each expression when instantiated gets a unique fei.
|
44
|
+
#
|
45
|
+
# Feis are also used in workitems, where the fei is the fei of the
|
46
|
+
# [participant] expression that emitted the workitem.
|
47
|
+
#
|
48
|
+
# Feis can thus indicate the position of a workitem in a process tree.
|
49
|
+
#
|
50
|
+
# Feis contain four pieces of information :
|
51
|
+
#
|
52
|
+
# * wfid : workflow instance id, the identifier for the process instance
|
53
|
+
# * sub_wfid : the identifier for the sub process within the main instance
|
54
|
+
# * expid : the expression id, where in the process tree
|
55
|
+
# * engine_id : only relevant in multi engine scenarii (defaults to 'engine')
|
43
56
|
#
|
44
57
|
class FlowExpressionId
|
45
58
|
|
@@ -66,12 +79,10 @@ module Ruote
|
|
66
79
|
end
|
67
80
|
|
68
81
|
def to_storage_id
|
69
|
-
|
70
82
|
"#{@h['expid']}!#{@h['sub_wfid']}!#{@h['wfid']}"
|
71
83
|
end
|
72
84
|
|
73
85
|
def self.to_storage_id (hfei)
|
74
|
-
|
75
86
|
"#{hfei['expid']}!#{hfei['sub_wfid']}!#{hfei['wfid']}"
|
76
87
|
end
|
77
88
|
|
@@ -88,12 +99,10 @@ module Ruote
|
|
88
99
|
# '0_5_7', the child_id will be '7'.
|
89
100
|
#
|
90
101
|
def child_id
|
91
|
-
|
92
102
|
h.expid.split(CHILD_SEP).last.to_i
|
93
103
|
end
|
94
104
|
|
95
105
|
def hash
|
96
|
-
|
97
106
|
to_storage_id.hash
|
98
107
|
end
|
99
108
|
|
@@ -117,7 +126,6 @@ module Ruote
|
|
117
126
|
# Returns child_id... For an expid of '0_1_4', this will be 4.
|
118
127
|
#
|
119
128
|
def self.child_id (h)
|
120
|
-
|
121
129
|
h['expid'].split(CHILD_SEP).last.to_i
|
122
130
|
end
|
123
131
|
|
data/lib/ruote/log/fs_history.rb
CHANGED
@@ -122,7 +122,7 @@ module Ruote
|
|
122
122
|
#
|
123
123
|
def by_date (date)
|
124
124
|
|
125
|
-
date = Time.parse(date.to_s).strftime('%
|
125
|
+
date = Time.parse(date.to_s).strftime('%Y-%m-%d')
|
126
126
|
|
127
127
|
lines = File.readlines(File.join(@path, "history_#{date}.json")) rescue []
|
128
128
|
|
@@ -158,7 +158,7 @@ module Ruote
|
|
158
158
|
rotate_if_necessary
|
159
159
|
|
160
160
|
@file.puts(Rufus::Json.encode(
|
161
|
-
[ "#{@last.strftime('%
|
161
|
+
[ "#{@last.strftime('%Y-%m-%d %T')}.#{"%06d" % @last.usec}", msg ]))
|
162
162
|
@file.flush
|
163
163
|
end
|
164
164
|
|
@@ -173,7 +173,7 @@ module Ruote
|
|
173
173
|
|
174
174
|
@file.close rescue nil
|
175
175
|
|
176
|
-
fn = [ 'history', @last.strftime('%
|
176
|
+
fn = [ 'history', @last.strftime('%Y-%m-%d') ].join('_') + '.json'
|
177
177
|
|
178
178
|
@file = File.open(File.join(@path, fn), 'a')
|
179
179
|
end
|
@@ -34,6 +34,8 @@ module Ruote
|
|
34
34
|
#
|
35
35
|
class StorageHistory
|
36
36
|
|
37
|
+
DATE_REGEX = /!(\d{4}-\d{2}-\d{2})!/
|
38
|
+
|
37
39
|
def initialize (context, options={})
|
38
40
|
|
39
41
|
@context = context
|
@@ -60,17 +62,20 @@ module Ruote
|
|
60
62
|
|
61
63
|
ids = @context.storage.ids('history')
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
+
fm = DATE_REGEX.match(ids.first)[1]
|
66
|
+
lm = DATE_REGEX.match(ids.last)[1]
|
67
|
+
|
68
|
+
first = Time.parse("#{fm} 00:00:00 UTC")
|
69
|
+
last = Time.parse("#{lm} 00:00:00 UTC") + 24 * 3600
|
65
70
|
|
66
71
|
[ first, last ]
|
67
72
|
end
|
68
73
|
|
69
74
|
def by_date (date)
|
70
75
|
|
71
|
-
date = Time.parse(date.to_s).strftime('%
|
76
|
+
date = Time.parse(date.to_s).strftime('%Y-%m-%d')
|
72
77
|
|
73
|
-
@context.storage.get_many('history',
|
78
|
+
@context.storage.get_many('history', /!#{date}!/)
|
74
79
|
end
|
75
80
|
|
76
81
|
#def history_to_tree (wfid)
|
@@ -101,12 +106,13 @@ module Ruote
|
|
101
106
|
msg['wfid'] || 'no_wfid'
|
102
107
|
end
|
103
108
|
|
104
|
-
|
109
|
+
_id = msg['_id']
|
110
|
+
msg['original_id'] = _id
|
111
|
+
msg['_id'] = "#{_id}!#{si}"
|
105
112
|
|
106
|
-
msg['original_id'] = msg['_id']
|
107
|
-
msg['_id'] = "#{t.strftime('%F')}!#{t.to_i}_#{"%06d" % t.usec}!#{si}"
|
108
113
|
msg['type'] = 'history'
|
109
114
|
msg['original_put_at'] = msg['put_at']
|
115
|
+
|
110
116
|
msg.delete('_rev')
|
111
117
|
|
112
118
|
@context.storage.put(msg)
|
@@ -148,6 +148,11 @@ module Ruote
|
|
148
148
|
interest = interest - 1
|
149
149
|
@waiting = [ @waiting.first, interest ]
|
150
150
|
|
151
|
+
#@debug ||= {}
|
152
|
+
#c = @debug[action] ||= 0
|
153
|
+
#@debug[action] = c+1
|
154
|
+
#p [ interest, @debug ]
|
155
|
+
|
151
156
|
(interest < 1)
|
152
157
|
|
153
158
|
else # wfid
|
@@ -194,6 +199,7 @@ module Ruote
|
|
194
199
|
|
195
200
|
def color (mod, s, clear=false)
|
196
201
|
|
202
|
+
return s if Ruote::WIN
|
197
203
|
return s unless STDOUT.tty?
|
198
204
|
|
199
205
|
"[#{mod}m#{s}[0m#{clear ? '' : "[#{@color}m"}"
|
data/lib/ruote/parser.rb
CHANGED
@@ -35,6 +35,8 @@ module Ruote
|
|
35
35
|
#
|
36
36
|
# A process definition parser.
|
37
37
|
#
|
38
|
+
# Can parse XML, JSON, Ruby (and more) process definition representations.
|
39
|
+
#
|
38
40
|
class Parser
|
39
41
|
|
40
42
|
def initialize (context)
|
@@ -55,11 +57,9 @@ module Ruote
|
|
55
57
|
|
56
58
|
if definition.index("\n") == nil
|
57
59
|
|
58
|
-
u = URI.parse(definition)
|
59
|
-
|
60
60
|
raise ArgumentError.new(
|
61
61
|
"remote process definitions are not allowed"
|
62
|
-
) if
|
62
|
+
) if Ruote::Parser.remote?(definition) && @context['remote_definition_allowed'] != true
|
63
63
|
|
64
64
|
return parse(open(definition).read)
|
65
65
|
end
|
@@ -147,6 +147,15 @@ module Ruote
|
|
147
147
|
tree.to_json
|
148
148
|
end
|
149
149
|
|
150
|
+
# Returns true if the defintion is a remote URI
|
151
|
+
#
|
152
|
+
def self.remote? (definition)
|
153
|
+
|
154
|
+
u = URI.parse(definition)
|
155
|
+
|
156
|
+
(u.scheme != nil) && ( ! ('A'..'Z').include?(u.scheme))
|
157
|
+
end
|
158
|
+
|
150
159
|
protected
|
151
160
|
|
152
161
|
# Evaluates the ruby string in the code, but at fist, thanks to the
|