htslib 0.2.2 → 0.2.5

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.
data/lib/hts/bam.rb CHANGED
@@ -57,7 +57,6 @@ module HTS
57
57
  build_index(index) if build_index
58
58
  @idx = load_index(index)
59
59
  @start_position = tell
60
- super # do nothing
61
60
  end
62
61
 
63
62
  def build_index(index_name = nil, min_shift: 0)
@@ -90,18 +89,21 @@ module HTS
90
89
  !@idx.null?
91
90
  end
92
91
 
93
- # Close the current file.
94
92
  def close
95
93
  LibHTS.hts_idx_destroy(@idx) if @idx&.null?
96
94
  @idx = nil
97
95
  super
98
96
  end
99
97
 
98
+ def fai=(fai)
99
+ check_closed
100
+ LibHTS.hts_set_fai_filename(@hts_file, fai) > 0 || raise
101
+ end
102
+
100
103
  def write_header(header)
101
104
  check_closed
102
105
 
103
106
  @header = header.dup
104
- LibHTS.hts_set_fai_filename(@hts_file, @file_name)
105
107
  LibHTS.sam_hdr_write(@hts_file, header)
106
108
  end
107
109
 
@@ -109,7 +111,8 @@ module HTS
109
111
  check_closed
110
112
 
111
113
  aln_dup = aln.dup
112
- LibHTS.sam_write1(@hts_file, header, aln_dup) > 0 || raise
114
+ r = LibHTS.sam_write1(@hts_file, header, aln_dup)
115
+ raise "Failed to write record" if r < 0
113
116
  end
114
117
 
115
118
  def each(copy: false, &block)
@@ -120,29 +123,6 @@ module HTS
120
123
  end
121
124
  end
122
125
 
123
- private def each_record_copy
124
- check_closed
125
- return to_enum(__method__) unless block_given?
126
-
127
- while LibHTS.sam_read1(@hts_file, header, bam1 = LibHTS.bam_init1) != -1
128
- record = Record.new(bam1, header)
129
- yield record
130
- end
131
- self
132
- end
133
-
134
- private def each_record_reuse
135
- check_closed
136
- # Each does not always start at the beginning of the file.
137
- # This is the common behavior of IO objects in Ruby.
138
- return to_enum(__method__) unless block_given?
139
-
140
- bam1 = LibHTS.bam_init1
141
- record = Record.new(bam1, header)
142
- yield record while LibHTS.sam_read1(@hts_file, header, bam1) != -1
143
- self
144
- end
145
-
146
126
  def query(region, copy: false, &block)
147
127
  if copy
148
128
  query_copy(region, &block)
@@ -151,45 +131,6 @@ module HTS
151
131
  end
152
132
  end
153
133
 
154
- private def query_copy(region)
155
- check_closed
156
- raise "Index file is required to call the query method." unless index_loaded?
157
- return to_enum(__method__, region) unless block_given?
158
-
159
- qiter = LibHTS.sam_itr_querys(@idx, header, region)
160
-
161
- begin
162
- loop do
163
- bam1 = LibHTS.bam_init1
164
- slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
165
- break if slen == -1
166
- raise if slen < -1
167
-
168
- yield Record.new(bam1, header)
169
- end
170
- ensure
171
- LibHTS.hts_itr_destroy(qiter)
172
- end
173
- self
174
- end
175
-
176
- private def query_reuse(region)
177
- check_closed
178
- raise "Index file is required to call the query method." unless index_loaded?
179
- return to_enum(__method__, region) unless block_given?
180
-
181
- qiter = LibHTS.sam_itr_querys(@idx, header, region)
182
-
183
- bam1 = LibHTS.bam_init1
184
- record = Record.new(bam1, header)
185
- begin
186
- yield record while LibHTS.sam_itr_next(@hts_file, qiter, bam1) > 0
187
- ensure
188
- LibHTS.hts_itr_destroy(qiter)
189
- end
190
- self
191
- end
192
-
193
134
  # @!macro [attach] define_getter
194
135
  # @method $1
195
136
  # Get $1 array
@@ -247,5 +188,71 @@ module HTS
247
188
 
248
189
  self
249
190
  end
191
+
192
+ private
193
+
194
+ def query_reuse(region)
195
+ check_closed
196
+ 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
+
202
+ bam1 = LibHTS.bam_init1
203
+ record = Record.new(bam1, header)
204
+ begin
205
+ yield record while LibHTS.sam_itr_next(@hts_file, qiter, bam1) > 0
206
+ ensure
207
+ LibHTS.hts_itr_destroy(qiter)
208
+ end
209
+ self
210
+ end
211
+
212
+ def query_copy(region)
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?
216
+
217
+ qiter = LibHTS.sam_itr_querys(@idx, header, region)
218
+ raise "Failed to query region: #{region}" if qiter.null?
219
+
220
+ begin
221
+ loop do
222
+ bam1 = LibHTS.bam_init1
223
+ slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
224
+ break if slen == -1
225
+ raise if slen < -1
226
+
227
+ yield Record.new(bam1, header)
228
+ end
229
+ ensure
230
+ LibHTS.hts_itr_destroy(qiter)
231
+ end
232
+ self
233
+ end
234
+
235
+ def each_record_reuse
236
+ check_closed
237
+ # Each does not always start at the beginning of the file.
238
+ # This is the common behavior of IO objects in Ruby.
239
+ return to_enum(__method__) unless block_given?
240
+
241
+ bam1 = LibHTS.bam_init1
242
+ record = Record.new(bam1, header)
243
+ yield record while LibHTS.sam_read1(@hts_file, header, bam1) != -1
244
+ self
245
+ end
246
+
247
+ def each_record_copy
248
+ check_closed
249
+ return to_enum(__method__) unless block_given?
250
+
251
+ while LibHTS.sam_read1(@hts_file, header, bam1 = LibHTS.bam_init1) != -1
252
+ record = Record.new(bam1, header)
253
+ yield record
254
+ end
255
+ self
256
+ end
250
257
  end
251
258
  end
@@ -8,22 +8,22 @@ module HTS
8
8
  @p1 = FFI::MemoryPointer.new(:pointer) # FIXME: naming
9
9
  end
10
10
 
11
- # For compatibility with htslib.cr.
11
+ # For compatibility with HTS.cr.
12
12
  def get_int(key)
13
13
  get(key, :int)
14
14
  end
15
15
 
16
- # For compatibility with htslib.cr.
16
+ # For compatibility with HTS.cr.
17
17
  def get_float(key)
18
18
  get(key, :float)
19
19
  end
20
20
 
21
- # For compatibility with htslib.cr.
21
+ # For compatibility with HTS.cr.
22
22
  def get_flag(key)
23
23
  get(key, :flag)
24
24
  end
25
25
 
26
- # For compatibility with htslib.cr.
26
+ # For compatibility with HTS.cr.
27
27
  def get_string(key)
28
28
  get(key, :string)
29
29
  end
@@ -1,11 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "header_record"
4
+
3
5
  module HTS
4
6
  class Bcf < Hts
5
7
  # A class for working with VCF records.
8
+ # NOTE: This class has a lot of methods that are not stable.
9
+ # The method names and the number of arguments may change in the future.
6
10
  class Header
7
- def initialize(hts_file)
8
- @bcf_hdr = LibHTS.bcf_hdr_read(hts_file)
11
+ def initialize(arg = nil)
12
+ case arg
13
+ when LibHTS::HtsFile
14
+ @bcf_hdr = LibHTS.bcf_hdr_read(arg)
15
+ when LibHTS::BcfHdr
16
+ @bcf_hdr = arg
17
+ when nil
18
+ @bcf_hdr = LibHTS.bcf_hdr_init("w")
19
+ else
20
+ raise TypeError, "Invalid argument"
21
+ end
9
22
  end
10
23
 
11
24
  def struct
@@ -20,6 +33,10 @@ module HTS
20
33
  LibHTS.bcf_hdr_get_version(@bcf_hdr)
21
34
  end
22
35
 
36
+ def set_version(version)
37
+ LibHTS.bcf_hdr_set_version(@bcf_hdr, version)
38
+ end
39
+
23
40
  def nsamples
24
41
  LibHTS.bcf_hdr_nsamples(@bcf_hdr)
25
42
  end
@@ -31,6 +48,45 @@ module HTS
31
48
  .map(&:read_string)
32
49
  end
33
50
 
51
+ def add_sample(sample, sync: true)
52
+ LibHTS.bcf_hdr_add_sample(@bcf_hdr, sample)
53
+ self.sync if sync
54
+ end
55
+
56
+ def merge(hdr)
57
+ LibHTS.bcf_hdr_merge(@bcf_hdr, hdr.struct)
58
+ end
59
+
60
+ def sync
61
+ LibHTS.bcf_hdr_sync(@bcf_hdr)
62
+ end
63
+
64
+ def read_bcf(fname)
65
+ LibHTS.bcf_hdr_set(@bcf_hdr, fname)
66
+ end
67
+
68
+ def append(line)
69
+ LibHTS.bcf_hdr_append(@bcf_hdr, line)
70
+ end
71
+
72
+ def delete(bcf_hl_type, key) # FIXME
73
+ type = bcf_hl_type_to_int(bcf_hl_type)
74
+ LibHTS.bcf_hdr_remove(@bcf_hdr, type, key)
75
+ end
76
+
77
+ def get_hrec(bcf_hl_type, key, value, str_class = nil)
78
+ type = bcf_hl_type_to_int(bcf_hl_type)
79
+ hrec = LibHTS.bcf_hdr_get_hrec(@bcf_hdr, type, key, value, str_class)
80
+ HeaderRecord.new(hrec)
81
+ end
82
+
83
+ def seqnames
84
+ n = FFI::MemoryPointer.new(:int)
85
+ names = LibHTS.bcf_hdr_seqnames(@bcf_hdr, n)
86
+ names.read_array_of_pointer(n.read_int)
87
+ .map(&:read_string)
88
+ end
89
+
34
90
  def to_s
35
91
  kstr = LibHTS::KString.new
36
92
  raise "Failed to get header string" unless LibHTS.bcf_hdr_format(@bcf_hdr, 0, kstr)
@@ -40,6 +96,27 @@ module HTS
40
96
 
41
97
  private
42
98
 
99
+ def bcf_hl_type_to_int(bcf_hl_type)
100
+ return bcf_hl_type if bcf_hl_type.is_a?(Integer)
101
+
102
+ case bcf_hl_type.to_s.upcase
103
+ when "FILTER", "FIL"
104
+ LibHTS::BCF_HL_FLT
105
+ when "INFO"
106
+ LibHTS::BCF_HL_INFO
107
+ when "FORMAT", "FMT"
108
+ LibHTS::BCF_HL_FMT
109
+ when "CONTIG", "CTG"
110
+ LibHTS::BCF_HL_CTG
111
+ when "STRUCTURED", "STR"
112
+ LibHTS::BCF_HL_STR
113
+ when "GENOTYPE", "GEN"
114
+ LibHTS::BCF_HL_GEN
115
+ else
116
+ raise TypeError, "Invalid argument"
117
+ end
118
+ end
119
+
43
120
  def initialize_copy(orig)
44
121
  @bcf_hdr = LibHTS.bcf_hdr_dup(orig.struct)
45
122
  end
@@ -3,9 +3,43 @@
3
3
  module HTS
4
4
  class Bcf < Hts
5
5
  class HeaderRecord
6
- def initialize
6
+ def initialize(arg = nil)
7
+ case arg
8
+ when LibHTS::BcfHrec
9
+ @bcf_hrec = arg
10
+ else
11
+ raise TypeError, "Invalid argument"
12
+ end
13
+ end
14
+
15
+ def struct
7
16
  @bcf_hrec
8
17
  end
18
+
19
+ def add_key(key)
20
+ LibHTS.bcf_hrec_add_key(@bcf_hrec, key, key.length)
21
+ end
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
+ LibHTS.bcf_hrec_format(@bcf_hrec, kstr)
35
+ kstr[:s]
36
+ end
37
+
38
+ private
39
+
40
+ def initialize_copy(orig)
41
+ @bcf_hrec = LibHTS.bcf_hrec_dup(orig.struct)
42
+ end
9
43
  end
10
44
  end
11
45
  end
data/lib/hts/bcf/info.rb CHANGED
@@ -9,22 +9,22 @@ module HTS
9
9
  @p1 = FFI::MemoryPointer.new(:pointer) # FIXME: naming
10
10
  end
11
11
 
12
- # For compatibility with htslib.cr.
12
+ # For compatibility with HTS.cr.
13
13
  def get_int(key)
14
14
  get(key, :int)
15
15
  end
16
16
 
17
- # For compatibility with htslib.cr.
17
+ # For compatibility with HTS.cr.
18
18
  def get_float(key)
19
19
  get(key, :float)
20
20
  end
21
21
 
22
- # For compatibility with htslib.cr.
22
+ # For compatibility with HTS.cr.
23
23
  def get_string(key)
24
24
  get(key, :string)
25
25
  end
26
26
 
27
- # For compatibility with htslib.cr.
27
+ # For compatibility with HTS.cr.
28
28
  def get_flag(key)
29
29
  get(key, :flag)
30
30
  end
data/lib/hts/bcf.rb CHANGED
@@ -52,7 +52,6 @@ module HTS
52
52
  build_index(index) if build_index
53
53
  @idx = load_index(index)
54
54
  @start_position = tell
55
- super # do nothing
56
55
  end
57
56
 
58
57
  def build_index(index_name = nil, min_shift: 14)
@@ -85,11 +84,16 @@ module HTS
85
84
  !@idx.null?
86
85
  end
87
86
 
88
- def write_header
87
+ def close
88
+ LibHTS.hts_idx_destroy(@idx) unless @idx&.null?
89
+ @idx = nil
90
+ super
91
+ end
92
+
93
+ def write_header(header)
89
94
  check_closed
90
95
 
91
96
  @header = header.dup
92
- LibHTS.hts_set_fai_filename(header, @file_name)
93
97
  LibHTS.bcf_hdr_write(@hts_file, header)
94
98
  end
95
99
 
@@ -97,7 +101,8 @@ module HTS
97
101
  check_closed
98
102
 
99
103
  var_dup = var.dup
100
- LibHTS.bcf_write(@hts_file, header, var_dup) > 0 || raise
104
+ r = LibHTS.bcf_write(@hts_file, header, var_dup)
105
+ raise "Failed to write record" if r < 0
101
106
  end
102
107
 
103
108
  # Close the current file.
@@ -122,29 +127,6 @@ module HTS
122
127
  end
123
128
  end
124
129
 
125
- private def each_record_copy
126
- check_closed
127
-
128
- return to_enum(__method__) unless block_given?
129
-
130
- while LibHTS.bcf_read(@hts_file, header, bcf1 = LibHTS.bcf_init) != -1
131
- record = Record.new(bcf1, header)
132
- yield record
133
- end
134
- self
135
- end
136
-
137
- private def each_record_reuse
138
- check_closed
139
-
140
- return to_enum(__method__) unless block_given?
141
-
142
- bcf1 = LibHTS.bcf_init
143
- record = Record.new(bcf1, header)
144
- yield record while LibHTS.bcf_read(@hts_file, header, bcf1) != -1
145
- self
146
- end
147
-
148
130
  def query(...)
149
131
  querys(...) # Fixme
150
132
  end
@@ -166,55 +148,6 @@ module HTS
166
148
  # private def queryi_reuse
167
149
  # end
168
150
 
169
- private def querys_copy(region)
170
- check_closed
171
-
172
- raise "query is only available for BCF files" unless file_format == "bcf"
173
- raise "Index file is required to call the query method." unless index_loaded?
174
- return to_enum(__method__, region) unless block_given?
175
-
176
- qitr = LibHTS.bcf_itr_querys(@idx, header, region)
177
-
178
- begin
179
- loop do
180
- bcf1 = LibHTS.bcf_init
181
- slen = LibHTS.hts_itr_next(@hts_file[:fp][:bgzf], qitr, bcf1, ::FFI::Pointer::NULL)
182
- break if slen == -1
183
- raise if slen < -1
184
-
185
- yield Record.new(bcf1, header)
186
- end
187
- ensure
188
- LibHTS.bcf_itr_destroy(qitr)
189
- end
190
- self
191
- end
192
-
193
- private def querys_reuse(region)
194
- check_closed
195
-
196
- raise "query is only available for BCF files" unless file_format == "bcf"
197
- raise "Index file is required to call the query method." unless index_loaded?
198
- return to_enum(__method__, region) unless block_given?
199
-
200
- qitr = LibHTS.bcf_itr_querys(@idx, header, region)
201
-
202
- bcf1 = LibHTS.bcf_init
203
- record = Record.new(bcf1, header)
204
- begin
205
- loop do
206
- slen = LibHTS.hts_itr_next(@hts_file[:fp][:bgzf], qitr, bcf1, ::FFI::Pointer::NULL)
207
- break if slen == -1
208
- raise if slen < -1
209
-
210
- yield record
211
- end
212
- ensure
213
- LibHTS.bcf_itr_destroy(qitr)
214
- end
215
- self
216
- end
217
-
218
151
  # @!macro [attach] define_getter
219
152
  # @method $1
220
153
  # Get $1 array
@@ -285,5 +218,81 @@ module HTS
285
218
  yield r.format(key)
286
219
  end
287
220
  end
221
+
222
+ private
223
+
224
+ def querys_reuse(region)
225
+ check_closed
226
+
227
+ raise "query is only available for BCF files" unless file_format == "bcf"
228
+ raise "Index file is required to call the query method." unless index_loaded?
229
+ return to_enum(__method__, region) unless block_given?
230
+
231
+ qiter = LibHTS.bcf_itr_querys(@idx, header, region)
232
+ raise "Failed to query region #{region}" if qiter.null?
233
+
234
+ bcf1 = LibHTS.bcf_init
235
+ record = Record.new(bcf1, header)
236
+ begin
237
+ loop do
238
+ slen = LibHTS.hts_itr_next(@hts_file[:fp][:bgzf], qiter, bcf1, ::FFI::Pointer::NULL)
239
+ break if slen == -1
240
+ raise if slen < -1
241
+
242
+ yield record
243
+ end
244
+ ensure
245
+ LibHTS.bcf_itr_destroy(qiter)
246
+ end
247
+ self
248
+ end
249
+
250
+ def querys_copy(region)
251
+ check_closed
252
+
253
+ raise "query is only available for BCF files" unless file_format == "bcf"
254
+ raise "Index file is required to call the query method." unless index_loaded?
255
+ return to_enum(__method__, region) unless block_given?
256
+
257
+ qiter = LibHTS.bcf_itr_querys(@idx, header, region)
258
+ raise "Failed to query region #{region}" if qiter.null?
259
+
260
+ begin
261
+ loop do
262
+ bcf1 = LibHTS.bcf_init
263
+ slen = LibHTS.hts_itr_next(@hts_file[:fp][:bgzf], qiter, bcf1, ::FFI::Pointer::NULL)
264
+ break if slen == -1
265
+ raise if slen < -1
266
+
267
+ yield Record.new(bcf1, header)
268
+ end
269
+ ensure
270
+ LibHTS.bcf_itr_destroy(qiter)
271
+ end
272
+ self
273
+ end
274
+
275
+ def each_record_reuse
276
+ check_closed
277
+
278
+ return to_enum(__method__) unless block_given?
279
+
280
+ bcf1 = LibHTS.bcf_init
281
+ record = Record.new(bcf1, header)
282
+ yield record while LibHTS.bcf_read(@hts_file, header, bcf1) != -1
283
+ self
284
+ end
285
+
286
+ def each_record_copy
287
+ check_closed
288
+
289
+ return to_enum(__method__) unless block_given?
290
+
291
+ while LibHTS.bcf_read(@hts_file, header, bcf1 = LibHTS.bcf_init) != -1
292
+ record = Record.new(bcf1, header)
293
+ yield record
294
+ end
295
+ self
296
+ end
288
297
  end
289
298
  end
data/lib/hts/hts.rb CHANGED
@@ -31,8 +31,8 @@ module HTS
31
31
  end
32
32
  end
33
33
 
34
- def initialize(*args)
35
- # do nothing
34
+ def initialize(*_args)
35
+ raise TypeError, "Can't make instance of HTS abstract class"
36
36
  end
37
37
 
38
38
  def struct