htslib 0.0.4 → 0.0.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: c8048806df4c335ea698c8d3ad9e51e12644f0d32667d3db5fac59a004db75bf
4
- data.tar.gz: 3d18183921f70b7b42dc5657195607c519c7d83c1e0e94b9b7a8f647d96f5504
3
+ metadata.gz: 3eb6fbb228a9fa0642c55cdfa39d5189b311df191725954ae46b8dda135dc8c7
4
+ data.tar.gz: c90ad39aa4919cefa56e534a706bf9659bba9c6ad69eb374491092ce16ae93f6
5
5
  SHA512:
6
- metadata.gz: f50e96a23cb75130c5aa463329cce3c2d5784ed75c608d4685d2662ee22fa93e55208c356bce0fee319028c6ae8e33b5b20d270a17fb63ca6e39a736f668a2e4
7
- data.tar.gz: c223f9b61979ace926fa53b408e85fa6f2e127cdde6ffa5bcfa1ac0ad7ce6c9c1ac5570522021c61e82d27498473299b8875f7d633b24367ae99dd2494758556
6
+ metadata.gz: 392ea7c6acb5b86e9e1c1a29f066049c54954edfd277be30541aee433a7349f9d74df09e663ec0269f30d6b87ff47d66a4a668470d3aa536e25a2058cf963546
7
+ data.tar.gz: 9cc235f8876b8fd4339593eb84a0f2cb8b605b9c82b624cd0f97691b4109a672f55ae90447bba17fb5efcb8257279ad8c2d87234bca390b1624c7aa8f9a7014e
@@ -21,6 +21,8 @@ module HTS
21
21
  @bam1.to_ptr
22
22
  end
23
23
 
24
+ attr_reader :header
25
+
24
26
  # def initialize_copy
25
27
  # super
26
28
  # end
@@ -161,6 +163,23 @@ module HTS
161
163
  Flag.new(@bam1[:core][:flag])
162
164
  end
163
165
 
166
+ def tag(str)
167
+ aux = LibHTS.bam_aux_get(@bam1, str)
168
+ return nil if aux.null?
169
+
170
+ t = aux.read_string(1)
171
+ case t
172
+ when "i", "I", "c", "C", "s", "S"
173
+ LibHTS.bam_aux2i(aux)
174
+ when "f", "d"
175
+ LibHTS.bam_aux2f(aux)
176
+ when "Z", "H"
177
+ LibHTS.bam_aux2Z(aux)
178
+ when "A"
179
+ LibHTS.bam_aux2A(aux)
180
+ end
181
+ end
182
+
164
183
  def to_s
165
184
  kstr = LibHTS::KString.new
166
185
  raise "Failed to format bam record" if LibHTS.sam_format1(@header.struct, @bam1, kstr) == -1
data/lib/hts/bam.rb CHANGED
@@ -7,12 +7,10 @@ require_relative "bam/header"
7
7
  require_relative "bam/cigar"
8
8
  require_relative "bam/flag"
9
9
  require_relative "bam/record"
10
- require_relative "utils/open_method"
11
10
 
12
11
  module HTS
13
12
  class Bam
14
13
  include Enumerable
15
- extend Utils::OpenMethod
16
14
 
17
15
  attr_reader :file_path, :mode, :header
18
16
  # HtfFile is FFI::BitStruct
@@ -35,9 +33,6 @@ module HTS
35
33
  @htf_file = LibHTS.hts_open(file_path, mode)
36
34
  @header = Bam::Header.new(LibHTS.sam_hdr_read(htf_file))
37
35
 
38
- # FIXME: should be defined here?
39
- @bam1 = LibHTS.bam_init1
40
-
41
36
  # read
42
37
  if mode[0] == "r"
43
38
  # load index
@@ -87,24 +82,29 @@ module HTS
87
82
  # LibHTS.bgzf_flush(@htf_file.fp.bgzf)
88
83
  end
89
84
 
90
- def each(&block)
85
+ def each
91
86
  # Each does not always start at the beginning of the file.
92
87
  # This is the common behavior of IO objects in Ruby.
93
88
  # This may change in the future.
94
- while LibHTS.sam_read1(htf_file, header, @bam1) > 0
95
- record = Record.new(@bam1, header)
96
- block.call(record)
89
+ return to_enum(__method__) unless block_given?
90
+
91
+ while LibHTS.sam_read1(htf_file, header, bam1 = LibHTS.bam_init1) > 0
92
+ record = Record.new(bam1, header)
93
+ yield record
97
94
  end
95
+ self
98
96
  end
99
97
 
100
98
  # query [WIP]
101
99
  def query(region)
102
100
  qiter = LibHTS.sam_itr_querys(@idx, header, region)
103
101
  begin
104
- slen = LibHTS.sam_itr_next(htf_file, qiter, @bam1)
102
+ bam1 = LibHTS.bam_init1
103
+ slen = LibHTS.sam_itr_next(htf_file, qiter, bam1)
105
104
  while slen > 0
106
- yield Record.new(@bam1, header)
107
- slen = LibHTS.sam_itr_next(htf_file, qiter, @bam1)
105
+ yield Record.new(bam1, header)
106
+ bam1 = LibHTS.bam_init1
107
+ slen = LibHTS.sam_itr_next(htf_file, qiter, bam1)
108
108
  end
109
109
  ensure
110
110
  LibHTS.hts_itr_destroy(qiter)
data/lib/hts/bcf/info.rb CHANGED
@@ -7,6 +7,7 @@ module HTS
7
7
  @record = record
8
8
  end
9
9
 
10
+ # @note Specify the type. If you don't specify a type, it will still work, but it will be slower.
10
11
  def get(key, type = nil)
11
12
  n = FFI::MemoryPointer.new(:int)
12
13
  p1 = @record.p1
@@ -20,19 +21,71 @@ module HTS
20
21
  p1.read_pointer
21
22
  end
22
23
 
23
- case type.to_sym
24
+ type ||= info_type_to_string(get_info_type(key))
25
+
26
+ case type&.to_sym
24
27
  when :int, :int32
25
28
  info_values.call(LibHTS::BCF_HT_INT)
26
29
  .read_array_of_int32(n.read_int)
27
30
  when :float, :real
28
31
  info_values.call(LibHTS::BCF_HT_REAL)
29
32
  .read_array_of_float(n.read_int)
30
- when :flag
31
- info_values.call(LibHTS::BCF_HT_FLAG)
32
- .read_int == 1
33
+ when :flag, :bool
34
+ case ret = LibHTS.bcf_get_info_flag(h, r, key, p1, n)
35
+ when 1 then true
36
+ when 0 then false
37
+ when -1 then nil
38
+ else
39
+ raise "Unknown return value from bcf_get_info_flag: #{ret}"
40
+ end
33
41
  when :string, :str
34
42
  info_values.call(LibHTS::BCF_HT_STR)
35
- .read_pointer.read_string
43
+ .read_string
44
+ end
45
+ end
46
+
47
+ def fields
48
+ n_info = @record.struct[:n_info]
49
+ Array.new(n_info) do |i|
50
+ fld = LibHTS::BcfInfo.new(
51
+ @record.struct[:d][:info] +
52
+ i * LibHTS::BcfInfo.size
53
+ )
54
+ {
55
+ name: LibHTS.bcf_hdr_int2id(
56
+ @record.bcf.header.struct, LibHTS::BCF_DT_ID, fld[:key]
57
+ ),
58
+ n: LibHTS.bcf_hdr_id2number(
59
+ @record.bcf.header.struct, LibHTS::BCF_HL_INFO, fld[:key]
60
+ ),
61
+ vtype: fld[:type], i: fld[:key]
62
+ }
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def get_info_type(key)
69
+ @record.struct[:n_info].times do |i|
70
+ fld = LibHTS::BcfInfo.new(
71
+ @record.struct[:d][:info] +
72
+ i * LibHTS::BcfInfo.size
73
+ )
74
+ id = LibHTS.bcf_hdr_int2id(
75
+ @record.bcf.header.struct, LibHTS::BCF_DT_ID, fld[:key]
76
+ )
77
+ return fld[:type] if id == key
78
+ end
79
+ end
80
+
81
+ def info_type_to_string(t)
82
+ case t
83
+ when 0 then :flag
84
+ when 1, 2, 3, 4 then :int
85
+ when 5 then :float
86
+ when 7 then :string
87
+ else
88
+ raise "Unknown info type: #{t}"
36
89
  end
37
90
  end
38
91
  end
@@ -29,12 +29,7 @@ module HTS
29
29
  hdr = @bcf.header.struct
30
30
  rid = @bcf1[:rid]
31
31
 
32
- return nil if hdr.null? || rid < 0 || rid >= hdr[:n][LibHTS::BCF_DT_CTG]
33
-
34
- LibHTS::BcfIdpair.new(
35
- hdr[:id][LibHTS::BCF_DT_CTG].to_ptr +
36
- LibHTS::BcfIdpair.size * rid # offset
37
- )[:key]
32
+ LibHTS.bcf_hdr_id2name(hdr, rid)
38
33
  end
39
34
 
40
35
  def pos
@@ -106,9 +101,8 @@ module HTS
106
101
 
107
102
  def to_s
108
103
  ksr = LibHTS::KString.new
109
- if LibHTS.vcf_format(@bcf.header.struct, @bcf1, ksr) == -1
110
- raise "Failed to format record"
111
- end
104
+ raise "Failed to format record" if LibHTS.vcf_format(@bcf.header.struct, @bcf1, ksr) == -1
105
+
112
106
  ksr[:s]
113
107
  end
114
108
  end
data/lib/hts/bcf.rb CHANGED
@@ -4,15 +4,13 @@
4
4
  # https://github.com/quinlan-lab/hts-python
5
5
 
6
6
  require_relative "bcf/header"
7
- require_relative "bcf/record"
8
7
  require_relative "bcf/info"
9
8
  require_relative "bcf/format"
10
- require_relative "utils/open_method"
9
+ require_relative "bcf/record"
11
10
 
12
11
  module HTS
13
12
  class Bcf
14
13
  include Enumerable
15
- extend Utils::OpenMethod
16
14
 
17
15
  attr_reader :file_path, :mode, :header
18
16
  # HtfFile is FFI::BitStruct
@@ -35,9 +33,6 @@ module HTS
35
33
  @htf_file = LibHTS.hts_open(file_path, mode)
36
34
  @header = Bcf::Header.new(LibHTS.bcf_hdr_read(htf_file))
37
35
 
38
- # FIXME: should be defined here?
39
- @bcf1 = LibHTS.bcf_init
40
-
41
36
  # IO like API
42
37
  if block_given?
43
38
  begin
@@ -61,11 +56,14 @@ module HTS
61
56
  LibHTS.hts_close(htf_file)
62
57
  end
63
58
 
64
- def each(&block)
65
- while LibHTS.bcf_read(htf_file, header, @bcf1) != -1
66
- record = Record.new(@bcf1, self)
67
- block.call(record)
59
+ def each
60
+ return to_enum(__method__) unless block_given?
61
+
62
+ while LibHTS.bcf_read(htf_file, header, bcf1 = LibHTS.bcf_init) != -1
63
+ record = Record.new(bcf1, self)
64
+ yield record
68
65
  end
66
+ self
69
67
  end
70
68
 
71
69
  def n_samples
data/lib/hts/faidx.rb CHANGED
@@ -3,17 +3,26 @@
3
3
  # Based on hts-python
4
4
  # https://github.com/quinlan-lab/hts-python
5
5
 
6
- require_relative "utils/open_method"
7
-
8
6
  module HTS
9
7
  class Faidx
10
- extend Utils::OpenMethod
11
-
12
8
  attr_reader :file_path
13
9
 
10
+ class << self
11
+ alias open new
12
+ end
13
+
14
14
  def initialize(file_path)
15
15
  @file_path = File.expand_path(file_path)
16
16
  @fai = LibHTS.fai_load(file_path)
17
+
18
+ # IO like API
19
+ if block_given?
20
+ begin
21
+ yield self
22
+ ensure
23
+ close
24
+ end
25
+ end
17
26
  end
18
27
 
19
28
  def close
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ffi/bit_struct"
3
+ require 'ffi/bit_field'
4
4
 
5
5
  module FFI
6
6
  class Struct
@@ -289,7 +289,7 @@ module HTS
289
289
  :isize, :hts_pos_t
290
290
  end
291
291
 
292
- class Bam1 < FFI::Struct
292
+ class Bam1 < FFI::ManagedStruct
293
293
  layout \
294
294
  :core, Bam1Core,
295
295
  :id, :uint64,
@@ -301,6 +301,10 @@ module HTS
301
301
  # bit_fields :_mempolicy,
302
302
  # :mempolicy, 2,
303
303
  # :_reserved, 30
304
+
305
+ def self.release(ptr)
306
+ LibHTS.bam_destroy1(ptr) unless ptr.null?
307
+ end
304
308
  end
305
309
 
306
310
  typedef :pointer, :bam_plp
@@ -457,7 +461,7 @@ module HTS
457
461
  :id, :string,
458
462
  :als, :pointer, # (\\0-separated string)
459
463
  :allele, :pointer,
460
- :info, BcfInfo.ptr,
464
+ :info, :pointer, # BcfInfo.ptr,
461
465
  :fmt, BcfFmt.ptr,
462
466
  :var, BcfVariant.ptr,
463
467
  :n_var, :int,
@@ -466,7 +470,7 @@ module HTS
466
470
  :indiv_dirty, :int
467
471
  end
468
472
 
469
- class Bcf1 < FFI::BitStruct
473
+ class Bcf1 < FFI::ManagedBitStruct
470
474
  layout \
471
475
  :pos, :hts_pos_t,
472
476
  :rlen, :hts_pos_t,
@@ -489,6 +493,10 @@ module HTS
489
493
  bit_fields :_n_fmt_sample,
490
494
  :n_fmt, 8,
491
495
  :n_sample, 24
496
+
497
+ def self.release(ptr)
498
+ LibHTS.bcf_destroy(ptr) unless ptr.null?
499
+ end
492
500
  end
493
501
  end
494
502
  end
@@ -167,6 +167,33 @@ module HTS
167
167
  LibHTS::BcfIdpair.size * int_id # offsets
168
168
  )[:key]
169
169
  end
170
+
171
+ def bcf_hdr_name2id(hdr, id)
172
+ bcf_hdr_id2int(hdr, BCF_DT_CTG, id)
173
+ end
174
+
175
+ def bcf_hdr_id2name(hdr, rid)
176
+ return nil if hdr.null? || rid < 0 || rid >= hdr[:n][LibHTS::BCF_DT_CTG]
177
+
178
+ LibHTS::BcfIdpair.new(
179
+ hdr[:id][LibHTS::BCF_DT_CTG].to_ptr +
180
+ LibHTS::BcfIdpair.size * rid # offset
181
+ )[:key]
182
+ end
183
+
184
+ def bcf_hdr_id2length(hdr, type, int_id)
185
+ LibHTS::BcfIdpair.new(
186
+ hdr[:id][LibHTS::BCF_DT_ID].to_ptr +
187
+ LibHTS::BcfIdpair.size * int_id # offset
188
+ )[:val][:info][type] >> 8 & 0xf
189
+ end
190
+
191
+ def bcf_hdr_id2number(hdr, type, int_id)
192
+ LibHTS::BcfIdpair.new(
193
+ hdr[:id][LibHTS::BCF_DT_ID].to_ptr +
194
+ LibHTS::BcfIdpair.size * int_id # offset
195
+ )[:val][:info][type] >> 12
196
+ end
170
197
  end
171
198
 
172
199
  # constants
data/lib/hts/tabix.rb CHANGED
@@ -3,13 +3,21 @@
3
3
  # Based on hts-python
4
4
  # https://github.com/quinlan-lab/hts-python
5
5
 
6
- require_relative "utils/open_method"
7
-
8
6
  module HTS
9
7
  class Tabix
10
- extend Utils::OpenMethod
11
-
12
- def initialize; end
8
+ class << self
9
+ alias open new
10
+ end
11
+ def initialize
12
+ # IO like API
13
+ if block_given?
14
+ begin
15
+ yield self
16
+ ensure
17
+ close
18
+ end
19
+ end
20
+ end
13
21
 
14
22
  def build; end
15
23
 
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.0.4"
4
+ VERSION = "0.0.5"
5
5
  end
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.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-22 00:00:00.000000000 Z
11
+ date: 2021-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -155,7 +155,6 @@ files:
155
155
  - lib/hts/libhts/tbx.rb
156
156
  - lib/hts/libhts/vcf.rb
157
157
  - lib/hts/tabix.rb
158
- - lib/hts/utils/open_method.rb
159
158
  - lib/hts/version.rb
160
159
  - lib/htslib.rb
161
160
  homepage: https://github.com/kojix2/ruby-htslib
@@ -177,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
176
  - !ruby/object:Gem::Version
178
177
  version: '0'
179
178
  requirements: []
180
- rubygems_version: 3.2.26
179
+ rubygems_version: 3.3.3
181
180
  signing_key:
182
181
  specification_version: 4
183
182
  summary: HTSlib bindings for Ruby
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module HTS
4
- module Utils
5
- module OpenMethod
6
- def open(path)
7
- object = new(path)
8
- if block_given?
9
- yield(object)
10
- object.close
11
- else
12
- object
13
- end
14
- end
15
- end
16
- end
17
- end