htslib 0.4.2 → 0.6.0
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 +4 -4
- data/README.md +83 -51
- data/TUTORIAL.md +11 -22
- data/ext/htslib_native/extconf.rb +41 -0
- data/ext/htslib_native/htslib_native.h +11 -0
- data/ext/htslib_native/htslib_native_ext.c +48 -0
- data/ext/htslib_native/native_bam.c +1167 -0
- data/ext/htslib_native/native_bcf.c +447 -0
- data/ext/htslib_native/native_faidx.c +164 -0
- data/ext/htslib_native/native_tabix.c +255 -0
- data/lib/hts/bam/auxi.rb +87 -342
- data/lib/hts/bam/base_mod.rb +38 -73
- data/lib/hts/bam/cigar.rb +9 -55
- data/lib/hts/bam/flag.rb +24 -30
- data/lib/hts/bam/header.rb +29 -56
- data/lib/hts/bam/mpileup.rb +158 -132
- data/lib/hts/bam/pileup.rb +120 -145
- data/lib/hts/bam/record.rb +233 -270
- data/lib/hts/bam.rb +154 -45
- data/lib/hts/bcf/errors.rb +4 -0
- data/lib/hts/bcf/format.rb +283 -377
- data/lib/hts/bcf/header.rb +40 -122
- data/lib/hts/bcf/header_record.rb +9 -35
- data/lib/hts/bcf/info.rb +73 -320
- data/lib/hts/bcf/record.rb +73 -101
- data/lib/hts/bcf.rb +178 -321
- data/lib/hts/faidx.rb +30 -87
- data/lib/hts/hts.rb +6 -94
- data/lib/hts/native.rb +13 -0
- data/lib/hts/tabix.rb +109 -51
- data/lib/hts/version.rb +1 -1
- data/lib/htslib.rb +6 -52
- metadata +13 -64
- data/lib/hts/ffi_ext/README.md +0 -8
- data/lib/hts/ffi_ext/pointer.rb +0 -18
- data/lib/hts/ffi_ext/struct.rb +0 -45
- data/lib/hts/libhts/bgzf.rb +0 -199
- data/lib/hts/libhts/constants.rb +0 -658
- data/lib/hts/libhts/cram.rb +0 -471
- data/lib/hts/libhts/fai.rb +0 -146
- data/lib/hts/libhts/hfile.rb +0 -121
- data/lib/hts/libhts/hts.rb +0 -477
- data/lib/hts/libhts/kfunc.rb +0 -38
- data/lib/hts/libhts/sam.rb +0 -760
- data/lib/hts/libhts/sam_funcs.rb +0 -155
- data/lib/hts/libhts/tbx.rb +0 -94
- data/lib/hts/libhts/tbx_funcs.rb +0 -36
- data/lib/hts/libhts/thread_pool.rb +0 -139
- data/lib/hts/libhts/vcf.rb +0 -567
- data/lib/hts/libhts/vcf_funcs.rb +0 -366
- data/lib/hts/libhts.rb +0 -47
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb6716391f6e8aa27cb4859140deb80073a7b02e149f17704a4b08e125567cb9
|
|
4
|
+
data.tar.gz: 20ec9fc316dd378bd869d590360fc8d50a9b2be075871e76a1b4148292614cf6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ed55104f781970f32e5918d15fbe2d0cf5c08e01524c29cf95656b6da902a1528f7630152ae8eb9adee815442230e74868707d348bc7947a871b9576d44bcf0d
|
|
7
|
+
data.tar.gz: c21d82a89b123e25e135486844d09ba83734fb1149269a158b1f2b81be94708ba3e55f95ee94d3a54e78b40a40db7ebcc71fdce969ecc16950802f84bee79461
|
data/README.md
CHANGED
|
@@ -16,11 +16,10 @@ Ruby-htslib is the [Ruby](https://www.ruby-lang.org) bindings to [HTSlib](https:
|
|
|
16
16
|
## Requirements
|
|
17
17
|
|
|
18
18
|
- [Ruby](https://github.com/ruby/ruby) 3.1 or above.
|
|
19
|
-
- [HTSlib](https://github.com/samtools/htslib)
|
|
19
|
+
- [HTSlib](https://github.com/samtools/htslib), including headers and `pkg-config` metadata
|
|
20
20
|
- Ubuntu : `apt install libhts-dev`
|
|
21
21
|
- macOS : `brew install htslib`
|
|
22
22
|
- Windows : [mingw-w64-htslib](https://packages.msys2.org/base/mingw-w64-htslib) is automatically fetched when installing the gem ([RubyInstaller](https://rubyinstaller.org) only).
|
|
23
|
-
- Build from source code (see the Development section)
|
|
24
23
|
|
|
25
24
|
## Installation
|
|
26
25
|
|
|
@@ -28,15 +27,15 @@ Ruby-htslib is the [Ruby](https://www.ruby-lang.org) bindings to [HTSlib](https:
|
|
|
28
27
|
gem install htslib
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
The gem builds a native extension and links to the system HTSlib. `pkg-config`
|
|
31
|
+
normally finds it automatically. For a non-standard installation, set
|
|
32
|
+
`PKG_CONFIG_PATH`, pass `--with-htslib-dir`, or set `HTSLIBDIR` while installing.
|
|
34
33
|
|
|
35
34
|
```sh
|
|
36
|
-
|
|
35
|
+
gem install htslib -- --with-htslib-dir=/your/htslib/prefix
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
RubyInstaller installs the declared MSYS2 HTSlib dependency on Windows.
|
|
40
39
|
|
|
41
40
|
## Usage
|
|
42
41
|
|
|
@@ -77,6 +76,41 @@ HTS::Bam.open("test/fixtures/moo.bam") do |bam|
|
|
|
77
76
|
end
|
|
78
77
|
```
|
|
79
78
|
|
|
79
|
+
Creating a BAM file from Ruby values
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
header = HTS::Bam::Header.new
|
|
83
|
+
header.update_hd(version: "1.6", sort_order: "unsorted")
|
|
84
|
+
header.add_sq("chr1", length: 1_000_000)
|
|
85
|
+
|
|
86
|
+
record = HTS::Bam::Record.new(
|
|
87
|
+
header,
|
|
88
|
+
qname: "read1",
|
|
89
|
+
chrom: "chr1", # resolved through the header
|
|
90
|
+
pos: 99, # zero-based
|
|
91
|
+
mapq: 60,
|
|
92
|
+
cigar: "4M",
|
|
93
|
+
sequence: "ACGT",
|
|
94
|
+
qualities: [30, 31, 32, 33],
|
|
95
|
+
aux: { "NM" => 0 }
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
HTS::Bam.open("output.bam", "wb") do |bam|
|
|
99
|
+
bam.write_header(header)
|
|
100
|
+
bam << record
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Use `quality_string:` for a Phred+33 string instead of numeric `qualities:`.
|
|
105
|
+
Omit qualities (or pass `nil`) to write missing qualities. `seq:` / `qual:`
|
|
106
|
+
are accepted as concise aliases. Reference names can also be assigned with
|
|
107
|
+
`record.chrom=` and `record.mate_chrom=`.
|
|
108
|
+
|
|
109
|
+
BAM/CRAM, BCF/VCF, and Tabix indexes are loaded lazily when an indexed
|
|
110
|
+
operation such as `query` or a region-limited pileup first needs them. Pass an
|
|
111
|
+
explicit `index:` path to `open` to validate and load that index immediately.
|
|
112
|
+
`index_loaded?` reports whether the index is currently loaded.
|
|
113
|
+
|
|
80
114
|
### HTS::Bcf - VCF / BCF - Variant Call Format file
|
|
81
115
|
|
|
82
116
|
Reading fields
|
|
@@ -88,12 +122,12 @@ bcf = HTS::Bcf.open("test/fixtures/test.bcf")
|
|
|
88
122
|
|
|
89
123
|
bcf.each do |r|
|
|
90
124
|
p chrom: r.chrom,
|
|
91
|
-
pos: r.pos,
|
|
125
|
+
pos: r.pos + 1, # VCF POS is 1-based; Record#pos is 0-based.
|
|
92
126
|
id: r.id,
|
|
93
127
|
qual: r.qual.round(2),
|
|
94
128
|
ref: r.ref,
|
|
95
129
|
alt: r.alt,
|
|
96
|
-
|
|
130
|
+
filters: r.filter,
|
|
97
131
|
info: r.info.to_h,
|
|
98
132
|
format: r.format.to_h
|
|
99
133
|
end
|
|
@@ -123,35 +157,56 @@ fa.close
|
|
|
123
157
|
|
|
124
158
|
```ruby
|
|
125
159
|
tb = HTS::Tabix.open("test/fixtures/test.vcf.gz")
|
|
160
|
+
# Numeric coordinates are 0-based, half-open: [2000, 3000).
|
|
126
161
|
tb.query("poo", 2000, 3000) do |line|
|
|
127
162
|
puts line.join("\t")
|
|
128
163
|
end
|
|
129
164
|
tb.close
|
|
130
165
|
```
|
|
131
166
|
|
|
132
|
-
### Low-
|
|
167
|
+
### Low-allocation traversal
|
|
133
168
|
|
|
134
|
-
|
|
135
|
-
`HTS::LibHTS` provides native C functions using [Ruby-FFI](https://github.com/ffi/ffi).
|
|
169
|
+
Large scans can avoid per-sample arrays and genotype strings:
|
|
136
170
|
|
|
137
171
|
```ruby
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
172
|
+
HTS::Bcf.open("variants.bcf", samples: %w[S1 S2], unpack: :format) do |bcf|
|
|
173
|
+
bcf.each do |record|
|
|
174
|
+
record.format.each_genotype do |sample_index, genotype|
|
|
175
|
+
genotype.each_allele do |allele, phased, missing|
|
|
176
|
+
# Consume the primitive values here.
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
record.format.each_i32("DP") { |sample_index, depth| }
|
|
181
|
+
record.format.each_i32_vector("AD") { |sample_index, values| values.each { |depth| } }
|
|
182
|
+
record.format.each_f32_vector("GL") { |sample_index, values| values.each { |likelihood| } }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
144
185
|
```
|
|
145
186
|
|
|
146
|
-
The
|
|
187
|
+
The genotype and numeric vector objects yielded by these iterators are borrowed
|
|
188
|
+
and reused. Consume them inside the block, or call `to_s` / `to_a` to retain an
|
|
189
|
+
owning value. Reading a different FORMAT key does not invalidate a view; reading
|
|
190
|
+
the same key again makes an old view raise `InvalidBorrowedViewError` instead of
|
|
191
|
+
silently returning overwritten data. `genotype_strings`, `get`, and `[]` remain
|
|
192
|
+
the allocating convenience APIs. Use `unpack: :site_only` when FORMAT columns
|
|
193
|
+
are not needed.
|
|
147
194
|
|
|
148
|
-
|
|
195
|
+
Tabix likewise lets callers avoid splitting unused columns. All yielded Ruby
|
|
196
|
+
strings and arrays below are owning values:
|
|
149
197
|
|
|
150
|
-
|
|
198
|
+
```ruby
|
|
199
|
+
tb.each_line("chr1:1-1000") { |line| }
|
|
200
|
+
tb.each_fields("chr1:1-1000") { |fields| }
|
|
201
|
+
tb.each_selected_fields("chr1:1-1000", 0, 3, 4) { |values| }
|
|
202
|
+
```
|
|
151
203
|
|
|
152
|
-
|
|
204
|
+
### Native backend migration
|
|
153
205
|
|
|
154
|
-
|
|
206
|
+
Version 0.5 uses a compiled extension for every supported high-level API. The
|
|
207
|
+
former low-level binding, pointer, and runtime library-switching APIs were
|
|
208
|
+
implementation details and have been removed. Native handles are not exposed;
|
|
209
|
+
install failures report the missing HTSlib build requirement.
|
|
155
210
|
|
|
156
211
|
### Need more speed?
|
|
157
212
|
|
|
@@ -165,22 +220,19 @@ Try Crystal. [HTS.cr](https://github.com/bio-cr/hts.cr) is implemented in Crysta
|
|
|
165
220
|
|
|
166
221
|
## Development
|
|
167
222
|
|
|
168
|
-
####
|
|
223
|
+
#### Build the extension
|
|
169
224
|
|
|
170
|
-
|
|
171
|
-
To get started with development:
|
|
225
|
+
Install the system HTSlib development package first, then:
|
|
172
226
|
|
|
173
227
|
```sh
|
|
174
|
-
git clone
|
|
228
|
+
git clone https://github.com/kojix2/ruby-htslib
|
|
175
229
|
cd ruby-htslib
|
|
176
230
|
bundle install
|
|
177
|
-
bundle exec rake htslib:build
|
|
178
231
|
bundle exec rake test
|
|
179
232
|
```
|
|
180
233
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
HTSlib has many macro functions. These macro functions cannot be called from FFI and must be reimplemented in Ruby.
|
|
234
|
+
Use `bundle exec rake test:local` for fixture-only tests and
|
|
235
|
+
`bundle exec rake test:remote` for the network-dependent URI suite.
|
|
184
236
|
|
|
185
237
|
#### Use the latest Ruby
|
|
186
238
|
|
|
@@ -196,30 +248,10 @@ Return value
|
|
|
196
248
|
|
|
197
249
|
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 allows you to do that. But the code gets a little messy. In Ruby, this is very common and doesn't cause any problems.
|
|
198
250
|
|
|
199
|
-
Memory management
|
|
200
|
-
|
|
201
|
-
Ruby and Crystal are languages that use garbage collection. However, the memory release policy for allocated C structures is slightly different: in Ruby-FFI, you can define a `self.release` method in `FFI::Struct`. This method is called when GC. So you don't have to worry about memory in high-level APIs like Bam::Record or Bcf::Record, etc. Crystal requires you to define a finalize method on each class. So you need to define it in Bam::Record or Bcf::Record.
|
|
202
|
-
|
|
203
|
-
Macro functions
|
|
204
|
-
|
|
205
|
-
In ruby-htslib, C macro functions are added to `LibHTS`, but in Crystal, `LibHTS` is a Lib, so methods cannot be added. methods are added to `LibHTS2`.
|
|
206
|
-
|
|
207
251
|
#### Naming convention
|
|
208
252
|
|
|
209
253
|
If you are not sure about the naming of a method, follow the Rust-htslib API. This is a very weak rule. if a more appropriate name is found later in Ruby, it will replace it.
|
|
210
254
|
|
|
211
|
-
#### Support for bitfields of structures
|
|
212
|
-
|
|
213
|
-
Since Ruby-FFI does not support structure bit fields, the following extensions are used.
|
|
214
|
-
|
|
215
|
-
- [ffi-bitfield](https://github.com/kojix2/ffi-bitfield) - Extension of Ruby-FFI to support bitfields.
|
|
216
|
-
|
|
217
|
-
#### Automatic validation
|
|
218
|
-
|
|
219
|
-
In the `script` directory, there are several tools to help implement ruby-htslib. Scripts using c2ffi can check the coverage of htslib functions in Ruby-htslib. They are useful when new versions of htslib are released.
|
|
220
|
-
|
|
221
|
-
- [c2ffi](https://github.com/rpav/c2ffi) is a tool to create JSON format metadata from C header files.
|
|
222
|
-
|
|
223
255
|
## Contributing
|
|
224
256
|
|
|
225
257
|
Ruby-htslib is a library under development, so even minor improvements like typo fixes are welcome! Please feel free to send us your pull requests.
|
data/TUTORIAL.md
CHANGED
|
@@ -17,33 +17,30 @@ Bcf o-- `Bcf::Record`
|
|
|
17
17
|
`Bcf::Record` o-- Info
|
|
18
18
|
`Bcf::Record` o-- Format
|
|
19
19
|
class Bam{
|
|
20
|
-
|
|
20
|
+
-@native
|
|
21
21
|
+@header : Bam::Header
|
|
22
22
|
+@file_name
|
|
23
23
|
+@index_name
|
|
24
24
|
+@mode
|
|
25
|
-
+struct()
|
|
26
25
|
+build_index()
|
|
27
26
|
+each() Enumerable
|
|
28
27
|
+query()
|
|
29
28
|
}
|
|
30
29
|
class Bcf{
|
|
31
|
-
|
|
30
|
+
-@native
|
|
32
31
|
+@header : Bcf::Header
|
|
33
32
|
+@file_name
|
|
34
33
|
+@index_name
|
|
35
34
|
+@mode
|
|
36
|
-
+struct()
|
|
37
35
|
+build_index()
|
|
38
36
|
+each() Enumerable
|
|
39
37
|
+query()
|
|
40
38
|
}
|
|
41
39
|
class Tabix~Hts~{
|
|
42
|
-
|
|
40
|
+
-@native
|
|
43
41
|
}
|
|
44
42
|
class `Bam::Header`{
|
|
45
|
-
|
|
46
|
-
+struct()
|
|
43
|
+
-@native
|
|
47
44
|
+target_count()
|
|
48
45
|
+target_names()
|
|
49
46
|
+name2tid()
|
|
@@ -51,9 +48,8 @@ class `Bam::Header`{
|
|
|
51
48
|
+to_s()
|
|
52
49
|
}
|
|
53
50
|
class `Bam::Record` {
|
|
54
|
-
|
|
51
|
+
-@native
|
|
55
52
|
+@header : Bam::Header
|
|
56
|
-
+struct()
|
|
57
53
|
+qname()
|
|
58
54
|
+qname=()
|
|
59
55
|
+tid()
|
|
@@ -97,14 +93,12 @@ class `Aux` {
|
|
|
97
93
|
+get_string()
|
|
98
94
|
}
|
|
99
95
|
class `Bcf::Header`{
|
|
100
|
-
|
|
101
|
-
+struct()
|
|
96
|
+
-@native
|
|
102
97
|
+to_s()
|
|
103
98
|
}
|
|
104
99
|
class `Bcf::Record`{
|
|
105
|
-
|
|
100
|
+
-@native
|
|
106
101
|
+@header : Bcf::Header
|
|
107
|
-
+struct()
|
|
108
102
|
+rid()
|
|
109
103
|
+rid=()
|
|
110
104
|
+chrom()
|
|
@@ -191,13 +185,8 @@ class Faidx{
|
|
|
191
185
|
gem install htslib
|
|
192
186
|
```
|
|
193
187
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
```ruby
|
|
197
|
-
require "htslib"
|
|
198
|
-
puts HTS.lib_path
|
|
199
|
-
# => "/home/kojix2/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/htslib-0.2.6/vendor/libhts.so"
|
|
200
|
-
```
|
|
188
|
+
The gem compiles its native extension against the system HTSlib. Install the
|
|
189
|
+
HTSlib development package before installing the gem.
|
|
201
190
|
|
|
202
191
|
## HTS::Bam - SAM / BAM / CRAM - Sequence Alignment Map file
|
|
203
192
|
|
|
@@ -342,12 +331,12 @@ bcf = HTS::Bcf.open("b.bcf")
|
|
|
342
331
|
|
|
343
332
|
bcf.each do |r|
|
|
344
333
|
p chrom: r.chrom,
|
|
345
|
-
pos: r.pos,
|
|
334
|
+
pos: r.pos + 1, # VCF POS is 1-based; Record#pos is 0-based.
|
|
346
335
|
id: r.id,
|
|
347
336
|
qual: r.qual.round(2),
|
|
348
337
|
ref: r.ref,
|
|
349
338
|
alt: r.alt,
|
|
350
|
-
|
|
339
|
+
filters: r.filter,
|
|
351
340
|
info: r.info.to_h,
|
|
352
341
|
format: r.format.to_h
|
|
353
342
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
|
|
5
|
+
htslib_dir = with_config("htslib-dir", ENV["HTSLIBDIR"])
|
|
6
|
+
if htslib_dir
|
|
7
|
+
include_dir = File.directory?(File.join(htslib_dir, "include")) ? File.join(htslib_dir, "include") : htslib_dir
|
|
8
|
+
library_dir = if File.directory?(File.join(htslib_dir, "lib"))
|
|
9
|
+
File.join(htslib_dir, "lib")
|
|
10
|
+
else
|
|
11
|
+
htslib_dir
|
|
12
|
+
end
|
|
13
|
+
dir_config("htslib", include_dir, library_dir)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
pkg_config("htslib") unless htslib_dir
|
|
17
|
+
|
|
18
|
+
abort "HTSlib headers were not found. Install the HTSlib development package or set --with-htslib-dir." unless \
|
|
19
|
+
have_header("htslib/hts.h") && have_header("htslib/sam.h") &&
|
|
20
|
+
have_header("htslib/vcf.h") && have_header("htslib/faidx.h") && have_header("htslib/tbx.h")
|
|
21
|
+
|
|
22
|
+
abort "HTSlib library was not found. Install HTSlib or set --with-htslib-dir." unless \
|
|
23
|
+
have_library("hts", "hts_version")
|
|
24
|
+
|
|
25
|
+
required_functions = {
|
|
26
|
+
"sam_read1" => "htslib/sam.h",
|
|
27
|
+
"bam_plp_init" => "htslib/sam.h",
|
|
28
|
+
"bam_mplp64_auto" => "htslib/sam.h",
|
|
29
|
+
"bam_mplp_init_overlaps" => "htslib/sam.h",
|
|
30
|
+
"hts_base_mod_state_alloc" => "htslib/sam.h",
|
|
31
|
+
"bcf_read" => "htslib/vcf.h",
|
|
32
|
+
"bcf_hdr_set" => "htslib/vcf.h",
|
|
33
|
+
"fai_load3_format" => "htslib/faidx.h",
|
|
34
|
+
"tbx_index_load3" => "htslib/tbx.h"
|
|
35
|
+
}
|
|
36
|
+
missing_functions = required_functions.reject { |function, header| have_func(function, header) }.keys
|
|
37
|
+
unless missing_functions.empty?
|
|
38
|
+
abort "HTSlib is missing required functions: #{missing_functions.join(', ')}. Install a supported HTSlib development package."
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
create_makefile("htslib_native_ext")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#ifndef RUBY_HTSLIB_NATIVE_H
|
|
2
|
+
#define RUBY_HTSLIB_NATIVE_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
|
|
6
|
+
void Init_htslib_native_faidx(VALUE native);
|
|
7
|
+
void Init_htslib_native_tabix(VALUE native);
|
|
8
|
+
void Init_htslib_native_bam(VALUE native);
|
|
9
|
+
void Init_htslib_native_bcf(VALUE native);
|
|
10
|
+
|
|
11
|
+
#endif
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#include "htslib_native.h"
|
|
2
|
+
#include <htslib/hts.h>
|
|
3
|
+
|
|
4
|
+
static VALUE native_htslib_version(VALUE self)
|
|
5
|
+
{
|
|
6
|
+
return rb_str_new_cstr(hts_version());
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static VALUE selected_fields(VALUE self, VALUE line, VALUE columns)
|
|
10
|
+
{
|
|
11
|
+
const char *bytes;
|
|
12
|
+
long length, column_count, field_start = 0, column = 0, offset, i;
|
|
13
|
+
VALUE result;
|
|
14
|
+
|
|
15
|
+
StringValue(line);
|
|
16
|
+
Check_Type(columns, T_ARRAY);
|
|
17
|
+
bytes = RSTRING_PTR(line);
|
|
18
|
+
length = RSTRING_LEN(line);
|
|
19
|
+
column_count = RARRAY_LEN(columns);
|
|
20
|
+
result = rb_ary_new_capa(column_count);
|
|
21
|
+
for (i = 0; i < column_count; i++) rb_ary_push(result, Qnil);
|
|
22
|
+
|
|
23
|
+
for (offset = 0; offset <= length; offset++) {
|
|
24
|
+
if (offset == length || bytes[offset] == '\t') {
|
|
25
|
+
for (i = 0; i < column_count; i++) {
|
|
26
|
+
long requested = NUM2LONG(rb_ary_entry(columns, i));
|
|
27
|
+
if (requested == column) {
|
|
28
|
+
rb_ary_store(result, i, rb_str_new(bytes + field_start, offset - field_start));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
column++;
|
|
32
|
+
field_start = offset + 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void Init_htslib_native_ext(void)
|
|
39
|
+
{
|
|
40
|
+
VALUE hts = rb_define_module("HTS");
|
|
41
|
+
VALUE native = rb_define_module_under(hts, "Native");
|
|
42
|
+
rb_define_module_function(native, "htslib_version", native_htslib_version, 0);
|
|
43
|
+
rb_define_module_function(native, "selected_fields", selected_fields, 2);
|
|
44
|
+
Init_htslib_native_faidx(native);
|
|
45
|
+
Init_htslib_native_tabix(native);
|
|
46
|
+
Init_htslib_native_bam(native);
|
|
47
|
+
Init_htslib_native_bcf(native);
|
|
48
|
+
}
|