class GtfsReader::FileReader

Iterates over the rows in a single file using a provided definition. @see each

Attributes

col_names[R]
columns[R]
definition[R]

Public Class Methods

new(data, definition, opts = {}) click to toggle source

@param data [IO,String] CSV data @param definition [FileDefinition] describes the expected columns in this

file
# File lib/gtfs_reader/file_reader.rb, line 20
def initialize(data, definition, opts = {})
  opts = { parse: true, validate: false, hash: true }.merge(opts)

  @csv = CSV.new(data, CSV_OPTIONS)
  @definition = definition
  @do_parse = opts[:parse]
  @return_hash = opts[:hash]
  @index = 0
  @csv_headers = @csv.shift.headers
  @columns = find_columns(opts[:validate])
end

Public Instance Methods

each() { |return_hash ? to_hash : to_a| ... } click to toggle source

@overload each(&blk)

@yieldparam hash [Hash] a hash of columns to their values in this row

@overload each

@return [Enumerator] an {::Enumerator} that iterates of the rows in the
  file

@see FileRow#to_hash

# File lib/gtfs_reader/file_reader.rb, line 42
def each
  return to_enum(:each) unless block_given?

  while (row = shift)
    yield(@return_hash ? row.to_hash : row.to_a)
  end
end
filename() click to toggle source
# File lib/gtfs_reader/file_reader.rb, line 32
def filename
  @definition.filename
end
shift() click to toggle source

@return [FileRow,nil] the next row from the file, or nil if the end of

the file has been reached.
# File lib/gtfs_reader/file_reader.rb, line 52
def shift
  row = @csv.shift
  file_row(row).tap { @index += 1 } if row
end

Private Instance Methods

check_columns(validate, prefix, expected, found_color, missing_color) click to toggle source
# File lib/gtfs_reader/file_reader.rb, line 90
def check_columns(validate, prefix, expected, found_color, missing_color)
  check = '✔'.colorize(found_color)
  cross = '✘'.colorize(missing_color)

  expected.map do |col|
    name = col.name
    missing =
      if @csv_headers.include?(name)
        @found_columns << col
        nil
      else
        name
      end

    if validate
      Log.info do
        mark = missing ? cross : check
        "#{prefix} #{name.to_s.rjust column_width} [#{mark}]"
      end
    end
    missing
  end.compact
end
column_width() click to toggle source
# File lib/gtfs_reader/file_reader.rb, line 114
def column_width
  @column_width ||= @definition.columns.collect(&:name).max_by(&:length).length
end
file_row(row) click to toggle source
# File lib/gtfs_reader/file_reader.rb, line 59
def file_row(row)
  FileRow.new(@index, @col_names, row, @definition, @do_parse)
end
find_columns(validate) click to toggle source

Check the list of headers in the file against the expected columns in the definition

# File lib/gtfs_reader/file_reader.rb, line 65
def find_columns(validate)
  @found_columns = []
  prefix = "#{filename.yellow}:"

  required = @definition.required_columns
  unless required.empty?
    Log.info { "#{prefix} #{'required columns'.magenta}" } if validate

    missing = check_columns(validate, prefix, required, :green, :red)
    raise RequiredColumnsMissing, missing if validate && missing.present?
  end

  optional = @definition.optional_columns
  unless optional.empty?
    Log.info { "#{prefix} #{'optional columns'.cyan}" } if validate
    check_columns(validate, prefix, optional, :cyan, :light_yellow)
  end

  cols = @definition.columns.collect(&:name)
  headers = @csv_headers.select { |h| cols.include?(h) }

  @col_names ||= @found_columns.map(&:name)
  ::Hash[*headers.inject([]) { |list, c| list << c << @definition[c] }]
end