ruote 2.3.0.1 → 2.3.0.2
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 +23 -0
- data/CREDITS.txt +4 -0
- data/LICENSE.txt +1 -1
- data/lib/ruote.rb +2 -0
- data/lib/ruote/context.rb +2 -1
- data/lib/ruote/dashboard.rb +169 -13
- data/lib/ruote/dboard/mutation.rb +282 -0
- data/lib/ruote/dboard/process_error.rb +1 -1
- data/lib/ruote/dboard/process_status.rb +61 -48
- data/lib/ruote/engine.rb +1 -1
- data/lib/ruote/exp/command.rb +1 -1
- data/lib/ruote/exp/commanded.rb +1 -1
- data/lib/ruote/exp/condition.rb +2 -1
- data/lib/ruote/exp/fe_add_branches.rb +1 -1
- data/lib/ruote/exp/fe_apply.rb +1 -1
- data/lib/ruote/exp/fe_await.rb +97 -48
- data/lib/ruote/exp/fe_cancel_process.rb +1 -1
- data/lib/ruote/exp/fe_command.rb +2 -3
- data/lib/ruote/exp/fe_concurrence.rb +162 -66
- data/lib/ruote/exp/fe_concurrent_iterator.rb +25 -7
- data/lib/ruote/exp/fe_cron.rb +1 -1
- data/lib/ruote/exp/fe_cursor.rb +10 -11
- data/lib/ruote/exp/fe_define.rb +1 -1
- data/lib/ruote/exp/fe_echo.rb +1 -1
- data/lib/ruote/exp/fe_equals.rb +1 -1
- data/lib/ruote/exp/fe_error.rb +1 -1
- data/lib/ruote/exp/fe_filter.rb +1 -1
- data/lib/ruote/exp/fe_forget.rb +1 -1
- data/lib/ruote/exp/fe_given.rb +1 -1
- data/lib/ruote/exp/fe_if.rb +87 -7
- data/lib/ruote/exp/fe_inc.rb +1 -1
- data/lib/ruote/exp/fe_iterator.rb +1 -1
- data/lib/ruote/exp/fe_listen.rb +1 -1
- data/lib/ruote/exp/fe_lose.rb +1 -1
- data/lib/ruote/exp/fe_noop.rb +1 -1
- data/lib/ruote/exp/fe_on_error.rb +1 -1
- data/lib/ruote/exp/fe_once.rb +1 -1
- data/lib/ruote/exp/fe_participant.rb +49 -16
- data/lib/ruote/exp/fe_read.rb +1 -1
- data/lib/ruote/exp/fe_redo.rb +1 -1
- data/lib/ruote/exp/fe_ref.rb +1 -1
- data/lib/ruote/exp/fe_registerp.rb +1 -1
- data/lib/ruote/exp/fe_reserve.rb +1 -1
- data/lib/ruote/exp/fe_restore.rb +1 -7
- data/lib/ruote/exp/fe_save.rb +1 -1
- data/lib/ruote/exp/fe_sequence.rb +1 -1
- data/lib/ruote/exp/fe_set.rb +1 -1
- data/lib/ruote/exp/fe_stall.rb +1 -1
- data/lib/ruote/exp/fe_subprocess.rb +1 -1
- data/lib/ruote/exp/fe_that.rb +1 -1
- data/lib/ruote/exp/fe_undo.rb +1 -1
- data/lib/ruote/exp/fe_unregisterp.rb +1 -1
- data/lib/ruote/exp/fe_wait.rb +1 -1
- data/lib/ruote/exp/flow_expression.rb +117 -8
- data/lib/ruote/exp/iterator.rb +1 -1
- data/lib/ruote/exp/ro_attributes.rb +1 -1
- data/lib/ruote/exp/ro_filters.rb +1 -1
- data/lib/ruote/exp/ro_on_x.rb +4 -2
- data/lib/ruote/exp/ro_persist.rb +1 -1
- data/lib/ruote/exp/ro_timers.rb +1 -1
- data/lib/ruote/exp/ro_variables.rb +1 -1
- data/lib/ruote/extract.rb +125 -0
- data/lib/ruote/fei.rb +10 -73
- data/lib/ruote/id/mnemo_wfid_generator.rb +1 -1
- data/lib/ruote/id/wfid_generator.rb +1 -1
- data/lib/ruote/log/default_history.rb +17 -3
- data/lib/ruote/log/fancy_printing.rb +12 -32
- data/lib/ruote/log/storage_history.rb +1 -1
- data/lib/ruote/log/wait_logger.rb +15 -7
- data/lib/ruote/merge.rb +123 -0
- data/lib/ruote/observer.rb +1 -1
- data/lib/ruote/part/block_participant.rb +1 -1
- data/lib/ruote/part/code_participant.rb +1 -1
- data/lib/ruote/part/engine_participant.rb +1 -1
- data/lib/ruote/part/local_participant.rb +9 -1
- data/lib/ruote/part/no_op_participant.rb +1 -1
- data/lib/ruote/part/null_participant.rb +1 -1
- data/lib/ruote/part/participant.rb +1 -1
- data/lib/ruote/part/rev_participant.rb +1 -1
- data/lib/ruote/part/smtp_participant.rb +1 -1
- data/lib/ruote/part/storage_participant.rb +18 -1
- data/lib/ruote/part/template.rb +1 -1
- data/lib/ruote/reader.rb +1 -1
- data/lib/ruote/reader/json.rb +1 -1
- data/lib/ruote/reader/radial.rb +4 -4
- data/lib/ruote/reader/ruby_dsl.rb +1 -1
- data/lib/ruote/reader/xml.rb +1 -1
- data/lib/ruote/receiver/base.rb +13 -1
- data/lib/ruote/storage/base.rb +8 -14
- data/lib/ruote/storage/composite_storage.rb +1 -1
- data/lib/ruote/storage/fs_storage.rb +1 -1
- data/lib/ruote/storage/hash_storage.rb +2 -1
- data/lib/ruote/svc/dispatch_pool.rb +29 -18
- data/lib/ruote/svc/dollar_sub.rb +5 -8
- data/lib/ruote/svc/error_handler.rb +1 -1
- data/lib/ruote/svc/expression_map.rb +1 -1
- data/lib/ruote/svc/participant_list.rb +8 -5
- data/lib/ruote/svc/tracker.rb +154 -56
- data/lib/ruote/svc/treechecker.rb +1 -1
- data/lib/ruote/tree_dot.rb +1 -1
- data/lib/ruote/util/deep.rb +4 -2
- data/lib/ruote/util/filter.rb +1 -1
- data/lib/ruote/util/hashdot.rb +1 -1
- data/lib/ruote/util/look.rb +1 -1
- data/lib/ruote/util/lookup.rb +1 -1
- data/lib/ruote/util/misc.rb +51 -1
- data/lib/ruote/util/mpatch.rb +1 -1
- data/lib/ruote/util/ometa.rb +1 -1
- data/lib/ruote/util/subprocess.rb +1 -1
- data/lib/ruote/util/time.rb +3 -3
- data/lib/ruote/util/tree.rb +43 -4
- data/lib/ruote/version.rb +2 -2
- data/lib/ruote/worker.rb +30 -18
- data/lib/ruote/workitem.rb +1 -1
- data/ruote.gemspec +6 -2
- data/test/functional/base.rb +0 -1
- data/test/functional/concurrent_base.rb +1 -1
- data/test/functional/eft_14_cursor.rb +42 -52
- data/test/functional/eft_16_if.rb +24 -16
- data/test/functional/eft_18_concurrent_iterator.rb +31 -1
- data/test/functional/eft_6_concurrence.rb +149 -34
- data/test/functional/ft_10_dollar.rb +14 -30
- data/test/functional/ft_12_launchitem.rb +15 -0
- data/test/functional/ft_1_process_status.rb +62 -13
- data/test/functional/ft_20_storage_participant.rb +25 -0
- data/test/functional/ft_38_participant_more.rb +1 -1
- data/test/functional/ft_42_storage_copy.rb +1 -3
- data/test/functional/ft_43_participant_on_reply.rb +63 -5
- data/test/functional/ft_66_flank.rb +41 -0
- data/test/functional/ft_6_on_cancel.rb +9 -18
- data/test/functional/ft_71_retries.rb +25 -12
- data/test/functional/ft_79_attach.rb +138 -0
- data/test/functional/ft_7_tags.rb +27 -0
- data/test/functional/ft_80_pause_on_apply.rb +64 -0
- data/test/functional/ft_81_mutation.rb +417 -0
- data/test/functional/ft_82_await_attribute.rb +84 -0
- data/test/functional/ft_83_trackers.rb +79 -0
- data/test/functional/storage.rb +3 -4
- data/test/unit/ut_12_wait_logger.rb +41 -3
- data/test/unit/ut_15_util.rb +30 -0
- data/test/unit/ut_17_merge.rb +54 -53
- data/test/unit/ut_1_fei.rb +2 -2
- data/test/unit/ut_24_radial_reader.rb +7 -0
- data/test/unit/ut_26_deep.rb +14 -0
- data/test/unit/ut_5_tree.rb +38 -28
- metadata +206 -169
- data/couch_url.txt +0 -1
- data/lib/ruote/exp/merge.rb +0 -134
data/lib/ruote/fei.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -25,6 +25,7 @@
|
|
25
25
|
require 'digest/md5'
|
26
26
|
|
27
27
|
require 'ruote/version'
|
28
|
+
require 'ruote/extract'
|
28
29
|
require 'ruote/workitem'
|
29
30
|
require 'ruote/util/misc'
|
30
31
|
require 'ruote/util/hashdot'
|
@@ -32,63 +33,6 @@ require 'ruote/util/hashdot'
|
|
32
33
|
|
33
34
|
module Ruote
|
34
35
|
|
35
|
-
# A shortcut for
|
36
|
-
#
|
37
|
-
# Ruote::FlowExpressionId.to_storage_id(fei)
|
38
|
-
#
|
39
|
-
def self.to_storage_id(fei)
|
40
|
-
|
41
|
-
Ruote::FlowExpressionId.to_storage_id(fei)
|
42
|
-
end
|
43
|
-
|
44
|
-
# A shorter shortcut for
|
45
|
-
#
|
46
|
-
# Ruote::FlowExpressionId.to_storage_id(fei)
|
47
|
-
#
|
48
|
-
def self.sid(fei)
|
49
|
-
|
50
|
-
Ruote::FlowExpressionId.to_storage_id(fei)
|
51
|
-
end
|
52
|
-
|
53
|
-
# A shortcut for
|
54
|
-
#
|
55
|
-
# Ruote::FlowExpressionId.is_a_fei?(o)
|
56
|
-
#
|
57
|
-
def self.is_a_fei?(o)
|
58
|
-
|
59
|
-
Ruote::FlowExpressionId.is_a_fei?(o)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Will do its best to return a wfid (String) or a fei (Hash instance)
|
63
|
-
# extract from the given o argument.
|
64
|
-
#
|
65
|
-
def self.extract_id(o)
|
66
|
-
|
67
|
-
return o if o.is_a?(String) and o.index('!').nil? # wfid
|
68
|
-
|
69
|
-
Ruote::FlowExpressionId.extract_h(o)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Given something, tries to return the fei (Ruote::FlowExpressionId) in it.
|
73
|
-
#
|
74
|
-
def self.extract_fei(o)
|
75
|
-
|
76
|
-
Ruote::FlowExpressionId.extract(o)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Given an object, will return the wfid (workflow instance id) nested into
|
80
|
-
# it (or nil if it can't find or doesn't know how to find).
|
81
|
-
#
|
82
|
-
# The wfid is a String instance.
|
83
|
-
#
|
84
|
-
def self.extract_wfid(o)
|
85
|
-
|
86
|
-
return o.strip == '' ? nil : o if o.is_a?(String)
|
87
|
-
return o.wfid if o.respond_to?(:wfid)
|
88
|
-
return o['wfid'] || o.fetch('fei', {})['wfid'] if o.respond_to?(:[])
|
89
|
-
nil
|
90
|
-
end
|
91
|
-
|
92
36
|
# This function is used to generate the subids. Each flow
|
93
37
|
# expression receives such an id (it's useful for cursors, loops and
|
94
38
|
# forgotten branches).
|
@@ -162,11 +106,13 @@ module Ruote
|
|
162
106
|
|
163
107
|
def self.to_storage_id(hfei)
|
164
108
|
|
165
|
-
hfei.respond_to?(:to_storage_id) ?
|
166
|
-
hfei.to_storage_id :
|
167
|
-
"#{hfei['expid']}!#{hfei['subid'] || hfei['sub_wfid']}!#{hfei['wfid']}"
|
168
|
-
|
169
109
|
# TODO : for 2.1.13, remove the subid || sub_wfid trick
|
110
|
+
|
111
|
+
if hfei.respond_to?(:to_storage_id)
|
112
|
+
hfei.to_storage_id
|
113
|
+
else
|
114
|
+
"#{hfei['expid']}!#{hfei['subid'] || hfei['sub_wfid']}!#{hfei['wfid']}"
|
115
|
+
end
|
170
116
|
end
|
171
117
|
|
172
118
|
# Turns the result of to_storage_id back to a FlowExpressionId instance.
|
@@ -217,16 +163,6 @@ module Ruote
|
|
217
163
|
|
218
164
|
alias eql? ==
|
219
165
|
|
220
|
-
SUBS = %w[ subid sub_wfid ]
|
221
|
-
IDS = %w[ engine_id expid wfid ]
|
222
|
-
|
223
|
-
# Returns true if the h is a representation of a FlowExpressionId instance.
|
224
|
-
#
|
225
|
-
def self.is_a_fei?(h)
|
226
|
-
|
227
|
-
h.respond_to?(:keys) && (h.keys - SUBS).sort == IDS
|
228
|
-
end
|
229
|
-
|
230
166
|
# Returns child_id... For an expid of '0_1_4', this will be 4.
|
231
167
|
#
|
232
168
|
def self.child_id(h)
|
@@ -285,7 +221,8 @@ module Ruote
|
|
285
221
|
'engine_id' => ss[-4] || 'engine',
|
286
222
|
'expid' => ss[-3],
|
287
223
|
'subid' => ss[-2],
|
288
|
-
'wfid' => ss[-1]
|
224
|
+
'wfid' => ss[-1]
|
225
|
+
}
|
289
226
|
end
|
290
227
|
|
291
228
|
raise ArgumentError.new(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -33,12 +33,14 @@ module Ruote
|
|
33
33
|
#
|
34
34
|
# NOTE:
|
35
35
|
#
|
36
|
-
#
|
36
|
+
# This default history is worthless when there are multiple workers.
|
37
37
|
# It only keeps track of the msgs processed by the worker in the same
|
38
38
|
# context. Msgs processed by other workers (in different Ruby runtimes) are
|
39
39
|
# not seen (they are tracked by the DefaultHistory next to those workers).
|
40
40
|
#
|
41
41
|
# By default, this history keeps track of the latest 1'000 msgs.
|
42
|
+
# This can be changed by passing a 'history_max_size' option to the storage
|
43
|
+
# when initializing ruote ('history_max_size' => 0) is acceptable.
|
42
44
|
#
|
43
45
|
class DefaultHistory
|
44
46
|
|
@@ -52,6 +54,8 @@ module Ruote
|
|
52
54
|
@context = context
|
53
55
|
@options = options
|
54
56
|
|
57
|
+
@max_size = context['history_max_size'] || DEFAULT_MAX_SIZE
|
58
|
+
|
55
59
|
@history = []
|
56
60
|
end
|
57
61
|
|
@@ -122,14 +126,24 @@ module Ruote
|
|
122
126
|
#
|
123
127
|
def on_msg(msg)
|
124
128
|
|
129
|
+
return if @max_size < 1
|
130
|
+
|
125
131
|
msg = Ruote.fulldup(msg)
|
126
132
|
msg['seen_at'] = Ruote.now_to_utc_s
|
127
133
|
|
128
134
|
@history << msg
|
129
135
|
|
130
|
-
while (@history.size >
|
136
|
+
while (@history.size > @max_size) do
|
131
137
|
@history.shift
|
132
138
|
end
|
139
|
+
|
140
|
+
rescue => e
|
141
|
+
|
142
|
+
$stderr.puts '>' + '-' * 79
|
143
|
+
$stderr.puts "#{self.class} issue, skipping"
|
144
|
+
$stderr.puts e.inspect
|
145
|
+
$stderr.puts e.backtrace[0, 2]
|
146
|
+
$stderr.puts '<' + '-' * 79
|
133
147
|
end
|
134
148
|
end
|
135
149
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -77,29 +77,6 @@ class Ruote::WaitLogger
|
|
77
77
|
].join('!')
|
78
78
|
end
|
79
79
|
|
80
|
-
def insp(o, opts={})
|
81
|
-
|
82
|
-
case o
|
83
|
-
when nil
|
84
|
-
'nil'
|
85
|
-
when Hash
|
86
|
-
trim = opts[:trim] || []
|
87
|
-
'{' +
|
88
|
-
o.reject { |k, v|
|
89
|
-
v.nil? && trim.include?(k.to_s)
|
90
|
-
}.collect { |k, v|
|
91
|
-
"#{k}: #{insp(v)}"
|
92
|
-
}.join(', ') +
|
93
|
-
'}'
|
94
|
-
when Array
|
95
|
-
'[' + o.collect { |e| insp(e) }.join(', ') + ']'
|
96
|
-
when String
|
97
|
-
o.match(/\s/) ? o.inspect : o
|
98
|
-
else
|
99
|
-
o.inspect
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
80
|
def radial_tree(msg)
|
104
81
|
|
105
82
|
_, t = Ruote::Exp::DefineExpression.reorganize(msg['tree'])
|
@@ -117,10 +94,13 @@ class Ruote::WaitLogger
|
|
117
94
|
|
118
95
|
@count = (@count + 1) % 10
|
119
96
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
97
|
+
wo = Ruote.current_worker
|
98
|
+
woi = [ wo.object_id.to_s[-2..-1] ]
|
99
|
+
if wo.class != Ruote::Worker || wo.name != 'worker'
|
100
|
+
woi << wo.class.name.split('::').last[0, 2]
|
101
|
+
woi << wo.name[0, 2]
|
102
|
+
end
|
103
|
+
woi = woi.join(':')
|
124
104
|
|
125
105
|
fei = msg['fei']
|
126
106
|
depth = fei ? fei['expid'].split('_').size : 0
|
@@ -210,7 +190,7 @@ class Ruote::WaitLogger
|
|
210
190
|
#
|
211
191
|
# display backtraces
|
212
192
|
|
213
|
-
rst = insp(
|
193
|
+
rst = Ruote.insp(
|
214
194
|
rest.reject { |k, v| %w[ error msg ].include?(k) },
|
215
195
|
:trim => %[ updated_tree ])[1..-2]
|
216
196
|
|
@@ -225,7 +205,7 @@ class Ruote::WaitLogger
|
|
225
205
|
|
226
206
|
color(
|
227
207
|
@color,
|
228
|
-
"#{@count} #{tm} #{
|
208
|
+
"#{@count} #{tm} #{woi} #{' ' * depth}#{act} * #{i} #{rst}",
|
229
209
|
true
|
230
210
|
) +
|
231
211
|
"\n" +
|
@@ -244,11 +224,11 @@ class Ruote::WaitLogger
|
|
244
224
|
''
|
245
225
|
end
|
246
226
|
|
247
|
-
rest = insp(rest, :trim => %[ updated_tree ])[1..-2]
|
227
|
+
rest = Ruote.insp(rest, :trim => %[ updated_tree ])[1..-2]
|
248
228
|
|
249
229
|
color(
|
250
230
|
@color,
|
251
|
-
"#{@count} #{tm} #{
|
231
|
+
"#{@count} #{tm} #{woi} #{' ' * depth}#{act} * #{i} #{pa}#{rest}",
|
252
232
|
true)
|
253
233
|
end
|
254
234
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013, 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
|
@@ -38,7 +38,7 @@ module Ruote
|
|
38
38
|
#
|
39
39
|
# The logic behind Ruote::Dashboard#wait_for is implemented here.
|
40
40
|
#
|
41
|
-
# This logger keeps track of the last
|
41
|
+
# This logger keeps track of the last 56 events. This number can
|
42
42
|
# be tweaked via the 'wait_logger_max' storage option
|
43
43
|
# (http://ruote.rubyforge.org/configuration.html)
|
44
44
|
#
|
@@ -51,7 +51,7 @@ module Ruote
|
|
51
51
|
# === options (storage initialization options)
|
52
52
|
#
|
53
53
|
# wait_logger_max(Integer)::
|
54
|
-
# defaults to
|
54
|
+
# defaults to 77, max number of recent records to keep track of
|
55
55
|
# wait_logger_timeout(Integer)::
|
56
56
|
# defaults to 60 (seconds), #wait_for times out after how many seconds?
|
57
57
|
#
|
@@ -84,7 +84,7 @@ module Ruote
|
|
84
84
|
@color = 33
|
85
85
|
@noisy = false
|
86
86
|
|
87
|
-
@log_max = context['wait_logger_max'] ||
|
87
|
+
@log_max = context['wait_logger_max'] || 77
|
88
88
|
@timeout = context['wait_logger_timeout'] || 60 # in seconds
|
89
89
|
|
90
90
|
@check_mutex = Mutex.new
|
@@ -178,8 +178,12 @@ module Ruote
|
|
178
178
|
while @waiting.any? and msg = @seen.shift
|
179
179
|
|
180
180
|
@waiting.delete_if do |thread, interests|
|
181
|
-
|
182
|
-
|
181
|
+
if matches(interests, msg)
|
182
|
+
thread['__result__'] = msg
|
183
|
+
true
|
184
|
+
else
|
185
|
+
false
|
186
|
+
end
|
183
187
|
end
|
184
188
|
end
|
185
189
|
end
|
@@ -267,7 +271,11 @@ module Ruote
|
|
267
271
|
interests.delete(interest) if satisfied
|
268
272
|
end
|
269
273
|
|
270
|
-
|
274
|
+
if interests.include?(:or_error)
|
275
|
+
(interests.size < 2)
|
276
|
+
else
|
277
|
+
(interests.size < 1)
|
278
|
+
end
|
271
279
|
end
|
272
280
|
end
|
273
281
|
end
|
data/lib/ruote/merge.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005-2013, 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
|
+
module Ruote
|
27
|
+
|
28
|
+
#--
|
29
|
+
# Gathering methods for merging workitems.
|
30
|
+
#++
|
31
|
+
|
32
|
+
# Merge workitem 'source' into workitem 'target'.
|
33
|
+
#
|
34
|
+
# If type is 'override', the source will prevail and be returned.
|
35
|
+
#
|
36
|
+
# If type is 'mix', the source fields will be merged into the target fields.
|
37
|
+
#
|
38
|
+
# If type is 'isolate', the source fields will be placed in a separte field
|
39
|
+
# in the target workitem. The name of this field is the child_id of the
|
40
|
+
# source workitem (a string from '0' to '99999' and beyond)
|
41
|
+
#
|
42
|
+
# The 'concat' type merges hashes and concats arrays. The 'union' type
|
43
|
+
# behaves much like 'concat', but it makes sure to remove duplicates.
|
44
|
+
#
|
45
|
+
# Warning: 'union' will remove duplicates that were present _before_ the
|
46
|
+
# merge.
|
47
|
+
#
|
48
|
+
def self.merge_workitem(index, target, source, merge_type)
|
49
|
+
|
50
|
+
if merge_type == 'override'
|
51
|
+
|
52
|
+
return source
|
53
|
+
end
|
54
|
+
|
55
|
+
if target == nil
|
56
|
+
|
57
|
+
case merge_type
|
58
|
+
|
59
|
+
when 'stack'
|
60
|
+
|
61
|
+
source['fields'] = { 'stack' => [ source['fields'] ] }
|
62
|
+
|
63
|
+
when 'isolate'
|
64
|
+
|
65
|
+
source['fields'] = { (index || 0).to_s => source['fields'] }
|
66
|
+
|
67
|
+
#when 'mix'
|
68
|
+
# do nothing
|
69
|
+
#when 'union', 'concat'
|
70
|
+
# do nothing
|
71
|
+
end
|
72
|
+
|
73
|
+
return source
|
74
|
+
end
|
75
|
+
|
76
|
+
# else, regular merge
|
77
|
+
|
78
|
+
case merge_type
|
79
|
+
|
80
|
+
when 'mix'
|
81
|
+
|
82
|
+
target['fields'].merge!(source['fields'])
|
83
|
+
|
84
|
+
when 'stack'
|
85
|
+
|
86
|
+
target['fields']['stack'] << source['fields']
|
87
|
+
|
88
|
+
when 'isolate'
|
89
|
+
|
90
|
+
index ||= target['fields'].keys.select { |k| k.match(/^\d+$/) }.size
|
91
|
+
target['fields'][index.to_s] = source['fields']
|
92
|
+
|
93
|
+
when 'union', 'concat', 'deep'
|
94
|
+
|
95
|
+
source['fields'].each do |k, sv|
|
96
|
+
|
97
|
+
tv = target['fields'][k]
|
98
|
+
|
99
|
+
if sv.is_a?(Array) and tv.is_a?(Array)
|
100
|
+
tv.concat(sv)
|
101
|
+
tv.uniq! if merge_type == 'union'
|
102
|
+
elsif sv.is_a?(Hash) and tv.is_a?(Hash)
|
103
|
+
merge_type == 'deep' ? deep_merge!(tv, sv) : tv.merge!(sv)
|
104
|
+
else
|
105
|
+
target['fields'][k] = sv
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
target
|
111
|
+
end
|
112
|
+
|
113
|
+
# Inspired by the one found in ActiveSupport, though not strictly
|
114
|
+
# equivalent.
|
115
|
+
#
|
116
|
+
def self.deep_merge!(target, source)
|
117
|
+
|
118
|
+
target.merge!(source) do |k, o, n|
|
119
|
+
o.is_a?(Hash) && n.is_a?(Hash) ? deep_merge!(o, n) : n
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|