htslib 0.0.1 → 0.0.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: 5c0c00377d4485fa702cc429c3005e98d1d095842d51fa6d27346fad9891c280
4
- data.tar.gz: 56e680d3f890ef1df37f2d99644c13bde250a130ca46e5d6b756ca16366fe81e
3
+ metadata.gz: d4fe8c4a8f710ee3b35793e997f394ba8f80e0fe5b507768de2af2c5ab1297a0
4
+ data.tar.gz: 1bb06ced745342f4de8665f046304364c9d419ae05eee355c3cd852d6b2b454a
5
5
  SHA512:
6
- metadata.gz: 1a38ecbb819edb2f81e5b76250c8ef070bf5d252925fecb859a4083462a7934feefd8ac50b2628f9f3912915982354bd61d424224302b45e9e2911321469bba6
7
- data.tar.gz: 01d5ac7826b5db6b6838986d05801b69c76320bbb4a89029cf21a6f01031c9bcc23c287526fbda02c8a2c0a32453e53ed6d689373754680c584f969214c58f6f
6
+ metadata.gz: 8c7fb677d2462a1ddf4cd146d9f9962b570f39762e98d893d77f89bbbf61c92329ed8391030f772bf4f98fb3dc874edc3c365dd2d85266e1e966b24effc1715c
7
+ data.tar.gz: fee9ec647e3ef51e83a1aec1c62ac02c796dcfefe4d5fd6c901e4b04e4253619e7337cee651df1ece9ca58c74a7a50620befd5cd8ab823696d0f893a437bd562
data/README.md CHANGED
@@ -4,12 +4,19 @@
4
4
  ![CI](https://github.com/kojix2/ruby-htslib/workflows/CI/badge.svg)
5
5
  [![The MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
6
6
  [![DOI](https://zenodo.org/badge/247078205.svg)](https://zenodo.org/badge/latestdoi/247078205)
7
+ [![Docs Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://rubydoc.info/gems/htslib)
7
8
 
8
9
  :dna: [HTSlib](https://github.com/samtools/htslib) - high-throughput sequencing data manipulation - for Ruby
9
10
 
10
11
  :apple: Feel free to fork it out if you can develop it!
11
12
 
12
- :bowtie: Just a prototype.
13
+ :bowtie: Just a prototype. Pre-alpha stage.
14
+
15
+ ## Requirements
16
+
17
+ * [htslib](https://github.com/samtools/htslib)
18
+ * Ubuntu : `apt install libhts-dev`
19
+ * macOS : `brew install htslib`
13
20
 
14
21
  ## Installation
15
22
 
@@ -17,16 +24,14 @@
17
24
  gem install htslib
18
25
  ```
19
26
 
20
- Set environment variable HTSLIBDIR.
27
+ If you installed htslib with Ubuntu/apt or Mac/homebrew, pkg-config will automatically detect the location of the shared library.
28
+
29
+ Or you can set the environment variable `HTSLIBDIR`.
21
30
 
22
31
  ```sh
23
- export HTSLIBDIR="/your/path/to/htslib"
32
+ export HTSLIBDIR="/your/path/to/htslib" # libhts.so
24
33
  ```
25
34
 
26
- ## Requirements
27
-
28
- * [htslib](https://github.com/samtools/htslib)
29
-
30
35
  ## Usage
31
36
 
32
37
  HTS::FFI - Low-level API
@@ -42,6 +47,23 @@ p b[:format]
42
47
 
43
48
  A high-level API based on [hts-python](https://github.com/quinlan-lab/hts-python) is under development.
44
49
 
50
+ ```ruby
51
+ require 'htslib'
52
+
53
+ bam = HTS::Bam.new("a.bam")
54
+
55
+ bam.each do |aln|
56
+ p name: aln.qname,
57
+ flag: aln.flag,
58
+ start: aln.start + 1,
59
+ mpos: aln.mate_pos + 1,
60
+ mqual: aln.mapping_quality,
61
+ seq: aln.sequence,
62
+ cigar: aln.cigar.to_s,
63
+ qual: aln.base_qualities.map { |i| (i + 33).chr }.join
64
+ end
65
+ ```
66
+
45
67
  ## Documentation
46
68
 
47
69
  * [RubyDoc.info - HTSlib](https://rdoc.info/gems/htslib)
@@ -51,15 +73,17 @@ A high-level API based on [hts-python](https://github.com/quinlan-lab/hts-python
51
73
  To get started with development
52
74
 
53
75
  ```sh
54
- git clone --recurse-submodules https://github.com/kojix2/ruby-htslib
76
+ git clone --recursive https://github.com/kojix2/ruby-htslib
55
77
  cd ruby-htslib
56
78
  bundle install
57
- bundle exec rake htslib:compile
58
- bundle exec rake spec
79
+ bundle exec rake htslib:build
80
+ bundle exec rake test
59
81
  ```
60
82
 
61
83
  ## Contributing
62
84
 
85
+ Ruby-htslib is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
86
+
63
87
  * [Report bugs](https://github.com/kojix2/ruby-htslib/issues)
64
88
  * Fix bugs and [submit pull requests](https://github.com/kojix2/ruby-htslib/pulls)
65
89
  * Write, clarify, or fix documentation
data/lib/hts/bam.rb CHANGED
@@ -10,20 +10,20 @@ require_relative 'bam/alignment'
10
10
  module HTS
11
11
  class Bam
12
12
  include Enumerable
13
- attr_reader :fname, :mode, :header, :htf
13
+ attr_reader :file_path, :mode, :header, :htf
14
14
 
15
- def initialize(fname, mode = 'r', create_index: nil, header: nil, fasta: nil)
16
- @fname = File.expand_path(fname)
17
- File.exist?(@fname) || raise("No such SAM/BAM file - #{@fname}")
15
+ def initialize(file_path, mode = 'r', create_index: nil, header: nil, fasta: nil)
16
+ @file_path = File.expand_path(file_path)
17
+ File.exist?(@file_path) || raise("No such SAM/BAM file - #{@file_path}")
18
18
 
19
19
  @mode = mode
20
- @htf = FFI.hts_open(@fname, mode)
20
+ @htf = FFI.hts_open(@file_path, mode)
21
21
 
22
22
  if mode[0] == 'r'
23
- @idx = FFI.sam_index_load(@htf, @fname)
23
+ @idx = FFI.sam_index_load(@htf, @file_path)
24
24
  if (@idx.null? && create_index.nil?) || create_index
25
- FFI.sam_index_build(fname, -1)
26
- @idx = FFI.sam_index_load(@htf, @fname)
25
+ FFI.sam_index_build(file_path, -1)
26
+ @idx = FFI.sam_index_load(@htf, @file_path)
27
27
  warn 'NO querying'
28
28
  end
29
29
  @header = Bam::Header.new(FFI.sam_hdr_read(@htf))
@@ -4,7 +4,6 @@
4
4
  # https://github.com/quinlan-lab/hts-python
5
5
 
6
6
  module HTS
7
- # A cigar object usually created from `Alignment`.
8
7
  class Bam
9
8
  class Alignment
10
9
  def initialize(bam1_t, bam_hdr_t)
data/lib/hts/fai.rb CHANGED
@@ -5,13 +5,52 @@
5
5
 
6
6
  module HTS
7
7
  class Fai
8
- def initialize; end
8
+ # FIXME: API
9
+ def self.open(path)
10
+ fai = new(path)
11
+ if block_given?
12
+ yield(fai)
13
+ fai.close
14
+ else
15
+ fai
16
+ end
17
+ end
9
18
 
10
- # def call
19
+ def initialize(path)
20
+ @path = File.expand_path(path)
21
+ @path.delete_suffix!('.fai')
22
+ FFI.fai_build(@path) unless File.exist?("#{@path}.fai")
23
+ @fai = FFI.fai_load(@path)
24
+ raise if @fai.null?
11
25
 
12
- def nseqs; end
26
+ # at_exit{FFI.fai_destroy(@fai)}
27
+ end
13
28
 
14
- def include?; end
29
+ def close
30
+ FFI.fai_destroy(@fai)
31
+ end
32
+
33
+ # the number of sequences in the index.
34
+ def size
35
+ FFI.faidx_nseq(@fai)
36
+ end
37
+ alias length size
38
+
39
+ # return the length of the requested chromosome.
40
+ def chrom_size(chrom)
41
+ raise ArgumentError, 'Expect chrom to be String or Symbol' unless chrom.is_a?(String) || chrom.is_a?(Symbol)
42
+
43
+ chrom = chrom.to_s
44
+ result = FFI.faidx_seq_len(@fai, chrom)
45
+ result == -1 ? nil : result
46
+ end
47
+ alias chrom_length chrom_size
48
+
49
+ # FIXME: naming and syntax
50
+ def cget; end
51
+
52
+ # FIXME: naming and syntax
53
+ def get; end
15
54
 
16
55
  # __iter__
17
56
  end
data/lib/hts/ffi.rb CHANGED
@@ -20,12 +20,54 @@ end
20
20
 
21
21
  module FFI
22
22
  class Struct
23
- def self.union_layout(*args)
24
- Class.new(FFI::Union) { layout(*args) }
23
+ class << self
24
+ def union_layout(*args)
25
+ Class.new(FFI::Union) { layout(*args) }
26
+ end
27
+
28
+ def struct_layout(*args)
29
+ Class.new(FFI::Struct) { layout(*args) }
30
+ end
25
31
  end
32
+ end
33
+
34
+ class BitStruct < Struct
35
+ class << self
36
+ module BitFieldsModule
37
+ def [](name)
38
+ bit_fields = self.class.bit_fields_hash_table
39
+ parent, start, width = bit_fields[name]
40
+ if parent
41
+ (super(parent) >> start) & ((1 << width) - 1)
42
+ else
43
+ super(name)
44
+ end
45
+ end
46
+ end
47
+ private_constant :BitFieldsModule
48
+
49
+ attr_reader :bit_fields_hash_table
50
+
51
+ def bitfields(*args)
52
+ unless instance_variable_defined?(:@bit_fields_hash_table)
53
+ @bit_fields_hash_table = {}
54
+ prepend BitFieldsModule
55
+ end
26
56
 
27
- def self.struct_layout(*args)
28
- Class.new(FFI::Struct) { layout(*args) }
57
+ parent = args.shift
58
+ labels = []
59
+ widths = []
60
+ args.each_slice(2) do |l, w|
61
+ labels << l
62
+ widths << w
63
+ end
64
+ starts = widths.inject([0]) do |result, w|
65
+ result << (result.last + w)
66
+ end
67
+ labels.zip(starts, widths).each do |l, s, w|
68
+ @bit_fields_hash_table[l] = [parent, s, w]
69
+ end
70
+ end
29
71
  end
30
72
  end
31
73
  end
data/lib/hts/ffi/bgzf.rb CHANGED
@@ -120,7 +120,7 @@ module HTS
120
120
  # Read one line from a BGZF file. It is faster than bgzf_getc()
121
121
  attach_function \
122
122
  :bgzf_getline,
123
- [BGZF, :int, Kstring],
123
+ [BGZF, :int, KString],
124
124
  :int
125
125
 
126
126
  # Read the next BGZF block.
@@ -8,13 +8,23 @@ module HTS
8
8
 
9
9
  # kstring
10
10
 
11
- class Kstring < ::FFI::Struct
11
+ class KString < ::FFI::Struct
12
12
  layout \
13
13
  :l, :size_t,
14
14
  :m, :size_t,
15
15
  :s, :string
16
16
  end
17
17
 
18
+ class KSeq < ::FFI::Struct
19
+ layout \
20
+ :name, KString,
21
+ :comment, KString,
22
+ :seq, KString,
23
+ :qual, KString,
24
+ :last_char, :int,
25
+ :f, :pointer # FIXME
26
+ end
27
+
18
28
  # BGZF
19
29
  class BGZF < ::FFI::Struct
20
30
  layout \
@@ -162,7 +172,7 @@ module HTS
162
172
  layout \
163
173
  :bitfields, :uint32, # FIXME
164
174
  :lineno, :int64,
165
- :line, Kstring,
175
+ :line, KString,
166
176
  :fn, :string,
167
177
  :fn_aux, :string,
168
178
  :fp,
@@ -259,36 +269,6 @@ module HTS
259
269
  class BamMplp < ::FFI::Struct
260
270
  end
261
271
 
262
- BAM_CMATCH = 0
263
- BAM_CINS = 1
264
- BAM_CDEL = 2
265
- BAM_CREF_SKIP = 3
266
- BAM_CSOFT_CLIP = 4
267
- BAM_CHARD_CLIP = 5
268
- BAM_CPAD = 6
269
- BAM_CEQUAL = 7
270
- BAM_CDIFF = 8
271
- BAM_CBACK = 9
272
-
273
- BAM_CIGAR_STR = 'MIDNSHP=XB'
274
- BAM_CIGAR_STR_PADDED = 'MIDNSHP=XB??????'
275
- BAM_CIGAR_SHIFT = 4
276
- BAM_CIGAR_MASK = 0xf
277
- BAM_CIGAR_TYPE = 0x3C1A7
278
-
279
- BAM_FPAIRED = 1
280
- BAM_FPROPER_PAIR = 2
281
- BAM_FUNMAP = 4
282
- BAM_FMUNMAP = 8
283
- BAM_FREVERSE = 16
284
- BAM_FMREVERSE = 32
285
- BAM_FREAD1 = 64
286
- BAM_FREAD2 = 128
287
- BAM_FSECONDARY = 256
288
- BAM_FQCFAIL = 512
289
- BAM_FDUP = 1024
290
- BAM_FSUPPLEMENTARY = 2048
291
-
292
272
  class TbxConf < ::FFI::Struct
293
273
  layout \
294
274
  :preset, :int32,
@@ -386,10 +366,10 @@ module HTS
386
366
  :nhrec, :int,
387
367
  :dirty, :int,
388
368
  :ntransl, :int,
389
- :transl, :pointer,
369
+ :transl, [:pointer, 2],
390
370
  :nsamples_ori, :int,
391
371
  :keep_samples, :pointer,
392
- :mem, Kstring,
372
+ :mem, KString,
393
373
  :m, [:int, 3]
394
374
  end
395
375
 
@@ -401,9 +381,10 @@ module HTS
401
381
  :m_als, :int,
402
382
  :m_allele, :int,
403
383
  :m_flt, :int,
384
+ :n_flt, :int,
404
385
  :flt, :pointer,
405
386
  :id, :string,
406
- :als, :string,
387
+ :als, :pointer, # (\\0-separated string)
407
388
  :allele, :pointer,
408
389
  :info, BcfInfo.ptr,
409
390
  :fmt, BcfFmt.ptr,
@@ -414,21 +395,29 @@ module HTS
414
395
  :indiv_dirty, :int
415
396
  end
416
397
 
417
- class Bcf1 < ::FFI::Struct
398
+ class Bcf1 < ::FFI::BitStruct
418
399
  layout \
419
400
  :pos, :hts_pos_t,
420
401
  :rlen, :hts_pos_t,
421
- :rid, :int,
402
+ :rid, :int32_t,
422
403
  :qual, :float,
423
- :piyo, :int, # FIXME
424
- :fuga, :int, # FIXME
425
- :shared, Kstring,
426
- :indiv, Kstring,
404
+ :n_info_allele, :uint32_t, # FIXME
405
+ :n_fmt_sample, :uint32_t, # FIXME
406
+ :shared, KString,
407
+ :indiv, KString,
427
408
  :d, BcfDec,
428
409
  :max_unpack, :int,
429
410
  :unpacked, :int,
430
411
  :unpack_size, [:int, 3],
431
412
  :errcode, :int
413
+
414
+ bitfields :n_info_allele,
415
+ :n_info, 16,
416
+ :n_allele, 16
417
+
418
+ bitfields :n_fmt_sample,
419
+ :n_fmt, 8,
420
+ :n_sample, 24
432
421
  end
433
422
  end
434
423
  end
data/lib/hts/ffi/hfile.rb CHANGED
@@ -23,7 +23,7 @@ module HTS
23
23
  # Append an extension or replace an existing extension
24
24
  attach_function \
25
25
  :haddextension,
26
- [Kstring, :string, :int, :string],
26
+ [KString, :string, :int, :string],
27
27
  :string
28
28
 
29
29
  # Flush (for output streams) and close the stream
data/lib/hts/ffi/hts.rb CHANGED
@@ -8,7 +8,7 @@ module HTS
8
8
 
9
9
  attach_function \
10
10
  :hts_lib_shutdown,
11
- [:void],
11
+ [],
12
12
  :void
13
13
 
14
14
  attach_function \
@@ -110,7 +110,7 @@ module HTS
110
110
  # Read a line (and its \n or \r\n terminator) from a file
111
111
  attach_function \
112
112
  :hts_getline,
113
- [HtsFile, :int, Kstring],
113
+ [HtsFile, :int, KString],
114
114
  :int
115
115
 
116
116
  attach_function \
data/lib/hts/ffi/sam.rb CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  module HTS
4
4
  module FFI
5
+ # constants
6
+ BAM_CMATCH = 0
7
+ BAM_CINS = 1
8
+ BAM_CDEL = 2
9
+ BAM_CREF_SKIP = 3
10
+ BAM_CSOFT_CLIP = 4
11
+ BAM_CHARD_CLIP = 5
12
+ BAM_CPAD = 6
13
+ BAM_CEQUAL = 7
14
+ BAM_CDIFF = 8
15
+ BAM_CBACK = 9
16
+
17
+ BAM_CIGAR_STR = 'MIDNSHP=XB'
18
+ BAM_CIGAR_STR_PADDED = 'MIDNSHP=XB??????'
19
+ BAM_CIGAR_SHIFT = 4
20
+ BAM_CIGAR_MASK = 0xf
21
+ BAM_CIGAR_TYPE = 0x3C1A7
22
+
5
23
  # macros
6
24
  class << self
7
25
  def bam_cigar_op(c)
@@ -13,7 +31,7 @@ module HTS
13
31
  end
14
32
 
15
33
  def bam_cigar_opchr(c)
16
- (BAM_CIGAR_STR + '??????')[bam_cigar_op(c)]
34
+ ("#{BAM_CIGAR_STR}??????")[bam_cigar_op(c)]
17
35
  end
18
36
 
19
37
  def bam_cigar_gen(l, o)
@@ -25,6 +43,19 @@ module HTS
25
43
  end
26
44
  end
27
45
 
46
+ BAM_FPAIRED = 1
47
+ BAM_FPROPER_PAIR = 2
48
+ BAM_FUNMAP = 4
49
+ BAM_FMUNMAP = 8
50
+ BAM_FREVERSE = 16
51
+ BAM_FMREVERSE = 32
52
+ BAM_FREAD1 = 64
53
+ BAM_FREAD2 = 128
54
+ BAM_FSECONDARY = 256
55
+ BAM_FQCFAIL = 512
56
+ BAM_FDUP = 1024
57
+ BAM_FSUPPLEMENTARY = 2048
58
+
28
59
  # macros
29
60
  # function-like macros
30
61
  class << self
@@ -148,13 +179,13 @@ module HTS
148
179
  # Returns a complete line of formatted text for a given type and ID.
149
180
  attach_function \
150
181
  :sam_hdr_find_line_id,
151
- [SamHdr, :string, :string, :string, Kstring],
182
+ [SamHdr, :string, :string, :string, KString],
152
183
  :int
153
184
 
154
185
  # Returns a complete line of formatted text for a given type and index.
155
186
  attach_function \
156
187
  :sam_hdr_find_line_pos,
157
- [SamHdr, :string, :int, Kstring],
188
+ [SamHdr, :string, :int, KString],
158
189
  :int
159
190
 
160
191
  # Remove a line with given type / id from a header
@@ -208,13 +239,13 @@ module HTS
208
239
  # Return the value associated with a key for a header line identified by ID_key:ID_val
209
240
  attach_function \
210
241
  :sam_hdr_find_tag_id,
211
- [SamHdr, :string, :string, :string, :string, Kstring],
242
+ [SamHdr, :string, :string, :string, :string, KString],
212
243
  :int
213
244
 
214
245
  # Return the value associated with a key for a header line identified by position
215
246
  attach_function \
216
247
  :sam_hdr_find_tag_pos,
217
- [SamHdr, :string, :int, :string, Kstring],
248
+ [SamHdr, :string, :int, :string, KString],
218
249
  :int
219
250
 
220
251
  # Remove the key from the line identified by type, ID_key and ID_value.
@@ -445,12 +476,12 @@ module HTS
445
476
 
446
477
  attach_function \
447
478
  :sam_parse1,
448
- [Kstring, SamHdr, Bam1],
479
+ [KString, SamHdr, Bam1],
449
480
  :int
450
481
 
451
482
  attach_function \
452
483
  :sam_format1,
453
- [SamHdr, Bam1, Kstring],
484
+ [SamHdr, Bam1, KString],
454
485
  :int
455
486
 
456
487
  # Read a record from a file
@@ -598,7 +629,7 @@ module HTS
598
629
  # sets a callback to initialise any per-pileup1_t fields.
599
630
  attach_function \
600
631
  :bam_plp_insertion,
601
- [:pointer, Kstring, :pointer],
632
+ [:pointer, KString, :pointer],
602
633
  :int
603
634
 
604
635
  # sets a callback to initialise any per-pileup1_t fields.
data/lib/hts/ffi/vcf.rb CHANGED
@@ -2,6 +2,75 @@
2
2
 
3
3
  module HTS
4
4
  module FFI
5
+ # constants
6
+ BCF_HL_FLT = 0 # header line
7
+ BCF_HL_INFO = 1
8
+ BCF_HL_FMT = 2
9
+ BCF_HL_CTG = 3
10
+ BCF_HL_STR = 4 # structured header line TAG=<A=..,B=..>
11
+ BCF_HL_GEN = 5 # generic header line
12
+ BCF_HT_FLAG = 0 # header type
13
+
14
+ BCF_HT_INT = 1
15
+ BCF_HT_REAL = 2
16
+ BCF_HT_STR = 3
17
+ BCF_HT_LONG = (BCF_HT_INT | 0x100) # BCF_HT_INT, but for int64_t values; VCF only!
18
+
19
+ BCF_VL_FIXED = 0 # variable length
20
+ BCF_VL_VAR = 1
21
+ BCF_VL_A = 2
22
+ BCF_VL_G = 3
23
+ BCF_VL_R = 4
24
+
25
+ BCF_DT_ID = 0 # dictionary type
26
+ BCF_DT_CTG = 1
27
+ BCF_DT_SAMPLE = 2
28
+
29
+ BCF_BT_NULL = 0
30
+ BCF_BT_INT8 = 1
31
+ BCF_BT_INT16 = 2
32
+ BCF_BT_INT32 = 3
33
+ BCF_BT_INT64 = 4 # Unofficial, for internal use only.
34
+ BCF_BT_FLOAT = 5
35
+ BCF_BT_CHAR = 7
36
+
37
+ VCF_REF = 0
38
+ VCF_SNP = 1
39
+ VCF_MNP = 2
40
+ VCF_INDEL = 4
41
+ VCF_OTHER = 8
42
+ VCF_BND = 16 # breakend
43
+ VCF_OVERLAP = 32 # overlapping deletion, ALT=*
44
+
45
+ BCF1_DIRTY_ID = 1
46
+ BCF1_DIRTY_ALS = 2
47
+ BCF1_DIRTY_FLT = 4
48
+ BCF1_DIRTY_INF = 8
49
+
50
+ BCF_ERR_CTG_UNDEF = 1
51
+ BCF_ERR_TAG_UNDEF = 2
52
+ BCF_ERR_NCOLS = 4
53
+ BCF_ERR_LIMITS = 8
54
+ BCF_ERR_CHAR = 16
55
+ BCF_ERR_CTG_INVALID = 32
56
+ BCF_ERR_TAG_INVALID = 64
57
+
58
+ # macros
59
+ class << self
60
+ def bcf_hdr_nsamples(hdr)
61
+ hdr[:n][BCF_DT_SAMPLE]
62
+ end
63
+ end
64
+
65
+ # constants
66
+ BCF_UN_STR = 1 # up to ALT inclusive
67
+ BCF_UN_FLT = 2 # up to FILTER
68
+ BCF_UN_INFO = 4 # up to INFO
69
+ BCF_UN_SHR = (BCF_UN_STR | BCF_UN_FLT | BCF_UN_INFO) # all shared information
70
+ BCF_UN_FMT = 8 # unpack format and each sample
71
+ BCF_UN_IND = BCF_UN_FMT # a synonym of BCF_UN_FMT
72
+ BCF_UN_ALL = (BCF_UN_SHR | BCF_UN_FMT) # everything
73
+
5
74
  attach_function \
6
75
  :bcf_hdr_init,
7
76
  [:string],
@@ -14,7 +83,7 @@ module HTS
14
83
 
15
84
  attach_function \
16
85
  :bcf_init,
17
- [:void],
86
+ [],
18
87
  Bcf1.by_ref
19
88
 
20
89
  attach_function \
@@ -54,7 +123,7 @@ module HTS
54
123
 
55
124
  attach_function \
56
125
  :vcf_parse,
57
- [Kstring, BcfHdr, Bcf1],
126
+ [KString, BcfHdr, Bcf1],
58
127
  :int
59
128
 
60
129
  attach_function \
@@ -64,7 +133,7 @@ module HTS
64
133
 
65
134
  attach_function \
66
135
  :vcf_format,
67
- [BcfHdr, Bcf1, Kstring],
136
+ [BcfHdr, Bcf1, KString],
68
137
  :int
69
138
 
70
139
  attach_function \
@@ -119,7 +188,7 @@ module HTS
119
188
 
120
189
  attach_function \
121
190
  :vcf_write_line,
122
- [HtsFile, Kstring],
191
+ [HtsFile, KString],
123
192
  :int
124
193
 
125
194
  attach_function \
@@ -144,7 +213,7 @@ module HTS
144
213
 
145
214
  attach_function \
146
215
  :bcf_hdr_format,
147
- [BcfHdr, :int, Kstring],
216
+ [BcfHdr, :int, KString],
148
217
  :int
149
218
 
150
219
  attach_function \
@@ -204,7 +273,7 @@ module HTS
204
273
 
205
274
  attach_function \
206
275
  :bcf_hrec_format,
207
- [BcfHrec, Kstring],
276
+ [BcfHrec, KString],
208
277
  :int
209
278
 
210
279
  attach_function \
@@ -369,27 +438,27 @@ module HTS
369
438
 
370
439
  attach_function \
371
440
  :bcf_fmt_array,
372
- [Kstring, :int, :int, :pointer],
441
+ [KString, :int, :int, :pointer],
373
442
  :int
374
443
 
375
444
  attach_function \
376
445
  :bcf_fmt_sized_array,
377
- [Kstring, :pointer],
446
+ [KString, :pointer],
378
447
  :uint8_t
379
448
 
380
449
  attach_function \
381
450
  :bcf_enc_vchar,
382
- [Kstring, :int, :string],
451
+ [KString, :int, :string],
383
452
  :int
384
453
 
385
454
  attach_function \
386
455
  :bcf_enc_vint,
387
- [Kstring, :int, :pointer, :int],
456
+ [KString, :int, :pointer, :int],
388
457
  :int
389
458
 
390
459
  attach_function \
391
460
  :bcf_enc_vfloat,
392
- [Kstring, :int, :pointer],
461
+ [KString, :int, :pointer],
393
462
  :int
394
463
 
395
464
  attach_function \
data/lib/hts/vcf.rb CHANGED
@@ -3,27 +3,37 @@
3
3
  # Based on hts-python
4
4
  # https://github.com/quinlan-lab/hts-python
5
5
 
6
+ require_relative 'vcf/header'
7
+ require_relative 'vcf/variant'
8
+
6
9
  module HTS
7
10
  class VCF
8
- def initialize; end
11
+ include Enumerable
12
+ attr_reader :file_path, :mode, :header, :htf
9
13
 
10
- def inspect; end
14
+ def initialize(file_path, mode = 'r')
15
+ @file_path = File.expand_path(file_path)
16
+ File.exist?(@file_path) || raise("No such VCF/BCF file - #{@file_path}")
11
17
 
12
- def each; end
18
+ @mode = mode
19
+ @htf = FFI.hts_open(@file_path, mode)
13
20
 
14
- def seq; end
21
+ @header = VCF::Header.new(FFI.bcf_hdr_read(@htf))
15
22
 
16
- def n_samples; end
17
- end
23
+ @c = FFI.bcf_init
24
+ end
18
25
 
19
- class Variant
20
- def initialize; end
26
+ # def inspect; end
21
27
 
22
- def inspect; end
28
+ def each(&block)
29
+ block.call(Variant.new(@c, self)) while FFI.bcf_read(@htf, @header.h, @c) != -1
30
+ end
23
31
 
24
- def formats; end
32
+ def seq(tid); end
25
33
 
26
- def genotypes; end
34
+ def n_samples
35
+ FFI.bcf_hdr_nsamples(header.h)
36
+ end
27
37
  end
28
38
 
29
39
  class Format
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTS
4
+ class VCF
5
+ class Header
6
+ attr_reader :h
7
+
8
+ def initialize(h)
9
+ @h = h
10
+ end
11
+
12
+ # FIXME: better name?
13
+ def seqs
14
+ Array.new(@h[:n_targets]) do |i|
15
+ FFI.sam_hdr_tid2name(@h, i)
16
+ end
17
+ end
18
+
19
+ def text
20
+ FFI.sam_hdr_str(@h)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTS
4
+ class VCF
5
+ class Variant
6
+ def initialize(bcf_t, vcf)
7
+ @c = bcf_t
8
+ FFI.bcf_unpack(@c, HTS::FFI::BCF_UN_ALL) # FIXME
9
+ @vcf = vcf
10
+ end
11
+
12
+ # def inspect; end
13
+
14
+ def formats; end
15
+
16
+ def genotypes; end
17
+
18
+ def pos
19
+ @c[:pos] + 1 # FIXME
20
+ end
21
+
22
+ def start
23
+ @c[:pos]
24
+ end
25
+
26
+ def stop
27
+ @c[:pos] + @c[:rlen]
28
+ end
29
+
30
+ def id
31
+ @c[:d][:id]
32
+ end
33
+
34
+ def qual
35
+ @c[:qual]
36
+ end
37
+
38
+ def ref
39
+ @c[:d][:allele].get_pointer(0).read_string
40
+ end
41
+ end
42
+ end
43
+ 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.0.1'
4
+ VERSION = '0.0.2'
5
5
  end
data/lib/htslib.rb CHANGED
@@ -9,15 +9,33 @@ module HTS
9
9
 
10
10
  class << self
11
11
  attr_accessor :ffi_lib
12
- end
13
-
14
- suffix = ::FFI::Platform::LIBSUFFIX
15
12
 
16
- self.ffi_lib = if ENV['HTSLIBDIR']
17
- File.expand_path("libhts.#{suffix}", ENV['HTSLIBDIR'])
13
+ def search_htslib(name = nil)
14
+ name ||= "libhts.#{::FFI::Platform::LIBSUFFIX}"
15
+ lib_path = if ENV['HTSLIBDIR']
16
+ File.expand_path(name, ENV['HTSLIBDIR'])
18
17
  else
19
- File.expand_path("../vendor/libhts.#{suffix}", __dir__)
18
+ File.expand_path("../vendor/#{name}", __dir__)
20
19
  end
20
+ return lib_path if File.exist?(lib_path)
21
+
22
+ begin
23
+ require 'pkg-config'
24
+ lib_dir = PKGConfig.variable('htslib', 'libdir')
25
+ lib_path = File.expand_path(name, lib_dir)
26
+ rescue PackageConfig::NotFoundError
27
+ warn "htslib.pc was not found in the pkg-config search path."
28
+ end
29
+ return lib_path if File.exist?(lib_path)
30
+
31
+ warn "htslib shared library '#{name}' not found."
32
+ end
33
+ end
34
+
35
+ self.ffi_lib = search_htslib
36
+
37
+ # You can change the path of the shared library with `HTS.ffi_lib=`
38
+ # before calling the FFI module.
21
39
  autoload :FFI, 'hts/ffi'
22
40
  end
23
41
 
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.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-25 00:00:00.000000000 Z
11
+ date: 2021-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -25,13 +25,13 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: pkg-config
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :development
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: minitest
42
+ name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry
56
+ name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -108,7 +108,7 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- description:
111
+ description:
112
112
  email:
113
113
  - 2xijok@gmail.com
114
114
  executables: []
@@ -134,13 +134,15 @@ files:
134
134
  - lib/hts/ffi/vcf.rb
135
135
  - lib/hts/tbx.rb
136
136
  - lib/hts/vcf.rb
137
+ - lib/hts/vcf/header.rb
138
+ - lib/hts/vcf/variant.rb
137
139
  - lib/hts/version.rb
138
140
  - lib/htslib.rb
139
141
  homepage: https://github.com/kojix2/ruby-htslib
140
142
  licenses:
141
143
  - MIT
142
144
  metadata: {}
143
- post_install_message:
145
+ post_install_message:
144
146
  rdoc_options: []
145
147
  require_paths:
146
148
  - lib
@@ -155,8 +157,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  - !ruby/object:Gem::Version
156
158
  version: '0'
157
159
  requirements: []
158
- rubygems_version: 3.0.3
159
- signing_key:
160
+ rubygems_version: 3.2.15
161
+ signing_key:
160
162
  specification_version: 4
161
163
  summary: HTSlib bindings for Ruby
162
164
  test_files: []