Class: TableFu
- Inherits:
-
Object
- Object
- TableFu
- Defined in:
- lib/table_fu.rb,
lib/table_fu.rb
Overview
TableFu turns a matric array(from a csv file for example) into a spreadsheet.
Allows formatting, macros, sorting, and faceting.
Documentation: propublica.github.com/table-fu
Defined Under Namespace
Classes: Datum, Formatting, Header, Row
Instance Attribute Summary collapse
-
#col_opts ⇒ Object
Returns the value of attribute col_opts.
-
#column_headers ⇒ Object
readonly
Returns the value of attribute column_headers.
-
#deleted_rows ⇒ Object
readonly
Returns the value of attribute deleted_rows.
-
#faceted_on ⇒ Object
Returns the value of attribute faceted_on.
-
#table ⇒ Object
readonly
Returns the value of attribute table.
-
#totals ⇒ Object
readonly
Returns the value of attribute totals.
Instance Method Summary collapse
-
#columns ⇒ Object
Return the headers defined in column headers or cherry picked from @col_opts.
-
#columns=(array) ⇒ Object
Set up the cherry picked columns.
-
#delete_rows!(arr) ⇒ Object
Pass it an array and it will delete it from the table, but save the data in @deleted_rows@ for later perusal.
-
#faceted? ⇒ Boolean
Return true if this table is faceted.
-
#faceted_by(column, opts = {}) ⇒ Object
Return an array of TableFu instances grouped by a column.
-
#formatting ⇒ Object
Return the formatting hash.
-
#formatting=(headers) ⇒ Object
Set the formatting hash.
-
#headers ⇒ Object
Return the headers of the array.
-
#initialize(table, column_opts = {}) {|_self| ... } ⇒ TableFu
constructor
Should be initialized with a matrix array or a string containing a csv, and expects the first array in the matrix to be column headers.
-
#only!(range) ⇒ Object
Inverse slice: Only keep the rows in the range after sorting.
-
#row_at(row_num) ⇒ Object
Returns a Row object for the row at a certain index.
-
#rows ⇒ Object
Returns all the Row objects for this object as a collection.
-
#sorted_by ⇒ Object
Return the sorted_by column.
-
#sorted_by=(header) ⇒ Object
Set the sorted_by column.
-
#sum_totals_for(column) ⇒ Object
Sum the values of a particular column.
-
#to_numeric(num) ⇒ Object
Return a numeric instance for a string number, or if it’s a string we return 1, this way if we total up a series of strings it’s a count.
-
#total_for(column) ⇒ Object
Sum the values of a particular column and return a Datum.
Constructor Details
#initialize(table, column_opts = {}) {|_self| ... } ⇒ TableFu
Should be initialized with a matrix array or a string containing a csv, and expects the first array in the matrix to be column headers.
24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/table_fu.rb', line 24 def initialize(table, column_opts = {}) # Assume if we're past a string or filehandle we need to parse a csv if table.is_a?(String) || table.is_a?(File) table = FasterCSV.parse(table) end @column_headers = table.slice!(0) @totals = {} @table = table @col_opts = column_opts yield self if block_given? end |
Instance Attribute Details
#col_opts ⇒ Object
Returns the value of attribute col_opts.
20 21 22 |
# File 'lib/table_fu.rb', line 20 def col_opts @col_opts end |
#column_headers ⇒ Object (readonly)
Returns the value of attribute column_headers.
19 20 21 |
# File 'lib/table_fu.rb', line 19 def column_headers @column_headers end |
#deleted_rows ⇒ Object (readonly)
Returns the value of attribute deleted_rows.
19 20 21 |
# File 'lib/table_fu.rb', line 19 def deleted_rows @deleted_rows end |
#faceted_on ⇒ Object
Returns the value of attribute faceted_on.
20 21 22 |
# File 'lib/table_fu.rb', line 20 def faceted_on @faceted_on end |
#table ⇒ Object (readonly)
Returns the value of attribute table.
19 20 21 |
# File 'lib/table_fu.rb', line 19 def table @table end |
#totals ⇒ Object (readonly)
Returns the value of attribute totals.
19 20 21 |
# File 'lib/table_fu.rb', line 19 def totals @totals end |
Instance Method Details
#columns ⇒ Object
Return the headers defined in column headers or cherry picked from @col_opts
76 77 78 |
# File 'lib/table_fu.rb', line 76 def columns @col_opts[:columns] || column_headers end |
#columns=(array) ⇒ Object
Set up the cherry picked columns
173 174 175 |
# File 'lib/table_fu.rb', line 173 def columns=(array) @col_opts[:columns] = array end |
#delete_rows!(arr) ⇒ Object
Pass it an array and it will delete it from the table, but save the data in @deleted_rows@ for later perusal.
Returns: nothing
43 44 45 46 47 48 49 50 |
# File 'lib/table_fu.rb', line 43 def delete_rows!(arr) @deleted_rows ||= [] arr.map do |item| @deleted_rows << @table[item] #account for header and 0 index @table[item] = nil end @table.compact! end |
#faceted? ⇒ Boolean
Return true if this table is faceted
148 149 150 |
# File 'lib/table_fu.rb', line 148 def faceted? not faceted_on.nil? end |
#faceted_by(column, opts = {}) ⇒ Object
Return an array of TableFu instances grouped by a column.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/table_fu.rb', line 101 def faceted_by(column, opts = {}) faceted_spreadsheets = {} rows.each do |row| unless row.column_for(column).value.nil? faceted_spreadsheets[row.column_for(column).value] ||= [] faceted_spreadsheets[row.column_for(column).value] << row end end # Create new table_fu instances for each facet tables = [] faceted_spreadsheets.each do |key,value| new_table = [@column_headers] + value table = TableFu.new(new_table) table.faceted_on = key table.col_opts = @col_opts #formatting should be carried through tables << table end tables.sort! do |a,b| a.faceted_on <=> b.faceted_on end if opts[:total] opts[:total].each do |c| tables.each do |f| f.sum_totals_for(c) end end end tables end |
#formatting ⇒ Object
Return the formatting hash
163 164 165 |
# File 'lib/table_fu.rb', line 163 def formatting @col_opts[:formatting] end |
#formatting=(headers) ⇒ Object
Set the formatting hash
168 169 170 |
# File 'lib/table_fu.rb', line 168 def formatting=(headers) @col_opts[:formatting] = headers end |
#headers ⇒ Object
Return the headers of the array
81 82 83 84 85 86 87 |
# File 'lib/table_fu.rb', line 81 def headers all_columns = [] columns.each do |header| all_columns << TableFu::Header.new(header, header, nil, self) end all_columns end |
#only!(range) ⇒ Object
Inverse slice: Only keep the rows in the range after sorting
54 55 56 57 58 59 |
# File 'lib/table_fu.rb', line 54 def only!(range) rows_to_exclude = rows.map do |row| range.include?(row.row_num) ? nil : row.row_num end delete_rows!(rows_to_exclude.compact) end |
#row_at(row_num) ⇒ Object
Returns a Row object for the row at a certain index
62 63 64 |
# File 'lib/table_fu.rb', line 62 def row_at(row_num) TableFu::Row.new(@table[row_num], row_num, self) end |
#rows ⇒ Object
Returns all the Row objects for this object as a collection
67 68 69 70 71 72 73 |
# File 'lib/table_fu.rb', line 67 def rows all_rows = [] @table.each_with_index do |row, index| all_rows << TableFu::Row.new(row, index, self) end all_rows.sort end |
#sorted_by ⇒ Object
Return the sorted_by column
153 154 155 |
# File 'lib/table_fu.rb', line 153 def sorted_by @col_opts[:sorted_by] end |
#sorted_by=(header) ⇒ Object
Set the sorted_by column
158 159 160 |
# File 'lib/table_fu.rb', line 158 def sorted_by=(header) @col_opts[:sorted_by] = header end |
#sum_totals_for(column) ⇒ Object
Sum the values of a particular column
90 91 92 |
# File 'lib/table_fu.rb', line 90 def sum_totals_for(column) @totals[column.to_s] = rows.inject(0) { |sum, r| to_numeric(r.datum_for(column).value) + sum } end |
#to_numeric(num) ⇒ Object
Return a numeric instance for a string number, or if it’s a string we return 1, this way if we total up a series of strings it’s a count
137 138 139 140 141 142 143 144 145 |
# File 'lib/table_fu.rb', line 137 def to_numeric(num) if num.nil? 0 elsif num.kind_of? Integer num else 1 # We count each instance of a string this way end end |
#total_for(column) ⇒ Object
Sum the values of a particular column and return a Datum
95 96 97 98 |
# File 'lib/table_fu.rb', line 95 def total_for(column) sum_totals_for(column) Datum.new(@totals[column.to_s], column, nil, self) end |