Class: HTS::Bam::BaseMod

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/hts/bam/base_mod.rb

Overview

Note:

BaseMod is a view object that references data in a Record. The state is maintained in hts_base_mod_state structure.

Base modification information from MM/ML tags

This class provides access to DNA/RNA base modifications such as methylation. It wraps the htslib base modification API and provides a Ruby-friendly interface.

Defined Under Namespace

Classes: Modification, NotParsedError, Position

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(record, auto_parse: true) ⇒ BaseMod

Initialize a new BaseMod object

Parameters:

  • record (Record)

    The BAM record to extract modifications from

  • auto_parse (Boolean) (defaults to: true)

    If true, parse MM/ML lazily on first access



134
135
136
137
138
139
140
# File 'lib/hts/bam/base_mod.rb', line 134

def initialize(record, auto_parse: true)
  @record = record
  @state = Native::BaseModHandle.open(record.__send__(:native_handle))
  @closed = false
  @auto_parse = !!auto_parse
  @parsed = false
end

Instance Attribute Details

#recordObject (readonly)

Returns the value of attribute record.



17
18
19
# File 'lib/hts/bam/base_mod.rb', line 17

def record
  @record
end

Instance Method Details

#[](position) ⇒ Position?

Array-style access to modifications at a position

Parameters:

  • position (Integer)

    Query position (0-based)

Returns:

  • (Position, nil)

    Position object with modifications, or nil if none



198
199
200
# File 'lib/hts/bam/base_mod.rb', line 198

def [](position)
  at_pos(position)
end

#at_pos(position, max_mods: 10) ⇒ Position?

Get modification information at a specific query position

Parameters:

  • position (Integer)

    Query position (0-based)

  • max_mods (Integer) (defaults to: 10)

    Maximum number of modifications to retrieve

Returns:

  • (Position, nil)

    Position object with modifications, or nil if none



185
186
187
188
189
190
191
192
193
# File 'lib/hts/bam/base_mod.rb', line 185

def at_pos(position, max_mods: 10)
  # Reset state to ensure deterministic results even after prior iteration
  parsed? ? parse : ensure_parsed!

  values = @state.at(position, max_mods)
  return nil unless values

  build_position(position, values)
end

#closevoid

This method returns an undefined value.

Explicitly free the state



144
145
146
147
148
149
150
# File 'lib/hts/bam/base_mod.rb', line 144

def close
  return if @closed

  @state.close
  @state = nil
  @closed = true
end

#each_position(max_mods: 10) {|Position| ... } ⇒ Enumerator Also known as: each

Iterate over all positions with modifications

Parameters:

  • max_mods (Integer) (defaults to: 10)

    Maximum number of modifications per position

Yields:

  • (Position)

    Position object for each modified position

Returns:

  • (Enumerator)

    If no block given



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/hts/bam/base_mod.rb', line 206

def each_position(max_mods: 10)
  return enum_for(__method__, max_mods: max_mods) unless block_given?

  current_position = nil
  modifications = []
  each_raw(max_mods: max_mods) do |position, canonical, modified, strand, qual|
    if current_position && position != current_position
      yield Position.new(current_position, modifications)
      modifications = []
    end
    current_position = position
    modifications << Modification.new(
      modified_base: modified, canonical_base: canonical,
      strand: strand, qual: qual
    )
  end
  yield Position.new(current_position, modifications) if current_position
  self
end

#each_raw(max_mods: 10) ⇒ Object

Iterate primitive modification values without Position/Modification object allocation.



230
231
232
233
234
235
236
# File 'lib/hts/bam/base_mod.rb', line 230

def each_raw(max_mods: 10)
  return enum_for(__method__, max_mods: max_mods) unless block_given?

  parsed? ? parse : ensure_parsed!
  @state.each_raw(max_mods) { |*values| yield(*values) }
  self
end

#ensure_parsed!(flags = 0) ⇒ void

This method returns an undefined value.

Ensure MM/ML have been parsed, performing lazy parse if enabled.

Parameters:

  • flags (Integer) (defaults to: 0)

Raises:



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

def ensure_parsed!(flags = 0)
  return if @parsed

  raise NotParsedError, "BaseMod is not parsed. Call #parse first (auto_parse is disabled)." unless @auto_parse

  parse(flags)
end

#inspectString

Inspect string

Returns:

  • (String)

    Inspect string



288
289
290
# File 'lib/hts/bam/base_mod.rb', line 288

def inspect
  to_s
end

#modification_typesArray<Integer> Also known as: recorded_types

Get list of modification types present in this record

Returns:

  • (Array<Integer>)

    Array of modification codes (char code or -ChEBI)



240
241
242
243
244
# File 'lib/hts/bam/base_mod.rb', line 240

def modification_types
  ensure_parsed!

  @state.types
end

#parse(flags = 0) ⇒ Integer

Parse MM and ML tags from the record

Parameters:

  • flags (Integer) (defaults to: 0)

    Parsing flags (default: 0)

Returns:

  • (Integer)

    Number of modification types found, or -1 on error

Raises:

  • (Error)

    If parsing fails



173
174
175
176
177
178
179
# File 'lib/hts/bam/base_mod.rb', line 173

def parse(flags = 0)
  ret = @state.parse(flags)
  raise Error, "Failed to parse base modifications" if ret < 0

  @parsed = true
  ret
end

#parsed?Boolean

Whether this object has parsed MM/ML tags already

Returns:

  • (Boolean)


154
155
156
# File 'lib/hts/bam/base_mod.rb', line 154

def parsed?
  @parsed
end

#query_type(code) ⇒ Hash?

Query information about a specific modification type by code

Parameters:

  • code (Integer, String)

    Modification code (char code or -ChEBI, or single char string)

Returns:

  • (Hash, nil)

    Hash with canonical, strand, implicit info, or nil if not found



251
252
253
254
255
256
257
# File 'lib/hts/bam/base_mod.rb', line 251

def query_type(code)
  ensure_parsed!

  code = code.ord if code.is_a?(String)

  @state.query(code)
end

#query_type_at(index) ⇒ Hash?

Query information about i-th modification type

Parameters:

  • index (Integer)

    Modification type index (0-based)

Returns:

  • (Hash, nil)

    Hash with code, canonical, strand, implicit info



262
263
264
265
266
# File 'lib/hts/bam/base_mod.rb', line 262

def query_type_at(index)
  ensure_parsed!

  @state.query_at(index)
end

#to_aArray<Position>

Get all modifications as an array

Returns:

  • (Array<Position>)

    Array of all positions with modifications



270
271
272
# File 'lib/hts/bam/base_mod.rb', line 270

def to_a
  each_position.to_a
end

#to_sString

String representation for debugging

Returns:

  • (String)

    String representation



276
277
278
279
280
281
282
283
284
# File 'lib/hts/bam/base_mod.rb', line 276

def to_s
  return "#<HTS::Bam::BaseMod (not parsed)>" unless @parsed

  mods = []
  each_position do |pos|
    mods << pos.to_s
  end
  "#<HTS::Bam::BaseMod #{mods.join(' ')}>"
end