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