htslib 0.0.5 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +71 -29
- data/lib/hts/bam/cigar.rb +7 -4
- data/lib/hts/bam/flag.rb +7 -3
- data/lib/hts/bam/header.rb +22 -7
- data/lib/hts/bam/record.rb +27 -21
- data/lib/hts/bam.rb +97 -52
- data/lib/hts/bcf/format.rb +28 -6
- data/lib/hts/bcf/header.rb +33 -5
- data/lib/hts/bcf/info.rb +28 -6
- data/lib/hts/bcf/record.rb +21 -13
- data/lib/hts/bcf.rb +69 -31
- data/lib/hts/faidx.rb +6 -4
- data/lib/hts/ffi_ext/struct.rb +1 -1
- data/lib/hts/hts.rb +56 -0
- data/lib/hts/libhts/bgzf.rb +10 -5
- data/lib/hts/libhts/constants.rb +23 -5
- data/lib/hts/libhts/cram.rb +297 -0
- data/lib/hts/libhts/hfile.rb +19 -11
- data/lib/hts/libhts/hts.rb +9 -3
- data/lib/hts/libhts/sam.rb +2 -590
- data/lib/hts/libhts/sam_funcs.rb +596 -0
- data/lib/hts/libhts/thread_pool.rb +139 -0
- data/lib/hts/libhts/vcf.rb +32 -439
- data/lib/hts/libhts/vcf_funcs.rb +430 -0
- data/lib/hts/libhts.rb +5 -3
- data/lib/hts/tabix.rb +42 -17
- data/lib/hts/version.rb +1 -1
- data/lib/htslib.rb +5 -5
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ecf4c183a1720313371e493fbf7876a08d17639ad853b1d26faeff3addb7c6e
|
4
|
+
data.tar.gz: cd1ed908a5dd8be184c8d9195c6fb5fabda5487d3c35e11476d9bd6d15c7dae8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4980914c7b92528055d2d0cf62fad6ca5edcde8ba1b9d426740538aee42fab53c7ef96ebe53adcaa9663368f024546c048b71760b68bd88e7cbb7647e200847c
|
7
|
+
data.tar.gz: a94b5d01702cc9873fdf6d1498658cff15c44ba8c90b08cafe514a883560c6aaa90cfbd83cede8a4ae1a5095c6f99710e76a8aacb0e0851e628c607c37719bd5
|
data/README.md
CHANGED
@@ -6,14 +6,12 @@
|
|
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
|
-
|
10
|
-
|
11
|
-
Ruby-htslib is the Ruby bindings to HTSlib, a C library for processing high throughput sequencing (HTS) data.
|
12
|
-
It will provide APIs to read and write file formats such as SAM, BAM, VCF, and BCF.
|
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.
|
13
10
|
|
14
11
|
:apple: Feel free to fork it out if you can develop it!
|
15
12
|
|
16
13
|
:bowtie: alpha stage.
|
14
|
+
|
17
15
|
## Requirements
|
18
16
|
|
19
17
|
* [Ruby](https://github.com/ruby/ruby) 2.7 or above.
|
@@ -38,51 +36,80 @@ export HTSLIBDIR="/your/path/to/htslib" # libhts.so
|
|
38
36
|
|
39
37
|
## Overview
|
40
38
|
|
41
|
-
###
|
39
|
+
### High level API
|
42
40
|
|
43
|
-
|
41
|
+
Read SAM / BAM / CRAM - Sequence Alignment Map file
|
44
42
|
|
45
43
|
```ruby
|
46
44
|
require 'htslib'
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
p
|
46
|
+
bam = HTS::Bam.open("a.bam")
|
47
|
+
|
48
|
+
bam.each do |r|
|
49
|
+
p name: r.qname,
|
50
|
+
flag: r.flag,
|
51
|
+
chr: r.chrom,
|
52
|
+
pos: r.start + 1,
|
53
|
+
mqual: r.mapping_quality,
|
54
|
+
cigar: r.cigar.to_s,
|
55
|
+
mchr: r.mate_chrom,
|
56
|
+
mpos: r.mate_start + 1,
|
57
|
+
isize: r.insert_size,
|
58
|
+
seq: r.sequence,
|
59
|
+
qual: r.base_qualities.map { |i| (i + 33).chr }.join,
|
60
|
+
tagMC: r.tag("MC")
|
61
|
+
end
|
62
|
+
|
63
|
+
bam.close
|
52
64
|
```
|
53
65
|
|
54
|
-
|
66
|
+
Read VCF / BCF - Variant Call Format file
|
55
67
|
|
56
|
-
|
68
|
+
```ruby
|
69
|
+
bcf = HTS::Bcf.open("b.bcf")
|
70
|
+
|
71
|
+
bcf.each do |r|
|
72
|
+
p chrom: r.chrom,
|
73
|
+
pos: r.pos,
|
74
|
+
id: r.id,
|
75
|
+
qual: r.qual.round(2),
|
76
|
+
ref: r.ref,
|
77
|
+
alt: r.alt,
|
78
|
+
filter: r.filter
|
79
|
+
# info: r.info
|
80
|
+
# format: r.format
|
81
|
+
end
|
57
82
|
|
58
|
-
|
83
|
+
bcf.close
|
84
|
+
```
|
59
85
|
|
60
|
-
|
86
|
+
### Low level API
|
87
|
+
|
88
|
+
`HTS::LibHTS` provides native C functions.
|
61
89
|
|
62
90
|
```ruby
|
63
91
|
require 'htslib'
|
64
92
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
flag: r.flag,
|
70
|
-
start: r.start + 1,
|
71
|
-
mpos: r.mate_pos + 1,
|
72
|
-
mqual: r.mapping_quality,
|
73
|
-
seq: r.sequence,
|
74
|
-
cigar: r.cigar.to_s,
|
75
|
-
qual: r.base_qualities.map { |i| (i + 33).chr }.join
|
76
|
-
end
|
93
|
+
a = HTS::LibHTS.hts_open("a.bam", "r")
|
94
|
+
b = HTS::LibHTS.hts_get_format(a)
|
95
|
+
p b[:category]
|
96
|
+
p b[:format]
|
77
97
|
```
|
78
98
|
|
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.
|
100
|
+
|
101
|
+
### Need more speed?
|
102
|
+
|
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.
|
104
|
+
|
79
105
|
## Documentation
|
80
106
|
|
107
|
+
* [API Documentation (develop branch)](https://kojix2.github.io/ruby-htslib/)
|
81
108
|
* [RubyDoc.info - HTSlib](https://rdoc.info/gems/htslib)
|
82
109
|
|
83
110
|
## Development
|
84
111
|
|
85
|
-
To get started with development
|
112
|
+
To get started with development:
|
86
113
|
|
87
114
|
```sh
|
88
115
|
git clone --recursive https://github.com/kojix2/ruby-htslib
|
@@ -92,8 +119,13 @@ bundle exec rake htslib:build
|
|
92
119
|
bundle exec rake test
|
93
120
|
```
|
94
121
|
|
95
|
-
|
96
|
-
|
122
|
+
[GNU Autotools](https://en.wikipedia.org/wiki/GNU_Autotools) is required to compile htslib.
|
123
|
+
|
124
|
+
Many macro functions are used in HTSlib. Since these macro functions cannot be called using FFI, they must be reimplemented in Ruby.
|
125
|
+
|
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.
|
97
129
|
|
98
130
|
#### FFI Extensions
|
99
131
|
|
@@ -113,6 +145,16 @@ Ruby-htslib is a library under development, so even small improvements like typo
|
|
113
145
|
* Suggest or add new features
|
114
146
|
* [financial contributions](https://github.com/sponsors/kojix2)
|
115
147
|
|
148
|
+
```
|
149
|
+
Do you need commit rights to ruby-htslib repository?
|
150
|
+
Do you want to get admin rights and take over the project?
|
151
|
+
If so, please feel free to contact us @kojix2.
|
152
|
+
```
|
153
|
+
|
154
|
+
#### Why do you implement htslib in a language like Ruby, which is not widely used in the bioinformatics?
|
155
|
+
|
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...
|
157
|
+
|
116
158
|
## Links
|
117
159
|
|
118
160
|
* [samtools/hts-spec](https://github.com/samtools/hts-specs)
|
data/lib/hts/bam/cigar.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# https://github.com/quinlan-lab/hts-python
|
5
5
|
|
6
6
|
module HTS
|
7
|
-
class Bam
|
7
|
+
class Bam < Hts
|
8
8
|
class Cigar
|
9
9
|
include Enumerable
|
10
10
|
|
@@ -18,14 +18,17 @@ module HTS
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def to_s
|
21
|
-
|
21
|
+
map { |op, len| "#{len}#{op}" }.join
|
22
22
|
end
|
23
23
|
|
24
24
|
def each
|
25
|
+
return to_enum(__method__) unless block_given?
|
26
|
+
|
25
27
|
@n_cigar.times do |i|
|
26
28
|
c = @pointer[i].read_uint32
|
27
|
-
|
28
|
-
|
29
|
+
op = LibHTS.bam_cigar_opchr(c)
|
30
|
+
len = LibHTS.bam_cigar_oplen(c)
|
31
|
+
yield [op, len]
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
data/lib/hts/bam/flag.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# https://github.com/brentp/hts-nim/blob/master/src/hts/bam/flag.nim
|
5
5
|
|
6
6
|
module HTS
|
7
|
-
class Bam
|
7
|
+
class Bam < Hts
|
8
8
|
class Flag
|
9
9
|
def initialize(flag_value)
|
10
10
|
raise TypeError unless flag_value.is_a? Integer
|
@@ -85,8 +85,12 @@ module HTS
|
|
85
85
|
has_flag? LibHTS::BAM_FSUPPLEMENTARY
|
86
86
|
end
|
87
87
|
|
88
|
-
def has_flag?(
|
89
|
-
@value
|
88
|
+
def has_flag?(m)
|
89
|
+
(@value & m) != 0
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
"0x#{format('%x', @value)}\t#{@value}\t#{LibHTS.bam_flag2str(@value)}"
|
90
94
|
end
|
91
95
|
end
|
92
96
|
end
|
data/lib/hts/bam/header.rb
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
# https://github.com/quinlan-lab/hts-python
|
5
5
|
|
6
6
|
module HTS
|
7
|
-
class Bam
|
7
|
+
class Bam < Hts
|
8
8
|
class Header
|
9
|
-
def initialize(
|
10
|
-
@sam_hdr =
|
9
|
+
def initialize(hts_file)
|
10
|
+
@sam_hdr = LibHTS.sam_hdr_read(hts_file)
|
11
11
|
end
|
12
12
|
|
13
13
|
def struct
|
@@ -18,16 +18,31 @@ module HTS
|
|
18
18
|
@sam_hdr.to_ptr
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def target_count
|
22
|
+
@sam_hdr[:n_targets]
|
23
|
+
end
|
24
|
+
|
25
|
+
def target_names
|
26
|
+
Array.new(target_count) do |i|
|
24
27
|
LibHTS.sam_hdr_tid2name(@sam_hdr, i)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
|
-
def
|
31
|
+
def target_lengths
|
32
|
+
Array.new(target_count) do |i|
|
33
|
+
LibHTS.sam_hdr_tid2len(@sam_hdr, i)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
29
38
|
LibHTS.sam_hdr_str(@sam_hdr)
|
30
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def initialize_copy(orig)
|
44
|
+
@sam_hdr = LibHTS.sam_hdr_dup(orig.struct)
|
45
|
+
end
|
31
46
|
end
|
32
47
|
end
|
33
48
|
end
|
data/lib/hts/bam/record.rb
CHANGED
@@ -4,10 +4,12 @@
|
|
4
4
|
# https://github.com/quinlan-lab/hts-python
|
5
5
|
|
6
6
|
module HTS
|
7
|
-
class Bam
|
7
|
+
class Bam < Hts
|
8
8
|
class Record
|
9
9
|
SEQ_NT16_STR = "=ACMGRSVTWYHKDBN"
|
10
10
|
|
11
|
+
attr_reader :header
|
12
|
+
|
11
13
|
def initialize(bam1_t, header)
|
12
14
|
@bam1 = bam1_t
|
13
15
|
@header = header
|
@@ -21,16 +23,6 @@ module HTS
|
|
21
23
|
@bam1.to_ptr
|
22
24
|
end
|
23
25
|
|
24
|
-
attr_reader :header
|
25
|
-
|
26
|
-
# def initialize_copy
|
27
|
-
# super
|
28
|
-
# end
|
29
|
-
|
30
|
-
def self.rom_sam_str; end
|
31
|
-
|
32
|
-
def tags; end
|
33
|
-
|
34
26
|
# returns the query name.
|
35
27
|
def qname
|
36
28
|
LibHTS.bam_get_qname(@bam1).read_string
|
@@ -69,18 +61,22 @@ module HTS
|
|
69
61
|
|
70
62
|
# returns the chromosome or '' if not mapped.
|
71
63
|
def chrom
|
72
|
-
tid = @bam1[:core][:tid]
|
73
64
|
return "" if tid == -1
|
74
65
|
|
75
66
|
LibHTS.sam_hdr_tid2name(@header, tid)
|
76
67
|
end
|
77
68
|
|
69
|
+
# returns the chromosome or '' if not mapped.
|
70
|
+
def contig
|
71
|
+
chrom
|
72
|
+
end
|
73
|
+
|
78
74
|
# returns the chromosome of the mate or '' if not mapped.
|
79
75
|
def mate_chrom
|
80
|
-
|
81
|
-
return "" if
|
76
|
+
mtid = mate_tid
|
77
|
+
return "" if mtid == -1
|
82
78
|
|
83
|
-
LibHTS.sam_hdr_tid2name(@header,
|
79
|
+
LibHTS.sam_hdr_tid2name(@header, mtid)
|
84
80
|
end
|
85
81
|
|
86
82
|
def strand
|
@@ -92,7 +88,7 @@ module HTS
|
|
92
88
|
# end
|
93
89
|
|
94
90
|
# insert size
|
95
|
-
def
|
91
|
+
def insert_size
|
96
92
|
@bam1[:core][:isize]
|
97
93
|
end
|
98
94
|
|
@@ -168,6 +164,11 @@ module HTS
|
|
168
164
|
return nil if aux.null?
|
169
165
|
|
170
166
|
t = aux.read_string(1)
|
167
|
+
|
168
|
+
# A (character), B (general array),
|
169
|
+
# f (real number), H (hexadecimal array),
|
170
|
+
# i (integer), or Z (string).
|
171
|
+
|
171
172
|
case t
|
172
173
|
when "i", "I", "c", "C", "s", "S"
|
173
174
|
LibHTS.bam_aux2i(aux)
|
@@ -175,11 +176,13 @@ module HTS
|
|
175
176
|
LibHTS.bam_aux2f(aux)
|
176
177
|
when "Z", "H"
|
177
178
|
LibHTS.bam_aux2Z(aux)
|
178
|
-
when "A"
|
179
|
-
LibHTS.bam_aux2A(aux)
|
179
|
+
when "A" # char
|
180
|
+
LibHTS.bam_aux2A(aux).chr
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
184
|
+
# def tags; end
|
185
|
+
|
183
186
|
def to_s
|
184
187
|
kstr = LibHTS::KString.new
|
185
188
|
raise "Failed to format bam record" if LibHTS.sam_format1(@header.struct, @bam1, kstr) == -1
|
@@ -187,9 +190,12 @@ module HTS
|
|
187
190
|
kstr[:s]
|
188
191
|
end
|
189
192
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
+
private
|
194
|
+
|
195
|
+
def initialize_copy(orig)
|
196
|
+
@header = orig.header
|
197
|
+
@bam = LibHTS.bam_dup1(orig.struct)
|
198
|
+
end
|
193
199
|
end
|
194
200
|
end
|
195
201
|
end
|
data/lib/hts/bam.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
# Based on hts-python
|
4
4
|
# https://github.com/quinlan-lab/hts-python
|
5
5
|
|
6
|
+
require_relative "../htslib"
|
7
|
+
|
8
|
+
require_relative "hts"
|
6
9
|
require_relative "bam/header"
|
7
10
|
require_relative "bam/cigar"
|
8
11
|
require_relative "bam/flag"
|
@@ -12,99 +15,141 @@ module HTS
|
|
12
15
|
class Bam
|
13
16
|
include Enumerable
|
14
17
|
|
15
|
-
attr_reader :
|
16
|
-
# HtfFile is FFI::BitStruct
|
17
|
-
attr_reader :htf_file
|
18
|
+
attr_reader :file_name, :index_path, :mode, :header
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def self.open(*args, **kw)
|
21
|
+
file = new(*args, **kw) # do not yield
|
22
|
+
return file unless block_given?
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
begin
|
25
|
+
yield file
|
26
|
+
ensure
|
27
|
+
file.close
|
28
|
+
end
|
29
|
+
file
|
30
|
+
end
|
25
31
|
|
26
|
-
|
27
|
-
|
32
|
+
def initialize(file_name, mode = "r", index: nil, fai: nil, threads: nil,
|
33
|
+
create_index: false)
|
34
|
+
if block_given?
|
35
|
+
message = "HTS::Bam.new() dose not take block; Please use HTS::Bam.open() instead"
|
28
36
|
raise message
|
29
37
|
end
|
30
38
|
|
31
|
-
|
39
|
+
# NOTE: Do not check for the existence of local files, since file_names may be remote URIs.
|
40
|
+
|
41
|
+
@file_name = file_name
|
32
42
|
@mode = mode
|
33
|
-
@
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
# create index
|
41
|
-
if create_index || (@idx.null? && create_index.nil?)
|
42
|
-
warn "Create index for #{file_path}"
|
43
|
-
LibHTS.sam_index_build(file_path, -1)
|
44
|
-
@idx = LibHTS.sam_index_load(htf_file, file_path)
|
45
|
-
end
|
46
|
-
else
|
47
|
-
# FIXME: implement
|
48
|
-
raise "not implemented yet."
|
43
|
+
@hts_file = LibHTS.hts_open(@file_name, mode)
|
44
|
+
|
45
|
+
raise Errno::ENOENT, "Failed to open #{@file_name}" if @hts_file.null?
|
46
|
+
|
47
|
+
if fai
|
48
|
+
r = LibHTS.hts_set_fai_filename(@hts_file, fai)
|
49
|
+
raise "Failed to load fasta index: #{fai}" if r < 0
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
yield self
|
55
|
-
ensure
|
56
|
-
close
|
57
|
-
end
|
52
|
+
if threads&.> 0
|
53
|
+
r = LibHTS.hts_set_threads(@hts_file, threads)
|
54
|
+
raise "Failed to set number of threads: #{threads}" if r < 0
|
58
55
|
end
|
59
|
-
end
|
60
56
|
|
61
|
-
|
62
|
-
|
57
|
+
return if @mode[0] == "w"
|
58
|
+
|
59
|
+
@header = Bam::Header.new(@hts_file)
|
60
|
+
|
61
|
+
create_index(index) if create_index
|
62
|
+
|
63
|
+
@idx = load_index(index)
|
64
|
+
|
65
|
+
@start_position = tell
|
63
66
|
end
|
64
67
|
|
65
|
-
def
|
66
|
-
|
68
|
+
def create_index(index_name = nil)
|
69
|
+
if index
|
70
|
+
warn "Create index for #{@file_name} to #{index_name}"
|
71
|
+
LibHTS.sam_index_build2(@file_name, index_name, -1)
|
72
|
+
else
|
73
|
+
warn "Create index for #{@file_name} to #{index_name}"
|
74
|
+
LibHTS.sam_index_build(@file_name, -1)
|
75
|
+
end
|
67
76
|
end
|
68
77
|
|
69
|
-
def
|
70
|
-
|
71
|
-
LibHTS.
|
78
|
+
def load_index(index_name = nil)
|
79
|
+
if index_name
|
80
|
+
LibHTS.sam_index_load2(@hts_file, @file_name, index_name)
|
81
|
+
else
|
82
|
+
LibHTS.sam_index_load3(@hts_file, @file_name, nil, 2) # should be 3 ? (copy remote file to local?)
|
72
83
|
end
|
73
84
|
end
|
74
85
|
|
86
|
+
def index_loaded?
|
87
|
+
!@idx.null?
|
88
|
+
end
|
89
|
+
|
75
90
|
# Close the current file.
|
76
91
|
def close
|
77
|
-
LibHTS.
|
92
|
+
LibHTS.hts_idx_destroy(@idx) if @idx&.null?
|
93
|
+
@idx = nil
|
94
|
+
LibHTS.hts_close(@hts_file)
|
95
|
+
@hts_file = nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def closed?
|
99
|
+
@hts_file.nil? || @hts_file.null?
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_header(header)
|
103
|
+
@header = header.dup
|
104
|
+
LibHTS.hts_set_fai_filename(@hts_file, @file_name)
|
105
|
+
LibHTS.sam_hdr_write(@hts_file, header)
|
106
|
+
end
|
107
|
+
|
108
|
+
def write(aln)
|
109
|
+
aln_dup = aln.dup
|
110
|
+
LibHTS.sam_write1(@hts_file, header, aln_dup) > 0 || raise
|
78
111
|
end
|
79
112
|
|
80
|
-
#
|
81
|
-
|
82
|
-
|
113
|
+
# Iterate over each record.
|
114
|
+
# Generate a new Record object each time.
|
115
|
+
# Slower than each.
|
116
|
+
def each_copy
|
117
|
+
return to_enum(__method__) unless block_given?
|
118
|
+
|
119
|
+
while LibHTS.sam_read1(@hts_file, header, bam1 = LibHTS.bam_init1) != -1
|
120
|
+
record = Record.new(bam1, header)
|
121
|
+
yield record
|
122
|
+
end
|
123
|
+
self
|
83
124
|
end
|
84
125
|
|
126
|
+
# Iterate over each record.
|
127
|
+
# Record object is reused.
|
128
|
+
# Faster than each_copy.
|
85
129
|
def each
|
86
130
|
# Each does not always start at the beginning of the file.
|
87
131
|
# This is the common behavior of IO objects in Ruby.
|
88
132
|
# This may change in the future.
|
89
133
|
return to_enum(__method__) unless block_given?
|
90
134
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
135
|
+
bam1 = LibHTS.bam_init1
|
136
|
+
record = Record.new(bam1, header)
|
137
|
+
yield record while LibHTS.sam_read1(@hts_file, header, bam1) != -1
|
95
138
|
self
|
96
139
|
end
|
97
140
|
|
98
141
|
# query [WIP]
|
99
142
|
def query(region)
|
143
|
+
raise "Index file is required to call the query method." unless index_loaded?
|
144
|
+
|
100
145
|
qiter = LibHTS.sam_itr_querys(@idx, header, region)
|
101
146
|
begin
|
102
147
|
bam1 = LibHTS.bam_init1
|
103
|
-
slen = LibHTS.sam_itr_next(
|
148
|
+
slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
|
104
149
|
while slen > 0
|
105
150
|
yield Record.new(bam1, header)
|
106
151
|
bam1 = LibHTS.bam_init1
|
107
|
-
slen = LibHTS.sam_itr_next(
|
152
|
+
slen = LibHTS.sam_itr_next(@hts_file, qiter, bam1)
|
108
153
|
end
|
109
154
|
ensure
|
110
155
|
LibHTS.hts_itr_destroy(qiter)
|
data/lib/hts/bcf/format.rb
CHANGED
@@ -5,17 +5,37 @@
|
|
5
5
|
# TODO: Make it more like Ruby.
|
6
6
|
|
7
7
|
module HTS
|
8
|
-
class Bcf
|
8
|
+
class Bcf < Hts
|
9
9
|
class Format
|
10
10
|
def initialize(record)
|
11
11
|
@record = record
|
12
12
|
@p1 = FFI::MemoryPointer.new(:pointer) # FIXME: naming
|
13
13
|
end
|
14
14
|
|
15
|
+
# For compatibility with htslib.cr.
|
16
|
+
def get_int(key)
|
17
|
+
get(key, :int)
|
18
|
+
end
|
19
|
+
|
20
|
+
# For compatibility with htslib.cr.
|
21
|
+
def get_float(key)
|
22
|
+
get(key, :float)
|
23
|
+
end
|
24
|
+
|
25
|
+
# For compatibility with htslib.cr.
|
26
|
+
def get_flag(key)
|
27
|
+
get(key, :flag)
|
28
|
+
end
|
29
|
+
|
30
|
+
# For compatibility with htslib.cr.
|
31
|
+
def get_string(key)
|
32
|
+
get(key, :string)
|
33
|
+
end
|
34
|
+
|
15
35
|
def get(key, type = nil)
|
16
36
|
n = FFI::MemoryPointer.new(:int)
|
17
37
|
p1 = @p1
|
18
|
-
h = @record.
|
38
|
+
h = @record.header.struct
|
19
39
|
r = @record.struct
|
20
40
|
|
21
41
|
format_values = proc do |type|
|
@@ -33,11 +53,13 @@ module HTS
|
|
33
53
|
format_values.call(LibHTS::BCF_HT_REAL)
|
34
54
|
.read_array_of_float(n.read_int)
|
35
55
|
when :flag
|
36
|
-
|
37
|
-
|
56
|
+
raise NotImplementedError, "Flag type not implemented yet."
|
57
|
+
# format_values.call(LibHTS::BCF_HT_FLAG)
|
58
|
+
# .read_int == 1
|
38
59
|
when :string, :str
|
39
|
-
|
40
|
-
|
60
|
+
raise NotImplementedError, "String type not implemented yet."
|
61
|
+
# format_values.call(LibHTS::BCF_HT_STR)
|
62
|
+
# .read_string
|
41
63
|
end
|
42
64
|
end
|
43
65
|
|