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