class SpeakyCsv::AttrImport

Imports a csv file as attribute hashes.

Attributes

logger[RW]

Public Class Methods

new(config, input_io) click to toggle source
# File lib/speaky_csv/attr_import.rb, line 11
def initialize(config, input_io)
  @config = config
  @input_io = input_io
  @log_output = StringIO.new
  @logger = Logger.new @log_output
end

Public Instance Methods

each() { |a| ... } click to toggle source

Yields successive attribute hashes for rows in the csv file

# File lib/speaky_csv/attr_import.rb, line 19
def each
  block_given? ? enumerator.each { |a| yield a } : enumerator
end
log() click to toggle source

Returns a string of all the log output from the import. Or returns nothing if a custom logger was used.

# File lib/speaky_csv/attr_import.rb, line 25
def log
  @log_output.string
end

Private Instance Methods

add_fields(row, attrs) click to toggle source

Adds configured fields to attrs

# File lib/speaky_csv/attr_import.rb, line 66
def add_fields(row, attrs)
  fields = (@config.fields - @config.export_only_fields).map(&:to_s)
  fields.each do |name|
    row.has_key? name or next
    attrs[name] = row.field name
  end
end
add_has_manys(row, attrs) click to toggle source

Adds configured has manys to attrs

# File lib/speaky_csv/attr_import.rb, line 75
def add_has_manys(row, attrs)
  headers_length = row.headers.compact.length
  pairs_start_on_evens = headers_length.even?
  (headers_length..row.fields.length).each do |i|
    i.send(pairs_start_on_evens ? :even? : :odd?) || next
    row[i] || next

    m = row[i].match(/^(\w+)_(\d+)_(\w+)$/)
    m || next
    has_many_name = m[1].pluralize
    has_many_index = m[2].to_i
    has_many_field = m[3]
    has_many_value = row[i + 1]

    has_many_config = @config.has_manys[has_many_name.to_sym]

    next unless has_many_config
    next unless has_many_config.fields.include?(has_many_field.to_sym)
    next if has_many_config.export_only_fields.include?(has_many_field.to_sym)

    attrs[has_many_name] ||= []
    attrs[has_many_name][has_many_index] ||= {}
    attrs[has_many_name][has_many_index][has_many_field] = has_many_value
  end
end
add_has_ones(row, attrs) click to toggle source

Adds configured has ones to attrs

# File lib/speaky_csv/attr_import.rb, line 102
def add_has_ones(row, attrs)
  @config.has_ones.each do |name,assoc_config|
    fields = (assoc_config.fields - assoc_config.export_only_fields).map(&:to_s)
    fields.each do |f|
      csv_name = "#{name}_#{f}"
      row.has_key? csv_name or next
      (attrs[name.to_s] ||= {})[f] = row.field "#{name}_#{f}"
    end
  end
end
enumerator() click to toggle source
# File lib/speaky_csv/attr_import.rb, line 31
def enumerator
  return @enumerator if defined? @enumerator

  @enumerator = Enumerator.new do |yielder|
    begin
      csv = CSV.new @input_io, headers: true

      csv.each do |row|
        attrs = {}
        validate_headers row
        add_fields row, attrs
        add_has_manys row, attrs
        add_has_ones row, attrs
        yielder << attrs
      end

    rescue CSV::MalformedCSVError
      logger.error "csv is malformed: #{$ERROR_INFO.message}"
    end
  end
end
validate_headers(row) click to toggle source

TODO: don't warn on has_one headers and clean up clunky loop

# File lib/speaky_csv/attr_import.rb, line 54
def validate_headers(row)
  valid_headers = @config.fields - @config.export_only_fields
  #valid_headers += @config.has_ones.map

  row.headers.compact.map(&:to_sym).each do |h|
    unless valid_headers.include?(h)
      logger.warn "ignoring unknown column #{h}"
    end
  end
end