htslib 0.2.5 → 0.2.8
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 +100 -54
- data/TUTORIAL.md +316 -0
- data/lib/hts/bam/auxi.rb +89 -6
- data/lib/hts/bam/cigar.rb +46 -6
- data/lib/hts/bam/flag.rb +43 -4
- data/lib/hts/bam/header.rb +8 -0
- data/lib/hts/bam/record.rb +17 -12
- data/lib/hts/bam.rb +114 -62
- data/lib/hts/bcf/format.rb +28 -24
- data/lib/hts/bcf/header.rb +8 -0
- data/lib/hts/bcf/info.rb +28 -24
- data/lib/hts/bcf/record.rb +2 -2
- data/lib/hts/bcf.rb +114 -74
- data/lib/hts/faidx/sequence.rb +62 -0
- data/lib/hts/faidx.rb +74 -17
- data/lib/hts/hts.rb +10 -7
- data/lib/hts/libhts/bgzf.rb +1 -1
- data/lib/hts/libhts/constants.rb +14 -14
- data/lib/hts/libhts/cram.rb +1 -1
- data/lib/hts/libhts/sam.rb +22 -10
- data/lib/hts/libhts/tbx.rb +2 -0
- data/lib/hts/libhts/tbx_funcs.rb +1 -1
- data/lib/hts/libhts/vcf.rb +1 -1
- data/lib/hts/libhts.rb +1 -1
- data/lib/hts/tabix.rb +116 -0
- data/lib/hts/version.rb +1 -1
- data/lib/htslib.rb +1 -1
- metadata +11 -9
- data/lib/hts/tbx.rb +0 -73
- /data/lib/hts/libhts/{faidx.rb → fai.rb} +0 -0
data/lib/hts/bam/auxi.rb
CHANGED
@@ -3,22 +3,96 @@
|
|
3
3
|
# Q. Why is the file name auxi.rb and not aux.rb?
|
4
4
|
#
|
5
5
|
# A. This is for compatibility with Windows.
|
6
|
+
#
|
6
7
|
# In Windows, aux is a reserved word
|
7
8
|
# You cannot create a file named aux.
|
9
|
+
#
|
10
|
+
# What?! That's crazy!
|
8
11
|
|
9
12
|
module HTS
|
10
13
|
class Bam < Hts
|
11
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.
|
12
20
|
class Aux
|
21
|
+
include Enumerable
|
22
|
+
attr_reader :record
|
23
|
+
|
13
24
|
def initialize(record)
|
14
25
|
@record = record
|
15
26
|
end
|
16
27
|
|
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`.
|
17
32
|
def get(key, type = nil)
|
18
33
|
aux = LibHTS.bam_aux_get(@record.struct, key)
|
19
34
|
return nil if aux.null?
|
20
35
|
|
21
|
-
type
|
36
|
+
get_ruby_aux(aux, type)
|
37
|
+
end
|
38
|
+
|
39
|
+
# For compatibility with HTS.cr.
|
40
|
+
def get_int(key)
|
41
|
+
get(key, "i")
|
42
|
+
end
|
43
|
+
|
44
|
+
# For compatibility with HTS.cr.
|
45
|
+
def get_float(key)
|
46
|
+
get(key, "f")
|
47
|
+
end
|
48
|
+
|
49
|
+
# For compatibility with HTS.cr.
|
50
|
+
def get_string(key)
|
51
|
+
get(key, "Z")
|
52
|
+
end
|
53
|
+
|
54
|
+
def [](key)
|
55
|
+
get(key)
|
56
|
+
end
|
57
|
+
|
58
|
+
def first
|
59
|
+
aux = LibHTS.bam_aux_first(@record.struct)
|
60
|
+
return nil if aux.null?
|
61
|
+
|
62
|
+
get_ruby_aux(aux)
|
63
|
+
end
|
64
|
+
|
65
|
+
def each
|
66
|
+
return enum_for(__method__) unless block_given?
|
67
|
+
|
68
|
+
aux = LibHTS.bam_aux_first(@record.struct)
|
69
|
+
return nil if aux.null?
|
70
|
+
|
71
|
+
loop do
|
72
|
+
yield get_ruby_aux(aux)
|
73
|
+
aux = LibHTS.bam_aux_next(@record.struct, aux)
|
74
|
+
break if aux.null?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_h
|
79
|
+
h = {}
|
80
|
+
aux = LibHTS.bam_aux_first(@record.struct)
|
81
|
+
return h if aux.null?
|
82
|
+
|
83
|
+
loop do
|
84
|
+
key = FFI::Pointer.new(aux.address - 2).read_string(2)
|
85
|
+
h[key] = get_ruby_aux(aux)
|
86
|
+
aux = LibHTS.bam_aux_next(@record.struct, aux)
|
87
|
+
break if aux.null?
|
88
|
+
end
|
89
|
+
h
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def get_ruby_aux(aux, type = nil)
|
95
|
+
type = type ? type.to_s : aux.read_string(1)
|
22
96
|
|
23
97
|
# A (character), B (general array),
|
24
98
|
# f (real number), H (hexadecimal array),
|
@@ -33,14 +107,23 @@ module HTS
|
|
33
107
|
LibHTS.bam_aux2Z(aux)
|
34
108
|
when "A" # char
|
35
109
|
LibHTS.bam_aux2A(aux).chr
|
110
|
+
when "B" # array
|
111
|
+
t2 = aux.read_string(2)[1] # just a little less efficient
|
112
|
+
l = LibHTS.bam_auxB_len(aux)
|
113
|
+
case t2
|
114
|
+
when "c", "C", "s", "S", "i", "I"
|
115
|
+
# FIXME : Not efficient.
|
116
|
+
Array.new(l) { |i| LibHTS.bam_auxB2i(aux, i) }
|
117
|
+
when "f", "d"
|
118
|
+
# FIXME : Not efficient.
|
119
|
+
Array.new(l) { |i| LibHTS.bam_auxB2f(aux, i) }
|
120
|
+
else
|
121
|
+
raise NotImplementedError, "type: #{type} #{t2}"
|
122
|
+
end
|
36
123
|
else
|
37
|
-
raise NotImplementedError, "type: #{
|
124
|
+
raise NotImplementedError, "type: #{type}"
|
38
125
|
end
|
39
126
|
end
|
40
|
-
|
41
|
-
def [](key)
|
42
|
-
get(key)
|
43
|
-
end
|
44
127
|
end
|
45
128
|
end
|
46
129
|
end
|
data/lib/hts/bam/cigar.rb
CHANGED
@@ -6,11 +6,31 @@ module HTS
|
|
6
6
|
class Cigar
|
7
7
|
include Enumerable
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
# a uint32_t array (with 32 bits for every CIGAR op: length<<4|operation)
|
10
|
+
attr_accessor :array
|
11
|
+
|
12
|
+
# Create a new Cigar object from a string.
|
13
|
+
# @param [String] cigar_str
|
14
|
+
# The CIGAR string is converted to a uint32_t array in htslib.
|
15
|
+
def self.parse(str)
|
16
|
+
c = FFI::MemoryPointer.new(:pointer)
|
17
|
+
m = FFI::MemoryPointer.new(:size_t)
|
18
|
+
LibHTS.sam_parse_cigar(str, FFI::Pointer::NULL, c, m)
|
19
|
+
cigar_array = c.read_pointer.read_array_of_uint32(m.read(:size_t))
|
20
|
+
obj = new
|
21
|
+
obj.array = cigar_array
|
22
|
+
obj
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(record = nil)
|
26
|
+
if record
|
27
|
+
# The record is used at initialization and is not retained after that.
|
28
|
+
bam1 = record.struct
|
29
|
+
n_cigar = bam1[:core][:n_cigar]
|
30
|
+
@array = LibHTS.bam_get_cigar(bam1).read_array_of_uint32(n_cigar)
|
31
|
+
else
|
32
|
+
@array = []
|
33
|
+
end
|
14
34
|
end
|
15
35
|
|
16
36
|
def to_s
|
@@ -20,12 +40,32 @@ module HTS
|
|
20
40
|
def each
|
21
41
|
return to_enum(__method__) unless block_given?
|
22
42
|
|
23
|
-
@
|
43
|
+
@array.each do |c|
|
24
44
|
op = LibHTS.bam_cigar_opchr(c)
|
25
45
|
len = LibHTS.bam_cigar_oplen(c)
|
26
46
|
yield [op, len]
|
27
47
|
end
|
28
48
|
end
|
49
|
+
|
50
|
+
def qlen
|
51
|
+
a = FFI::MemoryPointer.new(:uint32, @array.size)
|
52
|
+
a.write_array_of_uint32(@array)
|
53
|
+
LibHTS.bam_cigar2qlen(@array.size, a)
|
54
|
+
end
|
55
|
+
|
56
|
+
def rlen
|
57
|
+
a = FFI::MemoryPointer.new(:uint32, @array.size)
|
58
|
+
a.write_array_of_uint32(@array)
|
59
|
+
LibHTS.bam_cigar2rlen(@array.size, a)
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
other.is_a?(Cigar) && (@array == other.array)
|
64
|
+
end
|
65
|
+
|
66
|
+
def eql?(other)
|
67
|
+
other.is_a?(Cigar) && @array.eql?(other.array)
|
68
|
+
end
|
29
69
|
end
|
30
70
|
end
|
31
71
|
end
|
data/lib/hts/bam/flag.rb
CHANGED
@@ -28,8 +28,6 @@ module HTS
|
|
28
28
|
# BAM_FDUP = 1024
|
29
29
|
# BAM_FSUPPLEMENTARY = 2048
|
30
30
|
|
31
|
-
# TODO: Enabling bitwise operations?
|
32
|
-
|
33
31
|
TABLE = { paired?: LibHTS::BAM_FPAIRED,
|
34
32
|
proper_pair?: LibHTS::BAM_FPROPER_PAIR,
|
35
33
|
unmapped?: LibHTS::BAM_FUNMAP,
|
@@ -43,16 +41,57 @@ module HTS
|
|
43
41
|
duplicate?: LibHTS::BAM_FDUP,
|
44
42
|
supplementary?: LibHTS::BAM_FSUPPLEMENTARY }.freeze
|
45
43
|
|
46
|
-
|
44
|
+
# @!macro [attach] generate_flag_methods
|
45
|
+
# @!method $1
|
46
|
+
# @return [Boolean]
|
47
|
+
def self.generate(name)
|
47
48
|
define_method(name) do
|
48
|
-
|
49
|
+
(@value & TABLE[name]) != 0
|
49
50
|
end
|
50
51
|
end
|
52
|
+
private_class_method :generate
|
53
|
+
|
54
|
+
generate :paired?
|
55
|
+
generate :proper_pair?
|
56
|
+
generate :unmapped?
|
57
|
+
generate :mate_unmapped?
|
58
|
+
generate :reverse?
|
59
|
+
generate :mate_reverse?
|
60
|
+
generate :read1?
|
61
|
+
generate :read2?
|
62
|
+
generate :secondary?
|
63
|
+
generate :qcfail?
|
64
|
+
generate :duplicate?
|
65
|
+
generate :supplementary?
|
51
66
|
|
52
67
|
def has_flag?(f)
|
53
68
|
(@value & f) != 0
|
54
69
|
end
|
55
70
|
|
71
|
+
def &(other)
|
72
|
+
Flag.new(@value & other.to_i)
|
73
|
+
end
|
74
|
+
|
75
|
+
def |(other)
|
76
|
+
Flag.new(@value | other.to_i)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ^(other)
|
80
|
+
Flag.new(@value ^ other.to_i)
|
81
|
+
end
|
82
|
+
|
83
|
+
def ~
|
84
|
+
Flag.new(~@value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def <<(f)
|
88
|
+
Flag.new(@value << f.to_i)
|
89
|
+
end
|
90
|
+
|
91
|
+
def >>(other)
|
92
|
+
Flag.new(@value >> other.to_i)
|
93
|
+
end
|
94
|
+
|
56
95
|
def to_i
|
57
96
|
@value
|
58
97
|
end
|
data/lib/hts/bam/header.rb
CHANGED
data/lib/hts/bam/record.rb
CHANGED
@@ -12,8 +12,8 @@ module HTS
|
|
12
12
|
|
13
13
|
attr_reader :header
|
14
14
|
|
15
|
-
def initialize(
|
16
|
-
@bam1 = bam1_t
|
15
|
+
def initialize(header, bam1_t = nil)
|
16
|
+
@bam1 = bam1_t || LibHTS.bam_init1
|
17
17
|
@header = header
|
18
18
|
end
|
19
19
|
|
@@ -32,6 +32,10 @@ module HTS
|
|
32
32
|
LibHTS.bam_get_qname(@bam1).read_string
|
33
33
|
end
|
34
34
|
|
35
|
+
def qname=(name)
|
36
|
+
LibHTS.bam_set_qname(@bam1, name)
|
37
|
+
end
|
38
|
+
|
35
39
|
# Get the chromosome ID of the alignment. -1 if not mapped.
|
36
40
|
# @return [Integer] chromosome ID
|
37
41
|
def tid
|
@@ -151,12 +155,13 @@ module HTS
|
|
151
155
|
# Get the Bam::Cigar object.
|
152
156
|
# @return [Bam::Cigar] cigar
|
153
157
|
def cigar
|
154
|
-
Cigar.new(
|
158
|
+
Cigar.new(self)
|
155
159
|
end
|
156
160
|
|
157
161
|
# Calculate query length from CIGAR.
|
158
162
|
# @return [Integer] query length
|
159
163
|
def qlen
|
164
|
+
# cigar.qlen will be slower because it converts to a Ruby array.
|
160
165
|
LibHTS.bam_cigar2qlen(
|
161
166
|
@bam1[:core][:n_cigar],
|
162
167
|
LibHTS.bam_get_cigar(@bam1)
|
@@ -177,7 +182,7 @@ module HTS
|
|
177
182
|
def seq
|
178
183
|
r = LibHTS.bam_get_seq(@bam1)
|
179
184
|
seq = String.new
|
180
|
-
|
185
|
+
len.times do |i|
|
181
186
|
seq << SEQ_NT16_STR[LibHTS.bam_seqi(r, i)]
|
182
187
|
end
|
183
188
|
seq
|
@@ -194,8 +199,8 @@ module HTS
|
|
194
199
|
# @param [Integer] i index
|
195
200
|
# @return [String] base
|
196
201
|
def base(n)
|
197
|
-
n +=
|
198
|
-
return "." if (n >=
|
202
|
+
n += len if n < 0
|
203
|
+
return "." if (n >= len) || (n < 0) # eg. base(-1000)
|
199
204
|
|
200
205
|
r = LibHTS.bam_get_seq(@bam1)
|
201
206
|
SEQ_NT16_STR[LibHTS.bam_seqi(r, n)]
|
@@ -205,7 +210,7 @@ module HTS
|
|
205
210
|
# @return [Array] base qualities
|
206
211
|
def qual
|
207
212
|
q_ptr = LibHTS.bam_get_qual(@bam1)
|
208
|
-
q_ptr.read_array_of_uint8(
|
213
|
+
q_ptr.read_array_of_uint8(len)
|
209
214
|
end
|
210
215
|
|
211
216
|
# Get the base qualities as a string. (a.k.a QUAL)
|
@@ -219,8 +224,8 @@ module HTS
|
|
219
224
|
# @param [Integer] i index
|
220
225
|
# @return [Integer] base quality
|
221
226
|
def base_qual(n)
|
222
|
-
n +=
|
223
|
-
return 0 if (n >=
|
227
|
+
n += len if n < 0
|
228
|
+
return 0 if (n >= len) || (n < 0) # eg. base_qual(-1000)
|
224
229
|
|
225
230
|
q_ptr = LibHTS.bam_get_qual(@bam1)
|
226
231
|
q_ptr.get_uint8(n)
|
@@ -255,11 +260,11 @@ module HTS
|
|
255
260
|
end
|
256
261
|
end
|
257
262
|
|
258
|
-
# TODO: add a method to get the
|
263
|
+
# TODO: add a method to get the auxiliary fields as a hash.
|
259
264
|
|
260
|
-
# TODO: add a method to set the
|
265
|
+
# TODO: add a method to set the auxiliary fields.
|
261
266
|
|
262
|
-
# TODO: add a method to remove the
|
267
|
+
# TODO: add a method to remove the auxiliary fields.
|
263
268
|
|
264
269
|
# TODO: add a method to set variable length data (qname, cigar, seq, qual).
|
265
270
|
|
data/lib/hts/bam.rb
CHANGED
@@ -59,7 +59,7 @@ module HTS
|
|
59
59
|
@start_position = tell
|
60
60
|
end
|
61
61
|
|
62
|
-
def build_index(index_name = nil, min_shift: 0)
|
62
|
+
def build_index(index_name = nil, min_shift: 0, threads: 2)
|
63
63
|
check_closed
|
64
64
|
|
65
65
|
if index_name
|
@@ -67,10 +67,15 @@ module HTS
|
|
67
67
|
else
|
68
68
|
warn "Create index for #{@file_name}"
|
69
69
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
case LibHTS.sam_index_build3(@file_name, index_name, min_shift, (@nthreads || threads))
|
71
|
+
when 0 # successful
|
72
|
+
when -1 then raise "indexing failed"
|
73
|
+
when -2 then raise "opening #{@file_name} failed"
|
74
|
+
when -3 then raise "format not indexable"
|
75
|
+
when -4 then raise "failed to create and/or save the index"
|
76
|
+
else raise "unknown error"
|
77
|
+
end
|
78
|
+
self # for method chaining
|
74
79
|
end
|
75
80
|
|
76
81
|
def load_index(index_name = nil)
|
@@ -95,11 +100,6 @@ module HTS
|
|
95
100
|
super
|
96
101
|
end
|
97
102
|
|
98
|
-
def fai=(fai)
|
99
|
-
check_closed
|
100
|
-
LibHTS.hts_set_fai_filename(@hts_file, fai) > 0 || raise
|
101
|
-
end
|
102
|
-
|
103
103
|
def write_header(header)
|
104
104
|
check_closed
|
105
105
|
|
@@ -107,28 +107,19 @@ module HTS
|
|
107
107
|
LibHTS.sam_hdr_write(@hts_file, header)
|
108
108
|
end
|
109
109
|
|
110
|
-
def
|
110
|
+
def header=(header)
|
111
|
+
write_header(header)
|
112
|
+
end
|
113
|
+
|
114
|
+
def write(record)
|
111
115
|
check_closed
|
112
116
|
|
113
|
-
|
114
|
-
r = LibHTS.sam_write1(@hts_file, header, aln_dup)
|
117
|
+
r = LibHTS.sam_write1(@hts_file, header, record)
|
115
118
|
raise "Failed to write record" if r < 0
|
116
119
|
end
|
117
120
|
|
118
|
-
def
|
119
|
-
|
120
|
-
each_record_copy(&block)
|
121
|
-
else
|
122
|
-
each_record_reuse(&block)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def query(region, copy: false, &block)
|
127
|
-
if copy
|
128
|
-
query_copy(region, &block)
|
129
|
-
else
|
130
|
-
query_reuse(region, &block)
|
131
|
-
end
|
121
|
+
def <<(record)
|
122
|
+
write(record)
|
132
123
|
end
|
133
124
|
|
134
125
|
# @!macro [attach] define_getter
|
@@ -150,9 +141,10 @@ module HTS
|
|
150
141
|
alias isize insert_size
|
151
142
|
alias mpos mate_pos
|
152
143
|
|
144
|
+
# FXIME: experimental
|
153
145
|
def aux(tag)
|
154
|
-
warn "experimental"
|
155
146
|
check_closed
|
147
|
+
|
156
148
|
position = tell
|
157
149
|
ary = map { |r| r.aux(tag) }
|
158
150
|
seek(position)
|
@@ -177,8 +169,8 @@ module HTS
|
|
177
169
|
alias each_isize each_insert_size
|
178
170
|
alias each_mpos each_mate_pos
|
179
171
|
|
172
|
+
# FIXME: experimental
|
180
173
|
def each_aux(tag)
|
181
|
-
warn "experimental"
|
182
174
|
check_closed
|
183
175
|
return to_enum(__method__, tag) unless block_given?
|
184
176
|
|
@@ -189,47 +181,44 @@ module HTS
|
|
189
181
|
self
|
190
182
|
end
|
191
183
|
|
192
|
-
|
184
|
+
def each(copy: false, &block)
|
185
|
+
if copy
|
186
|
+
each_record_copy(&block)
|
187
|
+
else
|
188
|
+
each_record_reuse(&block)
|
189
|
+
end
|
190
|
+
end
|
193
191
|
|
194
|
-
def
|
192
|
+
def query(region, beg = nil, end_ = nil, copy: false, &block)
|
195
193
|
check_closed
|
196
194
|
raise "Index file is required to call the query method." unless index_loaded?
|
197
|
-
return to_enum(__method__, region) unless block_given?
|
198
|
-
|
199
|
-
qiter = LibHTS.sam_itr_querys(@idx, header, region)
|
200
|
-
raise "Failed to query region: #{region}" if qiter.null?
|
201
195
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
196
|
+
if beg && end_
|
197
|
+
tid = header.name2tid(region)
|
198
|
+
queryi(tid, beg, end_, copy:, &block)
|
199
|
+
elsif beg.nil? && end_.nil?
|
200
|
+
querys(region, copy:, &block)
|
201
|
+
else
|
202
|
+
raise ArgumentError, "beg and end_ must be specified together"
|
208
203
|
end
|
209
|
-
self
|
210
204
|
end
|
211
205
|
|
212
|
-
|
213
|
-
check_closed
|
214
|
-
raise "Index file is required to call the query method." unless index_loaded?
|
215
|
-
return to_enum(__method__, region) unless block_given?
|
206
|
+
private
|
216
207
|
|
217
|
-
|
218
|
-
|
208
|
+
def queryi(tid, beg, end_, copy: false, &block)
|
209
|
+
if copy
|
210
|
+
queryi_copy(tid, beg, end_, &block)
|
211
|
+
else
|
212
|
+
queryi_reuse(tid, beg, end_, &block)
|
213
|
+
end
|
214
|
+
end
|
219
215
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
raise if slen < -1
|
226
|
-
|
227
|
-
yield Record.new(bam1, header)
|
228
|
-
end
|
229
|
-
ensure
|
230
|
-
LibHTS.hts_itr_destroy(qiter)
|
216
|
+
def querys(region, copy: false, &block)
|
217
|
+
if copy
|
218
|
+
querys_copy(region, &block)
|
219
|
+
else
|
220
|
+
querys_reuse(region, &block)
|
231
221
|
end
|
232
|
-
self
|
233
222
|
end
|
234
223
|
|
235
224
|
def each_record_reuse
|
@@ -239,7 +228,7 @@ module HTS
|
|
239
228
|
return to_enum(__method__) unless block_given?
|
240
229
|
|
241
230
|
bam1 = LibHTS.bam_init1
|
242
|
-
record = Record.new(
|
231
|
+
record = Record.new(header, bam1)
|
243
232
|
yield record while LibHTS.sam_read1(@hts_file, header, bam1) != -1
|
244
233
|
self
|
245
234
|
end
|
@@ -249,10 +238,73 @@ module HTS
|
|
249
238
|
return to_enum(__method__) unless block_given?
|
250
239
|
|
251
240
|
while LibHTS.sam_read1(@hts_file, header, bam1 = LibHTS.bam_init1) != -1
|
252
|
-
record = Record.new(
|
241
|
+
record = Record.new(header, bam1)
|
253
242
|
yield record
|
254
243
|
end
|
255
244
|
self
|
256
245
|
end
|
246
|
+
|
247
|
+
def queryi_reuse(tid, beg, end_, &block)
|
248
|
+
return to_enum(__method__, region, beg, end_) unless block_given?
|
249
|
+
|
250
|
+
qiter = LibHTS.sam_itr_queryi(@idx, tid, beg, end_)
|
251
|
+
raise "Failed to query region: #{tid} #{beg} #{end_}" if qiter.null?
|
252
|
+
|
253
|
+
query_reuse_yield(qiter, &block)
|
254
|
+
self
|
255
|
+
end
|
256
|
+
|
257
|
+
def queryi_copy(tid, beg, end_, &block)
|
258
|
+
return to_enum(__method__, tid, beg, end_) unless block_given?
|
259
|
+
|
260
|
+
qiter = LibHTS.sam_itr_queryi(@idx, tid, beg, end_)
|
261
|
+
raise "Failed to query region: #{tid} #{beg} #{end_}" if qiter.null?
|
262
|
+
|
263
|
+
query_copy(qiter, &block)
|
264
|
+
self
|
265
|
+
end
|
266
|
+
|
267
|
+
def querys_reuse(region, &block)
|
268
|
+
return to_enum(__method__, region) unless block_given?
|
269
|
+
|
270
|
+
qiter = LibHTS.sam_itr_querys(@idx, header, region)
|
271
|
+
raise "Failed to query region: #{region}" if qiter.null?
|
272
|
+
|
273
|
+
query_reuse_yield(qiter, &block)
|
274
|
+
self
|
275
|
+
end
|
276
|
+
|
277
|
+
def querys_copy(region, &block)
|
278
|
+
return to_enum(__method__, region) unless block_given?
|
279
|
+
|
280
|
+
qiter = LibHTS.sam_itr_querys(@idx, header, region)
|
281
|
+
raise "Failed to query region: #{region}" if qiter.null?
|
282
|
+
|
283
|
+
query_copy(qiter, &block)
|
284
|
+
self
|
285
|
+
end
|
286
|
+
|
287
|
+
def query_reuse_yield(qiter)
|
288
|
+
bam1 = LibHTS.bam_init1
|
289
|
+
record = Record.new(header, bam1)
|
290
|
+
begin
|
291
|
+
yield record while LibHTS.sam_itr_next(@hts_file, qiter, bam1) > 0
|
292
|
+
ensure
|
293
|
+
LibHTS.hts_itr_destroy(qiter)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def query_copy(qiter)
|
298
|
+
loop do
|
299
|
+
bam1 = LibHTS.bam_init1
|
300
|
+
slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
|
301
|
+
break if slen == -1
|
302
|
+
raise if slen < -1
|
303
|
+
|
304
|
+
yield Record.new(header, bam1)
|
305
|
+
end
|
306
|
+
ensure
|
307
|
+
LibHTS.hts_itr_destroy(qiter)
|
308
|
+
end
|
257
309
|
end
|
258
310
|
end
|
data/lib/hts/bcf/format.rb
CHANGED
@@ -8,30 +8,10 @@ module HTS
|
|
8
8
|
@p1 = FFI::MemoryPointer.new(:pointer) # FIXME: naming
|
9
9
|
end
|
10
10
|
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# For compatibility with HTS.cr.
|
17
|
-
def get_float(key)
|
18
|
-
get(key, :float)
|
19
|
-
end
|
20
|
-
|
21
|
-
# For compatibility with HTS.cr.
|
22
|
-
def get_flag(key)
|
23
|
-
get(key, :flag)
|
24
|
-
end
|
25
|
-
|
26
|
-
# For compatibility with HTS.cr.
|
27
|
-
def get_string(key)
|
28
|
-
get(key, :string)
|
29
|
-
end
|
30
|
-
|
31
|
-
def [](key)
|
32
|
-
get(key)
|
33
|
-
end
|
34
|
-
|
11
|
+
# @note: Why is this method named "get" instead of "fetch"?
|
12
|
+
# This is for compatibility with the Crystal language
|
13
|
+
# which provides methods like `get_int`, `get_float`, etc.
|
14
|
+
# I think they are better than `fetch_int`` and `fetch_float`.
|
35
15
|
def get(key, type = nil)
|
36
16
|
n = FFI::MemoryPointer.new(:int)
|
37
17
|
p1 = @p1
|
@@ -73,6 +53,30 @@ module HTS
|
|
73
53
|
end
|
74
54
|
end
|
75
55
|
|
56
|
+
# For compatibility with HTS.cr.
|
57
|
+
def get_int(key)
|
58
|
+
get(key, :int)
|
59
|
+
end
|
60
|
+
|
61
|
+
# For compatibility with HTS.cr.
|
62
|
+
def get_float(key)
|
63
|
+
get(key, :float)
|
64
|
+
end
|
65
|
+
|
66
|
+
# For compatibility with HTS.cr.
|
67
|
+
def get_flag(key)
|
68
|
+
get(key, :flag)
|
69
|
+
end
|
70
|
+
|
71
|
+
# For compatibility with HTS.cr.
|
72
|
+
def get_string(key)
|
73
|
+
get(key, :string)
|
74
|
+
end
|
75
|
+
|
76
|
+
def [](key)
|
77
|
+
get(key)
|
78
|
+
end
|
79
|
+
|
76
80
|
def fields
|
77
81
|
ids.map do |id|
|
78
82
|
name = LibHTS.bcf_hdr_int2id(@record.header.struct, LibHTS::BCF_DT_ID, id)
|