scout-gear 7.1.0 → 7.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.vimproject +65 -2
- data/VERSION +1 -1
- data/bin/scout +5 -1
- data/lib/rbbt-scout.rb +5 -0
- data/lib/scout/concurrent_stream.rb +13 -8
- data/lib/scout/config.rb +168 -0
- data/lib/scout/exceptions.rb +5 -3
- data/lib/scout/indiferent_hash/options.rb +1 -0
- data/lib/scout/indiferent_hash.rb +4 -2
- data/lib/scout/log/color.rb +3 -2
- data/lib/scout/log/progress/report.rb +1 -0
- data/lib/scout/log/progress/util.rb +66 -1
- data/lib/scout/log/progress.rb +5 -3
- data/lib/scout/log.rb +3 -2
- data/lib/scout/misc/helper.rb +31 -0
- data/lib/scout/misc/monitor.rb +4 -1
- data/lib/scout/misc/system.rb +15 -0
- data/lib/scout/misc.rb +2 -0
- data/lib/scout/named_array.rb +68 -0
- data/lib/scout/open/stream.rb +58 -33
- data/lib/scout/path/find.rb +27 -3
- data/lib/scout/path/util.rb +7 -4
- data/lib/scout/persist/serialize.rb +7 -14
- data/lib/scout/persist.rb +46 -12
- data/lib/scout/resource/produce.rb +7 -94
- data/lib/scout/resource/software.rb +176 -0
- data/lib/scout/semaphore.rb +8 -1
- data/lib/scout/tsv/dumper.rb +112 -0
- data/lib/scout/tsv/index.rb +161 -0
- data/lib/scout/tsv/open.rb +128 -0
- data/lib/scout/tsv/parser.rb +230 -30
- data/lib/scout/tsv/path.rb +13 -0
- data/lib/scout/tsv/persist/adapter.rb +367 -0
- 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 +113 -0
- data/lib/scout/tsv/persist.rb +13 -0
- data/lib/scout/tsv/traverse.rb +143 -0
- 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 +82 -0
- data/lib/scout/tsv.rb +16 -3
- data/lib/scout/work_queue/worker.rb +4 -4
- data/lib/scout/work_queue.rb +22 -7
- data/lib/scout/workflow/definition.rb +101 -4
- data/lib/scout/workflow/step/config.rb +18 -0
- data/lib/scout/workflow/step/dependencies.rb +40 -0
- data/lib/scout/workflow/step/file.rb +15 -0
- data/lib/scout/workflow/step/info.rb +35 -4
- data/lib/scout/workflow/step/progress.rb +14 -0
- data/lib/scout/workflow/step/provenance.rb +148 -0
- data/lib/scout/workflow/step.rb +71 -17
- data/lib/scout/workflow/task.rb +10 -5
- data/lib/scout/workflow/usage.rb +3 -1
- data/lib/scout/workflow.rb +11 -3
- data/lib/scout-gear.rb +1 -0
- data/lib/scout.rb +1 -0
- data/scout-gear.gemspec +64 -10
- data/scout_commands/find +1 -1
- data/scout_commands/workflow/task +16 -9
- data/scout_commands/workflow/task_old +2 -2
- data/share/software/install_helpers +523 -0
- data/test/scout/log/test_progress.rb +0 -2
- data/test/scout/misc/test_system.rb +21 -0
- data/test/scout/open/test_stream.rb +160 -1
- data/test/scout/path/test_find.rb +14 -7
- data/test/scout/resource/test_software.rb +24 -0
- data/test/scout/test_config.rb +66 -0
- data/test/scout/test_meta_extension.rb +10 -0
- data/test/scout/test_named_array.rb +19 -0
- data/test/scout/test_persist.rb +96 -0
- data/test/scout/test_tmpfile.rb +1 -1
- data/test/scout/test_tsv.rb +50 -1
- data/test/scout/test_work_queue.rb +41 -13
- data/test/scout/tsv/persist/test_adapter.rb +44 -0
- data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
- data/test/scout/tsv/persist/test_tokyocabinet.rb +92 -0
- data/test/scout/tsv/test_dumper.rb +44 -0
- data/test/scout/tsv/test_index.rb +156 -0
- data/test/scout/tsv/test_open.rb +9 -0
- data/test/scout/tsv/test_parser.rb +114 -3
- data/test/scout/tsv/test_persist.rb +43 -0
- data/test/scout/tsv/test_traverse.rb +116 -0
- 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 +66 -9
- data/test/scout/workflow/step/test_dependencies.rb +25 -0
- data/test/scout/workflow/step/test_info.rb +15 -17
- data/test/scout/workflow/step/test_load.rb +19 -21
- data/test/scout/workflow/step/test_provenance.rb +25 -0
- data/test/scout/workflow/test_step.rb +206 -10
- data/test/scout/workflow/test_task.rb +0 -3
- data/test/test_helper.rb +9 -1
- metadata +50 -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
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#require_relative '../../../modules/rbbt-util/lib/rbbt/tsv/manipulate'
|
2
|
+
#Log.warn "USING OLD RBBT CODE: #{__FILE__}"
|
3
|
+
require_relative 'traverse'
|
4
|
+
require_relative 'util/process'
|
5
|
+
require_relative 'util/select'
|
6
|
+
module TSV
|
7
|
+
def [](*args)
|
8
|
+
v = super(*args)
|
9
|
+
NamedArray.setup(v, @fields) unless @unnamed || ! (Array === v)
|
10
|
+
v
|
11
|
+
end
|
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
|
82
|
+
end
|
data/lib/scout/tsv.rb
CHANGED
@@ -1,13 +1,26 @@
|
|
1
1
|
require_relative 'meta_extension'
|
2
|
+
require_relative 'tsv/util'
|
2
3
|
require_relative 'tsv/parser'
|
4
|
+
require_relative 'tsv/dumper'
|
5
|
+
require_relative 'tsv/persist'
|
6
|
+
require_relative 'tsv/index'
|
7
|
+
require_relative 'tsv/path'
|
8
|
+
require_relative 'tsv/traverse'
|
9
|
+
require_relative 'tsv/open'
|
3
10
|
|
4
11
|
module TSV
|
5
12
|
extend MetaExtension
|
6
|
-
extension_attr :key_field, :fields
|
13
|
+
extension_attr :key_field, :fields, :type, :filename, :namespace, :unnamed, :identifiers
|
7
14
|
|
8
15
|
def self.open(file, options = {})
|
9
|
-
|
10
|
-
|
16
|
+
persist, type = IndiferentHash.process_options options, :persist, :persist_type, :persist => false, :persist_type => "HDB"
|
17
|
+
Persist.persist(file, type, options.merge(:persist => persist)) do |filename|
|
18
|
+
data = filename ? ScoutCabinet.open(filename, true, type) : nil
|
19
|
+
options[:data] = data if data
|
20
|
+
options[:filename] = file
|
21
|
+
Open.open(file) do |f|
|
22
|
+
TSV.parse(f, **options)
|
23
|
+
end
|
11
24
|
end
|
12
25
|
end
|
13
26
|
end
|