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