Module: SmarterCSV::HeaderTransformations

Included in:
Reader
Defined in:
lib/smarter_csv/header_transformations.rb

Instance Method Summary collapse

Instance Method Details

#disambiguate_headers(headers, options) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/smarter_csv/header_transformations.rb', line 28

def disambiguate_headers(headers, options)
  counts = Hash.new(0)
  prefix = options[:missing_header_prefix] || 'column_'
  # Pre-collect non-blank header names so auto-generated names can avoid collisions.
  used = headers.reject { |h| blank?(h) }
  headers.each_with_index.map do |header, idx|
    if blank?(header)
      # Use absolute 1-based column position, consistent with how extra data columns
      # beyond the header count are named. If the positional name collides with an
      # existing header, append underscores until a free name is found — this avoids
      # stealing the positional name from any subsequent blank header.
      candidate = "#{prefix}#{idx + 1}"
      suffix = ''
      while used.include?(candidate)
        suffix += '_'
        candidate = "#{prefix}#{idx + 1}#{suffix}"
      end
      used << candidate
      candidate
    else
      counts[header] += 1
      counts[header] > 1 ? "#{header}#{options[:duplicate_header_suffix]}#{counts[header]}" : header
    end
  end
end

#header_transformations(header_array, options) ⇒ Object

transform the headers that were in the file:



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/smarter_csv/header_transformations.rb', line 6

def header_transformations(header_array, options)
  header_array.map!{|x| x.gsub(%r/#{options[:quote_char]}/, '')}
  header_array.map!{|x| x.strip} if options[:strip_whitespace]

  unless options[:keep_original_headers]
    # Normalize whitespace-only headers to "" before gsub so they are treated as
    # blank/missing by disambiguate_headers rather than converted to "_".
    header_array.map!{|x| blank?(x) ? '' : x} unless options[:strip_whitespace]
    header_array.map!{|x| x.gsub(/\s+|-+/, '_')}
    header_array.map!{|x| x.downcase} if options[:downcase_header]
  end

  # detect duplicate headers and disambiguate
  header_array = disambiguate_headers(header_array, options) if options[:duplicate_header_suffix]
  # symbolize headers
  header_array = header_array.map{|x| x.to_sym } unless options[:strings_as_keys] || options[:keep_original_headers]
  # doesn't make sense to re-map when we have user_provided_headers
  header_array = remap_headers(header_array, options) if options[:key_mapping]

  header_array
end

#remap_headers(headers, options) ⇒ Object

do some key mapping on the keys in the file header if you want to completely delete a key, then map it to nil or to ”



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/smarter_csv/header_transformations.rb', line 56

def remap_headers(headers, options)
  key_mapping = options[:key_mapping]
  if key_mapping.empty? || !key_mapping.is_a?(Hash) || key_mapping.keys.empty?
    raise(SmarterCSV::IncorrectOption, "ERROR: incorrect format for key_mapping! Expecting hash with from -> to mappings")
  end

  key_mapping = options[:key_mapping]
  # if silence_missing_keys are not set, raise error if missing header
  missing_keys = key_mapping.keys - headers
  # if the user passes a list of speciffic mapped keys that are optional
  missing_keys -= options[:silence_missing_keys] if options[:silence_missing_keys].is_a?(Array)

  unless missing_keys.empty? || options[:silence_missing_keys] == true
    raise SmarterCSV::KeyMappingError, "ERROR: can not map headers: #{missing_keys.join(', ')}"
  end

  headers.map! do |header|
    if key_mapping.has_key?(header)
      key_mapping[header].nil? ? nil : key_mapping[header]
    elsif options[:remove_unmapped_keys]
      nil
    else
      header
    end
  end
  headers
end