rbbt-util 2.1.0 → 3.0.2

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 (46) hide show
  1. data/bin/rbbt_query.rb +63 -0
  2. data/lib/rbbt-util.rb +5 -5
  3. data/lib/rbbt.rb +2 -11
  4. data/lib/rbbt/util/cmd.rb +1 -1
  5. data/lib/rbbt/util/fix_width_table.rb +9 -3
  6. data/lib/rbbt/util/log.rb +23 -7
  7. data/lib/rbbt/util/misc.rb +121 -15
  8. data/lib/rbbt/util/open.rb +14 -4
  9. data/lib/rbbt/util/persistence.rb +52 -21
  10. data/lib/rbbt/util/rake.rb +108 -21
  11. data/lib/rbbt/util/resource.rb +338 -0
  12. data/lib/rbbt/util/simpleDSL.rb +1 -1
  13. data/lib/rbbt/util/simpleopt.rb +1 -1
  14. data/lib/rbbt/util/task.rb +340 -0
  15. data/lib/rbbt/util/tc_hash.rb +19 -2
  16. data/lib/rbbt/util/tsv.rb +15 -10
  17. data/lib/rbbt/util/tsv/accessor.rb +16 -7
  18. data/lib/rbbt/util/tsv/attach.rb +220 -17
  19. data/lib/rbbt/util/tsv/index.rb +6 -1
  20. data/lib/rbbt/util/tsv/manipulate.rb +4 -5
  21. data/lib/rbbt/util/tsv/parse.rb +45 -21
  22. data/lib/rbbt/util/tsv/resource.rb +74 -0
  23. data/lib/rbbt/util/workflow.rb +99 -75
  24. data/test/rbbt/util/test_filecache.rb +2 -2
  25. data/test/rbbt/util/test_misc.rb +7 -2
  26. data/test/rbbt/util/test_persistence.rb +40 -5
  27. data/test/rbbt/util/test_resource.rb +92 -0
  28. data/test/rbbt/util/test_task.rb +118 -0
  29. data/test/rbbt/util/test_tsv.rb +5 -1
  30. data/test/rbbt/util/test_workflow.rb +77 -62
  31. data/test/rbbt/util/tsv/test_attach.rb +95 -7
  32. data/test/rbbt/util/tsv/test_index.rb +0 -1
  33. data/test/rbbt/util/tsv/test_manipulate.rb +20 -0
  34. data/test/rbbt/util/tsv/test_resource.rb +9 -0
  35. data/test/test_helper.rb +10 -0
  36. data/test/test_rbbt.rb +2 -37
  37. metadata +16 -18
  38. data/lib/rbbt/util/data_module.rb +0 -93
  39. data/lib/rbbt/util/path.rb +0 -155
  40. data/lib/rbbt/util/pkg_config.rb +0 -78
  41. data/lib/rbbt/util/pkg_data.rb +0 -119
  42. data/lib/rbbt/util/pkg_software.rb +0 -145
  43. data/test/rbbt/util/test_data_module.rb +0 -50
  44. data/test/rbbt/util/test_path.rb +0 -10
  45. data/test/rbbt/util/test_pkg_data.rb +0 -129
  46. data/test/test_pkg.rb +0 -28
@@ -1,3 +1,4 @@
1
+ require 'rbbt/util/resource'
1
2
  require 'rbbt/util/misc'
2
3
 
3
4
  class TSV
@@ -68,12 +69,12 @@ class TSV
68
69
  when (TSV === identifiers.first or identifiers.empty?)
69
70
  identifiers
70
71
  when
71
- identifiers.collect{|f| Path.path(f, datadir, namespace)}
72
+ identifiers.collect{|f| Resource::Path.path(f, nil, namespace)}
72
73
  end
73
74
  when (identifiers and not Array === identifiers)
74
- [Path.path(identifiers, datadir)]
75
+ [Resource::Path.path(identifiers, nil, namespace)]
75
76
  when filename
76
- Path.path(filename, datadir).identifier_files
77
+ Resource::Path.path(filename, nil, namespace).identifier_files
77
78
  else
78
79
  []
79
80
  end
@@ -176,7 +177,10 @@ class TSV
176
177
  if String === value && value =~ /__Ref:(.*)/
177
178
  return self[$1]
178
179
  else
179
- value = NamedArray.name value, fields if Array === value and fields
180
+
181
+ if Array === value and fields
182
+ value = NamedArray.name value, fields
183
+ end
180
184
  value
181
185
  end
182
186
  end
@@ -245,13 +249,18 @@ class TSV
245
249
  end
246
250
 
247
251
  def include?(key)
248
- data.include? key
252
+ @data.include? key
249
253
  end
250
254
 
251
- def to_s(keys = nil)
255
+ def to_s(keys = nil, no_options = false)
256
+ if FalseClass === keys or TrueClass === keys
257
+ no_options = keys
258
+ keys = nil
259
+ end
260
+
252
261
  str = ""
253
262
 
254
- str << "#: " << Misc.hash2string(EXTRA_ACCESSORS.collect{|key| [key, self.send(key)]}) << "\n"
263
+ str << "#: " << Misc.hash2string(EXTRA_ACCESSORS.collect{|key| [key, self.send(key)]}) << "\n" unless no_options
255
264
  if fields
256
265
  str << "#" << key_field << "\t" << fields * "\t" << "\n"
257
266
  end
@@ -1,5 +1,182 @@
1
1
  class TSV
2
+ def self.paste_merge(file1, file2, output, sep = "\t")
3
+ case
4
+ when (String === file1 and not file1.index("\n") and file1.length < 250 and File.exists?(file1))
5
+ file1 = CMD.cmd("sort -k1,1 -t'#{sep}' #{ file1 } | grep -v '^#{sep}' ", :pipe => true)
6
+ when (String === file1 or StringIO === file1)
7
+ file1 = CMD.cmd("sort -k1,1 -t'#{sep}' | grep -v '^#{sep}'", :in => file1, :pipe => true)
8
+ end
9
+
10
+ case
11
+ when (String === file2 and not file2.index("\n") and file2.length < 250 and File.exists?(file2))
12
+ file2 = CMD.cmd("sort -k1,1 -t'#{sep}' #{ file2 } | grep -v '^#{sep}' ", :pipe => true)
13
+ when (String === file2 or StringIO === file2)
14
+ file2 = CMD.cmd("sort -k1,1 -t'#{sep}' | grep -v '^#{sep}'", :in => file2, :pipe => true)
15
+ end
16
+
17
+ output = File.open(output, 'w') if String === output
18
+
19
+ cols1 = nil
20
+ cols2 = nil
21
+
22
+ done1 = false
23
+ done2 = false
24
+
25
+ key1 = key2 = nil
26
+ while key1.nil?
27
+ while (line1 = file1.gets) =~ /#/; end
28
+ key1, *parts1 = line1.sub("\n",'').split(sep, -1)
29
+ cols1 = parts1.length
30
+ end
31
+
32
+ while key2.nil?
33
+ while (line2 = file2.gets) =~ /#/; end
34
+ key2, *parts2 = line2.sub("\n",'').split(sep, -1)
35
+ cols2 = parts2.length
36
+ end
37
+
38
+ key = key1 < key2 ? key1 : key2
39
+ parts = [""] * (cols1 + cols2)
40
+ while not (done1 and done2)
41
+ while (not done1 and key1 == key)
42
+ parts1.each_with_index do |part, i|
43
+ parts[i] = (parts[i].nil? or parts[i].empty?) ? part : parts[i] << "|" << part
44
+ end
45
+ key1 = nil
46
+ while key1.nil? and not done1
47
+ if file1.eof?; done1 = true; else key1, *parts1 = file1.gets.sub("\n",'').split(sep, -1) end
48
+ end
49
+ end
50
+ while (not done2 and key2 == key)
51
+ parts2.each_with_index do |part, i|
52
+ i += cols1
53
+ parts[i] = (parts[i].nil? or parts[i].empty?) ? part : parts[i] << "|" << part
54
+ end
55
+ key2 = nil
56
+ while key2.nil? and not done2
57
+ if file2.eof?; done2 = true; else key2, *parts2 = file2.gets.sub("\n",'').split(sep, -1) end
58
+ end
59
+ end
60
+
61
+ output.puts [key, parts].flatten * sep
62
+ parts = [""] * (cols1 + cols2)
63
+
64
+ case
65
+ when done1
66
+ key = key2
67
+ when done2
68
+ key = key1
69
+ else
70
+ key = key1 < key2 ? key1 : key2
71
+ end
72
+ end
73
+
74
+ output.close
75
+ end
76
+
77
+ def self.paste(file1, file2, output, sep = "\t")
78
+ case
79
+ when (String === file1 and not file1.index("\n") and file1.length < 250 and File.exists?(file1))
80
+ file1 = CMD.cmd("sort -k1,1 -t'#{sep}' #{ file1 } ", :pipe => true)
81
+ when String === file1
82
+ file1 = CMD.cmd("sort -k1,1 -t'#{sep}'", :in => file1, :pipe => true)
83
+ end
84
+
85
+ case
86
+ when (String === file2 and not file2.index("\n") and file2.length < 250 and File.exists?(file2))
87
+ file2 = CMD.cmd("sort -k1,1 -t'#{sep}' #{ file2 } ", :pipe => true)
88
+ when String === file2
89
+ file2 = CMD.cmd("sort -k1,1 -t'#{sep}'", :in => file2, :pipe => true)
90
+ end
91
+
92
+ output = File.open(output, 'w') if String === output
93
+
94
+ cols1 = nil
95
+ cols2 = nil
96
+
97
+ done1 = false
98
+ done2 = false
99
+
100
+ while (line1 = file1.gets) =~ /#/; end
101
+ line1.strip!
102
+ parts1 = line1.split(sep)
103
+ key1 = parts1.shift
104
+ cols1 = parts1.length
2
105
 
106
+ while (line2 = file2.gets) =~ /#/; end
107
+ line2.strip!
108
+ parts2 = line2.split(sep)
109
+ key2 = parts2.shift
110
+ cols2 = parts2.length
111
+ while not (done1 or done2)
112
+ case
113
+ when key1 < key2
114
+ output.puts [key1, parts1, [""] * cols2] * sep
115
+ if file1.eof?
116
+ done1 = true
117
+ else
118
+ line1 = file1.gets
119
+ line1.strip!
120
+ parts1 = line1.split(sep)
121
+ key1 = parts1.shift
122
+ end
123
+ when key2 < key1
124
+ output.puts [key2, [""] * cols1, parts2] * sep
125
+ if file2.eof?
126
+ done2 = true
127
+ else
128
+ line2 = file2.gets
129
+ line2.strip!
130
+ parts2 = line2.split(sep)
131
+ key2 = parts2.shift
132
+ end
133
+ when key1 == key2
134
+ output.puts [key1, parts1, parts2] * sep
135
+ if file1.eof?
136
+ done1 = true
137
+ else
138
+ line1 = file1.gets
139
+ line1.strip!
140
+ parts1 = line1.split(sep)
141
+ key1 = parts1.shift
142
+ end
143
+ if file2.eof?
144
+ done2 = true
145
+ else
146
+ line2 = file2.gets
147
+ line2.strip!
148
+ parts2 = line2.split(sep)
149
+ key2 = parts2.shift
150
+ end
151
+ end
152
+ end
153
+
154
+ while not done1
155
+ output.puts [key1, parts1, [""] * cols2] * sep
156
+ if file1.eof?
157
+ done1 = true
158
+ else
159
+ line1 = file1.gets
160
+ line1.strip!
161
+ parts1 = line1.split(sep)
162
+ key1 = parts1.shift
163
+ end
164
+ end
165
+
166
+ while not done2
167
+ output.puts [key2, [""] * cols1, parts2] * sep
168
+ if file2.eof?
169
+ done2 = true
170
+ else
171
+ line2 = file2.gets
172
+ line2.strip!
173
+ parts2 = line2.split(sep)
174
+ key2 = parts2.shift
175
+ end
176
+ end
177
+
178
+ output.close
179
+ end
3
180
  #{{{ Attach Methods
4
181
 
5
182
  def attach_same_key(other, fields = nil)
@@ -26,7 +203,7 @@ class TSV
26
203
  def attach_source_key(other, source, fields = nil)
27
204
  fields = other.fields - [key_field].concat(self.fields) if fields.nil?
28
205
 
29
- other = other.tsv unless TSV === other
206
+ other = other.tsv(:persistence => :no_create) unless TSV === other
30
207
  field_positions = fields.collect{|field| other.identify_field field}
31
208
  field_names = field_positions.collect{|pos| pos == :key ? other.key_field : other.fields[pos] }
32
209
 
@@ -87,7 +264,11 @@ class TSV
87
264
  next unless other.include? source_key
88
265
  new_values = field_positions.collect do |pos|
89
266
  if pos == :key
90
- source_key
267
+ if other.type == :double
268
+ [source_key]
269
+ else
270
+ source_key
271
+ end
91
272
  else
92
273
  other[source_key][pos]
93
274
  end
@@ -119,7 +300,10 @@ class TSV
119
300
  #{{{ Attach Helper
120
301
 
121
302
  # May make an extra index!
122
- def self.find_path(files, in_namespace = false)
303
+ def self.find_path(files, options = {})
304
+ options = Misc.add_defaults options, :in_namespace => false
305
+ in_namespace = options[:in_namespace]
306
+
123
307
  if in_namespace
124
308
  ids = [files.first.all_namespace_fields(in_namespace)]
125
309
  ids += files[1..-1].collect{|f| f.all_fields}
@@ -128,9 +312,6 @@ class TSV
128
312
  end
129
313
  id_list = []
130
314
 
131
- ids.flatten.each do |field|
132
- end
133
-
134
315
  ids.each_with_index do |list, i|
135
316
  break if i == ids.length - 1
136
317
  match = list.select{|field|
@@ -148,8 +329,12 @@ class TSV
148
329
  end
149
330
  end
150
331
 
151
- def self.build_traverse_index(files, in_namespace = false)
152
- path = find_path(files, in_namespace)
332
+ def self.build_traverse_index(files, options = {})
333
+ options = Misc.add_defaults options, :in_namespace => false, :persist_input => false
334
+ in_namespace = options[:in_namespace]
335
+ persist_input = options[:persist_input]
336
+
337
+ path = find_path(files, options)
153
338
 
154
339
  return nil if path.nil?
155
340
 
@@ -157,11 +342,10 @@ class TSV
157
342
 
158
343
  Log.medium "Found Traversal: #{traversal_ids * " => "}"
159
344
 
160
- current_key = files.first.all_fields.first
161
- target = files.last.all_fields.first
162
- target = nil
163
345
  current_id, current_file = path.shift
164
- index = current_file.index :target => current_id, :fields => current_key, :persistence => false
346
+ current_key = current_file.all_fields.first
347
+
348
+ index = current_file.index :target => current_id, :fields => current_key, :persistence => persist_input
165
349
 
166
350
  while not path.empty?
167
351
  current_id, current_file = path.shift
@@ -175,7 +359,10 @@ class TSV
175
359
  index
176
360
  end
177
361
 
178
- def self.find_traversal(tsv1, tsv2, in_namespace = false)
362
+ def self.find_traversal(tsv1, tsv2, options = {})
363
+ options = Misc.add_defaults options, :in_namespace => false
364
+ in_namespace = options[:in_namespace]
365
+
179
366
  identifiers1 = tsv1.identifier_files || []
180
367
  identifiers2 = tsv2.identifier_files || []
181
368
 
@@ -188,7 +375,7 @@ class TSV
188
375
  files1.push identifiers1.shift
189
376
  identifiers2.each_with_index do |e,i|
190
377
  files2 = identifiers2[(0..i)]
191
- index = build_traverse_index(files1 + files2.reverse, in_namespace)
378
+ index = build_traverse_index(files1 + files2.reverse, options)
192
379
  return index if not index.nil?
193
380
  end
194
381
  end
@@ -197,8 +384,8 @@ class TSV
197
384
  end
198
385
 
199
386
  def attach(other, fields = nil, options = {})
200
- options = Misc.add_defaults options, :in_namespace => true
201
- in_namespace = Misc.process_options options, :in_namespace
387
+ options = Misc.add_defaults options, :in_namespace => false
388
+ in_namespace = options[:in_namespace]
202
389
 
203
390
  fields = other.fields - [key_field].concat(self.fields) if fields == :all
204
391
  fields = other.fields_in_namespace - [key_field].concat(self.fields) if fields.nil?
@@ -211,7 +398,7 @@ class TSV
211
398
  when (in_namespace and self.fields_in_namespace.include?(other.key_field))
212
399
  attach_source_key other, other.key_field, fields
213
400
  else
214
- index = TSV.find_traversal(self, other, in_namespace)
401
+ index = TSV.find_traversal(self, other, options)
215
402
  raise "Cannot traverse identifiers" if index.nil?
216
403
  attach_index other, index, fields
217
404
  end
@@ -225,4 +412,20 @@ class TSV
225
412
  reorder :key, detached_fields
226
413
  end
227
414
 
415
+ def paste(other, options = {})
416
+ tmpfile = TmpFile.tmp_file
417
+ TSV.paste(self.to_s, other.to_s, tmpfile)
418
+
419
+ new = TSV.new(tmpfile, options)
420
+
421
+ new.key_field = self.key_field unless self.key_field.nil?
422
+ if self.fields and other.fields
423
+ new.fields = self.fields + other.fields
424
+ end
425
+
426
+ FileUtils.rm tmpfile if File.exists? tmpfile
427
+
428
+ new
429
+ end
430
+
228
431
  end
@@ -232,6 +232,7 @@ class TSV
232
232
  end
233
233
 
234
234
  def self.field_matches(tsv, values)
235
+ values = [values] if not Array === values
235
236
  if values.flatten.sort[0..9].compact.collect{|n| n.to_i} == (1..10).to_a
236
237
  return {}
237
238
  end
@@ -247,7 +248,7 @@ class TSV
247
248
  if tsv.type == :double
248
249
  tsv.through do |key,entry_values|
249
250
  fields.zip(entry_values).each do |field,entry_field_values|
250
- field_values[field].concat entry_field_values
251
+ field_values[field].concat entry_field_values unless entry_field_values.nil?
251
252
  end
252
253
  end
253
254
  else
@@ -271,6 +272,10 @@ class TSV
271
272
  TSV.field_matches(self, values)
272
273
  end
273
274
 
275
+ def guess_field(values)
276
+ field_matches(values).sort_by{|field, matches| matches.uniq.length}.last
277
+ end
278
+
274
279
  def sorted_index(pos_start = nil, pos_end = nil)
275
280
  raise "Please specify indexing fields" if (pos_start.nil? and fields.length > 2)
276
281
 
@@ -1,4 +1,3 @@
1
-
2
1
  class TSV
3
2
 
4
3
  def through(new_key_field = :key, new_fields = nil, &block)
@@ -177,7 +176,7 @@ class TSV
177
176
  new.filename = filename
178
177
  new.case_insensitive = case_insensitive
179
178
 
180
- case
179
+ case
181
180
  when (method.nil? and block_given?)
182
181
  through do |key, values|
183
182
  new[key] = values if yield key, values
@@ -199,7 +198,7 @@ class TSV
199
198
  method = method.values.first
200
199
  case
201
200
  when (Array === method and (key == :key or key_field == key))
202
- method.each{|item| if values = self[item]; then new[item] = values; end}
201
+ method.each{|item| new[item] = self[item] if self.include? item}
203
202
  when Array === method
204
203
  through :key, key do |key, values|
205
204
  new[key] = self[key] if (values.flatten & method).any?
@@ -250,9 +249,9 @@ class TSV
250
249
  def add_field(name = nil)
251
250
  each do |key, values|
252
251
  new_values = yield(key, values)
253
- new_values = [new_values] if type == :double and not Array == new_values
252
+ new_values = [new_values] if type == :double and not Array === new_values
254
253
 
255
- self[key] = values + [yield(key, values)]
254
+ self[key] = values + [new_values]
256
255
  end
257
256
 
258
257
  self.fields = self.fields + [name] if fields != nil and name != nil
@@ -7,6 +7,7 @@ class TSV
7
7
  ## split with delimiter, do not remove empty
8
8
  fields = io.split(delimiter, -1)
9
9
 
10
+
10
11
  fields
11
12
  end
12
13
 
@@ -116,6 +117,8 @@ class TSV
116
117
  fix, exclude, select, grep =
117
118
  Misc.process_options options, :fix, :exclude, :select, :grep
118
119
 
120
+ exclude ||= Misc.process_options options, :reject if options.include? :reject
121
+
119
122
  #{{{ Process rest
120
123
  data = {}
121
124
  single = type.to_sym != :double
@@ -152,9 +155,10 @@ class TSV
152
155
  if single
153
156
  ids = parse_fields(parts[key_pos], sep2)
154
157
  ids.collect!{|id| id.downcase} if case_insensitive
158
+ ids = ids.reject{|_id| _id.empty?}.uniq
155
159
 
156
160
  id = ids.shift
157
- ids.each do |id2| data[id2] = "__Ref:#{id}" end
161
+ ids.each do |id2| data[id2] = "__Ref:#{id}" unless data.include? id2 end
158
162
 
159
163
  next if data.include?(id) and type != :flat
160
164
 
@@ -171,8 +175,8 @@ class TSV
171
175
 
172
176
  extra.collect! do |elem|
173
177
  case
174
- when String === cast
175
- elem.send(cast)
178
+ when (String === cast or Symbol === cast)
179
+ elem.send(cast.to_s)
176
180
  when Proc === cast
177
181
  cast.call elem
178
182
  end
@@ -195,9 +199,26 @@ class TSV
195
199
  else
196
200
  ids = parse_fields(parts[key_pos], sep2)
197
201
  ids.collect!{|id| id.downcase} if case_insensitive
202
+ ids = ids.reject{|_id| _id.empty?}.uniq
203
+
204
+ next if ids.empty?
198
205
 
199
206
  id = ids.shift
200
- ids.each do |id2| data[id2] = "__Ref:#{id}" end
207
+ while data.include? id and data[id] =~ /__Ref:(.*)/
208
+ data[id] = data[$1].collect{|e| e.dup}
209
+ end
210
+
211
+ all_ids = [id]
212
+ ids.each do |id2|
213
+ if data.include? id2
214
+ while data[id2] =~ /__Ref:(.*)/
215
+ data[id2] = data[$1].collect{|e| e.dup}
216
+ end
217
+ all_ids << id2
218
+ else
219
+ data[id2] = "__Ref:#{id}"
220
+ end
221
+ end
201
222
 
202
223
  if other_pos.nil? or (fields == nil and type == :flat)
203
224
  other_pos = (0..(parts.length - 1)).to_a
@@ -207,31 +228,34 @@ class TSV
207
228
  extra = parts.values_at(*other_pos).collect{|f| parse_fields(f, sep2)}
208
229
  extra.collect! do |list|
209
230
  case
210
- when String === cast
211
- list.collect{|elem| elem.send(cast)}
231
+ when (String === cast or Symbol === cast)
232
+ list.collect{|elem| elem.send(cast.to_s)}
212
233
  when Proc === cast
213
234
  list.collect{|elem| cast.call elem}
214
235
  end
215
236
  end if cast
216
237
 
217
238
  max_cols = extra.size if extra.size > (max_cols || 0)
218
- if not merge
219
- data[id] = extra unless data.include? id
220
- else
221
- if not data.include? id
222
- data[id] = extra
239
+
240
+ all_ids.each do |id|
241
+ if not merge
242
+ data[id] = extra unless data.include? id
223
243
  else
224
- entry = data[id]
225
- while entry =~ /__Ref:(.*)/ do entry = data[$1] end
226
- extra.each_with_index do |f, i|
227
- if f.empty?
228
- next unless keep_empty
229
- f= [""]
244
+ if not data.include? id
245
+ data[id] = extra
246
+ else
247
+ entry = data[id]
248
+ while entry =~ /__Ref:(.*)/ do entry = data[$1] end
249
+ extra.each_with_index do |f, i|
250
+ if f.empty?
251
+ next unless keep_empty
252
+ f= [""]
253
+ end
254
+ entry[i] ||= []
255
+ entry[i] = entry[i].concat f
230
256
  end
231
- entry[i] ||= []
232
- entry[i] = entry[i].concat f
257
+ data[id] = entry
233
258
  end
234
- data[id] = entry
235
259
  end
236
260
  end
237
261
  end
@@ -254,7 +278,7 @@ class TSV
254
278
 
255
279
  fields = nil if Fixnum === fields or (Array === fields and fields.select{|f| Fixnum === f}.any?)
256
280
  fields ||= other_fields
257
- [data, {:key_field => key_field, :fields => fields, :type => type, :case_insensitive => case_insensitive, :namespace => namespace, :datadir => options[:datadir], :identifiers => options[:identifiers], :cast => !!cast}]
281
+ [data, {:key_field => key_field, :fields => fields, :type => type, :case_insensitive => case_insensitive, :namespace => namespace, :datadir => options[:datadir], :identifiers => options[:identifiers], :cast => (cast.nil? ? false : cast)}]
258
282
  end
259
283
 
260
284
  end