class Roo::Base

Attributes

partial_match[RW]

changes:

  • added option :partial_match to allow to use headers that only partially match the query

  • added option :required_headers to force the result to have at least these columns

  • allow option :headers to contain an array with header labels that will be forced when no header row is found

  • improved proper range scanning (first_row->last_row and first_column->last_column)

Public Instance Methods

each(options = {}) { |row(line)| ... } click to toggle source
# File lib/libis/tools/extend/roo.rb, line 18
def each(options = {})
  return to_enum(:each, options) unless block_given?

  @partial_match = options.delete(:partial_match) if options.has_key?(:partial_match)
  required_headers = options.delete(:required_headers) if options.has_key?(:required_headers)

  if options.empty?
    first_row.upto(last_row) do |line|
      yield row(line)
    end
  else
    clean_sheet_if_need(options)
    @headers = search_or_set_header(options)
    if required_headers
      raise Roo::HeaderRowIncompleteError unless headers.keys & required_headers == required_headers
    end

    header_line.upto(last_row) do |line|
      yield(Hash[headers.map { |k, v| [k, cell(line, v)] }])
    end
  end
end

Private Instance Methods

row_with(query) click to toggle source
# File lib/libis/tools/extend/roo.rb, line 43
def row_with(query)
  line_no = first_row
  each do |row|
    headers = query.map { |q| row.grep(q)[0] }.compact

    if headers.length == query.length
      @header_line = line_no
      return headers
    elsif line_no > 100
      raise Roo::HeaderRowNotFoundError
    elsif headers.length > 0
      # partial match
      @header_line = line_no
      raise Roo::HeaderRowIncompleteError unless partial_match
      return headers
    end
    line_no += 1
  end
  raise Roo::HeaderRowNotFoundError
end
search_or_set_header(options) click to toggle source
# File lib/libis/tools/extend/roo.rb, line 64
def search_or_set_header(options)
  force_headers = options.delete(:headers)
  if options[:header_search]
    row_with(options[:header_search])
  elsif [:first_row, true].include?(force_headers)
    @header_line = first_row
  else
    return set_headers(options)
  end
  return Hash[row(header_line).map { |x| [x, header_index(x)] }]
rescue Roo::HeaderRowNotFoundError => e
  # Not OK unless a list of headers is supplied
  raise e unless force_headers.is_a?(Array)
  # Force the headers in the order they are given, but up to the last column
  @header_line = first_row - 1
  return Hash[force_headers.zip(first_column..last_column)].cleanup
end
set_headers(hash) click to toggle source
# File lib/libis/tools/extend/roo.rb, line 82
def set_headers(hash)
  # try to find header row with all values or give an error
  # then create new hash by indexing strings and keeping integers for header array
  row_with(hash.values)
  positions = Hash[row(header_line).map { |x| [x, header_index(x)] }]
  Hash[positions.map { |k, v| [hash.invert[k] || k, v] }]
end