class BlueButtonParser

Constants

ALWAYS_SKIP_LINES
DEFAULT_CONFIG

Attributes

config[R]
data[R]
text[R]

Public Class Methods

new(bb_data_text, config=DEFAULT_CONFIG, newline="\n") click to toggle source
# File lib/blue_button_parser.rb, line 82
def initialize(bb_data_text, config=DEFAULT_CONFIG, newline="\n")
  @text = bb_data_text
  @config= config
  @data = parse_text(@text, newline)
end

Private Instance Methods

column_widths(line, columns) click to toggle source
# File lib/blue_button_parser.rb, line 207
def column_widths(line, columns)
  columns.collect{|c| line.index(c)}
end
get_key_values(line, current_section) click to toggle source
# File lib/blue_button_parser.rb, line 168
def get_key_values(line, current_section)
  key_values = get_multi_key_values(line, current_section) 
  key_values = get_single_key_value(line) if key_values.nil?            
  return key_values
end
get_multi_key_values(line, current_section) click to toggle source
# File lib/blue_button_parser.rb, line 132
def get_multi_key_values(line, current_section)
  key_values = nil

  if key_sets = sect_config(current_section, :same_line_keys)
    unless key_sets.first.is_a?(Array)
      key_sets = [key_sets]
    end
    
    key_sets.each do |keys|
      regexp_str = keys.collect{|k| "#{k}: (.*)"}.join
      regexp = Regexp.new(regexp_str)
      if keys_match = line.match(regexp)
        key_values = Hash.new
        keys.each_with_index do |key, index|
          key_values[key] = keys_match[index + 1]
        end
        break
      end
    end
  end
  
  return key_values
end
get_single_key_value(line) click to toggle source
# File lib/blue_button_parser.rb, line 156
def get_single_key_value(line)    
  if key_match = line.match(/(.*)\: (.*)?/) 
    key_values = {key_match[1] => key_match[2]}
  elsif key_match = line.match(/(.*):$/)
    key_values = {key_match[1] => nil}
  else
    key_values = nil      
  end

  return key_values
end
key_ended?(line) click to toggle source
# File lib/blue_button_parser.rb, line 174
def key_ended?(line)
  # either an empty line or a line starting with a key (e.g. "Status:") means we're done with multi-line
  line.empty? or line.match(/^\S(.*): (\S*)/)
end
new_collection?(line, last_line, current_section) click to toggle source
# File lib/blue_button_parser.rb, line 96
def new_collection?(line, last_line, current_section)
  new_collection = nil

  if collections = sect_config(current_section, :collection)
    collections.each_pair do |name, collection_config|  
      if starts_with = collection_config[:item_starts_with]
        if line.match(Regexp.new("^#{starts_with}:"))
          new_collection = name
          break
        end
      elsif table_columns = collection_config[:table_columns]
        new_table = false
        
        if table_starts_with = collection_config[:table_starts_with]
          if last_line.match(Regexp.new("^#{table_starts_with}"))
            new_table = true
          end
        else
          new_table = true
        end
    
        if new_table
          regexp_str = ".?#{table_columns.join('.*')}.?"
          if line.match(Regexp.new(regexp_str))
            new_collection = name
            break
          end
        end
        
      end
    end
  end
  
  return new_collection
end
new_section?(line) click to toggle source
# File lib/blue_button_parser.rb, line 90
def new_section?(line)
  new_section = line.match(/^[-]+ (.*) [-]+/) 
  new_section = new_section[1] if new_section     
  return new_section
end
parse_table_line(line, columns, column_widths) click to toggle source
# File lib/blue_button_parser.rb, line 187
def parse_table_line(line, columns, column_widths)
  row = Hash.new
  columns.each_with_index do |column, index|
    start = column_widths[index]
    finish = if index == column_widths.size - 1
        line.size
      else
        column_widths[index + 1]
      end
    val_str = (line[start, finish-start]).strip
    val_str = val_str.empty? ? nil : val_str
    row[column] = val_str
  end
  return row
end
parse_text(text, newline="\n") click to toggle source
# File lib/blue_button_parser.rb, line 211
def parse_text(text, newline="\n")    
  # parse text line by line
  lines = text.split(newline)

  # state variables
  current_section = nil    
  current_collection = nil
  current_key = nil
  current_table = nil
  
  # put parsed data into this hash
  data = Hash.new    
  
  # start parsing
  lines.each_with_index do |line, index|
    skip_regexps = (ALWAYS_SKIP_LINES + (sect_config(current_section, :skip_lines) || [])).compact
    skip_regexps = skip_regexps.collect{|r| Regexp.new(r)}
    next if skip_regexps.find{|re| re.match(line)}
    
    if collection = new_collection?(line, lines[index - 1], current_section)
      current_collection = collection
      current_key = nil
      data[current_section][current_collection] ||= []
      if columns = table_columns(current_section, current_collection)
        current_table = {:columns => columns, :widths => column_widths(line, columns)}
        next
      else
        data[current_section][current_collection] << Hash.new
      end
    end

    if key_ended?(line)
      current_key = nil
    end

    if current_section and current_key
      value = line.rstrip
      if current_collection.nil?
        data[current_section][current_key] = [data[current_section][current_key], value].compact.join(" \n")
      else
        (data[current_section][current_collection].last)[current_key] = [(data[current_section][current_collection].last)[current_key], value].compact.join(" \n")
      end
    end
    
    if section = new_section?(line)
      current_section = section        
      current_collection = nil
      data[current_section] ||= {}
    elsif current_table
      if line.empty?
        current_collection = nil
        current_table = nil
      else
        data[current_section][current_collection] << parse_table_line(line, current_table[:columns], current_table[:widths])
      end
    elsif (!current_key and current_section and key_values = get_key_values(line, current_section))
      key_values.each_pair do |key, value|
        val = (value.nil? or value.strip.empty?) ? nil : value.strip #empty strings should be converted to nils
        if current_collection.nil?
          data[current_section][key] = val
        else
          (data[current_section][current_collection].last)[key] = val
        end
        current_key = key
      end
    end
  end

  return data
end
sect_config(current_section, key) click to toggle source
# File lib/blue_button_parser.rb, line 179
def sect_config(current_section, key)
  if @config[current_section]
    @config[current_section][key]
  else
    nil
  end
end
table_columns(current_section, current_collection) click to toggle source
# File lib/blue_button_parser.rb, line 203
def table_columns(current_section, current_collection)
  sect_config(current_section, :collection)[current_collection][:table_columns]
end