class Bibliothecary::MultiParsers::DependenciesCSV::CSVFile

Processing a CSV file isn’t as exact as using a real manifest file, but you can get pretty close as long as the data you’re importing is simple.

Constants

HEADERS

Header structures are:

<field to fill in for dependency> => {

match: [<regexp of incoming column name to match in priority order, highest priority first>...],
[default]: <optional default value for this field>

}

Attributes

result[R]

Public Class Methods

new(file_contents) click to toggle source
# File lib/bibliothecary/multi_parsers/dependencies_csv.rb, line 69
def initialize(file_contents)
  @file_contents = file_contents

  @result = nil

  # A Hash of "our field name" => ["header in CSV file", "lower priority header in CSV file"]
  @header_mappings = {}
end

Public Instance Methods

parse!() click to toggle source
# File lib/bibliothecary/multi_parsers/dependencies_csv.rb, line 78
def parse!
  table = parse_and_validate_csv_file

  @result = table.map.with_index do |row, idx|
    HEADERS.each_with_object({}) do |(header, info), obj|
      # find the first non-empty field in the row for this header, or nil if not found
      row_data = row[@header_mappings[header]]

      # some column have default data to fall back on
      if row_data
        obj[header.to_sym] = row_data
      elsif info.has_key?(:default)
        # if the default is nil, don't even add the key to the hash
        obj[header.to_sym] = info[:default] if info[:default]
      else
        # use 1-based index just like the 'csv' std lib, and count the headers as first row.
        raise "Missing required field '#{header}' on line #{idx + 2}."
      end
    end
  end
end

Private Instance Methods

map_table_headers_to_local_lookups(table, local_lookups) click to toggle source
# File lib/bibliothecary/multi_parsers/dependencies_csv.rb, line 114
def map_table_headers_to_local_lookups(table, local_lookups)
  result = local_lookups.each_with_object({ found: {}, missing: [] }) do |(header, info), obj|
    results = table.headers.each_with_object([]) do |table_header, matches|
      info[:match].each_with_index do |match_regexp, index|
        matches << [table_header, index] if table_header[match_regexp]
      end
    end

    if results.empty?
      # if a header has a default value it's optional
      obj[:missing] << header unless info.has_key?(:default)
    else
      # select the highest priority header possible
      obj[:found][header] ||= nil
      obj[:found][header] = ([obj[:found][header]] + results).compact.min_by(&:last)
    end
  end

  # strip off the priorities. only one mapping should remain.
  result[:found].transform_values!(&:first)

  result
end
parse_and_validate_csv_file() click to toggle source
# File lib/bibliothecary/multi_parsers/dependencies_csv.rb, line 102
def parse_and_validate_csv_file
  table = CSV.parse(@file_contents, headers: true)

  header_examination_results = map_table_headers_to_local_lookups(table, HEADERS)
  unless header_examination_results[:missing].empty?
    raise "Missing required headers #{header_examination_results[:missing].join(', ')} in CSV. Check to make sure header names are all lowercase."
  end
  @header_mappings = header_examination_results[:found]

  table
end