htslib 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea47a473d63b90fd2b1db4ecd65aa1ef38d47bbe5624e24ac583b5329301e5cb
4
- data.tar.gz: aab96376972d7b0a587978484b22e41ee049ea742cba937cd57c66a9c0c42f2a
3
+ metadata.gz: 2a49c4758453c5c39915d9d17ccc33ce104699fca39c4083d4b2801767b655f1
4
+ data.tar.gz: 46ee49f6b452471e26afedfce70489cd24eebf86b1a18240bab125d465921fb8
5
5
  SHA512:
6
- metadata.gz: 76d9aa699d0176557d8e44171018b132fc4df2c0e1f47a9784388693103799cf920c2ae437fb97f8429422a1edb5ebd43eae7b28a1f18452a5eeeac38244a981
7
- data.tar.gz: f2f1d50099a66e71574c4019e66452dd100371cbdc7d08b144856bab8f59f04aac4e207585534f26e29a06342a7fafe5c3ea0fb0d0e2e8dd9ed1822ddbcbdfe8
6
+ metadata.gz: 918c0919750eb3d436cf19b1011ffed0a8d0760b29e0a3c2e675a9efa563a3f5c3b9a9ae38232e67192df4d066c446bbc0443f00d07cab9ac0c3401b38bd3fb7
7
+ data.tar.gz: 343fbaec89a2e60a54feadd29856b26b772baa65ef52d181cd5845ed53a8e549504ddcdcc739dff716f9069a5b0b3e6f22f5136c2a612cc6014eb79ee225ab2b
data/README.md CHANGED
@@ -8,9 +8,7 @@
8
8
 
9
9
  Ruby-htslib is the [Ruby](https://www.ruby-lang.org) bindings to [HTSlib](https://github.com/samtools/htslib), a C library for high-throughput sequencing data formats. It allows you to read and write file formats commonly used in genomics, such as [SAM, BAM, VCF, and BCF](http://samtools.github.io/hts-specs/), in the Ruby language.
10
10
 
11
- :apple: Feel free to fork it out if you can develop it!
12
-
13
- :bowtie: Alpha stage.
11
+ :apple: Feel free to fork it!
14
12
 
15
13
  ## Requirements
16
14
 
@@ -18,6 +16,7 @@ Ruby-htslib is the [Ruby](https://www.ruby-lang.org) bindings to [HTSlib](https:
18
16
  * [HTSlib](https://github.com/samtools/htslib)
19
17
  * Ubuntu : `apt install libhts-dev`
20
18
  * macOS : `brew install htslib`
19
+ * Windows : [mingw-w64-htslib](https://packages.msys2.org/base/mingw-w64-htslib) is automatically fetched when installing the gem ([RubyInstaller](https://rubyinstaller.org) only).
21
20
  * Build from source code (see Development section)
22
21
 
23
22
  ## Installation
@@ -34,11 +33,13 @@ Alternatively, you can specify the directory of the shared library by setting th
34
33
  export HTSLIBDIR="/your/path/to/htslib" # libhts.so
35
34
  ```
36
35
 
36
+ ruby-htslib also works on Windows; if you use RubyInstaller, htslib will be prepared automatically.
37
+
37
38
  ## Overview
38
39
 
39
- ### High level API
40
+ ### High-level API
40
41
 
41
- Read SAM / BAM / CRAM - Sequence Alignment Map file
42
+ HTS::Bam - SAM / BAM / CRAM - Sequence Alignment Map file
42
43
 
43
44
  ```ruby
44
45
  require 'htslib'
@@ -56,14 +57,14 @@ bam.each do |r|
56
57
  mpos: r.mpos + 1,
57
58
  isiz: r.isize,
58
59
  seqs: r.seq,
59
- qual: r.qual.map { |i| (i + 33).chr }.join,
60
+ qual: r.qual_string,
60
61
  MC: r.aux("MC")
61
62
  end
62
63
 
63
64
  bam.close
64
65
  ```
65
66
 
66
- Read VCF / BCF - Variant Call Format file
67
+ HTS::Bcf - VCF / BCF - Variant Call Format file
67
68
 
68
69
  ```ruby
69
70
  bcf = HTS::Bcf.open("b.bcf")
@@ -96,9 +97,18 @@ fa.close
96
97
 
97
98
  </details>
98
99
 
99
- ### Low level API
100
+ <details>
101
+ <summary><b>Tbx</b></summary>
102
+
103
+ ```ruby
104
+
105
+ ```
100
106
 
101
- `HTS::LibHTS` provides native C functions.
107
+ </details>
108
+
109
+ ### Low-level API
110
+
111
+ `HTS::LibHTS` provides native C functions.
102
112
 
103
113
  ```ruby
104
114
  require 'htslib'
@@ -109,11 +119,17 @@ p b[:category]
109
119
  p b[:format]
110
120
  ```
111
121
 
112
- Note: htslib makes extensive use of macro functions for speed. You cannot use C macro functions in Ruby if they are not reimplemented in ruby-htslib. Only small number of C structs are implemented with FFI's ManagedStruct, which frees memory when Ruby's garbage collection fires. Other structs will need to be freed manually.
122
+ Macro functions
123
+
124
+ htslib has a lot of macro functions for speed. Ruby-FFI cannot call C macro functions. However, essential functions are reimplemented in Ruby, and you can call them.
125
+
126
+ Structs
127
+
128
+ Only a small number of C structs are implemented with FFI's ManagedStruct, which frees memory when Ruby's garbage collection fires. Other structs will need to be freed manually.
113
129
 
114
130
  ### Need more speed?
115
131
 
116
- Try Crystal. [htslib.cr](https://github.com/bio-crystal/htslib.cr) is implemented in Crystal language and provides an API compatible with ruby-htslib. Crystal language is not as flexible as Ruby language. You can not use `eval` methods, and you must always be careful with the data types. Writing one-time scripts in Crystal or playing with REPL may not be as much fun. However, if you have a clear idea of what you want to do in your mind, have already written code in Ruby, and need to run them over and over, try creating a command line tool in Crystal. The Crystal language is fast, as fast as the Rust and C languages. It will give you great power to create tools.
132
+ Try Crystal. [HTS.cr](https://github.com/bio-cr/hts.cr) is implemented in Crystal language and provides an API compatible with ruby-htslib. Crystal language is not as flexible as Ruby language. You can not use `eval` methods and must always be careful with the types. Writing one-time scripts in Crystal may be less fun. However, if you have a clear idea of what you want to do in your mind, have already written code in Ruby, and need to run them over and over, try creating a command line tool in Crystal. The Crystal language is as fast as the Rust and C languages. It will give you incredible power to make tools.
117
133
 
118
134
  ## Documentation
119
135
 
@@ -134,26 +150,29 @@ bundle exec rake test
134
150
 
135
151
  [GNU Autotools](https://en.wikipedia.org/wiki/GNU_Autotools) is required to compile htslib.
136
152
 
137
- Many macro functions are used in HTSlib. Since these macro functions cannot be called using FFI, they must be reimplemented in Ruby.
153
+ HTSlib has many macro functions. These macro functions cannot be called from FFI and must be reimplemented in Ruby.
138
154
 
139
155
  * Use the new version of Ruby to take full advantage of Ruby's potential.
140
- * This is possible because we have a small number of users. What a deal!
141
- * Remain compatible with [htslib.cr](https://github.com/bio-crystal/htslib.cr).
142
- * The most challenging part is the return value. In the Crystal language, methods are expected to return only one type. On the other hand, in the Ruby language, methods that return multiple classes are very common. For example, in the Crystal language, the compiler gets confused if the return value is one of six types: Int32, Int64, Float32, Float64, Nil, or String. In fact Crystal can do this. But the code gets a little messy. In Ruby, this is very common and doesn't cause any problems.
156
+ * This is possible because we have a small number of users.
157
+ * Remain compatible with [HTS.cr](https://github.com/bio-cr/hts.cr).
158
+ * The most challenging part is the return value. In the Crystal language, methods are expected to return only one type. On the other hand, in the Ruby language, methods that return multiple classes are very common. For example, in the Crystal language, the compiler gets confused if the return value is one of six types: Int32, Int64, Float32, Float64, Nil, or String. In fact Crystal allows you to do that. But the code gets a little messy. In Ruby, this is very common and doesn't cause any problems.
159
+ * Ruby and Crystal are languages that use garbage collection. However, the memory release policy for allocated C structures is slightly different: in Ruby-FFI, you can define a `self.release` method in `FFI::Struct`. This method is called when GC. So you don't have to worry about memory in high-level APIs like Bam::Record or Bcf::Record, etc. Crystal requires you to define a finalize method on each class. So you need to define it in Bam::Record or Bcf::Record.
143
160
 
144
- In the script directory, there are several tools to help implement ruby-htslib. These tools may be forked into independent repository in the future.
161
+ Method naming generally follows the Rust-htslib API.
145
162
 
146
163
  #### FFI Extensions
147
164
 
148
165
  * [ffi-bitfield](https://github.com/kojix2/ffi-bitfield) : Extension of Ruby-FFI to support bitfields.
149
166
 
150
- #### Automatic generation or automatic validation (Future plan)
167
+ #### Automatic validation
168
+
169
+ In the `script` directory, there are several tools to help implement ruby-htslib. Scripts using c2ffi can check the coverage of htslib functions in Ruby-htslib. They are useful when new versions of htslib are released.
151
170
 
152
- + [c2ffi](https://github.com/rpav/c2ffi) is a tool to create JSON format metadata from C header files. It is planned to use c2ffi to automatically generate bindings or tests.
171
+ * [c2ffi](https://github.com/rpav/c2ffi) is a tool to create JSON format metadata from C header files.
153
172
 
154
173
  ## Contributing
155
174
 
156
- Ruby-htslib is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
175
+ Ruby-htslib is a library under development, so even minor improvements like typo fixes are welcome! Please feel free to send us your pull requests.
157
176
 
158
177
  * [Report bugs](https://github.com/kojix2/ruby-htslib/issues)
159
178
  * Fix bugs and [submit pull requests](https://github.com/kojix2/ruby-htslib/pulls)
@@ -165,14 +184,14 @@ Ruby-htslib is a library under development, so even small improvements like typo
165
184
  ```
166
185
  # Ownership and Commitment Rights
167
186
 
168
- Do you need commit rights to ruby-htslib repository?
187
+ Do you need commit rights to the ruby-htslib repository?
169
188
  Do you want to get admin rights and take over the project?
170
189
  If so, please feel free to contact us @kojix2.
171
190
  ```
172
191
 
173
- #### Why do you implement htslib in a language like Ruby, which is not widely used in the bioinformatics?
192
+ #### Why do you implement htslib in a language like Ruby, which is not widely used in bioinformatics?
174
193
 
175
- One of the greatest joys of using a minor language like Ruby in bioinformatics is that there is nothing stopping you from reinventing the wheel. Reinventing the wheel can be fun. But with languages like Python and R, where many bioinformatics masters work, there is no chance left for beginners to create htslib bindings. Bioinformatics file formats, libraries and tools are very complex and I don't know how to understand them. So I wanted to implement the HTSLib binding myself to better understand how the pioneers of bioinformatics felt when establishing the file format and how they created their tools. I hope one day we can work on bioinformatics using Ruby and Crystal languages, not to replace other languages such as Python and R, but to add new power and value to this advancing field.
194
+ One of the greatest joys of using a minor language like Ruby in bioinformatics is that nothing stops you from reinventing the wheel. Reinventing the wheel can be fun. But with languages like Python and R, where many bioinformatics masters work, there is no chance for beginners to create htslib bindings. Bioinformatics file formats, libraries, and tools are very complex, and I need to learn how to understand them. So I started to implement the HTSLib binding myself to better understand how the pioneers of bioinformatics felt when establishing the file format and how they created their tools. I hope one day we can work on bioinformatics using Ruby and Crystal languages, not to replace other languages such as Python and R, but to add new power and value to this advancing field.
176
195
 
177
196
  ## Links
178
197
 
@@ -182,6 +201,7 @@ One of the greatest joys of using a minor language like Ruby in bioinformatics i
182
201
  ## Funding support
183
202
 
184
203
  This work was supported partially by [Ruby Association Grant 2020](https://www.ruby.or.jp/en/news/20201022).
204
+
185
205
  ## License
186
206
 
187
207
  [MIT License](https://opensource.org/licenses/MIT).
@@ -1,11 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "header_record"
4
+
3
5
  module HTS
4
6
  class Bam < Hts
5
7
  # A class for working with alignment header.
6
8
  class Header
7
- def initialize(hts_file)
8
- @sam_hdr = LibHTS.sam_hdr_read(hts_file)
9
+ def self.parse(str)
10
+ new(LibHTS.sam_hdr_parse(str.size, str))
11
+ end
12
+
13
+ def initialize(arg = nil)
14
+ case arg
15
+ when LibHTS::HtsFile
16
+ @sam_hdr = LibHTS.sam_hdr_read(arg)
17
+ when LibHTS::SamHdr
18
+ @sam_hdr = arg
19
+ when nil
20
+ @sam_hdr = LibHTS.sam_hdr_init
21
+ else
22
+ raise TypeError, "Invalid argument"
23
+ end
9
24
  end
10
25
 
11
26
  def struct
@@ -17,6 +32,7 @@ module HTS
17
32
  end
18
33
 
19
34
  def target_count
35
+ # FIXME: sam_hdr_nref
20
36
  @sam_hdr[:n_targets]
21
37
  end
22
38
 
@@ -32,6 +48,41 @@ module HTS
32
48
  end
33
49
  end
34
50
 
51
+ # experimental
52
+ def add_lines(str)
53
+ LibHTS.sam_hdr_add_lines(@sam_hdr, str, 0)
54
+ end
55
+
56
+ # experimental
57
+ def add_line(type, *args)
58
+ args = args.flat_map { |arg| [:string, arg] }
59
+ LibHTS.sam_hdr_add_line(@sam_hdr, type, *args, :pointer, FFI::Pointer::NULL)
60
+ end
61
+
62
+ # experimental
63
+ def find_line(type, key, value)
64
+ ks = LibHTS::KString.new
65
+ r = LibHTS.sam_hdr_find_line_id(@sam_hdr, type, key, value, ks)
66
+ r == 0 ? ks[:s] : nil
67
+ end
68
+
69
+ # experimental
70
+ def find_line_at(type, pos)
71
+ ks = LibHTS::KString.new
72
+ r = LibHTS.sam_hdr_find_line_pos(@sam_hdr, type, pos, ks)
73
+ r == 0 ? ks[:s] : nil
74
+ end
75
+
76
+ # experimental
77
+ def remove_line(type, key, value)
78
+ LibHTS.sam_hdr_remove_line_id(@sam_hdr, type, key, value)
79
+ end
80
+
81
+ # experimental
82
+ def remove_line_at(type, pos)
83
+ LibHTS.sam_hdr_remove_line_pos(@sam_hdr, type, pos)
84
+ end
85
+
35
86
  def to_s
36
87
  LibHTS.sam_hdr_str(@sam_hdr)
37
88
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTS
4
+ class Bam < Hts
5
+ class HeaderRecord
6
+ def initialize
7
+ @bam_hrec
8
+ end
9
+ end
10
+ end
11
+ end
@@ -17,6 +17,7 @@ module HTS
17
17
  @header = header
18
18
  end
19
19
 
20
+ # Return the FFI::Struct object.
20
21
  def struct
21
22
  @bam1
22
23
  end
@@ -25,17 +26,14 @@ module HTS
25
26
  @bam1.to_ptr
26
27
  end
27
28
 
28
- # returns the query name.
29
+ # Get the read name. (a.k.a QNAME)
30
+ # @return [String] query template name
29
31
  def qname
30
32
  LibHTS.bam_get_qname(@bam1).read_string
31
33
  end
32
34
 
33
- # Set (query) name.
34
- # def qname=(name)
35
- # raise 'Not Implemented'
36
- # end
37
-
38
- # returns the tid of the record or -1 if not mapped.
35
+ # Get the chromosome ID of the alignment. -1 if not mapped.
36
+ # @return [Integer] chromosome ID
39
37
  def tid
40
38
  @bam1[:core][:tid]
41
39
  end
@@ -44,7 +42,8 @@ module HTS
44
42
  @bam1[:core][:tid] = tid
45
43
  end
46
44
 
47
- # returns the tid of the mate or -1 if not mapped.
45
+ # Get the chromosome ID of the mate. -1 if not mapped.
46
+ # @return [Integer] chromosome ID
48
47
  def mtid
49
48
  @bam1[:core][:mtid]
50
49
  end
@@ -53,7 +52,8 @@ module HTS
53
52
  @bam1[:core][:mtid] = mtid
54
53
  end
55
54
 
56
- # returns 0-based start position.
55
+ # Get the 0-based leftmost coordinate of the alignment.
56
+ # @return [Integer] 0-based leftmost coordinate
57
57
  def pos
58
58
  @bam1[:core][:pos]
59
59
  end
@@ -62,7 +62,8 @@ module HTS
62
62
  @bam1[:core][:pos] = pos
63
63
  end
64
64
 
65
- # returns 0-based mate position
65
+ # Get the 0-based leftmost coordinate of the mate.
66
+ # @return [Integer] 0-based leftmost coordinate
66
67
  def mate_pos
67
68
  @bam1[:core][:mpos]
68
69
  end
@@ -74,6 +75,8 @@ module HTS
74
75
  alias mpos mate_pos
75
76
  alias mpos= mate_pos=
76
77
 
78
+ # Get the bin calculated by bam_reg2bin().
79
+ # @return [Integer] bin
77
80
  def bin
78
81
  @bam1[:core][:bin]
79
82
  end
@@ -82,12 +85,15 @@ module HTS
82
85
  @bam1[:core][:bin] = bin
83
86
  end
84
87
 
85
- # returns end position of the read.
88
+ # Get the rightmost base position of the alignment on the reference genome.
89
+ # @return [Integer] 0-based rightmost coordinate
86
90
  def endpos
87
91
  LibHTS.bam_endpos @bam1
88
92
  end
89
93
 
90
- # returns the chromosome or '' if not mapped.
94
+ # Get the reference sequence name of the alignment. (a.k.a RNAME)
95
+ # '' if not mapped.
96
+ # @return [String] reference sequence name
91
97
  def chrom
92
98
  return "" if tid == -1
93
99
 
@@ -96,7 +102,9 @@ module HTS
96
102
 
97
103
  alias contig chrom
98
104
 
99
- # returns the chromosome of the mate or '' if not mapped.
105
+ # Get the reference sequence name of the mate.
106
+ # '' if not mapped.
107
+ # @return [String] reference sequence name
100
108
  def mate_chrom
101
109
  return "" if mtid == -1
102
110
 
@@ -105,12 +113,20 @@ module HTS
105
113
 
106
114
  alias mate_contig mate_chrom
107
115
 
108
- # Get strand information.
116
+ # Get whether the query is on the reverse strand.
117
+ # @return [String] strand "+" or "-"
109
118
  def strand
110
119
  LibHTS.bam_is_rev(@bam1) ? "-" : "+"
111
120
  end
112
121
 
113
- # insert size
122
+ # Get whether the query's mate is on the reverse strand.
123
+ # @return [String] strand "+" or "-"
124
+ def mate_strand
125
+ LibHTS.bam_is_mrev(@bam1) ? "-" : "+"
126
+ end
127
+
128
+ # Get the observed template length. (a.k.a TLEN)
129
+ # @return [Integer] isize
114
130
  def insert_size
115
131
  @bam1[:core][:isize]
116
132
  end
@@ -122,7 +138,8 @@ module HTS
122
138
  alias isize insert_size
123
139
  alias isize= insert_size=
124
140
 
125
- # mapping quality
141
+ # Get the mapping quality of the alignment. (a.k.a MAPQ)
142
+ # @return [Integer] mapping quality
126
143
  def mapq
127
144
  @bam1[:core][:qual]
128
145
  end
@@ -131,11 +148,14 @@ module HTS
131
148
  @bam1[:core][:qual] = mapq
132
149
  end
133
150
 
134
- # returns a `Cigar` object.
151
+ # Get the Bam::Cigar object.
152
+ # @return [Bam::Cigar] cigar
135
153
  def cigar
136
154
  Cigar.new(LibHTS.bam_get_cigar(@bam1), @bam1[:core][:n_cigar])
137
155
  end
138
156
 
157
+ # Calculate query length from CIGAR.
158
+ # @return [Integer] query length
139
159
  def qlen
140
160
  LibHTS.bam_cigar2qlen(
141
161
  @bam1[:core][:n_cigar],
@@ -143,6 +163,8 @@ module HTS
143
163
  )
144
164
  end
145
165
 
166
+ # Calculate reference length from CIGAR.
167
+ # @return [Integer] reference length
146
168
  def rlen
147
169
  LibHTS.bam_cigar2rlen(
148
170
  @bam1[:core][:n_cigar],
@@ -150,7 +172,8 @@ module HTS
150
172
  )
151
173
  end
152
174
 
153
- # return the read sequence
175
+ # Get the sequence. (a.k.a SEQ)
176
+ # @return [String] sequence
154
177
  def seq
155
178
  r = LibHTS.bam_get_seq(@bam1)
156
179
  seq = String.new
@@ -161,11 +184,15 @@ module HTS
161
184
  end
162
185
  alias sequence seq
163
186
 
187
+ # Get the length of the query sequence.
188
+ # @return [Integer] query length
164
189
  def len
165
190
  @bam1[:core][:l_qseq]
166
191
  end
167
192
 
168
- # return only the base of the requested index "i" of the query sequence.
193
+ # Get the base of the requested index "i" of the query sequence.
194
+ # @param [Integer] i index
195
+ # @return [String] base
169
196
  def base(n)
170
197
  n += @bam1[:core][:l_qseq] if n < 0
171
198
  return "." if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base(-1000)
@@ -174,13 +201,23 @@ module HTS
174
201
  SEQ_NT16_STR[LibHTS.bam_seqi(r, n)]
175
202
  end
176
203
 
177
- # return the base qualities
204
+ # Get the base qualities.
205
+ # @return [Array] base qualities
178
206
  def qual
179
207
  q_ptr = LibHTS.bam_get_qual(@bam1)
180
208
  q_ptr.read_array_of_uint8(@bam1[:core][:l_qseq])
181
209
  end
182
210
 
183
- # return only the base quality of the requested index "i" of the query sequence.
211
+ # Get the base qualities as a string. (a.k.a QUAL)
212
+ # ASCII of base quality + 33.
213
+ # @return [String] base qualities
214
+ def qual_string
215
+ qual.map { |q| (q + 33).chr }.join
216
+ end
217
+
218
+ # Get the base quality of the requested index "i" of the query sequence.
219
+ # @param [Integer] i index
220
+ # @return [Integer] base quality
184
221
  def base_qual(n)
185
222
  n += @bam1[:core][:l_qseq] if n < 0
186
223
  return 0 if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base_qual(-1000)
@@ -189,7 +226,8 @@ module HTS
189
226
  q_ptr.get_uint8(n)
190
227
  end
191
228
 
192
- # returns a `Flag` object.
229
+ # Get Bam::Flag object of the alignment.
230
+ # @return [Bam::Flag] flag
193
231
  def flag
194
232
  Flag.new(@bam1[:core][:flag])
195
233
  end
@@ -205,7 +243,9 @@ module HTS
205
243
  end
206
244
  end
207
245
 
208
- # retruns the auxillary fields.
246
+ # Get the auxiliary data.
247
+ # @param [String] key tag name
248
+ # @return [String] value
209
249
  def aux(key = nil)
210
250
  aux = Aux.new(self)
211
251
  if key
@@ -230,6 +270,7 @@ module HTS
230
270
  end
231
271
  end
232
272
 
273
+ # @return [String] a string representation of the alignment.
233
274
  def to_s
234
275
  kstr = LibHTS::KString.new
235
276
  raise "Failed to format bam record" if LibHTS.sam_format1(@header.struct, @bam1, kstr) == -1
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
@@ -188,6 +188,10 @@ module HTS
188
188
  :n_mapped, :uint64,
189
189
  :n_unmapped, :uint64
190
190
  )
191
+
192
+ def self.release(ptr)
193
+ LibHTS.hts_idx_destroy(ptr) unless ptr.null?
194
+ end
191
195
  end
192
196
 
193
197
  class HtsReglist < FFI::Struct
@@ -213,6 +217,10 @@ module HTS
213
217
  :sdict, :pointer,
214
218
  :hrecs, :pointer,
215
219
  :ref_count, :uint32
220
+
221
+ def self.release(ptr)
222
+ LibHTS.sam_hdr_destroy(ptr) unless ptr.null?
223
+ end
216
224
  end
217
225
 
218
226
  BamHdr = SamHdr
@@ -251,6 +259,10 @@ module HTS
251
259
  layout \
252
260
  :pool, :pointer,
253
261
  :qsize, :int
262
+
263
+ def self.release(ptr)
264
+ LibHTS.hts_tpool_destroy(ptr) unless ptr.null?
265
+ end
254
266
  end
255
267
 
256
268
  class HtsOpt < FFI::Struct
@@ -300,6 +312,10 @@ module HTS
300
312
  :nocoor, 1,
301
313
  :multi, 1,
302
314
  :dummy, 27
315
+
316
+ def self.release(ptr)
317
+ LibHTS.hts_itr_destroy(ptr) unless ptr.null?
318
+ end
303
319
  end
304
320
 
305
321
  class Bam1Core < FFI::Struct
@@ -380,6 +396,10 @@ module HTS
380
396
  :conf, TbxConf.ptr,
381
397
  :idx, HtsIdx.ptr,
382
398
  :dict, :pointer
399
+
400
+ def self.release(ptr)
401
+ LibHTS.tbx_destroy(ptr) unless ptr.null?
402
+ end
383
403
  end
384
404
 
385
405
  # faidx
@@ -393,6 +413,10 @@ module HTS
393
413
  :name, :pointer,
394
414
  :hash, :pointer,
395
415
  :format, FaiFormatOptions
416
+
417
+ def self.release(ptr)
418
+ LibHTS.fai_destroy(ptr) unless ptr.null?
419
+ end
396
420
  end
397
421
 
398
422
  # bcf
@@ -412,6 +436,10 @@ module HTS
412
436
  :nkeys, :int,
413
437
  :keys, :pointer,
414
438
  :vals, :pointer
439
+
440
+ def self.release(ptr)
441
+ LibHTS.bcf_hrec_destroy(ptr) unless ptr.null?
442
+ end
415
443
  end
416
444
 
417
445
  class BcfInfo < FFI::BitStruct
@@ -461,6 +489,10 @@ module HTS
461
489
  :keep_samples, :pointer,
462
490
  :mem, KString,
463
491
  :m, [:int, 3]
492
+
493
+ def self.release(ptr)
494
+ LibHTS.bcf_hdr_destroy(ptr) unless ptr.null?
495
+ end
464
496
  end
465
497
 
466
498
  class BcfFmt < FFI::BitStruct
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTS
2
4
  module LibHTS
3
5
  class << self
@@ -294,15 +294,23 @@ module HTS
294
294
  end
295
295
 
296
296
  # Typed value I/O
297
- def bcf_int8_vector_end = -127 # INT8_MIN + 1
298
- def bcf_int16_vector_end = -32_767 # INT16_MIN + 1
299
- def bcf_int32_vector_end = -2_147_483_647 # INT32_MIN + 1
300
- def bcf_int64_vector_end = -9_223_372_036_854_775_807 # INT64_MIN + 1
297
+ # INT8_MIN + 1
298
+ def bcf_int8_vector_end = -127
299
+ # INT16_MIN + 1
300
+ def bcf_int16_vector_end = -32_767
301
+ # INT32_MIN + 1
302
+ def bcf_int32_vector_end = -2_147_483_647
303
+ # INT64_MIN + 1
304
+ def bcf_int64_vector_end = -9_223_372_036_854_775_807
301
305
  def bcf_str_vector_end = 0
302
- def bcf_int8_missing = -128 # INT8_MIN
303
- def bcf_int16_missing = (-32_767 - 1) # INT16_MIN
304
- def bcf_int32_missing = (-2_147_483_647 - 1) # INT32_MIN
305
- def bcf_int64_missing = (-9_223_372_036_854_775_807 - 1) # INT64_MIN
306
+ # INT8_MIN
307
+ def bcf_int8_missing = -128
308
+ # INT16_MIN
309
+ def bcf_int16_missing = (-32_767 - 1)
310
+ # INT32_MIN
311
+ def bcf_int32_missing = (-2_147_483_647 - 1)
312
+ # INT64_MIN
313
+ def bcf_int64_missing = (-9_223_372_036_854_775_807 - 1)
306
314
  def bcf_str_missing = 0x07
307
315
 
308
316
  BCF_MAX_BT_INT8 = 0x7f # INT8_MAX */
data/lib/hts/tbx.rb CHANGED
@@ -45,8 +45,6 @@ module HTS
45
45
 
46
46
  # build_index(index) if build_index
47
47
  @idx = load_index(index)
48
-
49
- super # do nothing
50
48
  end
51
49
 
52
50
  def build_index
@@ -68,9 +66,7 @@ module HTS
68
66
  def seqnames
69
67
  nseq = FFI::MemoryPointer.new(:int)
70
68
  LibHTS.tbx_seqnames(@idx, nseq).then do |pts|
71
- pts.read_array_of_pointer(nseq.read_int).map do |pt|
72
- pt.read_string
73
- end
69
+ pts.read_array_of_pointer(nseq.read_int).map(&:read_string)
74
70
  end
75
71
  end
76
72
  end
data/lib/hts/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTS
4
- VERSION = "0.2.3"
4
+ VERSION = "0.2.5"
5
5
  end
data/lib/htslib.rb CHANGED
@@ -52,6 +52,7 @@ module HTS
52
52
  # before calling the LibHTS module.
53
53
  autoload :LibHTS, "hts/libhts"
54
54
 
55
+ autoload :Hts, "hts/hts"
55
56
  autoload :Bam, "hts/bam"
56
57
  autoload :Bcf, "hts/bcf"
57
58
  autoload :Tbx, "hts/tbx"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htslib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-03 00:00:00.000000000 Z
11
+ date: 2022-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -136,6 +136,7 @@ files:
136
136
  - lib/hts/bam/cigar.rb
137
137
  - lib/hts/bam/flag.rb
138
138
  - lib/hts/bam/header.rb
139
+ - lib/hts/bam/header_record.rb
139
140
  - lib/hts/bam/record.rb
140
141
  - lib/hts/bcf.rb
141
142
  - lib/hts/bcf/format.rb