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.
- checksums.yaml +4 -4
- data/README.md +79 -49
- data/TUTORIAL.md +9 -20
- data/ext/htslib_native/extconf.rb +41 -0
- data/ext/htslib_native/htslib_native.h +11 -0
- data/ext/htslib_native/htslib_native_ext.c +48 -0
- data/ext/htslib_native/native_bam.c +1108 -0
- data/ext/htslib_native/native_bcf.c +369 -0
- data/ext/htslib_native/native_faidx.c +155 -0
- data/ext/htslib_native/native_tabix.c +246 -0
- data/lib/hts/bam/auxi.rb +87 -342
- data/lib/hts/bam/base_mod.rb +37 -73
- data/lib/hts/bam/cigar.rb +9 -55
- data/lib/hts/bam/flag.rb +19 -27
- data/lib/hts/bam/header.rb +29 -56
- data/lib/hts/bam/mpileup.rb +158 -132
- data/lib/hts/bam/pileup.rb +120 -145
- data/lib/hts/bam/record.rb +233 -270
- data/lib/hts/bam.rb +102 -42
- data/lib/hts/bcf/errors.rb +1 -0
- data/lib/hts/bcf/format.rb +278 -379
- data/lib/hts/bcf/header.rb +38 -122
- data/lib/hts/bcf/header_record.rb +9 -35
- data/lib/hts/bcf/info.rb +72 -320
- data/lib/hts/bcf/record.rb +61 -102
- data/lib/hts/bcf.rb +149 -323
- data/lib/hts/faidx.rb +28 -87
- data/lib/hts/hts.rb +6 -94
- data/lib/hts/native.rb +13 -0
- data/lib/hts/tabix.rb +93 -48
- data/lib/hts/version.rb +1 -1
- data/lib/htslib.rb +6 -52
- metadata +13 -64
- data/lib/hts/ffi_ext/README.md +0 -8
- data/lib/hts/ffi_ext/pointer.rb +0 -18
- data/lib/hts/ffi_ext/struct.rb +0 -45
- data/lib/hts/libhts/bgzf.rb +0 -199
- data/lib/hts/libhts/constants.rb +0 -658
- data/lib/hts/libhts/cram.rb +0 -471
- data/lib/hts/libhts/fai.rb +0 -146
- data/lib/hts/libhts/hfile.rb +0 -121
- data/lib/hts/libhts/hts.rb +0 -477
- data/lib/hts/libhts/kfunc.rb +0 -38
- data/lib/hts/libhts/sam.rb +0 -760
- data/lib/hts/libhts/sam_funcs.rb +0 -155
- data/lib/hts/libhts/tbx.rb +0 -94
- data/lib/hts/libhts/tbx_funcs.rb +0 -36
- data/lib/hts/libhts/thread_pool.rb +0 -139
- data/lib/hts/libhts/vcf.rb +0 -567
- data/lib/hts/libhts/vcf_funcs.rb +0 -366
- data/lib/hts/libhts.rb +0 -47
data/lib/hts/bcf/header.rb
CHANGED
|
@@ -23,18 +23,17 @@ module HTS
|
|
|
23
23
|
|
|
24
24
|
def initialize(arg = nil)
|
|
25
25
|
case arg
|
|
26
|
-
when
|
|
27
|
-
@
|
|
28
|
-
when LibHTS::BcfHdr
|
|
29
|
-
@bcf_hdr = arg
|
|
26
|
+
when Native::BcfHeaderHandle
|
|
27
|
+
@native = arg
|
|
30
28
|
when nil
|
|
31
|
-
@
|
|
29
|
+
@native = Native::BcfHeaderHandle.create
|
|
32
30
|
else
|
|
33
31
|
raise TypeError, "Invalid argument"
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
@sync_depth = 0
|
|
37
35
|
@sync_needed = false
|
|
36
|
+
@schema_version = 0
|
|
38
37
|
@subset_samples = nil
|
|
39
38
|
@subset_imap = nil
|
|
40
39
|
@subset_imap_pointer = nil
|
|
@@ -42,20 +41,12 @@ module HTS
|
|
|
42
41
|
yield self if block_given?
|
|
43
42
|
end
|
|
44
43
|
|
|
45
|
-
def struct
|
|
46
|
-
@bcf_hdr
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def to_ptr
|
|
50
|
-
@bcf_hdr.to_ptr
|
|
51
|
-
end
|
|
52
|
-
|
|
53
44
|
def get_version
|
|
54
|
-
|
|
45
|
+
@native.version
|
|
55
46
|
end
|
|
56
47
|
|
|
57
48
|
def set_version(version)
|
|
58
|
-
rc =
|
|
49
|
+
rc = @native.set_version(version)
|
|
59
50
|
raise "Failed to set VCF header version" if rc.negative?
|
|
60
51
|
|
|
61
52
|
mark_sync_needed!
|
|
@@ -64,7 +55,7 @@ module HTS
|
|
|
64
55
|
end
|
|
65
56
|
|
|
66
57
|
def nsamples
|
|
67
|
-
|
|
58
|
+
@native.nsamples
|
|
68
59
|
end
|
|
69
60
|
|
|
70
61
|
def target_count
|
|
@@ -84,13 +75,10 @@ module HTS
|
|
|
84
75
|
end
|
|
85
76
|
|
|
86
77
|
def samples
|
|
87
|
-
|
|
88
|
-
@bcf_hdr[:samples]
|
|
89
|
-
.read_array_of_pointer(nsamples)
|
|
90
|
-
.map(&:read_string)
|
|
78
|
+
@native.samples
|
|
91
79
|
end
|
|
92
80
|
|
|
93
|
-
attr_reader :subset_samples, :subset_imap_pointer
|
|
81
|
+
attr_reader :subset_samples, :subset_imap_pointer, :schema_version
|
|
94
82
|
|
|
95
83
|
def subset?
|
|
96
84
|
!@subset_imap.nil?
|
|
@@ -104,27 +92,18 @@ module HTS
|
|
|
104
92
|
subset_samples = normalize_subset_samples(samples)
|
|
105
93
|
validate_subset_samples!(subset_samples)
|
|
106
94
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, 0, ::FFI::Pointer::NULL, ::FFI::Pointer::NULL)
|
|
110
|
-
else
|
|
111
|
-
encoded_samples = subset_samples.map { |name| FFI::MemoryPointer.from_string(name) }
|
|
112
|
-
sample_pointers = FFI::MemoryPointer.new(:pointer, subset_samples.length)
|
|
113
|
-
sample_pointers.write_array_of_pointer(encoded_samples)
|
|
114
|
-
imap_pointer = FFI::MemoryPointer.new(:int, subset_samples.length)
|
|
115
|
-
subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, subset_samples.length, sample_pointers, imap_pointer)
|
|
116
|
-
end
|
|
95
|
+
result = @native.subset(subset_samples)
|
|
96
|
+
raise SubsetError, "Failed to subset BCF header samples #{subset_samples.inspect}" unless result
|
|
117
97
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
self.class.new(subset_hdr).tap do |header|
|
|
98
|
+
subset_header, imap = result
|
|
99
|
+
composed_imap = compose_subset_imap(imap)
|
|
100
|
+
self.class.new(subset_header).tap do |header|
|
|
122
101
|
header.send(:set_subset_state, subset_samples, composed_imap)
|
|
123
102
|
end
|
|
124
103
|
end
|
|
125
104
|
|
|
126
105
|
def add_sample(sample, sync: true)
|
|
127
|
-
rc =
|
|
106
|
+
rc = @native.add_sample(sample)
|
|
128
107
|
raise "Failed to add sample #{sample}" if rc.negative?
|
|
129
108
|
|
|
130
109
|
mark_sync_needed!
|
|
@@ -133,17 +112,14 @@ module HTS
|
|
|
133
112
|
end
|
|
134
113
|
|
|
135
114
|
def merge(hdr)
|
|
136
|
-
|
|
137
|
-
raise "Failed to merge BCF headers" if merged.to_ptr.null?
|
|
138
|
-
|
|
139
|
-
@bcf_hdr = merged
|
|
115
|
+
@native.merge(hdr.__send__(:native_handle))
|
|
140
116
|
mark_sync_needed!
|
|
141
117
|
sync_if_needed!
|
|
142
118
|
self
|
|
143
119
|
end
|
|
144
120
|
|
|
145
121
|
def sync
|
|
146
|
-
rc =
|
|
122
|
+
rc = @native.sync
|
|
147
123
|
raise "Failed to sync BCF header" if rc.negative?
|
|
148
124
|
|
|
149
125
|
@sync_needed = false
|
|
@@ -151,11 +127,13 @@ module HTS
|
|
|
151
127
|
end
|
|
152
128
|
|
|
153
129
|
def read_bcf(fname)
|
|
154
|
-
|
|
130
|
+
result = @native.read_file(fname)
|
|
131
|
+
@schema_version += 1 unless result.negative?
|
|
132
|
+
result
|
|
155
133
|
end
|
|
156
134
|
|
|
157
135
|
def append(line)
|
|
158
|
-
rc =
|
|
136
|
+
rc = @native.append(line)
|
|
159
137
|
raise "Failed to append VCF header line" if rc.negative?
|
|
160
138
|
|
|
161
139
|
mark_sync_needed!
|
|
@@ -164,18 +142,14 @@ module HTS
|
|
|
164
142
|
|
|
165
143
|
def delete(bcf_hl_type, key = nil) # FIXME
|
|
166
144
|
existed = hrec_exists?(bcf_hl_type, key)
|
|
167
|
-
|
|
168
|
-
LibHTS.bcf_hdr_remove(@bcf_hdr, type, key)
|
|
145
|
+
@native.remove(bcf_hl_type.to_s, key)
|
|
169
146
|
mark_sync_needed! if existed
|
|
170
147
|
existed
|
|
171
148
|
end
|
|
172
149
|
|
|
173
150
|
def get_hrec(bcf_hl_type, key, value, str_class = nil)
|
|
174
|
-
|
|
175
|
-
hrec
|
|
176
|
-
return nil if hrec.to_ptr.null?
|
|
177
|
-
|
|
178
|
-
HeaderRecord.new(owned_hrec(hrec))
|
|
151
|
+
hrec = @native.get_hrec(bcf_hl_type.to_s, key, value, str_class)
|
|
152
|
+
hrec ? HeaderRecord.new(hrec) : nil
|
|
179
153
|
end
|
|
180
154
|
|
|
181
155
|
def edit
|
|
@@ -251,33 +225,19 @@ module HTS
|
|
|
251
225
|
end
|
|
252
226
|
|
|
253
227
|
def seqnames
|
|
254
|
-
|
|
255
|
-
names = LibHTS.bcf_hdr_seqnames(@bcf_hdr, n)
|
|
256
|
-
begin
|
|
257
|
-
names.read_array_of_pointer(n.read_int)
|
|
258
|
-
.map(&:read_string)
|
|
259
|
-
ensure
|
|
260
|
-
LibHTS.hts_free(names) unless names.null?
|
|
261
|
-
end
|
|
228
|
+
@native.seqnames
|
|
262
229
|
end
|
|
263
230
|
|
|
264
231
|
def to_s
|
|
265
|
-
|
|
266
|
-
begin
|
|
267
|
-
raise "Failed to get header string" if LibHTS.bcf_hdr_format(@bcf_hdr, 0, kstr).negative?
|
|
268
|
-
|
|
269
|
-
kstr.read_string_copy
|
|
270
|
-
ensure
|
|
271
|
-
kstr.free_buffer
|
|
272
|
-
end
|
|
232
|
+
@native.to_s
|
|
273
233
|
end
|
|
274
234
|
|
|
275
235
|
def name2id(name)
|
|
276
|
-
|
|
236
|
+
@native.name2id(name)
|
|
277
237
|
end
|
|
278
238
|
|
|
279
239
|
def id2name(id)
|
|
280
|
-
|
|
240
|
+
@native.id2name(id)
|
|
281
241
|
end
|
|
282
242
|
|
|
283
243
|
private
|
|
@@ -324,6 +284,7 @@ module HTS
|
|
|
324
284
|
|
|
325
285
|
def mark_sync_needed!
|
|
326
286
|
@sync_needed = true
|
|
287
|
+
@schema_version += 1
|
|
327
288
|
end
|
|
328
289
|
|
|
329
290
|
def sync_if_needed!
|
|
@@ -331,58 +292,26 @@ module HTS
|
|
|
331
292
|
end
|
|
332
293
|
|
|
333
294
|
def hrec_exists?(bcf_hl_type, key)
|
|
334
|
-
|
|
335
|
-
lookup_key, lookup_value, str_class
|
|
336
|
-
hrec = borrowed_hrec(type, lookup_key, lookup_value, str_class)
|
|
337
|
-
!hrec.to_ptr.null?
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def borrowed_hrec(type, key, value, str_class)
|
|
341
|
-
LibHTS.bcf_hdr_get_hrec(@bcf_hdr, type, key, value, str_class)
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def owned_hrec(hrec)
|
|
345
|
-
LibHTS.bcf_hrec_dup(hrec).tap do |owned|
|
|
346
|
-
raise "Failed to duplicate BCF header record" if owned.to_ptr.null?
|
|
347
|
-
end
|
|
295
|
+
lookup_key, lookup_value, str_class = hrec_lookup_args(bcf_hl_type, key)
|
|
296
|
+
!@native.get_hrec(bcf_hl_type.to_s, lookup_key, lookup_value, str_class).nil?
|
|
348
297
|
end
|
|
349
298
|
|
|
350
299
|
def hrec_lookup_args(type, key)
|
|
351
|
-
case type
|
|
352
|
-
when
|
|
300
|
+
case type.to_s.upcase
|
|
301
|
+
when "FILTER", "FIL", "INFO", "FORMAT", "FMT", "CONTIG", "CTG"
|
|
353
302
|
["ID", key, nil]
|
|
354
|
-
when
|
|
303
|
+
when "GENOTYPE", "GEN"
|
|
355
304
|
[key, nil, nil]
|
|
356
305
|
else
|
|
357
306
|
["ID", key, nil]
|
|
358
307
|
end
|
|
359
308
|
end
|
|
360
309
|
|
|
361
|
-
def bcf_hl_type_to_int(bcf_hl_type)
|
|
362
|
-
return bcf_hl_type if bcf_hl_type.is_a?(Integer)
|
|
363
|
-
|
|
364
|
-
case bcf_hl_type.to_s.upcase
|
|
365
|
-
when "FILTER", "FIL"
|
|
366
|
-
LibHTS::BCF_HL_FLT
|
|
367
|
-
when "INFO"
|
|
368
|
-
LibHTS::BCF_HL_INFO
|
|
369
|
-
when "FORMAT", "FMT"
|
|
370
|
-
LibHTS::BCF_HL_FMT
|
|
371
|
-
when "CONTIG", "CTG"
|
|
372
|
-
LibHTS::BCF_HL_CTG
|
|
373
|
-
when "STRUCTURED", "STR"
|
|
374
|
-
LibHTS::BCF_HL_STR
|
|
375
|
-
when "GENOTYPE", "GEN"
|
|
376
|
-
LibHTS::BCF_HL_GEN
|
|
377
|
-
else
|
|
378
|
-
raise TypeError, "Invalid argument"
|
|
379
|
-
end
|
|
380
|
-
end
|
|
381
|
-
|
|
382
310
|
def initialize_copy(orig)
|
|
383
|
-
@
|
|
311
|
+
@native = orig.__send__(:native_handle).duplicate
|
|
384
312
|
@sync_depth = 0
|
|
385
313
|
@sync_needed = false
|
|
314
|
+
@schema_version = orig.schema_version
|
|
386
315
|
set_subset_state(orig.subset_samples, orig.send(:subset_imap))
|
|
387
316
|
end
|
|
388
317
|
|
|
@@ -393,7 +322,7 @@ module HTS
|
|
|
393
322
|
def set_subset_state(samples, imap)
|
|
394
323
|
@subset_samples = samples&.dup
|
|
395
324
|
@subset_imap = imap&.dup
|
|
396
|
-
@subset_imap_pointer =
|
|
325
|
+
@subset_imap_pointer = nil
|
|
397
326
|
end
|
|
398
327
|
|
|
399
328
|
private
|
|
@@ -417,25 +346,12 @@ module HTS
|
|
|
417
346
|
raise UnknownSampleError, "Unknown sample names: #{missing.join(', ')}" unless missing.empty?
|
|
418
347
|
end
|
|
419
348
|
|
|
420
|
-
def read_subset_imap(pointer, length)
|
|
421
|
-
return [] if length.zero?
|
|
422
|
-
|
|
423
|
-
pointer.read_array_of_int(length)
|
|
424
|
-
end
|
|
425
|
-
|
|
426
349
|
def compose_subset_imap(imap)
|
|
427
350
|
base_imap = @subset_imap || Array.new(samples.length, &:itself)
|
|
428
351
|
imap.map { |index| base_imap.fetch(index) }
|
|
429
352
|
end
|
|
430
353
|
|
|
431
|
-
def
|
|
432
|
-
return nil unless imap
|
|
433
|
-
return nil if imap.empty?
|
|
434
|
-
|
|
435
|
-
FFI::MemoryPointer.new(:int, imap.length).tap do |pointer|
|
|
436
|
-
pointer.write_array_of_int(imap)
|
|
437
|
-
end
|
|
438
|
-
end
|
|
354
|
+
def native_handle = @native
|
|
439
355
|
end
|
|
440
356
|
end
|
|
441
357
|
end
|
|
@@ -3,47 +3,21 @@
|
|
|
3
3
|
module HTS
|
|
4
4
|
class Bcf < Hts
|
|
5
5
|
class HeaderRecord
|
|
6
|
-
def initialize(
|
|
7
|
-
|
|
8
|
-
when LibHTS::BcfHrec
|
|
9
|
-
@bcf_hrec = arg
|
|
10
|
-
else
|
|
11
|
-
raise TypeError, "Invalid argument"
|
|
12
|
-
end
|
|
13
|
-
end
|
|
6
|
+
def initialize(native)
|
|
7
|
+
raise TypeError, "Invalid argument" unless native.is_a?(Native::BcfHeaderRecordHandle)
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
@bcf_hrec
|
|
9
|
+
@native = native
|
|
17
10
|
end
|
|
18
11
|
|
|
19
|
-
def add_key(key)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def set_value(i, val, quote: true)
|
|
24
|
-
is_quoted = quote ? 1 : 0
|
|
25
|
-
LibHTS.bcf_hrec_set_val(@bcf_hrec, i, val, val.length, is_quoted)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def find_key(key)
|
|
29
|
-
LibHTS.bcf_hrec_find_key(@bcf_hrec, key)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def to_s
|
|
33
|
-
kstr = LibHTS::KString.new
|
|
34
|
-
begin
|
|
35
|
-
LibHTS.bcf_hrec_format(@bcf_hrec, kstr)
|
|
36
|
-
kstr.read_string_copy
|
|
37
|
-
ensure
|
|
38
|
-
kstr.free_buffer
|
|
39
|
-
end
|
|
40
|
-
end
|
|
12
|
+
def add_key(key) = @native.add_key(key)
|
|
13
|
+
def set_value(index, value, quote: true) = @native.set_value(index, value, quote)
|
|
14
|
+
def find_key(key) = @native.find_key(key)
|
|
15
|
+
def to_s = @native.to_s
|
|
41
16
|
|
|
42
17
|
private
|
|
43
18
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
end
|
|
19
|
+
def native_handle = @native
|
|
20
|
+
def initialize_copy(original) = (@native = original.__send__(:native_handle).duplicate)
|
|
47
21
|
end
|
|
48
22
|
end
|
|
49
23
|
end
|