rbbt-util 2.1.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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