Class: HTS::Bcf::Header

Inherits:
Object
  • Object
show all
Defined in:
lib/hts/bcf/header.rb

Overview

A class for working with VCF records. NOTE: This class has a lot of methods that are not stable. The method names and the number of arguments may change in the future.

Constant Summary collapse

BCF_TYPE_MAP =
{
  int: "Integer",
  integer: "Integer",
  int32: "Integer",
  float: "Float",
  real: "Float",
  string: "String",
  str: "String",
  character: "Character",
  char: "Character",
  flag: "Flag"
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arg = nil) {|_self| ... } ⇒ Header

Returns a new instance of Header.

Yields:

  • (_self)

Yield Parameters:



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/hts/bcf/header.rb', line 24

def initialize(arg = nil)
  case arg
  when LibHTS::HtsFile
    @bcf_hdr = LibHTS.bcf_hdr_read(arg)
  when LibHTS::BcfHdr
    @bcf_hdr = arg
  when nil
    @bcf_hdr = LibHTS.bcf_hdr_init("w")
  else
    raise TypeError, "Invalid argument"
  end

  @sync_depth = 0
  @sync_needed = false
  @subset_samples = nil
  @subset_imap = nil
  @subset_imap_pointer = nil

  yield self if block_given?
end

Instance Attribute Details

#subset_samplesObject (readonly)

Returns the value of attribute subset_samples.



93
94
95
# File 'lib/hts/bcf/header.rb', line 93

def subset_samples
  @subset_samples
end

Instance Method Details

#add_contig(id, length: nil, **attributes) ⇒ Object



194
195
196
197
198
199
# File 'lib/hts/bcf/header.rb', line 194

def add_contig(id, length: nil, **attributes)
  fields = [["ID", id.to_s]]
  fields << ["length", length.to_s] unless length.nil?
  fields.concat normalize_meta_attributes(attributes)
  append_structured_meta("contig", fields)
end

#add_filter(id, description:, **attributes) ⇒ Object



205
206
207
208
209
# File 'lib/hts/bcf/header.rb', line 205

def add_filter(id, description:, **attributes)
  fields = [["ID", id.to_s], ["Description", description.to_s]]
  fields.concat normalize_meta_attributes(attributes)
  append_structured_meta("FILTER", fields)
end

#add_format(id, number:, type:, description:, **attributes) ⇒ Object



230
231
232
233
234
# File 'lib/hts/bcf/header.rb', line 230

def add_format(id, number:, type:, description:, **attributes)
  fields = [["ID", id.to_s], ["Number", normalize_bcf_number(number)], ["Type", normalize_bcf_type(type)], ["Description", description.to_s]]
  fields.concat normalize_meta_attributes(attributes)
  append_structured_meta("FORMAT", fields)
end

#add_info(id, number:, type:, description:, **attributes) ⇒ Object



215
216
217
218
219
# File 'lib/hts/bcf/header.rb', line 215

def add_info(id, number:, type:, description:, **attributes)
  fields = [["ID", id.to_s], ["Number", normalize_bcf_number(number)], ["Type", normalize_bcf_type(type)], ["Description", description.to_s]]
  fields.concat normalize_meta_attributes(attributes)
  append_structured_meta("INFO", fields)
end

#add_meta(key, value = nil, **attributes) ⇒ Object



245
246
247
248
249
250
251
252
253
# File 'lib/hts/bcf/header.rb', line 245

def add_meta(key, value = nil, **attributes)
  if attributes.empty?
    append("###{key}=#{value}")
    sync_if_needed!
    self
  else
    append_structured_meta(key.to_s, normalize_meta_attributes(attributes))
  end
end

#add_sample(sample, sync: true) ⇒ Object



131
132
133
134
135
136
137
138
# File 'lib/hts/bcf/header.rb', line 131

def add_sample(sample, sync: true)
  rc = LibHTS.bcf_hdr_add_sample(@bcf_hdr, sample)
  raise "Failed to add sample #{sample}" if rc.negative?

  mark_sync_needed!
  sync_if_needed! if sync
  self
end

#append(line) ⇒ Object



161
162
163
164
165
166
167
# File 'lib/hts/bcf/header.rb', line 161

def append(line)
  rc = LibHTS.bcf_hdr_append(@bcf_hdr, line)
  raise "Failed to append VCF header line" if rc.negative?

  mark_sync_needed!
  self
end

#delete(bcf_hl_type, key = nil) ⇒ Object

FIXME



169
170
171
172
173
174
175
# File 'lib/hts/bcf/header.rb', line 169

def delete(bcf_hl_type, key = nil) # FIXME
  existed = hrec_exists?(bcf_hl_type, key)
  type = bcf_hl_type_to_int(bcf_hl_type)
  LibHTS.bcf_hdr_remove(@bcf_hdr, type, key)
  mark_sync_needed! if existed
  existed
end

#editObject



185
186
187
188
189
190
191
192
# File 'lib/hts/bcf/header.rb', line 185

def edit
  @sync_depth += 1
  yield self
  self
ensure
  @sync_depth -= 1
  sync_if_needed!
end

#get_hrec(bcf_hl_type, key, value, str_class = nil) ⇒ Object



177
178
179
180
181
182
183
# File 'lib/hts/bcf/header.rb', line 177

def get_hrec(bcf_hl_type, key, value, str_class = nil)
  type = bcf_hl_type_to_int(bcf_hl_type)
  hrec = borrowed_hrec(type, key, value, str_class)
  return nil if hrec.to_ptr.null?

  HeaderRecord.new(hrec)
end

#get_tid(name) ⇒ Object



74
75
76
# File 'lib/hts/bcf/header.rb', line 74

def get_tid(name)
  name2id(name)
end

#get_versionObject



53
54
55
# File 'lib/hts/bcf/header.rb', line 53

def get_version
  LibHTS.bcf_hdr_get_version(@bcf_hdr)
end

#id2name(id) ⇒ Object



281
282
283
# File 'lib/hts/bcf/header.rb', line 281

def id2name(id)
  LibHTS.bcf_hdr_id2name(@bcf_hdr, id)
end

#merge(hdr) ⇒ Object



140
141
142
143
144
145
146
147
# File 'lib/hts/bcf/header.rb', line 140

def merge(hdr)
  merged = LibHTS.bcf_hdr_merge(@bcf_hdr, hdr.struct)
  raise "Failed to merge BCF headers" if merged.to_ptr.null?

  mark_sync_needed!
  sync_if_needed!
  self
end

#name2id(name) ⇒ Object



277
278
279
# File 'lib/hts/bcf/header.rb', line 277

def name2id(name)
  LibHTS.bcf_hdr_name2id(@bcf_hdr, name)
end

#nsamplesObject



66
67
68
# File 'lib/hts/bcf/header.rb', line 66

def nsamples
  LibHTS.bcf_hdr_nsamples(@bcf_hdr)
end

#read_bcf(fname) ⇒ Object



157
158
159
# File 'lib/hts/bcf/header.rb', line 157

def read_bcf(fname)
  LibHTS.bcf_hdr_set(@bcf_hdr, fname)
end

#remove_contig(id) ⇒ Object



201
202
203
# File 'lib/hts/bcf/header.rb', line 201

def remove_contig(id)
  delete("CONTIG", id.to_s).tap { sync_if_needed! }
end

#remove_filter(id) ⇒ Object



211
212
213
# File 'lib/hts/bcf/header.rb', line 211

def remove_filter(id)
  delete("FILTER", id.to_s).tap { sync_if_needed! }
end

#remove_format(id) ⇒ Object



241
242
243
# File 'lib/hts/bcf/header.rb', line 241

def remove_format(id)
  delete("FORMAT", id.to_s).tap { sync_if_needed! }
end

#remove_info(id) ⇒ Object



226
227
228
# File 'lib/hts/bcf/header.rb', line 226

def remove_info(id)
  delete("INFO", id.to_s).tap { sync_if_needed! }
end

#samplesObject



86
87
88
89
90
91
# File 'lib/hts/bcf/header.rb', line 86

def samples
  # bcf_hdr_id2name is macro function
  @bcf_hdr[:samples]
    .read_array_of_pointer(nsamples)
    .map(&:read_string)
end

#seqnamesObject



255
256
257
258
259
260
261
262
263
264
# File 'lib/hts/bcf/header.rb', line 255

def seqnames
  n = FFI::MemoryPointer.new(:int)
  names = LibHTS.bcf_hdr_seqnames(@bcf_hdr, n)
  begin
    names.read_array_of_pointer(n.read_int)
         .map(&:read_string)
  ensure
    LibHTS.hts_free(names) unless names.null?
  end
end

#set_version(version) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/hts/bcf/header.rb', line 57

def set_version(version)
  rc = LibHTS.bcf_hdr_set_version(@bcf_hdr, version)
  raise "Failed to set VCF header version" if rc.negative?

  mark_sync_needed!
  sync_if_needed!
  self
end

#structObject



45
46
47
# File 'lib/hts/bcf/header.rb', line 45

def struct
  @bcf_hdr
end

#subset(samples) ⇒ Object

Raises:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/hts/bcf/header.rb', line 107

def subset(samples)
  subset_samples = normalize_subset_samples(samples)
  validate_subset_samples!(subset_samples)

  sample_pointers = nil
  imap_pointer = nil
  if subset_samples.empty?
    subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, 0, ::FFI::Pointer::NULL, ::FFI::Pointer::NULL)
  else
    encoded_samples = subset_samples.map { |name| FFI::MemoryPointer.from_string(name) }
    sample_pointers = FFI::MemoryPointer.new(:pointer, subset_samples.length)
    sample_pointers.write_array_of_pointer(encoded_samples)
    imap_pointer = FFI::MemoryPointer.new(:int, subset_samples.length)
    subset_hdr = LibHTS.bcf_hdr_subset(@bcf_hdr, subset_samples.length, sample_pointers, imap_pointer)
  end

  raise SubsetError, "Failed to subset BCF header samples #{subset_samples.inspect}" if subset_hdr.to_ptr.null?

  composed_imap = compose_subset_imap(read_subset_imap(imap_pointer, subset_samples.length))
  self.class.new(subset_hdr).tap do |header|
    header.send(:set_subset_state, subset_samples, composed_imap)
  end
end

#subset?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/hts/bcf/header.rb', line 95

def subset?( )
  !@subset_imap.nil?
end

#subset_imap_pointerObject



103
104
105
# File 'lib/hts/bcf/header.rb', line 103

def subset_imap_pointer
  @subset_imap_pointer
end

#subset_sample_countObject



99
100
101
# File 'lib/hts/bcf/header.rb', line 99

def subset_sample_count
  subset? ? @subset_samples.length : 0
end

#syncObject



149
150
151
152
153
154
155
# File 'lib/hts/bcf/header.rb', line 149

def sync
  rc = LibHTS.bcf_hdr_sync(@bcf_hdr)
  raise "Failed to sync BCF header" if rc.negative?

  @sync_needed = false
  self
end

#target_countObject



70
71
72
# File 'lib/hts/bcf/header.rb', line 70

def target_count
  target_names.size
end

#target_name(rid) ⇒ Object



78
79
80
# File 'lib/hts/bcf/header.rb', line 78

def target_name(rid)
  id2name(rid)
end

#target_namesObject



82
83
84
# File 'lib/hts/bcf/header.rb', line 82

def target_names
  seqnames
end

#to_ptrObject



49
50
51
# File 'lib/hts/bcf/header.rb', line 49

def to_ptr
  @bcf_hdr.to_ptr
end

#to_sObject



266
267
268
269
270
271
272
273
274
275
# File 'lib/hts/bcf/header.rb', line 266

def to_s
  kstr = LibHTS::KString.new
  begin
    raise "Failed to get header string" unless LibHTS.bcf_hdr_format(@bcf_hdr, 0, kstr)

    kstr.read_string_copy
  ensure
    kstr.free_buffer
  end
end

#update_format(id, number:, type:, description:, **attributes) ⇒ Object



236
237
238
239
# File 'lib/hts/bcf/header.rb', line 236

def update_format(id, number:, type:, description:, **attributes)
  delete("FORMAT", id.to_s)
  add_format(id, number:, type:, description:, **attributes)
end

#update_info(id, number:, type:, description:, **attributes) ⇒ Object



221
222
223
224
# File 'lib/hts/bcf/header.rb', line 221

def update_info(id, number:, type:, description:, **attributes)
  delete("INFO", id.to_s)
  add_info(id, number:, type:, description:, **attributes)
end