scout-gear 7.1.0 → 7.2.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 +29 -0
- data/VERSION +1 -1
- data/bin/scout +5 -1
- data/lib/rbbt-scout.rb +5 -0
- data/lib/scout/concurrent_stream.rb +6 -2
- data/lib/scout/config.rb +168 -0
- data/lib/scout/exceptions.rb +4 -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 -1
- data/lib/scout/log/progress/report.rb +1 -0
- data/lib/scout/log/progress/util.rb +1 -1
- data/lib/scout/log/progress.rb +5 -3
- data/lib/scout/log.rb +3 -2
- data/lib/scout/misc/monitor.rb +3 -0
- data/lib/scout/misc/system.rb +15 -0
- data/lib/scout/misc.rb +1 -0
- data/lib/scout/named_array.rb +68 -0
- data/lib/scout/open/stream.rb +38 -7
- 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 +21 -1
- data/lib/scout/resource/produce.rb +7 -94
- data/lib/scout/resource/software.rb +176 -0
- data/lib/scout/tsv/dumper.rb +107 -0
- data/lib/scout/tsv/index.rb +49 -0
- data/lib/scout/tsv/parser.rb +203 -30
- data/lib/scout/tsv/path.rb +13 -0
- data/lib/scout/tsv/persist/adapter.rb +348 -0
- data/lib/scout/tsv/persist/tokyocabinet.rb +113 -0
- data/lib/scout/tsv/persist.rb +15 -0
- data/lib/scout/tsv/traverse.rb +48 -0
- data/lib/scout/tsv/util.rb +24 -0
- data/lib/scout/tsv.rb +16 -3
- data/lib/scout/work_queue/worker.rb +3 -3
- data/lib/scout/work_queue.rb +22 -7
- data/lib/scout/workflow/definition.rb +93 -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 +31 -4
- data/lib/scout/workflow/step/provenance.rb +148 -0
- data/lib/scout/workflow/step.rb +68 -19
- data/lib/scout/workflow/task.rb +3 -2
- data/lib/scout/workflow/usage.rb +1 -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 +34 -3
- data/scout_commands/find +1 -1
- data/scout_commands/workflow/task +16 -10
- 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 +159 -0
- 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 +35 -0
- data/test/scout/test_tmpfile.rb +2 -2
- data/test/scout/test_tsv.rb +41 -1
- data/test/scout/test_work_queue.rb +40 -13
- data/test/scout/tsv/persist/test_adapter.rb +34 -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 +64 -0
- data/test/scout/tsv/test_parser.rb +86 -0
- data/test/scout/tsv/test_persist.rb +36 -0
- data/test/scout/tsv/test_traverse.rb +9 -0
- data/test/scout/tsv/test_util.rb +0 -0
- data/test/scout/work_queue/test_worker.rb +3 -3
- 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 +16 -18
- 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 +6 -0
- metadata +33 -2
data/lib/scout/tsv/parser.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative '../named_array'
|
1
2
|
module TSV
|
2
3
|
def self.cast_value(value, cast)
|
3
4
|
if Array === value
|
@@ -13,9 +14,11 @@ module TSV
|
|
13
14
|
if positions.nil? && key == 0
|
14
15
|
key = items.shift
|
15
16
|
elsif positions.nil?
|
16
|
-
key = items.
|
17
|
+
key = items.delete_at(key)
|
18
|
+
key = key.split(sep2) if type == :double
|
17
19
|
else
|
18
20
|
key, items = items[key], items.values_at(*positions)
|
21
|
+
key = key.split(sep2) if type == :double
|
19
22
|
end
|
20
23
|
|
21
24
|
items = case type
|
@@ -29,7 +32,6 @@ module TSV
|
|
29
32
|
items.collect{|i| i.split(sep2, -1) }
|
30
33
|
end
|
31
34
|
|
32
|
-
key = key.partition(sep2).first if type == :double
|
33
35
|
|
34
36
|
if cast
|
35
37
|
items = cast_value(items, cast)
|
@@ -38,10 +40,12 @@ module TSV
|
|
38
40
|
[key, items]
|
39
41
|
end
|
40
42
|
|
41
|
-
def self.parse_stream(stream, data: nil,
|
43
|
+
def self.parse_stream(stream, data: nil, source_type: nil, type: :list, merge: true, one2one: false, fix: true, bar: false, first_line: nil, **kargs, &block)
|
42
44
|
begin
|
43
45
|
bar = Log::ProgressBar.new_bar(bar) if bar
|
44
46
|
|
47
|
+
source_type = type if source_type.nil?
|
48
|
+
|
45
49
|
data = {} if data.nil?
|
46
50
|
merge = false if type != :double
|
47
51
|
line = first_line || stream.gets
|
@@ -50,30 +54,85 @@ module TSV
|
|
50
54
|
line.strip!
|
51
55
|
line = Misc.fixutf8(line) if fix
|
52
56
|
bar.tick if bar
|
53
|
-
key, items = parse_line(line, type:
|
57
|
+
key, items = parse_line(line, type: source_type, **kargs)
|
54
58
|
|
55
|
-
if
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
if Array === key
|
60
|
+
keys = key
|
61
|
+
if one2one
|
62
|
+
key_items = keys.length.times.collect{|i| items.collect{|list| [list[i] || list[0]] } }
|
63
|
+
else
|
64
|
+
key_items = false
|
65
|
+
end
|
66
|
+
else
|
67
|
+
keys = [key]
|
68
|
+
key_items = false
|
59
69
|
end
|
60
70
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
71
|
+
keys.each_with_index do |key,i|
|
72
|
+
if key_items
|
73
|
+
these_items = key_items[i]
|
74
|
+
else
|
75
|
+
these_items = items
|
76
|
+
end
|
77
|
+
|
78
|
+
these_items = case [source_type, type]
|
79
|
+
when [:single, :single]
|
80
|
+
these_items
|
81
|
+
when [:list, :single]
|
82
|
+
these_items.first
|
83
|
+
when [:flat, :single]
|
84
|
+
these_items.first
|
85
|
+
when [:double, :single]
|
86
|
+
these_items.first.first
|
87
|
+
when [:single, :list]
|
88
|
+
[these_items]
|
89
|
+
when [:list, :list]
|
90
|
+
these_items
|
91
|
+
when [:flat, :list]
|
92
|
+
these_items
|
93
|
+
when [:double, :list]
|
94
|
+
these_items.collect{|l| l.first }
|
95
|
+
when [:single, :flat]
|
96
|
+
[these_items]
|
97
|
+
when [:list, :flat]
|
98
|
+
these_items
|
99
|
+
when [:flat, :flat]
|
100
|
+
these_items
|
101
|
+
when [:double, :flat]
|
102
|
+
these_items.flatten
|
103
|
+
when [:single, :double]
|
104
|
+
[[these_items]]
|
105
|
+
when [:list, :double]
|
106
|
+
these_items.collect{|l| [l] }
|
107
|
+
when [:flat, :double]
|
108
|
+
[these_items]
|
109
|
+
when [:double, :double]
|
110
|
+
these_items
|
111
|
+
end
|
112
|
+
|
113
|
+
if block_given?
|
114
|
+
res = block.call(key, these_items)
|
115
|
+
data[key] = res unless res.nil? || FalseClass === data
|
116
|
+
next
|
117
|
+
end
|
118
|
+
|
119
|
+
if ! merge || ! data.include?(key)
|
120
|
+
data[key] = these_items
|
70
121
|
else
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
122
|
+
current = data[key]
|
123
|
+
if merge == :concat
|
124
|
+
these_items.each_with_index do |new,i|
|
125
|
+
next if new.empty?
|
126
|
+
current[i].concat(new)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
merged = []
|
130
|
+
these_items.each_with_index do |new,i|
|
131
|
+
next if new.empty?
|
132
|
+
merged[i] = current[i] + new
|
133
|
+
end
|
134
|
+
data[key] = merged
|
75
135
|
end
|
76
|
-
data[key] = merged
|
77
136
|
end
|
78
137
|
end
|
79
138
|
ensure
|
@@ -86,7 +145,7 @@ module TSV
|
|
86
145
|
end
|
87
146
|
end
|
88
147
|
|
89
|
-
def self.parse_header(stream, fix: true, header_hash: '#', sep: "\
|
148
|
+
def self.parse_header(stream, fix: true, header_hash: '#', sep: "\t")
|
90
149
|
raise "Closed stream" if IO === stream && stream.closed?
|
91
150
|
|
92
151
|
options = {}
|
@@ -131,14 +190,128 @@ module TSV
|
|
131
190
|
[options, key_field, fields, first_line, preamble]
|
132
191
|
end
|
133
192
|
|
134
|
-
|
135
|
-
|
193
|
+
KEY_PARAMETERS = begin
|
194
|
+
params = []
|
195
|
+
(method(:parse_line).parameters + method(:parse_stream).parameters).each do |type, name|
|
196
|
+
params << name if type == :key
|
197
|
+
end
|
198
|
+
params
|
199
|
+
end
|
200
|
+
|
201
|
+
class Parser
|
202
|
+
attr_accessor :stream, :options, :key_field, :fields, :first_line, :preamble
|
203
|
+
def initialize(file, fix: true, header_hash: "#", sep: "\t")
|
204
|
+
if IO === file
|
205
|
+
@stream = file
|
206
|
+
else
|
207
|
+
@stream = Open.open(file)
|
208
|
+
end
|
209
|
+
@options, @key_field, @fields, @first_line, @preamble = TSV.parse_header(@stream, fix:fix, header_hash:header_hash, sep:sep)
|
210
|
+
@options[:sep] = sep if @options[:sep].nil?
|
211
|
+
end
|
212
|
+
|
213
|
+
def all_fields
|
214
|
+
[@key_field] + @fields
|
215
|
+
end
|
216
|
+
|
217
|
+
def traverse(key_field: nil, fields: nil, filename: nil, namespace: nil, **kwargs, &block)
|
218
|
+
if fields
|
219
|
+
all_field_names ||= [@key_field] + @fields
|
220
|
+
positions = NamedArray.identify_name(all_field_names, fields)
|
221
|
+
kwargs[:positions] = positions
|
222
|
+
field_names = all_field_names.values_at *positions
|
223
|
+
else
|
224
|
+
field_names = @fields
|
225
|
+
end
|
226
|
+
|
227
|
+
if key_field
|
228
|
+
all_field_names ||= [@key_field] + @fields
|
229
|
+
key = NamedArray.identify_name(all_field_names, key_field)
|
230
|
+
kwargs[:key] = key
|
231
|
+
key_field_name = all_field_names[key]
|
232
|
+
if fields.nil?
|
233
|
+
field_names = all_field_names - [@key_field]
|
234
|
+
end
|
235
|
+
else
|
236
|
+
key_field_name = @key_field
|
237
|
+
end
|
238
|
+
|
239
|
+
@options.each do |option,value|
|
240
|
+
option = option.to_sym
|
241
|
+
next unless KEY_PARAMETERS.include? option
|
242
|
+
kwargs[option] = value unless kwargs.include?(option)
|
243
|
+
end
|
244
|
+
|
245
|
+
kwargs[:source_type] = @options[:type]
|
246
|
+
kwargs[:data] = false if kwargs[:data].nil?
|
247
|
+
|
248
|
+
data = TSV.parse_stream(@stream, first_line: @first_line, **kwargs, &block)
|
249
|
+
|
250
|
+
TSV.setup(data, :key_field => key_field_name, :fields => field_names, :type => @type) if data
|
251
|
+
|
252
|
+
data || self
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.parse(stream, fix: true, header_hash: "#", sep: "\t", filename: nil, namespace: nil, **kwargs, &block)
|
258
|
+
parser = TSV::Parser.new stream, fix: fix, header_hash: header_hash, sep: sep
|
259
|
+
kwargs = parser.options.merge(kwargs)
|
136
260
|
|
137
|
-
|
138
|
-
|
139
|
-
|
261
|
+
type = kwargs[:type] ||= :double
|
262
|
+
if (data = kwargs[:data]) && data.respond_to?(:persistence_class)
|
263
|
+
TSV.setup(data, type: type)
|
264
|
+
data.extend TSVAdapter
|
140
265
|
end
|
141
|
-
|
142
|
-
|
266
|
+
|
267
|
+
kwargs[:data] = {} if kwargs[:data].nil?
|
268
|
+
|
269
|
+
data = parser.traverse **kwargs, &block
|
270
|
+
data.type = type
|
271
|
+
data.filename = filename
|
272
|
+
data.namespace = namespace
|
273
|
+
data
|
143
274
|
end
|
275
|
+
|
276
|
+
#def self.parse_alt(stream, key_field: nil, fields: nil, filename: nil, namespace: nil, **kwargs, &block)
|
277
|
+
# options, key_field_name, field_names, first_line, preamble = parse_header(stream)
|
278
|
+
|
279
|
+
# if fields
|
280
|
+
# all_field_names ||= [key_field_name] + field_names
|
281
|
+
# positions = NamedArray.identify_name(all_field_names, fields)
|
282
|
+
# kwargs[:positions] = positions
|
283
|
+
# field_names = all_field_names.values_at *positions
|
284
|
+
# end
|
285
|
+
|
286
|
+
# if key_field
|
287
|
+
# all_field_names ||= [key_field_name] + field_names
|
288
|
+
# key = NamedArray.identify_name(all_field_names, key_field)
|
289
|
+
# kwargs[:key] = key
|
290
|
+
# key_field_name = all_field_names[key]
|
291
|
+
# if fields.nil?
|
292
|
+
# field_names = all_field_names - [key_field_name]
|
293
|
+
# end
|
294
|
+
# end
|
295
|
+
|
296
|
+
# options.each do |option,value|
|
297
|
+
# option = option.to_sym
|
298
|
+
# next unless KEY_PARAMETERS.include? option
|
299
|
+
# kwargs[option] = value unless kwargs.include?(option)
|
300
|
+
# end
|
301
|
+
|
302
|
+
# kwargs[:source_type] = options[:type]
|
303
|
+
|
304
|
+
# type = kwargs[:type] ||= :double
|
305
|
+
# if (data = kwargs[:data]) && data.respond_to?(:persistence_class)
|
306
|
+
# TSV.setup(data, type: type, key_field: key_field_name, fields: field_names)
|
307
|
+
# data.extend TSVAdapter
|
308
|
+
# end
|
309
|
+
|
310
|
+
# data = parse_stream(stream, first_line: first_line, **kwargs, &block)
|
311
|
+
|
312
|
+
# TSV.setup(data, :key_field => key_field_name, :fields => field_names, :type => type, filename: filename, namespace: namespace)
|
313
|
+
|
314
|
+
# data
|
315
|
+
#end
|
316
|
+
|
144
317
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Path
|
2
|
+
def tsv(...)
|
3
|
+
found = self.find
|
4
|
+
found = self.set_extension('tsv').find unless found.exists?
|
5
|
+
TSV.open(found, ...)
|
6
|
+
end
|
7
|
+
|
8
|
+
def index(...)
|
9
|
+
found = self.find
|
10
|
+
found = self.set_extension('tsv').find unless found.exists?
|
11
|
+
TSV.index(found, ...)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
require_relative '../../open/lock'
|
2
|
+
|
3
|
+
module TSVAdapter
|
4
|
+
attr_accessor :persistence_path, :persistence_class, :closed, :writable
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :lock_dir
|
8
|
+
def lock_dir
|
9
|
+
@lock_dir ||= Path.setup('tmp/tsv_locks')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
EXTENSION_ATTR_HASH_KEY = "__extension_attr_hash__"
|
14
|
+
EXTENSION_ATTR_HASH_SERIALIZER = Marshal
|
15
|
+
|
16
|
+
def load_extension_attr_hash
|
17
|
+
EXTENSION_ATTR_HASH_SERIALIZER.load(self[EXTENSION_ATTR_HASH_KEY])
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_extension_attr_hash
|
21
|
+
self[EXTENSION_ATTR_HASH_KEY]= EXTENSION_ATTR_HASH_SERIALIZER.dump(self.extension_attr_hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.extended(base)
|
25
|
+
if base.include?(EXTENSION_ATTR_HASH_KEY)
|
26
|
+
TSV.setup(base, base.load_extension_attr_hash)
|
27
|
+
elsif TSV === base
|
28
|
+
base[EXTENSION_ATTR_HASH_KEY] = EXTENSION_ATTR_HASH_SERIALIZER.dump(base.extension_attr_hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
class << base
|
32
|
+
alias orig_set []=
|
33
|
+
alias orig_get []
|
34
|
+
|
35
|
+
def [](key)
|
36
|
+
self.read_lock do
|
37
|
+
load_value(super(key))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, value)
|
42
|
+
self.write_lock do
|
43
|
+
super(key, save_value(value))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
case base.type
|
49
|
+
when :single
|
50
|
+
class << base
|
51
|
+
def load_value(value)
|
52
|
+
value
|
53
|
+
end
|
54
|
+
def save_value(value)
|
55
|
+
value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
when :list, :flat
|
59
|
+
class << base
|
60
|
+
def load_value(value)
|
61
|
+
value.nil? ? nil : value.split("\t")
|
62
|
+
end
|
63
|
+
def save_value(value)
|
64
|
+
value * "\t"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
when :double
|
68
|
+
class << base
|
69
|
+
def load_value(value)
|
70
|
+
value.nil? ? nil : value.split("\t").collect{|v| v.split("|") }
|
71
|
+
end
|
72
|
+
def save_value(value)
|
73
|
+
value.collect{|v| v * "|" } * "\t"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def keys(*args)
|
80
|
+
k = self.read_lock do
|
81
|
+
super(*args)
|
82
|
+
end
|
83
|
+
|
84
|
+
if k[0] == EXTENSION_ATTR_HASH_KEY
|
85
|
+
k.slice(1,k.length-1)
|
86
|
+
elsif k[-1] == EXTENSION_ATTR_HASH_KEY
|
87
|
+
k.slice(0,k.length-2)
|
88
|
+
else
|
89
|
+
k - [EXTENSION_ATTR_HASH_KEY]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def each(&block)
|
94
|
+
self.read_lock do
|
95
|
+
super do |k,v|
|
96
|
+
next if k == EXTENSION_ATTR_HASH_KEY
|
97
|
+
yield(k, load_value(v))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def collect(&block)
|
103
|
+
res = []
|
104
|
+
if block_given?
|
105
|
+
each do |k,v|
|
106
|
+
res << yield(k, v)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
each do |k,v|
|
110
|
+
res << [k, v]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
res
|
114
|
+
end
|
115
|
+
|
116
|
+
def values
|
117
|
+
collect{|k,v| v }
|
118
|
+
end
|
119
|
+
|
120
|
+
alias map collect
|
121
|
+
|
122
|
+
def closed?
|
123
|
+
@closed
|
124
|
+
end
|
125
|
+
|
126
|
+
def write?
|
127
|
+
@writable
|
128
|
+
end
|
129
|
+
|
130
|
+
def read?
|
131
|
+
! (write? || closed?)
|
132
|
+
end
|
133
|
+
|
134
|
+
def write(*args)
|
135
|
+
begin
|
136
|
+
super(*args)
|
137
|
+
@writable = true
|
138
|
+
rescue NoMethodError
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def close(*args)
|
143
|
+
begin
|
144
|
+
super(*args)
|
145
|
+
@closed = true
|
146
|
+
rescue NoMethodError
|
147
|
+
end
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def read(*args)
|
152
|
+
begin
|
153
|
+
super(*args)
|
154
|
+
rescue NoMethodError
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def delete(key)
|
159
|
+
self.write_lock do
|
160
|
+
out(key)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def lock
|
165
|
+
return yield if @locked
|
166
|
+
lock_filename = Persist.persistence_path(persistence_path, {:dir => TSVAdapter.lock_dir})
|
167
|
+
Open.lock(lock_filename) do
|
168
|
+
begin
|
169
|
+
@locked = true
|
170
|
+
yield
|
171
|
+
ensure
|
172
|
+
@locked = false
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def lock_and_close
|
178
|
+
lock do
|
179
|
+
begin
|
180
|
+
yield
|
181
|
+
ensure
|
182
|
+
close
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def write_and_read
|
188
|
+
if write?
|
189
|
+
begin
|
190
|
+
return yield
|
191
|
+
ensure
|
192
|
+
read
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
lock do
|
197
|
+
write(true) if closed? || !write?
|
198
|
+
begin
|
199
|
+
yield
|
200
|
+
ensure
|
201
|
+
read
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def write_and_close
|
207
|
+
if write?
|
208
|
+
begin
|
209
|
+
return yield
|
210
|
+
ensure
|
211
|
+
close unless @locked
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
lock do
|
216
|
+
write(true) if closed? || ! write?
|
217
|
+
res = begin
|
218
|
+
yield
|
219
|
+
ensure
|
220
|
+
close
|
221
|
+
end
|
222
|
+
res
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def with_read(&block)
|
227
|
+
if read? || write?
|
228
|
+
return yield
|
229
|
+
else
|
230
|
+
read_and_close &block
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def with_write(&block)
|
235
|
+
if write?
|
236
|
+
return yield
|
237
|
+
else
|
238
|
+
if self.read?
|
239
|
+
self.write_and_read do
|
240
|
+
return yield
|
241
|
+
end
|
242
|
+
else
|
243
|
+
self.write_and_close do
|
244
|
+
return yield
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
def read_and_close
|
252
|
+
if read? || write?
|
253
|
+
begin
|
254
|
+
return yield
|
255
|
+
ensure
|
256
|
+
close unless @locked
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
lock do
|
261
|
+
read true if closed? || ! read?
|
262
|
+
begin
|
263
|
+
yield
|
264
|
+
ensure
|
265
|
+
close
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def read_lock
|
271
|
+
read if closed?
|
272
|
+
if read? || write?
|
273
|
+
return yield
|
274
|
+
end
|
275
|
+
|
276
|
+
lock do
|
277
|
+
close
|
278
|
+
read true
|
279
|
+
begin
|
280
|
+
yield
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def write_lock
|
286
|
+
write if closed?
|
287
|
+
if write?
|
288
|
+
return yield
|
289
|
+
end
|
290
|
+
|
291
|
+
lock do
|
292
|
+
close
|
293
|
+
write true
|
294
|
+
begin
|
295
|
+
yield
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def merge!(hash)
|
301
|
+
hash.each do |key,values|
|
302
|
+
self[key] = values
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def range(*args)
|
307
|
+
begin
|
308
|
+
self.read_lock do
|
309
|
+
super(*args)
|
310
|
+
end
|
311
|
+
rescue
|
312
|
+
[]
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def include?(*args)
|
317
|
+
self.read_lock do
|
318
|
+
super(*args) #- TSV::ENTRY_KEYS.to_a
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
MAX_CHAR = 255.chr
|
323
|
+
|
324
|
+
def prefix(key)
|
325
|
+
self.read_lock do
|
326
|
+
range(key, 1, key + MAX_CHAR, 1)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def get_prefix(key)
|
331
|
+
keys = prefix(key)
|
332
|
+
select(:key => keys)
|
333
|
+
end
|
334
|
+
|
335
|
+
def size(*args)
|
336
|
+
self.read_lock do
|
337
|
+
super(*args)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def values_at(*keys)
|
342
|
+
self.read_lock do
|
343
|
+
keys.collect do |k|
|
344
|
+
self[k]
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|