class BFA::Writer

Public Class Methods

encode(filename, rgfa, compressed=true) click to toggle source
# File lib/bfa/writer.rb, line 32
def self.encode(filename, rgfa, compressed=true)
  bw = self.new(filename, compressed)
  bw.encode(rgfa)
  bw.close
  return nil
end
new(filename, compressed=true) click to toggle source

@return [RGFATools::BFAWriter]

# File lib/bfa/writer.rb, line 12
def initialize(filename, compressed=true)
  @template = ""
  @data = []
  file = File.new(filename, "w")
  @io = compressed ? Zlib::GzipWriter.new(file) : file
  @io.print BFA::Constants::MAGIC_STRING
end

Public Instance Methods

close() click to toggle source
# File lib/bfa/writer.rb, line 28
def close
  @io.close
end
encode(rgfa) click to toggle source
# File lib/bfa/writer.rb, line 20
def encode(rgfa)
  add_headers(rgfa)
  add_segments(rgfa)
  add_links(rgfa)
  add_containments(rgfa)
  add_paths(rgfa)
end

Private Instance Methods

add_byte_array(array) click to toggle source
# File lib/bfa/writer.rb, line 209
def add_byte_array(array)
  array = array.parse_datastring(:H) if array.kind_of?(String)
  array = array.to_byte_array
  add_numeric_values(:C, array)
end
add_cigar(cigar) click to toggle source
# File lib/bfa/writer.rb, line 181
def add_cigar(cigar)
  cigar = cigar.to_cigar
  if cigar.empty?
    add_numeric_value(:I, 0)
  else
    add_numeric_values(:I, cigar.map(&:to_binary))
  end
end
add_containments(rgfa) click to toggle source
# File lib/bfa/writer.rb, line 69
def add_containments(rgfa)
  add_edges(rgfa, true)
end
add_cstr(string) click to toggle source
# File lib/bfa/writer.rb, line 224
def add_cstr(string)
  # <assert> string.kind_of?(String) or string.kind_of?(Symbol)
  add_string(string.to_s + "\0")
end
add_data_item(datatype, value) click to toggle source

Add a value to the record @param value [Object|String] a ruby object or its rgfa datastring

representation

@param datatype [RGFA::Line::FIELD_DATATYPE] the datatype of the data @return [void]

# File lib/bfa/writer.rb, line 150
def add_data_item(datatype, value)
  # <assert> RGFA::Line::FIELD_DATATYPE.include?(datatype)
  case datatype
  when :A
    add_fixlenstr(value)
  when :Z
    add_cstr(value)
  when :J
    value = value.to_gfa_datastring(:J) if value.kind_of?(String)
    add_cstr(value)
  when :i
    add_int(value)
  when :f
    add_double(value)
  when :B
    add_numeric_array(value)
  when :H
    add_byte_array(value)
  end
  return nil
end
add_double(float) click to toggle source
# File lib/bfa/writer.rb, line 197
def add_double(float)
  add_numeric_value(:f, Float(float))
end
add_edges(rgfa, containments=false) click to toggle source
# File lib/bfa/writer.rb, line 77
def add_edges(rgfa, containments=false)
  add_size_of(containments ? rgfa.containments : rgfa.links)
  sn = rgfa.segment_names
  link_id = 0
  sn.each_with_index do |segment_name, segment_id|
    if containments
      edges = rgfa.contained_in(segment_name)
    else
      edges = [:+, :-].map do |orientation|
        rgfa.links_from([segment_name, orientation], false)
      end.flatten
    end
    edges.each do |edge|
      dir_id = {:from => segment_id,
                :to => rgfa.segment(edge.to).line_id}
      [:from, :to].each do |dir|
        dir_id[dir] += 1
        dir_id[dir] = -dir_id[dir] if edge.get(:"#{dir}_orient") == :-
        add_numeric_value(:i, dir_id[dir])
      end
      add_cigar(edge.overlap)
      add_numeric_value(:I, edge.pos) if containments
      add_optfields(edge)
      write_data
      if not containments
        edge.line_id = link_id
        link_id += 1
      end
    end
  end
end
add_fixlenstr(string) click to toggle source
# File lib/bfa/writer.rb, line 215
def add_fixlenstr(string)
  add_string(string)
end
add_headers(rgfa) click to toggle source
# File lib/bfa/writer.rb, line 41
def add_headers(rgfa)
  headers_array = rgfa.header.tags
  add_size_of(headers_array)
  headers_array.each do |fieldname, val_type, value|
    add_optfield(fieldname, value, val_type)
  end
  write_data
end
add_int(int) click to toggle source
# File lib/bfa/writer.rb, line 190
def add_int(int)
  int = Integer(int)
  int_type = RGFA::NumericArray.integer_type(int..int)
  replace_fixlenstr(int_type)
  add_numeric_value(RGFA::NumericArray.integer_type(int..int).to_sym, int)
end
add_numeric_array(array) click to toggle source
# File lib/bfa/writer.rb, line 201
def add_numeric_array(array)
  array = array.parse_datastring(:B) if array.kind_of?(String)
  array = array.to_numeric_array
  st = array.compute_subtype
  add_fixlenstr(st)
  add_numeric_values(st.to_sym, array)
end
add_numeric_value(val_type, number) click to toggle source
# File lib/bfa/writer.rb, line 242
def add_numeric_value(val_type, number)
  # <assert> NUMERIC_TEMPLATE_CODE.has_key?(val_type)
  # <assert> number.kind_of?(Numeric)
  add_value(NUMERIC_TEMPLATE_CODE[val_type], number)
end
add_numeric_values(val_type, array, with_size = true) click to toggle source
# File lib/bfa/writer.rb, line 248
def add_numeric_values(val_type, array, with_size = true)
  # <assert> NUMERIC_TEMPLATE_CODE.has_key?(val_type)
  # <assert> array.kind_of?(Array)
  # <assert> array.each? {|e| e.kind_of?(Numeric)}
  add_size_of(array) if with_size
  add_values(NUMERIC_TEMPLATE_CODE[val_type], array)
end
add_optfield(fieldname, value, val_type) click to toggle source

Add an optional field to the record

# File lib/bfa/writer.rb, line 132
def add_optfield(fieldname, value, val_type)
  val_type ||= value.gfa_datatype
  add_fixlenstr(fieldname)
  add_fixlenstr(val_type)
  add_data_item(val_type, value)
end
add_optfields(rgfa_line) click to toggle source
# File lib/bfa/writer.rb, line 50
def add_optfields(rgfa_line)
  add_size_of(rgfa_line.optional_fieldnames)
  rgfa_line.optional_fieldnames.each do |of|
    add_optfield(of, rgfa_line.get(of), rgfa_line.get_datatype(of))
  end
end
add_paths(rgfa) click to toggle source
# File lib/bfa/writer.rb, line 109
def add_paths(rgfa)
  add_size_of(rgfa.paths)
  rgfa.paths.each do |path|
    add_varlenstr(path.path_name)
    links = path.links
    # <debug> "Path links: #{links.inspect}"
    n_links = links.size
    n_links = -n_links if path.circular?
    add_numeric_value(:i, n_links)
    link_ids = links.map do |link, link_or|
      line_id = link.line_id + 1
      # <debug> "line_id: #{line_id.inspect}"
      # <debug> "link_or: #{link_or.inspect}"
      link_or ? line_id : -line_id
    end
    # <debug> "link ids: #{link_ids.inspect}"
    add_numeric_values(:i, link_ids, false)
    add_optfields(path)
    write_data
  end
end
add_segments(rgfa) click to toggle source
# File lib/bfa/writer.rb, line 57
def add_segments(rgfa)
  add_size_of(rgfa.segment_names)
  rgfa.segment_names.each_with_index do |segment_name, i|
    s = rgfa.segment!(segment_name)
    add_varlenstr(segment_name)
    add_sequence(s.sequence)
    add_optfields(s)
    write_data
    s.line_id = i
  end
end
add_sequence(seq) click to toggle source
# File lib/bfa/writer.rb, line 172
def add_sequence(seq)
  if seq == "*"
    add_numeric_value(:I, 0)
  else
    add_size_of(seq)
    add_values(NUMERIC_TEMPLATE_CODE[:C], seq.to_4bits)
  end
end
add_size_of(object) click to toggle source
# File lib/bfa/writer.rb, line 256
def add_size_of(object)
  # <assert> object.kind_of?(Array) or object.kind_of?(String)
  add_value(SIZEOF_TEMPLATE_CODE, object.size)
end
add_string(string) click to toggle source
# File lib/bfa/writer.rb, line 235
def add_string(string)
  # <assert> string.kind_of?(String) or string.kind_of?(Symbol)
  # <assert> string.size > 0
  string = string.to_s
  add_value("Z#{string.size}", string)
end
add_value(template, value) click to toggle source
# File lib/bfa/writer.rb, line 261
def add_value(template, value)
  # <assert> value.kind_of?(String) or value.kind_of?(Numeric)
  @template << template
  @data << value
end
add_values(template, array) click to toggle source
# File lib/bfa/writer.rb, line 267
def add_values(template, array)
  # <assert> array.kind_of?(Array)
  @template += (template + array.size.to_s)
  @data += array
end
add_varlenstr(string) click to toggle source
# File lib/bfa/writer.rb, line 229
def add_varlenstr(string)
  # <assert> string.kind_of?(String) or string.kind_of?(Symbol)
  add_size_of(string.to_s)
  add_string(string)
end
replace_fixlenstr(string) click to toggle source
# File lib/bfa/writer.rb, line 219
def replace_fixlenstr(string)
  # <assert> @data.last.size == string.size
  @data.last.replace(string)
end
write_data() click to toggle source
# File lib/bfa/writer.rb, line 139
def write_data
  @io.print(@data.pack(@template))
  @template = ""
  @data = []
end