scout-gear 7.1.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.
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