htslib 0.0.6 → 0.1.0

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: f05bc93a621f3d5fb8d06e44c20ac4a3a95c5f6e243df2aebc97e10125fcb779
4
- data.tar.gz: 73e747aa0999e54b3c8f01b981b91c4e293167265276a24eac85ea0fd6b85c13
3
+ metadata.gz: c90062954caa8dc2155f77ff3d03534d933ba81148f9bdb7c8dc173f73efca64
4
+ data.tar.gz: fb24ced637a8b9b897ecd9c5afed1c6f75902995e48c25daa849baa06611517b
5
5
  SHA512:
6
- metadata.gz: 8d0f3f8bb9f7a9c063222fd2dc6463f58bdfd784aff39757921dda1c8d417023b024ca9f6c92d7f0eecd30b8064adb1b94966cf962cf9e0e56d67303de0a903b
7
- data.tar.gz: 8ef35b7aef04bf2f51ae0ba110d9ffc81c26d7a0c97a821aa1274c04b31ec29515b33c278391494f6a0d8efc5e2d965060ccd190ee0f92a2ec3562fb59c49169
6
+ metadata.gz: fed4e6689d48493416ebd409401df284fedaddb567d3558196b3ba3c253376dd1c4bea8db536fdb6ff8bbebe85512850d7d5c17605544ce26a09e814e7172eb5
7
+ data.tar.gz: b9d596e6445671254568b4bd3cc5b694a1011914ae67b1afc11aaa66a195f49b7371d001f9e10cc204a4c20e501cd8eb63092d63b9b392c701571a12843b5c91
data/README.md CHANGED
@@ -6,10 +6,7 @@
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
- :dna: [HTSlib](https://github.com/samtools/htslib) - for Ruby
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](http://samtools.github.io/hts-specs/).
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
 
@@ -39,51 +36,80 @@ export HTSLIBDIR="/your/path/to/htslib" # libhts.so
39
36
 
40
37
  ## Overview
41
38
 
42
- ### Low level API
39
+ ### High level API
43
40
 
44
- `HTS::LibHTS` provides native functions.
41
+ Read SAM / BAM / CRAM - Sequence Alignment Map file
45
42
 
46
43
  ```ruby
47
44
  require 'htslib'
48
45
 
49
- a = HTS::LibHTS.hts_open("a.bam", "r")
50
- b = HTS::LibHTS.hts_get_format(a)
51
- p b[:category]
52
- p b[:format]
46
+ bam = HTS::Bam.open("test/fixtures/moo.bam")
47
+
48
+ bam.each do |r|
49
+ pp name: r.qname,
50
+ flag: r.flag,
51
+ chrm: r.chrom,
52
+ strt: r.pos + 1,
53
+ mapq: r.mapq,
54
+ cigr: r.cigar.to_s,
55
+ mchr: r.mate_chrom,
56
+ mpos: r.mpos + 1,
57
+ isiz: r.isize,
58
+ seqs: r.seq,
59
+ qual: r.qual.map { |i| (i + 33).chr }.join,
60
+ MC: r.aux("MC")
61
+ end
62
+
63
+ bam.close
53
64
  ```
54
65
 
55
- Note: Managed struct is not used in ruby-htslib. You may need to free the memory by yourself.
66
+ Read VCF / BCF - Variant Call Format file
67
+
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.to_h,
80
+ format: r.format.to_h
81
+ end
56
82
 
57
- ### High level API (Plan)
83
+ bcf.close
84
+ ```
58
85
 
59
- `Cram` `Bam` `Bcf` `Faidx` `Tabix`
86
+ ### Low level API
60
87
 
61
- A high-level API is under development. We will change and improve the API to make it better.
88
+ `HTS::LibHTS` provides native C functions.
62
89
 
63
90
  ```ruby
64
91
  require 'htslib'
65
92
 
66
- bam = HTS::Bam.new("a.bam")
67
-
68
- bam.each do |r|
69
- p name: r.qname,
70
- flag: r.flag,
71
- start: r.start + 1,
72
- mpos: r.mate_pos + 1,
73
- mqual: r.mapping_quality,
74
- seq: r.sequence,
75
- cigar: r.cigar.to_s,
76
- qual: r.base_qualities.map { |i| (i + 33).chr }.join
77
- 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]
78
97
  ```
79
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
+
80
105
  ## Documentation
81
106
 
107
+ * [API Documentation (develop branch)](https://kojix2.github.io/ruby-htslib/)
82
108
  * [RubyDoc.info - HTSlib](https://rdoc.info/gems/htslib)
83
109
 
84
110
  ## Development
85
111
 
86
- To get started with development
112
+ To get started with development:
87
113
 
88
114
  ```sh
89
115
  git clone --recursive https://github.com/kojix2/ruby-htslib
@@ -93,8 +119,13 @@ bundle exec rake htslib:build
93
119
  bundle exec rake test
94
120
  ```
95
121
 
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
+
96
126
  * Actively use the advanced features of Ruby.
97
- * Consider compatibility with [htslib.cr](https://github.com/bio-crystal/htslib.cr) to some extent.
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.
98
129
 
99
130
  #### FFI Extensions
100
131
 
@@ -114,6 +145,16 @@ Ruby-htslib is a library under development, so even small improvements like typo
114
145
  * Suggest or add new features
115
146
  * [financial contributions](https://github.com/sponsors/kojix2)
116
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
+
117
158
  ## Links
118
159
 
119
160
  * [samtools/hts-spec](https://github.com/samtools/hts-specs)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTS
4
+ class Bam < Hts
5
+ class Aux
6
+ def initialize(record)
7
+ @record = record
8
+ end
9
+
10
+ def get(key, type = nil)
11
+ aux = LibHTS.bam_aux_get(@record.struct, key)
12
+ return nil if aux.null?
13
+
14
+ type ||= aux.read_string(1)
15
+
16
+ # A (character), B (general array),
17
+ # f (real number), H (hexadecimal array),
18
+ # i (integer), or Z (string).
19
+
20
+ case type
21
+ when "i", "I", "c", "C", "s", "S"
22
+ LibHTS.bam_aux2i(aux)
23
+ when "f", "d"
24
+ LibHTS.bam_aux2f(aux)
25
+ when "Z", "H"
26
+ LibHTS.bam_aux2Z(aux)
27
+ when "A" # char
28
+ LibHTS.bam_aux2A(aux).chr
29
+ else
30
+ raise NotImplementedError, "type: #{t}"
31
+ end
32
+ end
33
+
34
+ def [](key)
35
+ get(key)
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/hts/bam/cigar.rb CHANGED
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Based on hts-python
4
- # https://github.com/quinlan-lab/hts-python
5
-
6
3
  module HTS
7
- class Bam
4
+ class Bam < Hts
8
5
  class Cigar
9
6
  include Enumerable
10
7
 
@@ -18,7 +15,7 @@ module HTS
18
15
  end
19
16
 
20
17
  def to_s
21
- to_a.flatten.join
18
+ map { |op, len| "#{len}#{op}" }.join
22
19
  end
23
20
 
24
21
  def each
@@ -26,8 +23,9 @@ module HTS
26
23
 
27
24
  @n_cigar.times do |i|
28
25
  c = @pointer[i].read_uint32
29
- yield [LibHTS.bam_cigar_oplen(c),
30
- LibHTS.bam_cigar_opchr(c)]
26
+ op = LibHTS.bam_cigar_opchr(c)
27
+ len = LibHTS.bam_cigar_oplen(c)
28
+ yield [op, len]
31
29
  end
32
30
  end
33
31
  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
@@ -27,70 +27,34 @@ module HTS
27
27
  # BAM_FDUP = 1024
28
28
  # BAM_FSUPPLEMENTARY = 2048
29
29
 
30
- # TODO: Enabling bitwise operations
31
- # hts-nim
32
- # proc `and`*(f: Flag, o: uint16): uint16 {. borrow, inline .}
33
- # proc `and`*(f: Flag, o: Flag): uint16 {. borrow, inline .}
34
- # proc `or`*(f: Flag, o: uint16): uint16 {. borrow .}
35
- # proc `or`*(o: uint16, f: Flag): uint16 {. borrow .}
36
- # proc `==`*(f: Flag, o: Flag): bool {. borrow, inline .}
37
- # proc `==`*(f: Flag, o: uint16): bool {. borrow, inline .}
38
- # proc `==`*(o: uint16, f: Flag): bool {. borrow, inline .}
30
+ # TODO: Enabling bitwise operations?
39
31
 
40
- def paired?
41
- has_flag? LibHTS::BAM_FPAIRED
42
- end
43
-
44
- def proper_pair?
45
- has_flag? LibHTS::BAM_FPROPER_PAIR
46
- end
47
-
48
- def unmapped?
49
- has_flag? LibHTS::BAM_FUNMAP
50
- end
51
-
52
- def mate_unmapped?
53
- has_flag? LibHTS::BAM_FMUNMAP
54
- end
55
-
56
- def reverse?
57
- has_flag? LibHTS::BAM_FREVERSE
58
- end
59
-
60
- def mate_reverse?
61
- has_flag? LibHTS::BAM_FMREVERSE
62
- end
63
-
64
- def read1?
65
- has_flag? LibHTS::BAM_FREAD1
66
- end
67
-
68
- def read2?
69
- has_flag? LibHTS::BAM_FREAD2
70
- end
71
-
72
- def secondary?
73
- has_flag? LibHTS::BAM_FSECONDARY
74
- end
75
-
76
- def qcfail?
77
- has_flag? LibHTS::BAM_FQCFAIL
78
- end
79
-
80
- def dup?
81
- has_flag? LibHTS::BAM_FDUP
82
- end
32
+ TABLE = { paired?: LibHTS::BAM_FPAIRED,
33
+ proper_pair?: LibHTS::BAM_FPROPER_PAIR,
34
+ unmapped?: LibHTS::BAM_FUNMAP,
35
+ mate_unmapped?: LibHTS::BAM_FMUNMAP,
36
+ reverse?: LibHTS::BAM_FREVERSE,
37
+ mate_reverse?: LibHTS::BAM_FMREVERSE,
38
+ read1?: LibHTS::BAM_FREAD1,
39
+ read2?: LibHTS::BAM_FREAD2,
40
+ secondary?: LibHTS::BAM_FSECONDARY,
41
+ qcfail?: LibHTS::BAM_FQCFAIL,
42
+ duplicate?: LibHTS::BAM_FDUP,
43
+ supplementary?: LibHTS::BAM_FSUPPLEMENTARY }.freeze
83
44
 
84
- def supplementary?
85
- has_flag? LibHTS::BAM_FSUPPLEMENTARY
45
+ TABLE.each do |name, v|
46
+ define_method(name) do
47
+ has_flag?(v)
48
+ end
86
49
  end
87
50
 
88
- def has_flag?(m)
89
- (@value & m) != 0
51
+ def has_flag?(f)
52
+ (@value & f) != 0
90
53
  end
91
54
 
92
55
  def to_s
93
- "0x#{format('%x', @value)}\t#{@value}\t#{LibHTS.bam_flag2str(@value)}"
56
+ LibHTS.bam_flag2str(@value)
57
+ # "0x#{format('%x', @value)}\t#{@value}\t#{LibHTS.bam_flag2str(@value)}"
94
58
  end
95
59
  end
96
60
  end
@@ -1,13 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Based on hts-python
4
- # https://github.com/quinlan-lab/hts-python
5
-
6
3
  module HTS
7
- class Bam
4
+ class Bam < Hts
8
5
  class Header
9
- def initialize(pointer)
10
- @sam_hdr = pointer
6
+ def initialize(hts_file)
7
+ @sam_hdr = LibHTS.sam_hdr_read(hts_file)
11
8
  end
12
9
 
13
10
  def struct
@@ -22,16 +19,27 @@ module HTS
22
19
  @sam_hdr[:n_targets]
23
20
  end
24
21
 
25
- # FIXME: better name?
26
- def seqs
27
- Array.new(@sam_hdr[:n_targets]) do |i|
22
+ def target_names
23
+ Array.new(target_count) do |i|
28
24
  LibHTS.sam_hdr_tid2name(@sam_hdr, i)
29
25
  end
30
26
  end
31
27
 
28
+ def target_len
29
+ Array.new(target_count) do |i|
30
+ LibHTS.sam_hdr_tid2len(@sam_hdr, i)
31
+ end
32
+ end
33
+
32
34
  def to_s
33
35
  LibHTS.sam_hdr_str(@sam_hdr)
34
36
  end
37
+
38
+ private
39
+
40
+ def initialize_copy(orig)
41
+ @sam_hdr = LibHTS.sam_hdr_dup(orig.struct)
42
+ end
35
43
  end
36
44
  end
37
45
  end
@@ -1,13 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Based on hts-python
4
- # https://github.com/quinlan-lab/hts-python
3
+ require_relative "flag"
4
+ require_relative "cigar"
5
+ require_relative "aux"
5
6
 
6
7
  module HTS
7
- class Bam
8
+ class Bam < Hts
8
9
  class Record
9
10
  SEQ_NT16_STR = "=ACMGRSVTWYHKDBN"
10
11
 
12
+ attr_reader :header
13
+
11
14
  def initialize(bam1_t, header)
12
15
  @bam1 = bam1_t
13
16
  @header = header
@@ -21,16 +24,6 @@ module HTS
21
24
  @bam1.to_ptr
22
25
  end
23
26
 
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
27
  # returns the query name.
35
28
  def qname
36
29
  LibHTS.bam_get_qname(@bam1).read_string
@@ -46,26 +39,49 @@ module HTS
46
39
  @bam1[:core][:tid]
47
40
  end
48
41
 
42
+ def tid=(tid)
43
+ @bam1[:core][:tid] = tid
44
+ end
45
+
49
46
  # returns the tid of the mate or -1 if not mapped.
50
- def mate_tid
47
+ def mtid
51
48
  @bam1[:core][:mtid]
52
49
  end
53
50
 
51
+ def mtid=(mtid)
52
+ @bam1[:core][:mtid] = mtid
53
+ end
54
+
54
55
  # returns 0-based start position.
55
- def start
56
+ def pos
56
57
  @bam1[:core][:pos]
57
58
  end
58
59
 
59
- # returns end position of the read.
60
- def stop
61
- LibHTS.bam_endpos @bam1
60
+ def pos=(pos)
61
+ @bam1[:core][:pos] = pos
62
62
  end
63
63
 
64
64
  # returns 0-based mate position
65
- def mate_start
65
+ def mpos
66
66
  @bam1[:core][:mpos]
67
67
  end
68
- alias mate_pos mate_start
68
+
69
+ def mpos=(mpos)
70
+ @bam1[:core][:mpos] = mpos
71
+ end
72
+
73
+ def bin
74
+ @bam1[:core][:bin]
75
+ end
76
+
77
+ def bin=(bin)
78
+ @bam1[:core][:bin] = bin
79
+ end
80
+
81
+ # returns end position of the read.
82
+ def endpos
83
+ LibHTS.bam_endpos @bam1
84
+ end
69
85
 
70
86
  # returns the chromosome or '' if not mapped.
71
87
  def chrom
@@ -74,32 +90,44 @@ module HTS
74
90
  LibHTS.sam_hdr_tid2name(@header, tid)
75
91
  end
76
92
 
93
+ alias contig chrom
94
+
77
95
  # returns the chromosome of the mate or '' if not mapped.
78
96
  def mate_chrom
79
- mtid = mate_tid
80
97
  return "" if mtid == -1
81
98
 
82
99
  LibHTS.sam_hdr_tid2name(@header, mtid)
83
100
  end
84
101
 
102
+ alias mate_contig mate_chrom
103
+
104
+ # Get strand information.
85
105
  def strand
86
106
  LibHTS.bam_is_rev(@bam1) ? "-" : "+"
87
107
  end
88
108
 
89
- # def start=(v)
90
- # raise 'Not Implemented'
91
- # end
92
-
93
109
  # insert size
94
- def isize
110
+ def insert_size
95
111
  @bam1[:core][:isize]
96
112
  end
97
113
 
114
+ alias isize insert_size
115
+
116
+ def insert_size=(isize)
117
+ @bam1[:core][:isize] = isize
118
+ end
119
+
120
+ alias isize= insert_size=
121
+
98
122
  # mapping quality
99
- def mapping_quality
123
+ def mapq
100
124
  @bam1[:core][:qual]
101
125
  end
102
126
 
127
+ def mapq=(mapq)
128
+ @bam1[:core][:qual] = mapq
129
+ end
130
+
103
131
  # returns a `Cigar` object.
104
132
  def cigar
105
133
  Cigar.new(LibHTS.bam_get_cigar(@bam1), @bam1[:core][:n_cigar])
@@ -120,7 +148,7 @@ module HTS
120
148
  end
121
149
 
122
150
  # return the read sequence
123
- def sequence
151
+ def seq
124
152
  r = LibHTS.bam_get_seq(@bam1)
125
153
  seq = String.new
126
154
  (@bam1[:core][:l_qseq]).times do |i|
@@ -128,59 +156,74 @@ module HTS
128
156
  end
129
157
  seq
130
158
  end
159
+ alias sequence seq
160
+
161
+ def len
162
+ @bam1[:core][:l_qseq]
163
+ end
131
164
 
132
165
  # return only the base of the requested index "i" of the query sequence.
133
- def base_at(n)
166
+ def base(n)
134
167
  n += @bam1[:core][:l_qseq] if n < 0
135
- return "." if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base_at(-1000)
168
+ return "." if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base(-1000)
136
169
 
137
170
  r = LibHTS.bam_get_seq(@bam1)
138
171
  SEQ_NT16_STR[LibHTS.bam_seqi(r, n)]
139
172
  end
140
173
 
141
174
  # return the base qualities
142
- def base_qualities
175
+ def qual
143
176
  q_ptr = LibHTS.bam_get_qual(@bam1)
144
177
  q_ptr.read_array_of_uint8(@bam1[:core][:l_qseq])
145
178
  end
146
179
 
147
180
  # return only the base quality of the requested index "i" of the query sequence.
148
- def base_quality_at(n)
181
+ def base_qual(n)
149
182
  n += @bam1[:core][:l_qseq] if n < 0
150
- return 0 if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base_quality_at(-1000)
183
+ return 0 if (n >= @bam1[:core][:l_qseq]) || (n < 0) # eg. base_qual(-1000)
151
184
 
152
185
  q_ptr = LibHTS.bam_get_qual(@bam1)
153
186
  q_ptr.get_uint8(n)
154
187
  end
155
188
 
156
- def flag_str
157
- LibHTS.bam_flag2str(@bam1[:core][:flag])
158
- end
159
-
160
189
  # returns a `Flag` object.
161
190
  def flag
162
191
  Flag.new(@bam1[:core][:flag])
163
192
  end
164
193
 
165
- def tag(str)
166
- aux = LibHTS.bam_aux_get(@bam1, str)
167
- return nil if aux.null?
194
+ def flag=(flag)
195
+ case flag
196
+ when Integer
197
+ @bam1[:core][:flag] = flag
198
+ when Flag
199
+ @bam1[:core][:flag] = flag.value
200
+ else
201
+ raise "Invalid flag type: #{flag.class}"
202
+ end
203
+ end
204
+
205
+ # retruns the auxillary fields.
206
+ def aux(key = nil)
207
+ aux = Aux.new(self)
208
+ if key
209
+ aux.get(key)
210
+ else
211
+ aux
212
+ end
213
+ end
214
+
215
+ # TODO: add a method to get the auxillary fields as a hash.
168
216
 
169
- t = aux.read_string(1)
217
+ # TODO: add a method to set the auxillary fields.
170
218
 
171
- # A (character), B (general array),
172
- # f (real number), H (hexadecimal array),
173
- # i (integer), or Z (string).
219
+ # TODO: add a method to remove the auxillary fields.
174
220
 
175
- case t
176
- when "i", "I", "c", "C", "s", "S"
177
- LibHTS.bam_aux2i(aux)
178
- when "f", "d"
179
- LibHTS.bam_aux2f(aux)
180
- when "Z", "H"
181
- LibHTS.bam_aux2Z(aux)
182
- when "A" # char
183
- LibHTS.bam_aux2A(aux).chr
221
+ # TODO: add a method to set variable length data (qname, cigar, seq, qual).
222
+
223
+ # Calling flag is delegated to the Flag object.
224
+ Flag::TABLE.each_key do |m|
225
+ define_method(m) do
226
+ flag.send(m)
184
227
  end
185
228
  end
186
229
 
@@ -191,9 +234,12 @@ module HTS
191
234
  kstr[:s]
192
235
  end
193
236
 
194
- # TODO:
195
- # def eql?
196
- # def hash
237
+ private
238
+
239
+ def initialize_copy(orig)
240
+ @header = orig.header
241
+ @bam = LibHTS.bam_dup1(orig.struct)
242
+ end
197
243
  end
198
244
  end
199
245
  end