htslib 0.0.4 → 0.0.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: 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