htslib 0.4.1 → 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 -123
- 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 -109
- 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 -79
- data/lib/hts/libhts/tbx_funcs.rb +0 -32
- data/lib/hts/libhts/thread_pool.rb +0 -139
- data/lib/hts/libhts/vcf.rb +0 -557
- data/lib/hts/libhts/vcf_funcs.rb +0 -353
- 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,28 +92,18 @@ module HTS
|
|
|
104
92
|
subset_samples = normalize_subset_samples(samples)
|
|
105
93
|
validate_subset_samples!(subset_samples)
|
|
106
94
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if subset_samples.empty?
|
|
110
|
-
subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, 0, ::FFI::Pointer::NULL, ::FFI::Pointer::NULL)
|
|
111
|
-
else
|
|
112
|
-
encoded_samples = subset_samples.map { |name| FFI::MemoryPointer.from_string(name) }
|
|
113
|
-
sample_pointers = FFI::MemoryPointer.new(:pointer, subset_samples.length)
|
|
114
|
-
sample_pointers.write_array_of_pointer(encoded_samples)
|
|
115
|
-
imap_pointer = FFI::MemoryPointer.new(:int, subset_samples.length)
|
|
116
|
-
subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, subset_samples.length, sample_pointers, imap_pointer)
|
|
117
|
-
end
|
|
95
|
+
result = @native.subset(subset_samples)
|
|
96
|
+
raise SubsetError, "Failed to subset BCF header samples #{subset_samples.inspect}" unless result
|
|
118
97
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
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|
|
|
123
101
|
header.send(:set_subset_state, subset_samples, composed_imap)
|
|
124
102
|
end
|
|
125
103
|
end
|
|
126
104
|
|
|
127
105
|
def add_sample(sample, sync: true)
|
|
128
|
-
rc =
|
|
106
|
+
rc = @native.add_sample(sample)
|
|
129
107
|
raise "Failed to add sample #{sample}" if rc.negative?
|
|
130
108
|
|
|
131
109
|
mark_sync_needed!
|
|
@@ -134,17 +112,14 @@ module HTS
|
|
|
134
112
|
end
|
|
135
113
|
|
|
136
114
|
def merge(hdr)
|
|
137
|
-
|
|
138
|
-
raise "Failed to merge BCF headers" if merged.to_ptr.null?
|
|
139
|
-
|
|
140
|
-
@bcf_hdr = merged
|
|
115
|
+
@native.merge(hdr.__send__(:native_handle))
|
|
141
116
|
mark_sync_needed!
|
|
142
117
|
sync_if_needed!
|
|
143
118
|
self
|
|
144
119
|
end
|
|
145
120
|
|
|
146
121
|
def sync
|
|
147
|
-
rc =
|
|
122
|
+
rc = @native.sync
|
|
148
123
|
raise "Failed to sync BCF header" if rc.negative?
|
|
149
124
|
|
|
150
125
|
@sync_needed = false
|
|
@@ -152,11 +127,13 @@ module HTS
|
|
|
152
127
|
end
|
|
153
128
|
|
|
154
129
|
def read_bcf(fname)
|
|
155
|
-
|
|
130
|
+
result = @native.read_file(fname)
|
|
131
|
+
@schema_version += 1 unless result.negative?
|
|
132
|
+
result
|
|
156
133
|
end
|
|
157
134
|
|
|
158
135
|
def append(line)
|
|
159
|
-
rc =
|
|
136
|
+
rc = @native.append(line)
|
|
160
137
|
raise "Failed to append VCF header line" if rc.negative?
|
|
161
138
|
|
|
162
139
|
mark_sync_needed!
|
|
@@ -165,18 +142,14 @@ module HTS
|
|
|
165
142
|
|
|
166
143
|
def delete(bcf_hl_type, key = nil) # FIXME
|
|
167
144
|
existed = hrec_exists?(bcf_hl_type, key)
|
|
168
|
-
|
|
169
|
-
LibHTS.bcf_hdr_remove(@bcf_hdr, type, key)
|
|
145
|
+
@native.remove(bcf_hl_type.to_s, key)
|
|
170
146
|
mark_sync_needed! if existed
|
|
171
147
|
existed
|
|
172
148
|
end
|
|
173
149
|
|
|
174
150
|
def get_hrec(bcf_hl_type, key, value, str_class = nil)
|
|
175
|
-
|
|
176
|
-
hrec
|
|
177
|
-
return nil if hrec.to_ptr.null?
|
|
178
|
-
|
|
179
|
-
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
|
|
180
153
|
end
|
|
181
154
|
|
|
182
155
|
def edit
|
|
@@ -252,33 +225,19 @@ module HTS
|
|
|
252
225
|
end
|
|
253
226
|
|
|
254
227
|
def seqnames
|
|
255
|
-
|
|
256
|
-
names = LibHTS.bcf_hdr_seqnames(@bcf_hdr, n)
|
|
257
|
-
begin
|
|
258
|
-
names.read_array_of_pointer(n.read_int)
|
|
259
|
-
.map(&:read_string)
|
|
260
|
-
ensure
|
|
261
|
-
LibHTS.hts_free(names) unless names.null?
|
|
262
|
-
end
|
|
228
|
+
@native.seqnames
|
|
263
229
|
end
|
|
264
230
|
|
|
265
231
|
def to_s
|
|
266
|
-
|
|
267
|
-
begin
|
|
268
|
-
raise "Failed to get header string" if LibHTS.bcf_hdr_format(@bcf_hdr, 0, kstr).negative?
|
|
269
|
-
|
|
270
|
-
kstr.read_string_copy
|
|
271
|
-
ensure
|
|
272
|
-
kstr.free_buffer
|
|
273
|
-
end
|
|
232
|
+
@native.to_s
|
|
274
233
|
end
|
|
275
234
|
|
|
276
235
|
def name2id(name)
|
|
277
|
-
|
|
236
|
+
@native.name2id(name)
|
|
278
237
|
end
|
|
279
238
|
|
|
280
239
|
def id2name(id)
|
|
281
|
-
|
|
240
|
+
@native.id2name(id)
|
|
282
241
|
end
|
|
283
242
|
|
|
284
243
|
private
|
|
@@ -325,6 +284,7 @@ module HTS
|
|
|
325
284
|
|
|
326
285
|
def mark_sync_needed!
|
|
327
286
|
@sync_needed = true
|
|
287
|
+
@schema_version += 1
|
|
328
288
|
end
|
|
329
289
|
|
|
330
290
|
def sync_if_needed!
|
|
@@ -332,58 +292,26 @@ module HTS
|
|
|
332
292
|
end
|
|
333
293
|
|
|
334
294
|
def hrec_exists?(bcf_hl_type, key)
|
|
335
|
-
|
|
336
|
-
lookup_key, lookup_value, str_class
|
|
337
|
-
hrec = borrowed_hrec(type, lookup_key, lookup_value, str_class)
|
|
338
|
-
!hrec.to_ptr.null?
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
def borrowed_hrec(type, key, value, str_class)
|
|
342
|
-
LibHTS.bcf_hdr_get_hrec(@bcf_hdr, type, key, value, str_class)
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
def owned_hrec(hrec)
|
|
346
|
-
LibHTS.bcf_hrec_dup(hrec).tap do |owned|
|
|
347
|
-
raise "Failed to duplicate BCF header record" if owned.to_ptr.null?
|
|
348
|
-
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?
|
|
349
297
|
end
|
|
350
298
|
|
|
351
299
|
def hrec_lookup_args(type, key)
|
|
352
|
-
case type
|
|
353
|
-
when
|
|
300
|
+
case type.to_s.upcase
|
|
301
|
+
when "FILTER", "FIL", "INFO", "FORMAT", "FMT", "CONTIG", "CTG"
|
|
354
302
|
["ID", key, nil]
|
|
355
|
-
when
|
|
303
|
+
when "GENOTYPE", "GEN"
|
|
356
304
|
[key, nil, nil]
|
|
357
305
|
else
|
|
358
306
|
["ID", key, nil]
|
|
359
307
|
end
|
|
360
308
|
end
|
|
361
309
|
|
|
362
|
-
def bcf_hl_type_to_int(bcf_hl_type)
|
|
363
|
-
return bcf_hl_type if bcf_hl_type.is_a?(Integer)
|
|
364
|
-
|
|
365
|
-
case bcf_hl_type.to_s.upcase
|
|
366
|
-
when "FILTER", "FIL"
|
|
367
|
-
LibHTS::BCF_HL_FLT
|
|
368
|
-
when "INFO"
|
|
369
|
-
LibHTS::BCF_HL_INFO
|
|
370
|
-
when "FORMAT", "FMT"
|
|
371
|
-
LibHTS::BCF_HL_FMT
|
|
372
|
-
when "CONTIG", "CTG"
|
|
373
|
-
LibHTS::BCF_HL_CTG
|
|
374
|
-
when "STRUCTURED", "STR"
|
|
375
|
-
LibHTS::BCF_HL_STR
|
|
376
|
-
when "GENOTYPE", "GEN"
|
|
377
|
-
LibHTS::BCF_HL_GEN
|
|
378
|
-
else
|
|
379
|
-
raise TypeError, "Invalid argument"
|
|
380
|
-
end
|
|
381
|
-
end
|
|
382
|
-
|
|
383
310
|
def initialize_copy(orig)
|
|
384
|
-
@
|
|
311
|
+
@native = orig.__send__(:native_handle).duplicate
|
|
385
312
|
@sync_depth = 0
|
|
386
313
|
@sync_needed = false
|
|
314
|
+
@schema_version = orig.schema_version
|
|
387
315
|
set_subset_state(orig.subset_samples, orig.send(:subset_imap))
|
|
388
316
|
end
|
|
389
317
|
|
|
@@ -394,7 +322,7 @@ module HTS
|
|
|
394
322
|
def set_subset_state(samples, imap)
|
|
395
323
|
@subset_samples = samples&.dup
|
|
396
324
|
@subset_imap = imap&.dup
|
|
397
|
-
@subset_imap_pointer =
|
|
325
|
+
@subset_imap_pointer = nil
|
|
398
326
|
end
|
|
399
327
|
|
|
400
328
|
private
|
|
@@ -418,25 +346,12 @@ module HTS
|
|
|
418
346
|
raise UnknownSampleError, "Unknown sample names: #{missing.join(', ')}" unless missing.empty?
|
|
419
347
|
end
|
|
420
348
|
|
|
421
|
-
def read_subset_imap(pointer, length)
|
|
422
|
-
return [] if length.zero?
|
|
423
|
-
|
|
424
|
-
pointer.read_array_of_int(length)
|
|
425
|
-
end
|
|
426
|
-
|
|
427
349
|
def compose_subset_imap(imap)
|
|
428
350
|
base_imap = @subset_imap || Array.new(samples.length, &:itself)
|
|
429
351
|
imap.map { |index| base_imap.fetch(index) }
|
|
430
352
|
end
|
|
431
353
|
|
|
432
|
-
def
|
|
433
|
-
return nil unless imap
|
|
434
|
-
return nil if imap.empty?
|
|
435
|
-
|
|
436
|
-
FFI::MemoryPointer.new(:int, imap.length).tap do |pointer|
|
|
437
|
-
pointer.write_array_of_int(imap)
|
|
438
|
-
end
|
|
439
|
-
end
|
|
354
|
+
def native_handle = @native
|
|
440
355
|
end
|
|
441
356
|
end
|
|
442
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
|