htslib 0.4.2 → 0.5.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +79 -49
  3. data/TUTORIAL.md +9 -20
  4. data/ext/htslib_native/extconf.rb +41 -0
  5. data/ext/htslib_native/htslib_native.h +11 -0
  6. data/ext/htslib_native/htslib_native_ext.c +48 -0
  7. data/ext/htslib_native/native_bam.c +1108 -0
  8. data/ext/htslib_native/native_bcf.c +369 -0
  9. data/ext/htslib_native/native_faidx.c +155 -0
  10. data/ext/htslib_native/native_tabix.c +246 -0
  11. data/lib/hts/bam/auxi.rb +87 -342
  12. data/lib/hts/bam/base_mod.rb +37 -73
  13. data/lib/hts/bam/cigar.rb +9 -55
  14. data/lib/hts/bam/flag.rb +19 -27
  15. data/lib/hts/bam/header.rb +29 -56
  16. data/lib/hts/bam/mpileup.rb +158 -132
  17. data/lib/hts/bam/pileup.rb +120 -145
  18. data/lib/hts/bam/record.rb +233 -270
  19. data/lib/hts/bam.rb +102 -42
  20. data/lib/hts/bcf/errors.rb +1 -0
  21. data/lib/hts/bcf/format.rb +278 -379
  22. data/lib/hts/bcf/header.rb +38 -122
  23. data/lib/hts/bcf/header_record.rb +9 -35
  24. data/lib/hts/bcf/info.rb +72 -320
  25. data/lib/hts/bcf/record.rb +61 -102
  26. data/lib/hts/bcf.rb +149 -323
  27. data/lib/hts/faidx.rb +28 -87
  28. data/lib/hts/hts.rb +6 -94
  29. data/lib/hts/native.rb +13 -0
  30. data/lib/hts/tabix.rb +93 -48
  31. data/lib/hts/version.rb +1 -1
  32. data/lib/htslib.rb +6 -52
  33. metadata +13 -64
  34. data/lib/hts/ffi_ext/README.md +0 -8
  35. data/lib/hts/ffi_ext/pointer.rb +0 -18
  36. data/lib/hts/ffi_ext/struct.rb +0 -45
  37. data/lib/hts/libhts/bgzf.rb +0 -199
  38. data/lib/hts/libhts/constants.rb +0 -658
  39. data/lib/hts/libhts/cram.rb +0 -471
  40. data/lib/hts/libhts/fai.rb +0 -146
  41. data/lib/hts/libhts/hfile.rb +0 -121
  42. data/lib/hts/libhts/hts.rb +0 -477
  43. data/lib/hts/libhts/kfunc.rb +0 -38
  44. data/lib/hts/libhts/sam.rb +0 -760
  45. data/lib/hts/libhts/sam_funcs.rb +0 -155
  46. data/lib/hts/libhts/tbx.rb +0 -94
  47. data/lib/hts/libhts/tbx_funcs.rb +0 -36
  48. data/lib/hts/libhts/thread_pool.rb +0 -139
  49. data/lib/hts/libhts/vcf.rb +0 -567
  50. data/lib/hts/libhts/vcf_funcs.rb +0 -366
  51. data/lib/hts/libhts.rb +0 -47
data/lib/hts/bam/auxi.rb CHANGED
@@ -1,318 +1,157 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Q. Why is the file name auxi.rb and not aux.rb?
4
- #
5
- # A. This is for compatibility with Windows.
6
- #
7
- # In Windows, aux is a reserved word
8
- # You cannot create a file named aux.
9
- #
10
- # What?! That's crazy!
11
-
12
3
  module HTS
13
4
  class Bam < Hts
14
- # Auxiliary record data
15
- #
16
- # @noge Aux is a View object.
17
- # The result of the alignment is assigned to the bam1 structure.
18
- # Ruby's Aux class references a part of it. There is no one-to-one
19
- # correspondence between C structures and Ruby's Aux class.
20
5
  class Aux
21
6
  include Enumerable
22
7
  attr_reader :record
23
8
 
24
- def initialize(record)
25
- @record = record
26
- end
9
+ def initialize(record) = @record = record
27
10
 
28
- # @note Why is this method named "get" instead of "fetch"?
29
- # This is for compatibility with the Crystal language
30
- # which provides methods like `get_int`, `get_float`, etc.
31
- # I think they are better than `fetch_int`` and `fetch_float`.
32
11
  def get(key, type = nil)
33
- aux_ptr = LibHTS.bam_aux_get(@record.struct, key)
34
- return nil if aux_ptr.null?
35
-
36
- get_ruby_aux(aux_ptr, type)
12
+ pair = native.aux_get(key, type&.to_s)
13
+ pair&.last
37
14
  end
38
15
 
39
- # For compatibility with HTS.cr.
40
- def get_int(key)
41
- get(key, "i")
42
- end
16
+ def get_int(key) = get(key, "i")
17
+ def get_float(key) = get(key, "f")
18
+ def get_string(key) = get(key, "Z")
19
+ def [](key) = get(key)
43
20
 
44
- # For compatibility with HTS.cr.
45
- def get_float(key)
46
- get(key, "f")
47
- end
21
+ def each_array(key, &block)
22
+ return enum_for(__method__, key) unless block_given?
48
23
 
49
- # For compatibility with HTS.cr.
50
- def get_string(key)
51
- get(key, "Z")
52
- end
24
+ pair = native.aux_get(key, nil)
25
+ return nil unless pair
26
+ raise TypeError, "AUX tag #{key} is not a B array" unless pair.first.start_with?("B:")
53
27
 
54
- def [](key)
55
- get(key)
28
+ pair.last.each(&block)
29
+ self
56
30
  end
57
31
 
58
- # Set auxiliary tag value (auto-detects type from value)
59
- # For compatibility with HTS.cr.
60
- # @param key [String] tag name (2 characters)
61
- # @param value [Integer, Float, String, Array] tag value
62
32
  def []=(key, value)
63
33
  case value
64
- when Integer
65
- update_int(key, value)
66
- when Float
67
- update_float(key, value)
68
- when String
69
- update_string(key, value)
70
- when Array
71
- update_array(key, value)
72
- else
73
- raise ArgumentError, "Unsupported type: #{value.class}"
34
+ when Integer then update_int(key, value)
35
+ when Float then update_float(key, value)
36
+ when String then update_string(key, value)
37
+ when Array then update_array(key, value)
38
+ else raise ArgumentError, "Unsupported type: #{value.class}"
74
39
  end
75
40
  end
76
41
 
77
- # Update or add an integer tag
78
- # For compatibility with HTS.cr.
79
- # @param key [String] tag name (2 characters)
80
- # @param value [Integer] integer value
81
42
  def update_int(key, value)
82
43
  validate_tag!(key)
83
- ret = LibHTS.bam_aux_update_int(@record.struct, key, value.to_i)
84
- raise "Failed to update integer tag '#{key}': errno #{FFI.errno}" if ret < 0
44
+ raise "Failed to update integer tag '#{key}'" if native.aux_update_int(key, value.to_i).negative?
85
45
 
86
46
  value
87
47
  end
88
48
 
89
- # Update or add a signed 8-bit integer tag.
90
- def update_int8(key, value)
91
- update_exact_integer(key, value, "c", -128, 127)
92
- end
93
-
94
- # Update or add an unsigned 8-bit integer tag.
95
- def update_uint8(key, value)
96
- update_exact_integer(key, value, "C", 0, 255)
97
- end
49
+ def update_int8(key, value) = update_exact_integer(key, value, "c", -128, 127)
50
+ def update_uint8(key, value) = update_exact_integer(key, value, "C", 0, 255)
51
+ def update_int16(key, value) = update_exact_integer(key, value, "s", -32_768, 32_767)
52
+ def update_uint16(key, value) = update_exact_integer(key, value, "S", 0, 65_535)
53
+ def update_int32(key, value) = update_exact_integer(key, value, "i", -2_147_483_648, 2_147_483_647)
54
+ def update_uint32(key, value) = update_exact_integer(key, value, "I", 0, 4_294_967_295)
98
55
 
99
- # Update or add a signed 16-bit integer tag.
100
- def update_int16(key, value)
101
- update_exact_integer(key, value, "s", -32_768, 32_767)
102
- end
103
-
104
- # Update or add an unsigned 16-bit integer tag.
105
- def update_uint16(key, value)
106
- update_exact_integer(key, value, "S", 0, 65_535)
107
- end
108
-
109
- # Update or add a signed 32-bit integer tag.
110
- def update_int32(key, value)
111
- update_exact_integer(key, value, "i", -2_147_483_648, 2_147_483_647)
112
- end
113
-
114
- # Update or add an unsigned 32-bit integer tag.
115
- def update_uint32(key, value)
116
- update_exact_integer(key, value, "I", 0, 4_294_967_295)
117
- end
118
-
119
- # Update or add a floating-point tag
120
- # For compatibility with HTS.cr.
121
- # @param key [String] tag name (2 characters)
122
- # @param value [Float] floating-point value
123
56
  def update_float(key, value)
124
57
  validate_tag!(key)
125
- ret = LibHTS.bam_aux_update_float(@record.struct, key, value.to_f)
126
- raise "Failed to update float tag '#{key}': errno #{FFI.errno}" if ret < 0
58
+ raise "Failed to update float tag '#{key}'" if native.aux_update_float(key, value.to_f).negative?
127
59
 
128
60
  value
129
61
  end
130
62
 
131
- # Update or add a string tag
132
- # For compatibility with HTS.cr.
133
- # @param key [String] tag name (2 characters)
134
- # @param value [String] string value
135
63
  def update_string(key, value)
136
64
  validate_tag!(key)
137
65
  string = value.to_s
138
66
  validate_string_value!(string)
139
- ret = LibHTS.bam_aux_update_str(@record.struct, key, -1, string)
140
- raise "Failed to update string tag '#{key}': errno #{FFI.errno}" if ret < 0
67
+ raise "Failed to update string tag '#{key}'" if native.aux_update_string(key, string).negative?
141
68
 
142
69
  string
143
70
  end
144
71
 
145
- # Update or add a character tag.
146
72
  def update_char(key, value)
147
73
  validate_tag!(key)
148
-
149
74
  string = value.to_s
150
75
  validate_char_value!(string)
151
-
152
76
  replace_with_append(key, "A", string.b)
153
77
  string
154
78
  end
155
79
 
156
- # Update or add a hexadecimal string tag.
157
80
  def update_hex(key, value)
158
81
  validate_tag!(key)
159
-
160
82
  string = value.to_s
161
83
  validate_hex_value!(string)
162
-
163
84
  replace_with_append(key, "H", string.b + "\0")
164
85
  string
165
86
  end
166
87
 
167
- # Update or add a double-precision floating-point tag.
168
88
  def update_double(key, value)
169
89
  validate_tag!(key)
170
-
171
90
  replace_with_append(key, "d", [Float(value)].pack("E"))
172
91
  value.to_f
173
92
  end
174
93
 
175
- # Update or add an array tag
176
- # For compatibility with HTS.cr.
177
- # @param key [String] tag name (2 characters)
178
- # @param value [Array] array of integers or floats
179
- # @param type [String, nil] element type ('c', 'C', 's', 'S', 'i', 'I', 'f'). Auto-detected if nil.
180
94
  def update_array(key, value, type: nil)
181
95
  validate_tag!(key)
182
96
  raise ArgumentError, "Array cannot be empty" if value.empty?
183
97
 
184
- # Auto-detect type if not specified
185
- if type.nil?
186
- if value.all? { |v| v.is_a?(Integer) }
187
- # Use 'i' for signed 32-bit integers by default
188
- type = "i"
189
- elsif value.all? { |v| v.is_a?(Float) || v.is_a?(Integer) }
190
- type = "f"
191
- else
192
- raise ArgumentError, "Array must contain only integers or floats"
193
- end
194
- end
195
-
196
- payload = pack_array_payload(value, type)
197
- ptr = FFI::MemoryPointer.new(:uint8, payload.bytesize)
198
- ptr.put_bytes(0, payload)
199
- ret = LibHTS.bam_aux_update_array(@record.struct, key, type.ord, value.size, ptr)
200
-
201
- raise "Failed to update array tag '#{key}': errno #{FFI.errno}" if ret < 0
98
+ type ||= if value.all? { |item| item.is_a?(Integer) }
99
+ "i"
100
+ elsif value.all? { |item| item.is_a?(Numeric) }
101
+ "f"
102
+ else
103
+ raise ArgumentError, "Array must contain only integers or floats"
104
+ end
105
+ validate_array!(value, type)
106
+ raise "Failed to update array tag '#{key}'" if native.aux_update_array(key, type, value).negative?
202
107
 
203
108
  value
204
109
  end
205
110
 
206
- # Delete an auxiliary tag
207
- # For compatibility with HTS.cr.
208
- # @param key [String] tag name (2 characters)
209
- # @return [Boolean] true if tag was deleted, false if tag was not found
210
- def delete(key)
211
- aux_ptr = LibHTS.bam_aux_get(@record.struct, key)
212
- return false if aux_ptr.null?
213
-
214
- ret = LibHTS.bam_aux_del(@record.struct, aux_ptr)
215
- raise "Failed to delete tag '#{key}': errno #{FFI.errno}" if ret < 0
216
-
217
- true
218
- end
219
-
220
- # Check if a tag exists
221
- # For compatibility with HTS.cr.
222
- # @param key [String] tag name (2 characters)
223
- # @return [Boolean] true if tag exists
224
- def key?(key)
225
- aux_ptr = LibHTS.bam_aux_get(@record.struct, key)
226
- !aux_ptr.null?
227
- end
228
-
111
+ def delete(key) = native.aux_delete(key)
112
+ def key?(key) = native.aux_key?(key)
229
113
  alias include? key?
230
114
 
231
- def first
232
- aux_ptr = first_pointer
233
- return nil if aux_ptr.null?
234
-
235
- get_ruby_aux(aux_ptr)
236
- end
115
+ def first = entries.first&.last
237
116
 
238
117
  def each_value
239
118
  return enum_for(__method__) unless block_given?
240
119
 
241
- aux_ptr = first_pointer
242
- return nil if aux_ptr.null?
243
-
244
- loop do
245
- yield get_ruby_aux(aux_ptr)
246
- aux_ptr = LibHTS.bam_aux_next(@record.struct, aux_ptr)
247
- break if aux_ptr.null?
248
- end
120
+ entries.each { |_, _, value| yield value }
249
121
  end
250
122
 
251
- # Iterate auxiliary tags as key-value pairs.
252
- #
253
- # @yieldparam tag [String] 2-byte AUX tag name
254
- # @yieldparam value [Object] Ruby representation of the AUX value
255
123
  def each
256
124
  return enum_for(__method__) unless block_given?
257
125
 
258
- aux_ptr = first_pointer
259
- return nil if aux_ptr.null?
260
-
261
- loop do
262
- tag = FFI::Pointer.new(aux_ptr.address - 2).read_string(2)
263
- yield tag, get_ruby_aux(aux_ptr)
264
- aux_ptr = LibHTS.bam_aux_next(@record.struct, aux_ptr)
265
- break if aux_ptr.null?
266
- end
126
+ entries.each { |tag, _, value| yield tag, value }
267
127
  end
268
-
269
128
  alias each_pair each
270
129
 
271
- # Iterate auxiliary tags with their SAM/BAM type.
272
- #
273
- # @yieldparam tag [String] 2-byte AUX tag name
274
- # @yieldparam type [String] AUX type, e.g. "i", "Z", or "B:C"
275
- # @yieldparam value [Object] Ruby representation of the AUX value
276
- def each_with_type
130
+ def each_tag_id
277
131
  return enum_for(__method__) unless block_given?
278
132
 
279
- aux_ptr = first_pointer
280
- return nil if aux_ptr.null?
281
-
282
- loop do
283
- tag = FFI::Pointer.new(aux_ptr.address - 2).read_string(2)
284
- yield tag, aux_type(aux_ptr), get_ruby_aux(aux_ptr)
285
- aux_ptr = LibHTS.bam_aux_next(@record.struct, aux_ptr)
286
- break if aux_ptr.null?
287
- end
133
+ entries.each { |tag, _, value| yield self.class.tag_id(tag), value }
134
+ self
288
135
  end
289
136
 
290
- def to_h
291
- h = {}
292
- aux_ptr = first_pointer
293
- return h if aux_ptr.null?
137
+ def self.tag_id(tag)
138
+ raise ArgumentError, "AUX tag must be a 2-byte String" unless tag.is_a?(String) && tag.bytesize == 2
294
139
 
295
- loop do
296
- key = FFI::Pointer.new(aux_ptr.address - 2).read_string(2)
297
- h[key] = get_ruby_aux(aux_ptr)
298
- aux_ptr = LibHTS.bam_aux_next(@record.struct, aux_ptr)
299
- break if aux_ptr.null?
300
- end
301
- h
140
+ tag.getbyte(0) | (tag.getbyte(1) << 8)
302
141
  end
303
142
 
304
- private
143
+ def each_with_type(&block)
144
+ return enum_for(__method__) unless block_given?
305
145
 
306
- def first_pointer
307
- LibHTS.bam_aux_first(@record.struct)
146
+ entries.each(&block)
308
147
  end
309
148
 
310
- def aux_type(aux_ptr)
311
- type = aux_ptr.read_string(1)
312
- return type unless type == "B"
149
+ def to_h = entries.to_h { |tag, _, value| [tag, value] }
313
150
 
314
- "#{type}:#{aux_ptr.read_string(2)[1]}"
315
- end
151
+ private
152
+
153
+ def native = @record.__send__(:native_handle)
154
+ def entries = native.aux_entries
316
155
 
317
156
  def validate_tag!(key)
318
157
  return if key.is_a?(String) && key.bytesize == 2 && key.ascii_only?
@@ -321,9 +160,7 @@ module HTS
321
160
  end
322
161
 
323
162
  def validate_string_value!(string)
324
- return unless string.include?("\0")
325
-
326
- raise ArgumentError, "String AUX tags must not contain NUL bytes"
163
+ raise ArgumentError, "String AUX tags must not contain NUL bytes" if string.include?("\0")
327
164
  end
328
165
 
329
166
  def validate_char_value!(string)
@@ -334,143 +171,51 @@ module HTS
334
171
 
335
172
  def validate_hex_value!(string)
336
173
  raise ArgumentError, "Hex AUX tags must contain an even number of characters" if string.bytesize.odd?
337
-
338
174
  return if string.ascii_only? && /\A[0-9A-Fa-f]*\z/.match?(string)
339
175
 
340
- raise ArgumentError,
341
- "Hex AUX tags must contain only ASCII hexadecimal characters"
176
+ raise ArgumentError, "Hex AUX tags must contain only ASCII hexadecimal characters"
342
177
  end
343
178
 
344
179
  def update_exact_integer(key, value, type, min, max)
345
180
  validate_tag!(key)
346
-
347
181
  integer = Integer(value)
348
182
  raise RangeError, "Value #{integer} is out of range for AUX type #{type}" unless integer.between?(min, max)
349
183
 
350
- replace_with_append(key, type, pack_scalar_payload(integer, type))
184
+ payload = case type
185
+ when "c" then [integer].pack("c")
186
+ when "C" then [integer].pack("C")
187
+ when "s" then [integer].pack("s<")
188
+ when "S" then [integer].pack("S<")
189
+ when "i" then [integer].pack("l<")
190
+ when "I" then [integer].pack("L<")
191
+ end
192
+ replace_with_append(key, type, payload)
351
193
  integer
352
194
  end
353
195
 
354
196
  def replace_with_append(key, type, payload)
355
- delete(key) if key?(key)
356
-
357
- ptr = FFI::MemoryPointer.new(:uint8, payload.bytesize)
358
- ptr.put_bytes(0, payload)
359
- ret = LibHTS.bam_aux_append(@record.struct, key, type.ord, payload.bytesize, ptr)
360
- raise "Failed to update #{type} tag '#{key}': errno #{FFI.errno}" if ret < 0
361
-
362
- true
363
- end
364
-
365
- def pack_scalar_payload(value, type)
366
- case type
367
- when "c"
368
- [value].pack("c")
369
- when "C"
370
- [value].pack("C")
371
- when "s"
372
- [value].pack("s<")
373
- when "S"
374
- [value].pack("S<")
375
- when "i"
376
- [value].pack("l<")
377
- when "I"
378
- [value].pack("L<")
379
- else
380
- raise ArgumentError, "Unsupported scalar AUX type: #{type}"
381
- end
382
- end
383
-
384
- def pack_array_payload(value, type)
385
- case type
386
- when "c"
387
- validate_integer_array_range!(value, -128, 127, type)
388
- value.pack("c*")
389
- when "C"
390
- validate_integer_array_range!(value, 0, 255, type)
391
- value.pack("C*")
392
- when "s"
393
- validate_integer_array_range!(value, -32_768, 32_767, type)
394
- value.pack("s<*")
395
- when "S"
396
- validate_integer_array_range!(value, 0, 65_535, type)
397
- value.pack("S<*")
398
- when "i"
399
- validate_integer_array_range!(value, -2_147_483_648, 2_147_483_647, type)
400
- value.pack("l<*")
401
- when "I"
402
- validate_integer_array_range!(value, 0, 4_294_967_295, type)
403
- value.pack("L<*")
404
- when "f"
405
- value.map(&:to_f).pack("e*")
406
- else
407
- raise ArgumentError, "Invalid array type: #{type}"
408
- end
409
- end
410
-
411
- def validate_integer_array_range!(value, min, max, type)
412
- value.each do |element|
413
- integer = Integer(element)
414
- unless integer.between?(min, max)
415
- raise RangeError, "Array element #{integer} is out of range for AUX array type #{type}"
416
- end
417
- end
418
- end
419
-
420
- def get_ruby_aux(aux_ptr, type = nil)
421
- actual_type = aux_ptr.read_string(1)
422
- type = type ? type.to_s : actual_type
423
- validate_aux_type!(actual_type, type)
424
-
425
- # A (character), B (general array),
426
- # f (real number), H (hexadecimal array),
427
- # i (integer), or Z (string).
428
-
429
- case type
430
- when "i", "I", "c", "C", "s", "S"
431
- LibHTS.bam_aux2i(aux_ptr)
432
- when "f", "d"
433
- LibHTS.bam_aux2f(aux_ptr)
434
- when "Z", "H"
435
- LibHTS.bam_aux2Z(aux_ptr)
436
- when "A" # char
437
- LibHTS.bam_aux2A(aux_ptr).chr
438
- when "B" # array
439
- t2 = aux_ptr.read_string(2)[1] # just a little less efficient
440
- l = LibHTS.bam_auxB_len(aux_ptr)
441
- case t2
442
- when "c", "C", "s", "S", "i", "I"
443
- # FIXME : Not efficient.
444
- Array.new(l) { |i| LibHTS.bam_auxB2i(aux_ptr, i) }
445
- when "f", "d"
446
- # FIXME : Not efficient.
447
- Array.new(l) { |i| LibHTS.bam_auxB2f(aux_ptr, i) }
448
- else
449
- raise NotImplementedError, "type: #{type} #{t2}"
197
+ delete(key)
198
+ raise "Failed to update #{type} tag '#{key}'" if native.aux_append(key, type, payload).negative?
199
+ end
200
+
201
+ def validate_array!(value, type)
202
+ ranges = {
203
+ "c" => (-128..127), "C" => (0..255), "s" => (-32_768..32_767),
204
+ "S" => (0..65_535), "i" => (-2_147_483_648..2_147_483_647),
205
+ "I" => (0..4_294_967_295)
206
+ }
207
+ if (range = ranges[type])
208
+ value.each do |element|
209
+ integer = Integer(element)
210
+ unless range.cover?(integer)
211
+ raise RangeError,
212
+ "Array element #{integer} is out of range for AUX array type #{type}"
213
+ end
450
214
  end
215
+ elsif type == "f"
216
+ value.each { |element| Float(element) }
451
217
  else
452
- raise NotImplementedError, "type: #{type}"
453
- end
454
- end
455
-
456
- def validate_aux_type!(actual_type, requested_type)
457
- return if aux_type_compatible?(actual_type, requested_type)
458
-
459
- raise TypeError, "AUX type mismatch: requested #{requested_type.inspect}, actual #{actual_type.inspect}"
460
- end
461
-
462
- def aux_type_compatible?(actual_type, requested_type)
463
- case requested_type
464
- when "i", "I", "c", "C", "s", "S"
465
- %w[i I c C s S].include?(actual_type)
466
- when "f", "d"
467
- %w[f d].include?(actual_type)
468
- when "Z", "H"
469
- %w[Z H].include?(actual_type)
470
- when "A", "B"
471
- actual_type == requested_type
472
- else
473
- true
218
+ raise ArgumentError, "Invalid array type: #{type}"
474
219
  end
475
220
  end
476
221
  end