Module: SmarterCSV::Headers

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

Instance Method Summary collapse

Instance Method Details

#process_headers(filehandle, options) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/smarter_csv/headers.rb', line 5

def process_headers(filehandle, options)
  @raw_header = nil # header as it appears in the file
  @headers = nil # the processed headers
  header_array = []
  file_header_size = nil

  # if headers_in_file, get the headers -> We get the number of columns, even when user provided headers
  if options[:headers_in_file] # extract the header line
    # process the header line in the CSV file..
    # the first line of a CSV file contains the header .. it might be commented out, so we need to read it anyhow
    header_line = @raw_header = next_line_with_counts(filehandle, options)
    header_line = preprocess_header_line(header_line, options) unless header_line.nil?
    raise SmarterCSV::EmptyFileError, "Empty CSV file" if blank?(header_line)

    file_header_array, file_header_size = parse(header_line, options)

    # A quoted header containing an embedded newline is stitched across physical lines,
    # the same way data rows are (the parser signals an unclosed quoted field with
    # size -1). The embedded newline then becomes '_' via the header transformations.
    while file_header_size == -1
      next_line = filehandle.gets(options[:row_sep])
      raise SmarterCSV::MalformedCSV, "Unclosed quoted field detected in the header" if next_line.nil?

      @file_line_count += 1
      @raw_header += next_line
      header_line = preprocess_header_line(@raw_header, options)
      file_header_array, file_header_size = parse(header_line, options)
    end

    file_header_array = header_transformations(file_header_array, options)

  else
    unless options[:user_provided_headers]
      raise SmarterCSV::IncorrectOption, "ERROR: If :headers_in_file is set to false, you have to provide :user_provided_headers"
    end
  end

  if options[:user_provided_headers]
    unless options[:user_provided_headers].is_a?(Array) && !options[:user_provided_headers].empty?
      raise(SmarterCSV::IncorrectOption, "ERROR: incorrect format for user_provided_headers! Expecting array with headers.")
    end

    # use user-provided headers
    user_header_array = options[:user_provided_headers]
    # user_provided_headers: their count should match the headers_in_file if any
    if defined?(file_header_size) && !file_header_size.nil?
      if user_header_array.size != file_header_size
        raise SmarterCSV::HeaderSizeMismatch, "ERROR: :user_provided_headers defines #{user_header_array.size} headers !=  CSV-file has #{file_header_size} headers"
      else
        # we could print out the mapping of file_header_array to header_array here
      end
    end

    # dup: the array belongs to the caller. The reader appends column_N entries for
    # extra data columns — those must go to our own copy, not the caller's array.
    header_array = user_header_array.dup
  else
    header_array = file_header_array
  end

  [header_array, header_array.size]
end