class RacingOnRails::Grid::Grid

Parse and render Array of Arrays of Strings. To be replaced by Tabular.

Attributes

column_count[R]
column_map[R]
columns[RW]
custom_columns[RW]
delimiter[R]
padding[R]
quoted[R]
rows[RW]

Public Class Methods

new(source = '', *options) click to toggle source

The Grid class maps columns by default – it changes them to lowercase and replaces spaces with underscores.

Options ===

  • delimiter: Cell delimiter. Defaults to tab

  • quoted: Cells are surrounded by quotes – remove first and last character. Default to false

  • columns = Array of column names as Strings or Array of Columns

  • header_row: First row is a list of column name. Header rows are parsed are deleted, so rows.first will return the second row from the source text.

    Defaults to false
  • #column_map: Hash of column names. Replace column names from the original file with another name if the default mapping isn't enough.

    Example: 'birth date' => 'date_of_birth'. 
    All keys are forced to lowercase for case-insenstive comparions
    
  • row_class: Map each row to this Class. Example: :row_class => Person

If both columns and header_row options are provided, columns is used to create the columns, and the first row is deleted and ignored

TODO Consider using regex for column maps

# File lib/racing_on_rails/grid/grid.rb, line 27
def initialize(source = '', *options)
  raise ArgumentError("'source' cannot be nil") if source.nil?

  options.flatten! if options
  @truncated = false
  @calculated_padding = false
  @custom_columns = []

  if (options.nil? || options.empty?)
    options_hash = {}
  else
    options_hash = options.first
  end

  @delimiter  = options_hash[:delimiter]  || '\t'
  @header_row = options_hash[:header_row] || false
  @quoted     = options_hash[:quoted]     || false

  @column_map = {}
  if options_hash[:column_map]
    options_hash[:column_map].each do |key, value|
      @column_map[key.downcase] = value
    end
  end

  @row_class = options_hash[:row_class]
  if @row_class
    @row_class_instance = @row_class.new
  end

  if source.is_a?(String)
    source = source.split(%r\n/)
  end

  if @header_row and source.is_a?(Array) and !source.empty?
    columns_array = source.delete_at(0)
  end

  if options_hash[:columns]
    columns_array = options_hash[:columns]
  end
  self.columns = create_columns(columns_array)
  self.rows = source
end

Public Instance Methods

[](row) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 72
def [](row)
  if row > rows.size
    raise(ArgumentError, "#{row} is greater then the number of rows: #{rows.size}")
  end
  rows[row]
end
after_columns_created() click to toggle source

Callback for sub classes

# File lib/racing_on_rails/grid/grid.rb, line 195
def after_columns_created
end
calculate_padding() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 296
def calculate_padding
  @calculated_padding = true
  @padding = []
  rows.each_with_index do |row, row_index|
    row_padding = []
    for index in 0..(column_count - 1)
      cell = row[index] || ''
      if cell.size <= column_size(index)
        padding = column_size(index) - cell.size
        row_padding << padding
      else
        row_padding << 0
      end
    end
    @padding << row_padding
  end
end
calculated_padding?() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 318
def calculated_padding?
  @calculated_padding
end
column_size(index) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 129
def column_size(index)
  if columns[index]
    columns[index].size
  else
    0
  end
end
create_columns(columns_array) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 137
def create_columns(columns_array)
  self.columns = []
  return if columns_array.nil?

  columns_array = columns_array.split(%r#{@delimiter}/) unless columns_array.is_a?(Array)
  self.columns = columns_array.collect do |column_name|
    description = column_name
    if column_name.is_a?(Column)
      column_name
    else
      column_name = column_name || ""
      column_name.strip! if column_name.respond_to?(:strip!)
      if quoted && column_name.respond_to?(:gsub!)
        column_name.gsub!(%r^"/, '')
        column_name.gsub!(%r"$/, '')
        description = column_name
      end
      if !column_name.blank? && @column_map[column_name.downcase]
        column_name = @column_map[column_name.downcase]
      end

      if column_name.is_a?(Column)
        column = column_name
      else
        column = Column.new(:name => column_name.to_s, :description => description)
      end

      unless column.name.blank?
        field = column.name.downcase
        field = field.underscore
        field.gsub!(' ', '_')
        if @column_map[field]
          if @column_map[field].is_a?(Column)
            column = @column_map[field]
          else
            column.field = @column_map[field]
          end
        else
          column.field = field
        end
      end
      column
    end
  end

  after_columns_created
  validate_columns

  columns.each do |column|
    unless column.description.blank?
      if !column.fixed_size && (column.description.size > column.size)
        column.size = column.description.size 
      end
    end
  end
end
delete_blank_rows() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 322
def delete_blank_rows
  rows.delete_if {|row|
    row.blank?
  }
end
header_to_s(row) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 244
def header_to_s(row)
  text = ''
  for index in 0..(column_count - 1)
    cell = row[index] || ''
    if cell.size <= column_size(index)
      if columns[index].justification == Column::LEFT
        cell = cell.ljust(column_size(index))
      else
        cell = cell.rjust(column_size(index))
      end
    else
      cell = cell.truncate(column_size(index))
    end
    if index + 1 == row.size
      text = "#{text}#{cell}"
    else
      text = "#{text}#{cell}   "
    end
  end
  "#{text}\n"
end
index_for_column_name(name) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 209
def index_for_column_name(name)
  columns.each_with_index do |column, index|
    if column.name == name
      return index
    end
  end
  ''
end
inspect() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 218
def inspect
  text = ""
  text << "#{columns}\n" if columns
  for row in rows
    text << row.inspect
  end
  text
end
row_count() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 117
def row_count
  rows.size
end
row_to_s(row, row_index) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 266
def row_to_s(row, row_index)
  text = ''
  for index in 0..(column_count - 1)
    cell = row[index] || ''
    if columns[index].justification == Column::LEFT
      cell = cell.ljust(column_size(index))
    else
      cell = cell.rjust(column_size(index))
    end
    if index + 1 == row.size
      text = "#{text}#{cell}"
    else
      text = "#{text}#{cell}   "
    end
  end
  "#{text}\n"
end
rows=(source) click to toggle source

Delimited String or Array of Strings or Arrays

# File lib/racing_on_rails/grid/grid.rb, line 87
def rows=(source)
  source.each do |row|
    row = row.split(%r#{@delimiter}/) unless row.is_a?(Array)
    index = 0
    row = row.collect do |cell|
      if cell
        cell.strip!
        if quoted
          cell.gsub!(%r^"/, '')
          cell.gsub!(%r"$/, '')
        end

        if index >= column_count
          self.columns << Column.new
        end

        column = columns[index]
        if !column.fixed_size && (cell.size > column.size)
          column.size = cell.size
        end
      end

      index = index + 1
      cell
    end

    rows << Row.new(row, self)
  end
end
to_s(include_columns = true) click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 227
def to_s(include_columns = true)
  truncate_rows unless truncated?
  calculate_padding unless calculated_padding?

  text = ""
  if include_columns && columns && columns.any?(&:present?)
    descriptions = columns.collect do |column|
      column.description
    end
    text = text + header_to_s(descriptions)
  end
  rows.each_with_index do |row, row_index|
    text = text + row_to_s(row, row_index)
  end
  text
end
truncate_rows() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 284
def truncate_rows
  @truncated = true
  for row in rows
    for index in 0..(column_count - 1)
      cell = row[index]
      if cell && cell.size > column_size(index)
        row[index] = cell.truncate(column_size(index))
      end
    end
  end
end
truncated?() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 314
def truncated?
  @truncated
end
validate_columns() click to toggle source
# File lib/racing_on_rails/grid/grid.rb, line 198
def validate_columns
  return unless @row_class_instance

  columns.each do |column|
    if column.field.nil? || !(@row_class_instance.respond_to?("#{column.field}="))
      column.field = nil
      @custom_columns << column.name unless column.name.blank?
    end
  end
end