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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93ee916dafed0ba04e486a59c81d2bd9befbceda3d679ef820e32d8817597afe
4
- data.tar.gz: 7dda13879d0c3707354ab69fe9967f60f0300c1971011218a5cf79e5e211ee25
3
+ metadata.gz: 2a49c4758453c5c39915d9d17ccc33ce104699fca39c4083d4b2801767b655f1
4
+ data.tar.gz: 46ee49f6b452471e26afedfce70489cd24eebf86b1a18240bab125d465921fb8
5
5
  SHA512:
6
- metadata.gz: 8cf68e9276f353bdea4389f5584066870a4887f07891387cf143408cf215c43232f2c390c08b80c57225a8d8b3722a9dcc5ba5cc3cc716079cf004bd34df0da0
7
- data.tar.gz: f30abf9c0d0dd07201e150dea5ec6976e7d968bc2f6bf2c347c1dec18cdfaaa5c141793208587f1629fa3cefeaaadd268083a105ab42dd450ce2ac8cfa0e2d7e
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,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Q. Why is the file name auxi.rb and not aux.rb?
4
+ #
5
+ # A. This is for compatibility with Windows.
6
+ # In Windows, aux is a reserved word
7
+ # You cannot create a file named aux.
8
+
3
9
  module HTS
4
10
  class Bam < Hts
5
11
  # Auxiliary record data
@@ -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
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative "flag"
4
4
  require_relative "cigar"
5
- require_relative "aux"
5
+ require_relative "auxi"
6
6
 
7
7
  module HTS
8
8
  class Bam < Hts
@@ -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