Class: Tabular::Table

Inherits:
Object
  • Object
show all
Includes:
Blank, Keys, Zero
Defined in:
lib/tabular/table.rb

Overview

Simple Enumerable list of Hashes. Use Table.read(file_path) to read file. Can also create a Table with Table.new. Either pass in data or set options and then call row=.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Zero

#is_zero?

Methods included from Keys

#key_to_sym

Methods included from Blank

#is_blank?

Constructor Details

#initialize(rows = [], *options) ⇒ Table

Pass data in as rows. Expects rows to be an Enumerable of Enumerables. Maps rows to Hash-like Tabular::Rows.

Options: :columns => { :original_name => :preferred_name, :column_name => { :column_type => :boolean } }

The :columns option will likely be deprecated and options for mappers and renderers added



71
72
73
74
# File 'lib/tabular/table.rb', line 71

def initialize(rows = [], *options)
  @options = Table.extract_options(options)
  self.rows = rows
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



9
10
11
# File 'lib/tabular/table.rb', line 9

def options
  @options
end

#row_mapperObject

Returns the value of attribute row_mapper.



10
11
12
# File 'lib/tabular/table.rb', line 10

def row_mapper
  @row_mapper
end

#rowsObject

Returns the value of attribute rows.



9
10
11
# File 'lib/tabular/table.rb', line 9

def rows
  @rows
end

Class Method Details

.read(file, *options) ⇒ Object

file : file path as String or File Assumes .txt = tab-delimited, .csv = CSV, .xls = Excel. Assumes first row is the header. Normalizes column names to lower-case with underscores.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/tabular/table.rb', line 15

def self.read(file, *options)
  file_path = case file
  when File
     file.path
  else
    file
  end

  raise "Could not find '#{file_path}'" unless File.exists?(file_path)
  options = extract_options(options)

  format = self.format_from(options.delete(:as), file_path)
  data = read_file(file_path, format)

  Table.new data, options
end

.read_file(file_path, format) ⇒ Object

format : :csv, :txt, or :xls Returns Array of Arrays



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
# File 'lib/tabular/table.rb', line 34

def self.read_file(file_path, format)
  case format
  when :xls
    require "spreadsheet"
    # Row#to_a coerces Excel data to Strings, but we want Dates and Numbers
    data = []
    Spreadsheet.open(file_path).worksheets.first.each do |excel_row|
      data << excel_row.inject([]) { |row, cell| row << cell; row }
    end
    data
  when :txt
    require "csv"
    if RUBY_VERSION < "1.9"
      ::CSV.open(file_path, "r", "\t").collect { |row| row }
    else
      CSV.read(file_path, :col_sep => "\t")
    end
  when :csv
    if RUBY_VERSION < "1.9"
      require "fastercsv"
      FasterCSV.read(file_path)
    else
      require "csv"
      CSV.read(file_path)
    end
  else
    raise "Cannot read '#{format}' format. Expected :xls, :xlsx, :txt, or :csv"
  end
end

Instance Method Details

#<<(row) ⇒ Object

Add row to end of table. Create missing columns and link the source row to Row#source. To control how source data is added to the Table, use Table#mapper= to set a class that implements map(row) and returns a Hash.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/tabular/table.rb', line 99

def <<(row)
  if row_mapper
    cells = row_mapper.map(row)
  else
    cells = row
  end

  if @columns.nil? && !cells.respond_to?(:keys)
    @columns = Tabular::Columns.new(self, cells, options[:columns])
    return columns
  end

  _row = Tabular::Row.new(self, cells, row)
  _row.keys.each do |key|
    columns << key
  end
  rows << _row
  _row
end

#[](index) ⇒ Object

Return Row at zero-based index, or nil if Row is out of bounds



92
93
94
# File 'lib/tabular/table.rb', line 92

def [](index)
  rows[index]
end

#columnsObject

Instance of Tabular::Columns



124
125
126
# File 'lib/tabular/table.rb', line 124

def columns
  @columns ||= Tabular::Columns.new(self, [])
end

#delete_blank_columns!Object

Remove all columns that only contain a blank string, zero, or nil



129
130
131
132
133
134
135
# File 'lib/tabular/table.rb', line 129

def delete_blank_columns!
  columns.map(&:key).each do |key|
    if rows.all? { |row| is_blank?(row[key]) || is_zero?(row[key]) }
      delete_column key
    end
  end
end

#delete_column(key) ⇒ Object



162
163
164
165
166
167
# File 'lib/tabular/table.rb', line 162

def delete_column(key)
  rows.each do |row|
    row.delete key
  end
  columns.delete key
end

#delete_homogenous_columns!Object

Remove all columns that contain the same value in all rows



138
139
140
141
142
143
144
145
146
147
# File 'lib/tabular/table.rb', line 138

def delete_homogenous_columns!
  return if rows.size < 2
  
  columns.map(&:key).each do |key|
    value = rows.first[key]
    if rows.all? { |row| row[key] == value }
      delete_column key
    end
  end
end

#inspectObject



119
120
121
# File 'lib/tabular/table.rb', line 119

def inspect
  rows.map { |row| row.join(",") }.join("\n")
end

#renderer=(value) ⇒ Object

Set default Renderer. If present, will be used for all cells and Column headers.



170
171
172
# File 'lib/tabular/table.rb', line 170

def renderer=(value)
  columns.renderer = value
end

#renderersObject

List of Renderers



175
176
177
# File 'lib/tabular/table.rb', line 175

def renderers
  columns.renderers
end

#strip!Object

Remove preceding and trailing whitespace from all cells. By default, Table does not strip whitespace from cells.



151
152
153
154
155
156
157
158
159
160
# File 'lib/tabular/table.rb', line 151

def strip!
  rows.each do |row|
    columns.each do |column|
      value = row[column.key]
      if value.respond_to?(:strip)
        row[column.key] = value.strip
      end
    end
  end
end

#to_sObject



179
180
181
# File 'lib/tabular/table.rb', line 179

def to_s
  "#<#{self.class} #{rows.size}>"
end