scout-gear 7.2.0 → 7.3.0
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.
- checksums.yaml +4 -4
- data/.vimproject +37 -3
- data/VERSION +1 -1
- data/lib/scout/concurrent_stream.rb +9 -8
- data/lib/scout/exceptions.rb +1 -0
- data/lib/scout/log/color.rb +0 -1
- data/lib/scout/log/progress/util.rb +65 -0
- data/lib/scout/misc/helper.rb +31 -0
- data/lib/scout/misc/monitor.rb +1 -1
- data/lib/scout/misc.rb +1 -0
- data/lib/scout/open/stream.rb +21 -27
- data/lib/scout/persist.rb +42 -28
- data/lib/scout/semaphore.rb +8 -1
- data/lib/scout/tsv/dumper.rb +13 -8
- data/lib/scout/tsv/index.rb +127 -15
- data/lib/scout/tsv/open.rb +128 -0
- data/lib/scout/tsv/parser.rb +70 -43
- data/lib/scout/tsv/path.rb +4 -4
- data/lib/scout/tsv/persist/adapter.rb +52 -33
- data/lib/scout/tsv/persist/fix_width_table.rb +324 -0
- data/lib/scout/tsv/persist/serialize.rb +117 -0
- data/lib/scout/tsv/persist/tokyocabinet.rb +3 -3
- data/lib/scout/tsv/persist.rb +0 -2
- data/lib/scout/tsv/traverse.rb +130 -35
- data/lib/scout/tsv/util/filter.rb +303 -0
- data/lib/scout/tsv/util/process.rb +73 -0
- data/lib/scout/tsv/util/select.rb +220 -0
- data/lib/scout/tsv/util.rb +77 -19
- data/lib/scout/tsv.rb +2 -2
- data/lib/scout/work_queue/worker.rb +1 -1
- data/lib/scout/workflow/definition.rb +8 -0
- data/lib/scout/workflow/step/info.rb +4 -0
- data/lib/scout/workflow/step/progress.rb +14 -0
- data/lib/scout/workflow/step.rb +10 -5
- data/lib/scout/workflow/task.rb +8 -4
- data/lib/scout/workflow/usage.rb +2 -0
- data/scout-gear.gemspec +33 -10
- data/scout_commands/workflow/task +3 -2
- data/scout_commands/workflow/task_old +2 -2
- data/test/scout/open/test_stream.rb +1 -1
- data/test/scout/test_persist.rb +61 -0
- data/test/scout/test_tmpfile.rb +1 -1
- data/test/scout/test_tsv.rb +10 -1
- data/test/scout/test_work_queue.rb +1 -0
- data/test/scout/tsv/persist/test_adapter.rb +10 -0
- data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
- data/test/scout/tsv/test_index.rb +94 -2
- data/test/scout/tsv/test_open.rb +9 -0
- data/test/scout/tsv/test_parser.rb +28 -3
- data/test/scout/tsv/test_persist.rb +7 -0
- data/test/scout/tsv/test_traverse.rb +110 -3
- data/test/scout/tsv/test_util.rb +23 -0
- data/test/scout/tsv/util/test_filter.rb +188 -0
- data/test/scout/tsv/util/test_process.rb +47 -0
- data/test/scout/tsv/util/test_select.rb +44 -0
- data/test/scout/work_queue/test_worker.rb +63 -6
- data/test/scout/workflow/step/test_load.rb +3 -3
- data/test/scout/workflow/test_step.rb +10 -10
- data/test/test_helper.rb +3 -1
- metadata +19 -6
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'set'
|
2
|
+
module Filtered
|
3
|
+
|
4
|
+
class FilterArray
|
5
|
+
attr_accessor :filters
|
6
|
+
|
7
|
+
def ids
|
8
|
+
ids = filters.inject(nil){|list,filter| list.nil? ? filter.ids.dup : Misc.merge_sorted_arrays(list, filter.ids.dup)}
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(name, *args)
|
12
|
+
filters.each do |filter|
|
13
|
+
filter.send(name, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#{{{ FILTER
|
19
|
+
|
20
|
+
class Filter
|
21
|
+
attr_accessor :data, :match, :fieldnum, :value, :list, :unsaved
|
22
|
+
attr_accessor :persistence
|
23
|
+
|
24
|
+
def initialize(data, match, value, persistence = nil)
|
25
|
+
@data = data
|
26
|
+
@match = match
|
27
|
+
@value = value
|
28
|
+
@unsaved = []
|
29
|
+
|
30
|
+
case
|
31
|
+
when Hash === persistence
|
32
|
+
@persistence = persistence
|
33
|
+
when String === persistence
|
34
|
+
@persistence = begin
|
35
|
+
file = ScoutCabinet.open(persistence, true, "HDB")
|
36
|
+
TSV.setup file, :type => :list
|
37
|
+
file.extend TSVAdapter
|
38
|
+
file
|
39
|
+
end
|
40
|
+
@persistence.read
|
41
|
+
end
|
42
|
+
|
43
|
+
@list = nil
|
44
|
+
case
|
45
|
+
when @match == :key
|
46
|
+
@value = Set.new(@value)
|
47
|
+
class << self
|
48
|
+
self
|
49
|
+
end.class_eval <<-EOC
|
50
|
+
def match_entry(key, entry)
|
51
|
+
key == @value or (Set === @value and @value.include? key)
|
52
|
+
end
|
53
|
+
EOC
|
54
|
+
when @match.match(/field:(.*)/)
|
55
|
+
@fieldnum = data.identify_field $1
|
56
|
+
class << self
|
57
|
+
self
|
58
|
+
end.class_eval <<-EOC
|
59
|
+
def match_entry(key, entry)
|
60
|
+
value = entry[@fieldnum]
|
61
|
+
value == @value or (Array === value and value.include? @value)
|
62
|
+
end
|
63
|
+
EOC
|
64
|
+
else
|
65
|
+
raise "Unknown match: #{ @match }"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def key
|
70
|
+
case
|
71
|
+
when String === value
|
72
|
+
value
|
73
|
+
else
|
74
|
+
Marshal.dump(value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def save(ids)
|
79
|
+
if persistence
|
80
|
+
persistence.write_and_close do
|
81
|
+
persistence[self.key] = ids
|
82
|
+
end
|
83
|
+
else
|
84
|
+
if @list.nil?
|
85
|
+
@list = ids
|
86
|
+
else
|
87
|
+
@list.replace ids
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def update
|
93
|
+
ids = []
|
94
|
+
|
95
|
+
data.with_unnamed do
|
96
|
+
data.unfiltered_each do |key, entry|
|
97
|
+
ids << key if match_entry(key, entry)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
save(ids.sort)
|
102
|
+
end
|
103
|
+
|
104
|
+
def saved
|
105
|
+
if persistence.nil?
|
106
|
+
return nil if list.nil?
|
107
|
+
list
|
108
|
+
else
|
109
|
+
return nil if not persistence.include?(self.key)
|
110
|
+
persistence.write_and_close do
|
111
|
+
persistence[self.key]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_unsaved
|
117
|
+
save(Misc.merge_sorted_arrays(unsaved.sort, saved || [])) if unsaved.any?
|
118
|
+
unsaved.clear
|
119
|
+
end
|
120
|
+
|
121
|
+
def ids
|
122
|
+
add_unsaved
|
123
|
+
|
124
|
+
list = saved
|
125
|
+
if list.nil?
|
126
|
+
update
|
127
|
+
list = saved
|
128
|
+
end
|
129
|
+
list
|
130
|
+
end
|
131
|
+
|
132
|
+
def add(id)
|
133
|
+
unsaved.push id
|
134
|
+
end
|
135
|
+
|
136
|
+
def clean
|
137
|
+
add_unsaved
|
138
|
+
if persistence and persistence.include? self.key
|
139
|
+
persistence.write_and_close do
|
140
|
+
persistence.delete self.key
|
141
|
+
end
|
142
|
+
else
|
143
|
+
@list = nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def reset
|
148
|
+
add_unsaved
|
149
|
+
if persistence
|
150
|
+
persistence.write_and_close do
|
151
|
+
persistence.clear
|
152
|
+
end
|
153
|
+
else
|
154
|
+
@list = nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#}}} FILTER
|
160
|
+
|
161
|
+
def self.extended(base)
|
162
|
+
if not base.respond_to? :unfiltered_set
|
163
|
+
class << base
|
164
|
+
attr_accessor :filter_dir, :filters
|
165
|
+
|
166
|
+
alias unfiltered_set []=
|
167
|
+
alias []= filtered_set
|
168
|
+
|
169
|
+
alias unfiltered_filename filename
|
170
|
+
alias filename filtered_filename
|
171
|
+
|
172
|
+
alias unfiltered_keys keys
|
173
|
+
alias keys filtered_keys
|
174
|
+
|
175
|
+
alias unfiltered_values values
|
176
|
+
alias values filtered_values
|
177
|
+
|
178
|
+
alias unfiltered_each each
|
179
|
+
alias each filtered_each
|
180
|
+
|
181
|
+
alias unfiltered_collect collect
|
182
|
+
alias collect filtered_collect
|
183
|
+
|
184
|
+
alias unfiltered_delete delete
|
185
|
+
alias delete filtered_delete
|
186
|
+
end
|
187
|
+
end
|
188
|
+
base.filters = []
|
189
|
+
end
|
190
|
+
|
191
|
+
def filtered_filename
|
192
|
+
if filters.empty?
|
193
|
+
unfiltered_filename
|
194
|
+
else
|
195
|
+
unfiltered_filename + ":Filtered[#{filters.collect{|f| [f.match, Array === f.value ? Misc.digest(:values => f.value) : f.value] * "="} * ", "}]"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def filtered_set(key, value, clean = false)
|
200
|
+
if filters.empty?
|
201
|
+
self.send(:unfiltered_set, key, value, clean)
|
202
|
+
else
|
203
|
+
filters.each do |filter|
|
204
|
+
filter.add key if filter.match_entry key, value
|
205
|
+
end
|
206
|
+
self.send(:unfiltered_set, key, value, clean)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def filtered_keys
|
211
|
+
if filters.empty?
|
212
|
+
self.send(:unfiltered_keys)
|
213
|
+
else
|
214
|
+
filters.inject(nil){|list,filter| list.nil? ? filter.ids.dup : Misc.intersect_sorted_arrays(list, filter.ids.dup)}
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def filtered_values
|
219
|
+
if filters.empty?
|
220
|
+
self.send(:unfiltered_values)
|
221
|
+
else
|
222
|
+
ids = filters.inject(nil){|list,filter| list.nil? ? filter.ids.dup : Misc.intersect_sorted_arrays(list, filter.ids.dup)}
|
223
|
+
self.send :values_at, *ids
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def filtered_each(&block)
|
228
|
+
if filters.empty?
|
229
|
+
self.send(:unfiltered_each, &block)
|
230
|
+
else
|
231
|
+
ids = filters.inject(nil){|list,filter| list.nil? ? filter.ids.dup : Misc.intersect_sorted_arrays(list, filter.ids.dup)}
|
232
|
+
|
233
|
+
ids.each do |id|
|
234
|
+
value = self[id]
|
235
|
+
yield id, value if block_given?
|
236
|
+
[id, value]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def filtered_collect(&block)
|
242
|
+
if filters.empty?
|
243
|
+
self.send(:unfiltered_collect, &block)
|
244
|
+
else
|
245
|
+
ids = filters.inject(nil){|list,filter| list = (list.nil? ? filter.ids.dup : Misc.intersect_sorted_arrays(list, filter.ids.dup))}
|
246
|
+
|
247
|
+
new = self.annotate({})
|
248
|
+
|
249
|
+
ids.zip(self.send(:values_at, *ids)).each do |id, values|
|
250
|
+
new[id] = values
|
251
|
+
end
|
252
|
+
new.send :collect, &block
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def filtered_delete(key)
|
257
|
+
if filters.empty?
|
258
|
+
self.send(:unfiltered_delete, key)
|
259
|
+
else
|
260
|
+
reset_filters
|
261
|
+
self.send :unfiltered_delete, key
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def add_filter(match, value, persistence = nil)
|
266
|
+
if persistence.nil? and filter_dir
|
267
|
+
persistence = File.join(filter_dir, match.to_s + '.filter')
|
268
|
+
end
|
269
|
+
|
270
|
+
filter = Filter.new self, match, value, persistence
|
271
|
+
filters.push filter
|
272
|
+
end
|
273
|
+
|
274
|
+
def pop_filter
|
275
|
+
filters.pop.add_unsaved if filters.any?
|
276
|
+
end
|
277
|
+
|
278
|
+
def size
|
279
|
+
filters.empty? ? super : filters.collect{|f| f.ids.length }.min
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
module TSV
|
285
|
+
def filter(filter_dir = nil)
|
286
|
+
self.extend Filtered
|
287
|
+
self.filter_dir = filter_dir
|
288
|
+
self.filters = []
|
289
|
+
self
|
290
|
+
end
|
291
|
+
|
292
|
+
def reset_filters
|
293
|
+
if @filter_dir.nil? or @filter_dir.empty?
|
294
|
+
@filters.each do |filter| filter.reset end if Array === @filters
|
295
|
+
return
|
296
|
+
end
|
297
|
+
|
298
|
+
Dir.glob(File.join(@filter_dir, '*.filter')).each do |f|
|
299
|
+
FileUtils.rm f
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module TSV
|
2
|
+
def process(field, &block)
|
3
|
+
field_pos = identify_field field
|
4
|
+
|
5
|
+
through do |key, values|
|
6
|
+
case
|
7
|
+
when type == :single
|
8
|
+
field_values = values
|
9
|
+
when type == :flat
|
10
|
+
field_values = values
|
11
|
+
else
|
12
|
+
next if values.nil?
|
13
|
+
field_values = values[field_pos]
|
14
|
+
end
|
15
|
+
|
16
|
+
new_values = case
|
17
|
+
when block.arity == 1
|
18
|
+
yield(field_values)
|
19
|
+
when block.arity == 2
|
20
|
+
yield(field_values, key)
|
21
|
+
when block.arity == 3
|
22
|
+
yield(field_values, key, values)
|
23
|
+
else
|
24
|
+
raise "Unexpected arity in block, must be 1, 2 or 3: #{block.arity}"
|
25
|
+
end
|
26
|
+
|
27
|
+
case
|
28
|
+
when type == :single
|
29
|
+
self[key] = new_values
|
30
|
+
when type == :flat
|
31
|
+
self[key] = new_values
|
32
|
+
else
|
33
|
+
if ! values[field_pos].frozen? && ((String === values[field_pos] && String === new_values) ||
|
34
|
+
(Array === values[field_pos] && Array === new_values))
|
35
|
+
values[field_pos].replace new_values
|
36
|
+
else
|
37
|
+
values[field_pos] = new_values
|
38
|
+
end
|
39
|
+
self[key] = values
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_field(name = nil)
|
47
|
+
through do |key, values|
|
48
|
+
new_values = yield(key, values)
|
49
|
+
new_values = [new_values] if type == :double and not Array === new_values
|
50
|
+
|
51
|
+
case
|
52
|
+
when (values.nil? and (fields.nil? or fields.empty?))
|
53
|
+
values = [new_values]
|
54
|
+
when values.nil?
|
55
|
+
values = [nil] * fields.length + [new_values]
|
56
|
+
when Array === values
|
57
|
+
values += [new_values]
|
58
|
+
else
|
59
|
+
values << new_values
|
60
|
+
end
|
61
|
+
|
62
|
+
self[key] = values
|
63
|
+
end
|
64
|
+
|
65
|
+
if not fields.nil? and not name.nil?
|
66
|
+
new_fields = self.fields + [name]
|
67
|
+
self.fields = new_fields
|
68
|
+
end
|
69
|
+
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
module TSV
|
2
|
+
def select(method = nil, invert = false, &block)
|
3
|
+
new = TSV.setup({}, :key_field => key_field, :fields => fields, :type => type, :filename => filename, :identifiers => identifiers)
|
4
|
+
|
5
|
+
self.annotate(new)
|
6
|
+
|
7
|
+
case
|
8
|
+
when (method.nil? and block_given?)
|
9
|
+
through do |key, values|
|
10
|
+
new[key] = values if invert ^ (yield key, values)
|
11
|
+
end
|
12
|
+
when Array === method
|
13
|
+
method = Set.new method
|
14
|
+
with_unnamed do
|
15
|
+
case type
|
16
|
+
when :single
|
17
|
+
through do |key, value|
|
18
|
+
new[key] = value if invert ^ (method.include? key or method.include? value)
|
19
|
+
end
|
20
|
+
when :list, :flat
|
21
|
+
through do |key, values|
|
22
|
+
new[key] = values if invert ^ (method.include? key or (method & values).length > 0)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
through do |key, values|
|
26
|
+
new[key] = values if invert ^ (method.include? key or (method & values.flatten).length > 0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
when Regexp === method
|
31
|
+
with_unnamed do
|
32
|
+
through do |key, values|
|
33
|
+
new[key] = values if invert ^ ([key,values].flatten.select{|v| v =~ method}.any?)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
when (String === method || Symbol === method)
|
37
|
+
if block_given?
|
38
|
+
case
|
39
|
+
when block.arity == 1
|
40
|
+
with_unnamed do
|
41
|
+
case
|
42
|
+
when (method == key_field or method == :key)
|
43
|
+
through do |key, values|
|
44
|
+
new[key] = values if invert ^ (yield(key))
|
45
|
+
end
|
46
|
+
when (type == :single or type == :flat)
|
47
|
+
through do |key, value|
|
48
|
+
new[key] = value if invert ^ (yield(value))
|
49
|
+
end
|
50
|
+
else
|
51
|
+
pos = identify_field method
|
52
|
+
raise "Field #{ method } not identified. Available: #{ fields * ", " }" if pos.nil?
|
53
|
+
|
54
|
+
through do |key, values|
|
55
|
+
new[key] = values if invert ^ (yield(values[pos]))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
when block.arity == 2
|
60
|
+
with_unnamed do
|
61
|
+
case
|
62
|
+
when (method == key_field or method == :key)
|
63
|
+
through do |key, values|
|
64
|
+
new[key] = values if invert ^ (yield(key, key))
|
65
|
+
end
|
66
|
+
when (type == :single or type == :flat)
|
67
|
+
through do |key, value|
|
68
|
+
new[key] = value if invert ^ (yield(key, value))
|
69
|
+
end
|
70
|
+
else
|
71
|
+
pos = identify_field method
|
72
|
+
through do |key, values|
|
73
|
+
new[key] = values if invert ^ (yield(key, values[pos]))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
else
|
81
|
+
with_unnamed do
|
82
|
+
through do |key, values|
|
83
|
+
new[key] = values if invert ^ ([key,values].flatten.select{|v| v == method}.any?)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
when Hash === method
|
88
|
+
key = method.keys.first
|
89
|
+
method = method.values.first
|
90
|
+
case
|
91
|
+
when (Array === method and (key == :key or key_field == key))
|
92
|
+
with_unnamed do
|
93
|
+
Annotated.purge(method).each{|key|
|
94
|
+
new[key] = self[key] if invert ^ (self.include? key)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
when Array === method
|
98
|
+
with_unnamed do
|
99
|
+
method = Set.new method unless Set === method
|
100
|
+
case type
|
101
|
+
when :single
|
102
|
+
through :key, key do |key, value|
|
103
|
+
new[key] = self[key] if invert ^ (method.include? value)
|
104
|
+
end
|
105
|
+
when :list
|
106
|
+
through :key, key do |key, values|
|
107
|
+
new[key] = self[key] if invert ^ (method.include? values.first)
|
108
|
+
end
|
109
|
+
when :flat #untested
|
110
|
+
through :key, key do |key, values|
|
111
|
+
new[key] = self[key] if invert ^ ((method & values.flatten).any?)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
through :key, key do |key, values|
|
115
|
+
new[key] = self[key] if invert ^ ((method & values.flatten).any?)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
when Regexp === method
|
121
|
+
with_unnamed do
|
122
|
+
through :key, key do |key, values|
|
123
|
+
values = [values] if type == :single
|
124
|
+
new[key] = self[key] if invert ^ (values.flatten.select{|v| v =~ method}.any?)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
when (String === method and method =~ /name:(.*)/)
|
129
|
+
name = $1
|
130
|
+
old_unnamed = self.unnamed
|
131
|
+
self.unnamed = false
|
132
|
+
if name.strip =~ /^\/(.*)\/$/
|
133
|
+
regexp = Regexp.new $1
|
134
|
+
through :key, key do |key, values|
|
135
|
+
case type
|
136
|
+
when :single
|
137
|
+
values = values.annotate([values])
|
138
|
+
when :double
|
139
|
+
values = values[0]
|
140
|
+
end
|
141
|
+
new[key] = self[key] if invert ^ (values.select{|v| v.name =~ regexp}.any?)
|
142
|
+
end
|
143
|
+
else
|
144
|
+
through :key, key do |key, values|
|
145
|
+
case type
|
146
|
+
when :single
|
147
|
+
values = values.annotate([values])
|
148
|
+
when :double
|
149
|
+
values = values[0]
|
150
|
+
end
|
151
|
+
new[key] = self[key] if invert ^ (values.select{|v| v.name == name}.any?)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
self.unnamed = old_unnamed
|
155
|
+
|
156
|
+
when String === method
|
157
|
+
if method =~ /^([<>]=?)(.*)/
|
158
|
+
with_unnamed do
|
159
|
+
through :key, key do |key, values|
|
160
|
+
value = Array === values ? values.flatten.first : values
|
161
|
+
new[key] = self[key] if value.to_f.send($1, $2.to_f)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
else
|
165
|
+
with_unnamed do
|
166
|
+
through :key, key do |key, values|
|
167
|
+
values = [values] if type == :single
|
168
|
+
new[key] = self[key] if invert ^ (values.flatten.select{|v| v == method}.length > 0)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
when Numeric === method
|
173
|
+
with_unnamed do
|
174
|
+
through :key, key do |key, values|
|
175
|
+
new[key] = self[key] if invert ^ (values.flatten.length >= method)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
when Proc === method
|
179
|
+
with_unnamed do
|
180
|
+
through :key, key do |key, values|
|
181
|
+
values = [values] if type == :single
|
182
|
+
new[key] = self[key] if invert ^ (values.flatten.select{|v| method.call(v)}.length > 0)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
new
|
188
|
+
end
|
189
|
+
|
190
|
+
def reorder(key_field = nil, fields = nil, merge: true, one2one: :fill)
|
191
|
+
res = self.annotate({})
|
192
|
+
key_field_name, field_names = through key_field, fields, one2one: one2one do |k,v|
|
193
|
+
if @type == :double && merge && res.include?(k)
|
194
|
+
current = res[k]
|
195
|
+
if merge == :concat
|
196
|
+
v.each_with_index do |new,i|
|
197
|
+
next if new.empty?
|
198
|
+
current[i].concat(new)
|
199
|
+
end
|
200
|
+
else
|
201
|
+
merged = []
|
202
|
+
v.each_with_index do |new,i|
|
203
|
+
next if new.empty?
|
204
|
+
merged[i] = current[i] + new
|
205
|
+
end
|
206
|
+
res[k] = merged
|
207
|
+
end
|
208
|
+
else
|
209
|
+
res[k] = v
|
210
|
+
end
|
211
|
+
end
|
212
|
+
res.key_field = key_field_name
|
213
|
+
res.fields = field_names
|
214
|
+
res
|
215
|
+
end
|
216
|
+
|
217
|
+
def slice(fields)
|
218
|
+
reorder :key, fields
|
219
|
+
end
|
220
|
+
end
|
data/lib/scout/tsv/util.rb
CHANGED
@@ -1,24 +1,82 @@
|
|
1
1
|
#require_relative '../../../modules/rbbt-util/lib/rbbt/tsv/manipulate'
|
2
2
|
#Log.warn "USING OLD RBBT CODE: #{__FILE__}"
|
3
|
+
require_relative 'traverse'
|
4
|
+
require_relative 'util/process'
|
5
|
+
require_relative 'util/select'
|
3
6
|
module TSV
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# end
|
10
|
-
# end
|
11
|
-
#end
|
12
|
-
|
13
|
-
#[:select, :reject].each do |method|
|
14
|
-
# define_method(method) do |*args,&block|
|
15
|
-
# res = super(*args) do |k,v|
|
16
|
-
# NamedArray.setup(v, @fields) unless @unnamed
|
17
|
-
# block.call k, v
|
18
|
-
# end
|
19
|
-
# self.annotate(res)
|
20
|
-
# res
|
21
|
-
# end
|
22
|
-
#end
|
7
|
+
def [](*args)
|
8
|
+
v = super(*args)
|
9
|
+
NamedArray.setup(v, @fields) unless @unnamed || ! (Array === v)
|
10
|
+
v
|
11
|
+
end
|
23
12
|
|
13
|
+
def each(*args, &block)
|
14
|
+
if block_given?
|
15
|
+
super(*args) do |k,v|
|
16
|
+
NamedArray.setup(v, @fields) unless @unnamed || ! (Array === v)
|
17
|
+
block.call(k, v)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
super(*args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def collect(*args, &block)
|
25
|
+
if block_given?
|
26
|
+
res = []
|
27
|
+
each do |k,v|
|
28
|
+
res << yield(k, v)
|
29
|
+
end
|
30
|
+
res
|
31
|
+
else
|
32
|
+
super(*args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_unnamed
|
37
|
+
begin
|
38
|
+
old_unnamed = unnamed
|
39
|
+
unnamed = true
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
unnamed = old_unnamed
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def summary
|
47
|
+
key = nil
|
48
|
+
values = nil
|
49
|
+
self.each do |k, v|
|
50
|
+
key = k
|
51
|
+
values = v
|
52
|
+
break
|
53
|
+
end
|
54
|
+
|
55
|
+
filename = @filename
|
56
|
+
filename = "No filename" if filename.nil? || filename.empty?
|
57
|
+
filename.find if Path === filename
|
58
|
+
filename = File.basename(filename) + " [" + File.basename(persistence_path) + "]" if respond_to?(:persistence_path) and persistence_path
|
59
|
+
|
60
|
+
with_unnamed do
|
61
|
+
<<-EOF
|
62
|
+
Filename = #{filename}
|
63
|
+
Key field = #{key_field || "*No key field*"}
|
64
|
+
Fields = #{fields ? Log.fingerprint(fields) : "*No field info*"}
|
65
|
+
Type = #{type}
|
66
|
+
Size = #{size}
|
67
|
+
namespace = #{Log.fingerprint namespace}
|
68
|
+
identifiers = #{Log.fingerprint identifiers}
|
69
|
+
Example:
|
70
|
+
- #{key} -- #{Log.fingerprint values }
|
71
|
+
EOF
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def all_fields
|
76
|
+
[@key_field] + @fields
|
77
|
+
end
|
78
|
+
|
79
|
+
def fingerprint
|
80
|
+
"TSV:{"<< Log.fingerprint(self.all_fields|| []) << ";" << Log.fingerprint(self.keys) << "}"
|
81
|
+
end
|
24
82
|
end
|
data/lib/scout/tsv.rb
CHANGED
@@ -6,10 +6,11 @@ require_relative 'tsv/persist'
|
|
6
6
|
require_relative 'tsv/index'
|
7
7
|
require_relative 'tsv/path'
|
8
8
|
require_relative 'tsv/traverse'
|
9
|
+
require_relative 'tsv/open'
|
9
10
|
|
10
11
|
module TSV
|
11
12
|
extend MetaExtension
|
12
|
-
extension_attr :key_field, :fields, :type, :filename, :namespace, :unnamed
|
13
|
+
extension_attr :key_field, :fields, :type, :filename, :namespace, :unnamed, :identifiers
|
13
14
|
|
14
15
|
def self.open(file, options = {})
|
15
16
|
persist, type = IndiferentHash.process_options options, :persist, :persist_type, :persist => false, :persist_type => "HDB"
|
@@ -22,6 +23,5 @@ module TSV
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
26
|
end
|
27
27
|
|