htslib 0.1.0 → 0.2.2

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: c90062954caa8dc2155f77ff3d03534d933ba81148f9bdb7c8dc173f73efca64
4
- data.tar.gz: fb24ced637a8b9b897ecd9c5afed1c6f75902995e48c25daa849baa06611517b
3
+ metadata.gz: 93ee916dafed0ba04e486a59c81d2bd9befbceda3d679ef820e32d8817597afe
4
+ data.tar.gz: 7dda13879d0c3707354ab69fe9967f60f0300c1971011218a5cf79e5e211ee25
5
5
  SHA512:
6
- metadata.gz: fed4e6689d48493416ebd409401df284fedaddb567d3558196b3ba3c253376dd1c4bea8db536fdb6ff8bbebe85512850d7d5c17605544ce26a09e814e7172eb5
7
- data.tar.gz: b9d596e6445671254568b4bd3cc5b694a1011914ae67b1afc11aaa66a195f49b7371d001f9e10cc204a4c20e501cd8eb63092d63b9b392c701571a12843b5c91
6
+ metadata.gz: 8cf68e9276f353bdea4389f5584066870a4887f07891387cf143408cf215c43232f2c390c08b80c57225a8d8b3722a9dcc5ba5cc3cc716079cf004bd34df0da0
7
+ data.tar.gz: f30abf9c0d0dd07201e150dea5ec6976e7d968bc2f6bf2c347c1dec18cdfaaa5c141793208587f1629fa3cefeaaadd268083a105ab42dd450ce2ac8cfa0e2d7e
data/README.md CHANGED
@@ -6,15 +6,15 @@
6
6
  [![DOI](https://zenodo.org/badge/247078205.svg)](https://zenodo.org/badge/latestdoi/247078205)
7
7
  [![Docs Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://rubydoc.info/gems/htslib)
8
8
 
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.
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
11
  :apple: Feel free to fork it out if you can develop it!
12
12
 
13
- :bowtie: alpha stage.
13
+ :bowtie: Alpha stage.
14
14
 
15
15
  ## Requirements
16
16
 
17
- * [Ruby](https://github.com/ruby/ruby) 2.7 or above.
17
+ * [Ruby](https://github.com/ruby/ruby) 3.1 or above.
18
18
  * [HTSlib](https://github.com/samtools/htslib)
19
19
  * Ubuntu : `apt install libhts-dev`
20
20
  * macOS : `brew install htslib`
@@ -27,7 +27,7 @@ gem install htslib
27
27
  ```
28
28
 
29
29
  If you have installed htslib with apt on Ubuntu or homebrew on Mac, [pkg-config](https://github.com/ruby-gnome/pkg-config)
30
- will automatically detect the location of the shared library.
30
+ will automatically detect the location of the shared library. If pkg-config does not work well, set `PKG_CONFIG_PATH`.
31
31
  Alternatively, you can specify the directory of the shared library by setting the environment variable `HTSLIBDIR`.
32
32
 
33
33
  ```sh
@@ -83,9 +83,22 @@ end
83
83
  bcf.close
84
84
  ```
85
85
 
86
+ <details>
87
+ <summary><b>Faidx</b></summary>
88
+
89
+ ```ruby
90
+ fa = HTS::Faidx.open("c.fa")
91
+
92
+ fa.fetch("chr1:1-10")
93
+
94
+ fa.close
95
+ ```
96
+
97
+ </details>
98
+
86
99
  ### Low level API
87
100
 
88
- `HTS::LibHTS` provides native C functions.
101
+ `HTS::LibHTS` provides native C functions.
89
102
 
90
103
  ```ruby
91
104
  require 'htslib'
@@ -96,11 +109,11 @@ p b[:category]
96
109
  p b[:format]
97
110
  ```
98
111
 
99
- 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.
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.
100
113
 
101
114
  ### Need more speed?
102
115
 
103
- Try Crystal. [htslib.cr](https://github.com/bio-crystal/htslib.cr) is implemented in Crystal language and provides an API compatible with ruby-htslib. Crsytal language is not as flexible as Ruby language. You can not use eval methods, and you must always be aware of the types. It is not very suitable for writing one-time scripts or experimenting with different code. However, If you have already written code in ruby-htslib, have a clear idea of the manipulations you want to do, and need to execute them many times, then by all means try to implement the command line tool using htslib.cr. The Crystal language is very fast and can perform almost as well as the Rust and C languages.
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.
104
117
 
105
118
  ## Documentation
106
119
 
@@ -123,9 +136,12 @@ bundle exec rake test
123
136
 
124
137
  Many macro functions are used in HTSlib. Since these macro functions cannot be called using FFI, they must be reimplemented in Ruby.
125
138
 
126
- * Actively use the advanced features of Ruby.
127
- * Remain compatibile with [htslib.cr](https://github.com/bio-crystal/htslib.cr).
128
- * The most difficult part is the return value. In the Crystal language, it is convenient for a method to return only one type. In the Ruby language, on the other hand, it is more convenient to return multiple classes. For example, in the Crystal language, it is confusing that a return value can take four types: Int32, Float32, Nil, and String. In Ruby, on the other hand, it is very common and does not cause any problems.
139
+ * 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.
143
+
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.
129
145
 
130
146
  #### FFI Extensions
131
147
 
@@ -145,7 +161,10 @@ Ruby-htslib is a library under development, so even small improvements like typo
145
161
  * Suggest or add new features
146
162
  * [financial contributions](https://github.com/sponsors/kojix2)
147
163
 
164
+
148
165
  ```
166
+ # Ownership and Commitment Rights
167
+
149
168
  Do you need commit rights to ruby-htslib repository?
150
169
  Do you want to get admin rights and take over the project?
151
170
  If so, please feel free to contact us @kojix2.
@@ -153,7 +172,7 @@ If so, please feel free to contact us @kojix2.
153
172
 
154
173
  #### Why do you implement htslib in a language like Ruby, which is not widely used in the bioinformatics?
155
174
 
156
- 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. And that effort is still going on today...
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.
157
176
 
158
177
  ## Links
159
178
 
data/lib/hts/bam/aux.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module HTS
4
4
  class Bam < Hts
5
+ # Auxiliary record data
5
6
  class Aux
6
7
  def initialize(record)
7
8
  @record = record
data/lib/hts/bam/cigar.rb CHANGED
@@ -2,16 +2,15 @@
2
2
 
3
3
  module HTS
4
4
  class Bam < Hts
5
+ # CIGAR string
5
6
  class Cigar
6
7
  include Enumerable
7
8
 
8
9
  def initialize(pointer, n_cigar)
9
- @pointer = pointer
10
10
  @n_cigar = n_cigar
11
- end
12
-
13
- def to_ptr
14
- @pointer
11
+ # Read the pointer before the memory is changed.
12
+ # Especially when called from a block of `each` iterator.
13
+ @c = pointer.read_array_of_uint32(n_cigar)
15
14
  end
16
15
 
17
16
  def to_s
@@ -21,8 +20,7 @@ module HTS
21
20
  def each
22
21
  return to_enum(__method__) unless block_given?
23
22
 
24
- @n_cigar.times do |i|
25
- c = @pointer[i].read_uint32
23
+ @c.each do |c|
26
24
  op = LibHTS.bam_cigar_opchr(c)
27
25
  len = LibHTS.bam_cigar_oplen(c)
28
26
  yield [op, len]
data/lib/hts/bam/flag.rb CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  module HTS
7
7
  class Bam < Hts
8
+ # SAM flags
8
9
  class Flag
9
10
  def initialize(flag_value)
10
11
  raise TypeError unless flag_value.is_a? Integer
@@ -52,6 +53,10 @@ module HTS
52
53
  (@value & f) != 0
53
54
  end
54
55
 
56
+ def to_i
57
+ @value
58
+ end
59
+
55
60
  def to_s
56
61
  LibHTS.bam_flag2str(@value)
57
62
  # "0x#{format('%x', @value)}\t#{@value}\t#{LibHTS.bam_flag2str(@value)}"
@@ -2,6 +2,7 @@
2
2
 
3
3
  module HTS
4
4
  class Bam < Hts
5
+ # A class for working with alignment header.
5
6
  class Header
6
7
  def initialize(hts_file)
7
8
  @sam_hdr = LibHTS.sam_hdr_read(hts_file)
@@ -6,6 +6,7 @@ require_relative "aux"
6
6
 
7
7
  module HTS
8
8
  class Bam < Hts
9
+ # A class for working with alignment records.
9
10
  class Record
10
11
  SEQ_NT16_STR = "=ACMGRSVTWYHKDBN"
11
12
 
@@ -62,14 +63,17 @@ module HTS
62
63
  end
63
64
 
64
65
  # returns 0-based mate position
65
- def mpos
66
+ def mate_pos
66
67
  @bam1[:core][:mpos]
67
68
  end
68
69
 
69
- def mpos=(mpos)
70
+ def mate_pos=(mpos)
70
71
  @bam1[:core][:mpos] = mpos
71
72
  end
72
73
 
74
+ alias mpos mate_pos
75
+ alias mpos= mate_pos=
76
+
73
77
  def bin
74
78
  @bam1[:core][:bin]
75
79
  end
@@ -111,12 +115,11 @@ module HTS
111
115
  @bam1[:core][:isize]
112
116
  end
113
117
 
114
- alias isize insert_size
115
-
116
118
  def insert_size=(isize)
117
119
  @bam1[:core][:isize] = isize
118
120
  end
119
121
 
122
+ alias isize insert_size
120
123
  alias isize= insert_size=
121
124
 
122
125
  # mapping quality
data/lib/hts/bam.rb CHANGED
@@ -9,10 +9,11 @@ require_relative "bam/flag"
9
9
  require_relative "bam/record"
10
10
 
11
11
  module HTS
12
+ # A class for working with SAM, BAM, CRAM files.
12
13
  class Bam
13
14
  include Enumerable
14
15
 
15
- attr_reader :file_name, :index_name, :mode, :header
16
+ attr_reader :file_name, :index_name, :mode, :header, :nthreads
16
17
 
17
18
  def self.open(*args, **kw)
18
19
  file = new(*args, **kw) # do not yield
@@ -27,7 +28,7 @@ module HTS
27
28
  end
28
29
 
29
30
  def initialize(file_name, mode = "r", index: nil, fai: nil, threads: nil,
30
- create_index: false)
31
+ build_index: false)
31
32
  if block_given?
32
33
  message = "HTS::Bam.new() dose not take block; Please use HTS::Bam.open() instead"
33
34
  raise message
@@ -38,6 +39,7 @@ module HTS
38
39
  @file_name = file_name
39
40
  @index_name = index
40
41
  @mode = mode
42
+ @nthreads = threads
41
43
  @hts_file = LibHTS.hts_open(@file_name, mode)
42
44
 
43
45
  raise Errno::ENOENT, "Failed to open #{@file_name}" if @hts_file.null?
@@ -47,32 +49,34 @@ module HTS
47
49
  raise "Failed to load fasta index: #{fai}" if r < 0
48
50
  end
49
51
 
50
- if threads&.> 0
51
- r = LibHTS.hts_set_threads(@hts_file, threads)
52
- raise "Failed to set number of threads: #{threads}" if r < 0
53
- end
52
+ set_threads(threads) if threads
54
53
 
55
54
  return if @mode[0] == "w"
56
55
 
57
56
  @header = Bam::Header.new(@hts_file)
58
-
59
- create_index(index) if create_index
60
-
57
+ build_index(index) if build_index
61
58
  @idx = load_index(index)
62
-
63
59
  @start_position = tell
60
+ super # do nothing
64
61
  end
65
62
 
66
- def create_index(index_name = nil)
67
- warn "Create index for #{@file_name} to #{index_name}"
68
- if index
69
- LibHTS.sam_index_build2(@file_name, index_name, -1)
63
+ def build_index(index_name = nil, min_shift: 0)
64
+ check_closed
65
+
66
+ if index_name
67
+ warn "Create index for #{@file_name} to #{index_name}"
70
68
  else
71
- LibHTS.sam_index_build(@file_name, -1)
69
+ warn "Create index for #{@file_name}"
72
70
  end
71
+ r = LibHTS.sam_index_build3(@file_name, index_name, min_shift, @nthreads)
72
+ raise "Failed to build index for #{@file_name}" if r < 0
73
+
74
+ self
73
75
  end
74
76
 
75
77
  def load_index(index_name = nil)
78
+ check_closed
79
+
76
80
  if index_name
77
81
  LibHTS.sam_index_load2(@hts_file, @file_name, index_name)
78
82
  else
@@ -81,6 +85,8 @@ module HTS
81
85
  end
82
86
 
83
87
  def index_loaded?
88
+ check_closed
89
+
84
90
  !@idx.null?
85
91
  end
86
92
 
@@ -92,7 +98,7 @@ module HTS
92
98
  end
93
99
 
94
100
  def write_header(header)
95
- raise IOError, "closed stream" if closed?
101
+ check_closed
96
102
 
97
103
  @header = header.dup
98
104
  LibHTS.hts_set_fai_filename(@hts_file, @file_name)
@@ -100,17 +106,22 @@ module HTS
100
106
  end
101
107
 
102
108
  def write(aln)
103
- raise IOError, "closed stream" if closed?
109
+ check_closed
104
110
 
105
111
  aln_dup = aln.dup
106
112
  LibHTS.sam_write1(@hts_file, header, aln_dup) > 0 || raise
107
113
  end
108
114
 
109
- # Iterate over each record.
110
- # Generate a new Record object each time.
111
- # Slower than each.
112
- def each_copy
113
- raise IOError, "closed stream" if closed?
115
+ def each(copy: false, &block)
116
+ if copy
117
+ each_record_copy(&block)
118
+ else
119
+ each_record_reuse(&block)
120
+ end
121
+ end
122
+
123
+ private def each_record_copy
124
+ check_closed
114
125
  return to_enum(__method__) unless block_given?
115
126
 
116
127
  while LibHTS.sam_read1(@hts_file, header, bam1 = LibHTS.bam_init1) != -1
@@ -120,14 +131,10 @@ module HTS
120
131
  self
121
132
  end
122
133
 
123
- # Iterate over each record.
124
- # Record object is reused.
125
- # Faster than each_copy.
126
- def each
127
- raise IOError, "closed stream" if closed?
134
+ private def each_record_reuse
135
+ check_closed
128
136
  # Each does not always start at the beginning of the file.
129
137
  # This is the common behavior of IO objects in Ruby.
130
- # This may change in the future.
131
138
  return to_enum(__method__) unless block_given?
132
139
 
133
140
  bam1 = LibHTS.bam_init1
@@ -136,23 +143,109 @@ module HTS
136
143
  self
137
144
  end
138
145
 
139
- # query [WIP]
140
- def query(region)
141
- raise IOError, "closed stream" if closed?
146
+ def query(region, copy: false, &block)
147
+ if copy
148
+ query_copy(region, &block)
149
+ else
150
+ query_reuse(region, &block)
151
+ end
152
+ end
153
+
154
+ private def query_copy(region)
155
+ check_closed
142
156
  raise "Index file is required to call the query method." unless index_loaded?
157
+ return to_enum(__method__, region) unless block_given?
143
158
 
144
159
  qiter = LibHTS.sam_itr_querys(@idx, header, region)
160
+
145
161
  begin
146
- bam1 = LibHTS.bam_init1
147
- slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
148
- while slen > 0
149
- yield Record.new(bam1, header)
162
+ loop do
150
163
  bam1 = LibHTS.bam_init1
151
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)
152
169
  end
153
170
  ensure
154
171
  LibHTS.hts_itr_destroy(qiter)
155
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
+ # @!macro [attach] define_getter
194
+ # @method $1
195
+ # Get $1 array
196
+ # @return [Array] the $1 array
197
+ define_getter :qname
198
+ define_getter :flag
199
+ define_getter :chrom
200
+ define_getter :pos
201
+ define_getter :mapq
202
+ define_getter :cigar
203
+ define_getter :mate_chrom
204
+ define_getter :mate_pos
205
+ define_getter :insert_size
206
+ define_getter :seq
207
+ define_getter :qual
208
+
209
+ alias isize insert_size
210
+ alias mpos mate_pos
211
+
212
+ def aux(tag)
213
+ warn "experimental"
214
+ check_closed
215
+ position = tell
216
+ ary = map { |r| r.aux(tag) }
217
+ seek(position)
218
+ ary
219
+ end
220
+
221
+ # @!macro [attach] define_iterator
222
+ # @method each_$1
223
+ # Get $1 iterator
224
+ define_iterator :qname
225
+ define_iterator :flag
226
+ define_iterator :chrom
227
+ define_iterator :pos
228
+ define_iterator :mapq
229
+ define_iterator :cigar
230
+ define_iterator :mate_chrom
231
+ define_iterator :mate_pos
232
+ define_iterator :insert_size
233
+ define_iterator :seq
234
+ define_iterator :qual
235
+
236
+ alias each_isize each_insert_size
237
+ alias each_mpos each_mate_pos
238
+
239
+ def each_aux(tag)
240
+ warn "experimental"
241
+ check_closed
242
+ return to_enum(__method__, tag) unless block_given?
243
+
244
+ each do |record|
245
+ yield record.aux(tag)
246
+ end
247
+
248
+ self
156
249
  end
157
250
  end
158
251
  end
@@ -38,8 +38,8 @@ module HTS
38
38
  h = @record.header.struct
39
39
  r = @record.struct
40
40
 
41
- format_values = proc do |type|
42
- ret = LibHTS.bcf_get_format_values(h, r, key, p1, n, type)
41
+ format_values = proc do |typ|
42
+ ret = LibHTS.bcf_get_format_values(h, r, key, p1, n, typ)
43
43
  return nil if ret < 0 # return from method.
44
44
 
45
45
  p1.read_pointer
@@ -79,10 +79,10 @@ module HTS
79
79
  num = LibHTS.bcf_hdr_id2number(@record.header.struct, LibHTS::BCF_HL_FMT, id)
80
80
  type = LibHTS.bcf_hdr_id2type(@record.header.struct, LibHTS::BCF_HL_FMT, id)
81
81
  {
82
- name: name,
82
+ name:,
83
83
  n: num,
84
84
  type: ht_type_to_sym(type),
85
- id: id
85
+ id:
86
86
  }
87
87
  end
88
88
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module HTS
4
4
  class Bcf < Hts
5
+ # A class for working with VCF records.
5
6
  class Header
6
7
  def initialize(hts_file)
7
8
  @bcf_hdr = LibHTS.bcf_hdr_read(hts_file)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTS
4
+ class Bcf < Hts
5
+ class HeaderRecord
6
+ def initialize
7
+ @bcf_hrec
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/hts/bcf/info.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module HTS
4
4
  class Bcf < Hts
5
+ # Info field
5
6
  class Info
6
7
  def initialize(record)
7
8
  @record = record
@@ -76,10 +77,10 @@ module HTS
76
77
  num = LibHTS.bcf_hdr_id2number(@record.header.struct, LibHTS::BCF_HL_INFO, key)
77
78
  type = LibHTS.bcf_hdr_id2type(@record.header.struct, LibHTS::BCF_HL_INFO, key)
78
79
  {
79
- name: name,
80
+ name:,
80
81
  n: num,
81
82
  type: ht_type_to_sym(type),
82
- key: key
83
+ key:
83
84
  }
84
85
  end
85
86
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module HTS
4
4
  class Bcf < Hts
5
+ # A class for working with VCF records.
5
6
  class Record
6
7
  def initialize(bcf_t, header)
7
8
  @bcf1 = bcf_t
@@ -60,35 +61,6 @@ module HTS
60
61
  LibHTS.bcf_update_id(@header, @bcf1, ".")
61
62
  end
62
63
 
63
- def filter
64
- LibHTS.bcf_unpack(@bcf1, LibHTS::BCF_UN_FLT)
65
- d = @bcf1[:d]
66
- n_flt = d[:n_flt]
67
-
68
- case n_flt
69
- when 0
70
- "PASS"
71
- when 1
72
- i = d[:flt].read_int
73
- LibHTS.bcf_hdr_int2id(@header.struct, LibHTS::BCF_DT_ID, i)
74
- when 2..nil
75
- d[:flt].get_array_of_int(0, n_flt).map do |i|
76
- LibHTS.bcf_hdr_int2id(@header.struct, LibHTS::BCF_DT_ID, i)
77
- end
78
- else
79
- raise "Unexpected number of filters. n_flt: #{n_flt}"
80
- end
81
- end
82
-
83
- # Get variant quality.
84
- def qual
85
- @bcf1[:qual]
86
- end
87
-
88
- def qual=(qual)
89
- @bcf1[:qual] = qual
90
- end
91
-
92
64
  def ref
93
65
  LibHTS.bcf_unpack(@bcf1, LibHTS::BCF_UN_STR)
94
66
  @bcf1[:d][:allele].get_pointer(0).read_string
@@ -108,6 +80,35 @@ module HTS
108
80
  ).map(&:read_string)
109
81
  end
110
82
 
83
+ # Get variant quality.
84
+ def qual
85
+ @bcf1[:qual]
86
+ end
87
+
88
+ def qual=(qual)
89
+ @bcf1[:qual] = qual
90
+ end
91
+
92
+ def filter
93
+ LibHTS.bcf_unpack(@bcf1, LibHTS::BCF_UN_FLT)
94
+ d = @bcf1[:d]
95
+ n_flt = d[:n_flt]
96
+
97
+ case n_flt
98
+ when 0
99
+ "PASS"
100
+ when 1
101
+ id = d[:flt].read_int
102
+ LibHTS.bcf_hdr_int2id(@header.struct, LibHTS::BCF_DT_ID, id)
103
+ when 2..nil
104
+ d[:flt].get_array_of_int(0, n_flt).map do |i|
105
+ LibHTS.bcf_hdr_int2id(@header.struct, LibHTS::BCF_DT_ID, i)
106
+ end
107
+ else
108
+ raise "Unexpected number of filters. n_flt: #{n_flt}"
109
+ end
110
+ end
111
+
111
112
  def info(key = nil)
112
113
  LibHTS.bcf_unpack(@bcf1, LibHTS::BCF_UN_SHR)
113
114
  info = Info.new(self)
@@ -136,7 +137,7 @@ module HTS
136
137
 
137
138
  private
138
139
 
139
- def initialize_copy(orig)\
140
+ def initialize_copy(orig)
140
141
  @header = orig.header
141
142
  @bcf1 = LibHTS.bcf_dup(orig.struct)
142
143
  end