Class: DataTable
- Inherits:
-
Object
- Object
- DataTable
- Defined in:
- lib/data-table/data_table.rb,
lib/data-table/version.rb
Overview
Config Options
id: the html id title: the title of the data table subtitle: the subtitle of the data table css_class: an extra css class to get applied to the table empty_text: the text to display of the collection is empty display_header => false: hide the column headers for the data table alternate_rows => false: turn off alternating of row css classes alternate_cols => true: turn on alternating of column classes, defaults to false
columns: an array of hashes of the column specs for this table
group_by: an array of columns to group on pivot_on: an array of columns to pivot on
subtotals: an array of hashes that contain the subtotal information for each column that should be subtotaled totals: an array of hashes that contain the total information for each column that should be totaled
Constant Summary collapse
- VERSION =
"1.0.1"
Instance Attribute Summary collapse
-
#alternate_cols ⇒ Object
Returns the value of attribute alternate_cols.
-
#alternate_rows ⇒ Object
Returns the value of attribute alternate_rows.
-
#css_class ⇒ Object
Returns the value of attribute css_class.
-
#custom_headers ⇒ Object
Returns the value of attribute custom_headers.
-
#display_header ⇒ Object
Returns the value of attribute display_header.
-
#empty_text ⇒ Object
Returns the value of attribute empty_text.
-
#grouped_data ⇒ Object
readonly
CONFIG.
-
#hide_if_empty ⇒ Object
Returns the value of attribute hide_if_empty.
-
#id ⇒ Object
Returns the value of attribute id.
-
#pivoted_data ⇒ Object
readonly
CONFIG.
-
#repeat_headers_for_groups ⇒ Object
Returns the value of attribute repeat_headers_for_groups.
-
#subtotal_calculations ⇒ Object
readonly
CONFIG.
-
#subtotals ⇒ Object
readonly
CONFIG.
-
#title ⇒ Object
Returns the value of attribute title.
-
#total_calculations ⇒ Object
readonly
CONFIG.
-
#totals ⇒ Object
readonly
CONFIG.
Class Method Summary collapse
- .default_css_styles ⇒ Object
-
.render(collection) {|t| ... } ⇒ Object
GENERAL RENDERING.
Instance Method Summary collapse
- #calculate(data, column_name, function) ⇒ Object
- #calculate_avg(collection, column_name) ⇒ Object
- #calculate_max(collection, column_name) ⇒ Object
- #calculate_min(collection, column_name) ⇒ Object
- #calculate_subtotals! ⇒ Object
- #calculate_sum(collection, column_name) ⇒ Object
- #calculate_totals! ⇒ Object
-
#column(id, title = "", opts = {}, &b) ⇒ Object
Define a new column for the table.
- #custom_header(&blk) ⇒ Object
- #default_options! ⇒ Object
-
#group_by(group_column, &blk) ⇒ Object
TODO: allow for group column only, block only and group column and block.
- #group_data! ⇒ Object
- #has_subtotals? ⇒ Boolean
- #has_totals? ⇒ Boolean
-
#initialize(collection) ⇒ DataTable
constructor
A new instance of DataTable.
- #pivot_data! ⇒ Object
-
#pivot_on(pivot_column) ⇒ Object
PIVOTING.
- #prepare_data ⇒ Object
- #render ⇒ Object
- #render_custom_table_header ⇒ Object
- #render_data_table ⇒ Object
- #render_data_table_body(collection) ⇒ Object
- #render_data_table_header ⇒ Object
- #render_group(group_header, group_data) ⇒ Object
- #render_group_header(group_header) ⇒ Object
- #render_grouped_data_table_body(collection) ⇒ Object
- #render_row(row, row_index, css_class = '', row_attributes = {}) ⇒ Object
- #render_rows(collection) ⇒ Object
- #render_subtotals(group_header, group_data) ⇒ Object
-
#render_totals ⇒ Object
TOTALS AND SUBTOTALS.
- #row_attributes(&b) ⇒ Object
-
#row_style(&b) ⇒ Object
define a custom block to be used to determine the css class for a row.
-
#subtotal(column_name, function = nil, &b) ⇒ Object
define a new total column definition.
- #th(header_text, options) ⇒ Object
-
#total(column_name, function = nil, &b) ⇒ Object
define a new total column definition.
Constructor Details
#initialize(collection) ⇒ DataTable
Returns a new instance of DataTable.
31 32 33 34 35 36 37 38 39 40 |
# File 'lib/data-table/data_table.rb', line 31 def initialize(collection) @collection = collection @columns = [] @groupings, @pivot_columns = [], [] @pivoted_data, @grouped_data = false, false @subtotals, @totals = {}, {} end |
Instance Attribute Details
#alternate_cols ⇒ Object
Returns the value of attribute alternate_cols.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def alternate_cols @alternate_cols end |
#alternate_rows ⇒ Object
Returns the value of attribute alternate_rows.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def alternate_rows @alternate_rows end |
#css_class ⇒ Object
Returns the value of attribute css_class.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def css_class @css_class end |
#custom_headers ⇒ Object
Returns the value of attribute custom_headers.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def custom_headers @custom_headers end |
#display_header ⇒ Object
Returns the value of attribute display_header.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def display_header @display_header end |
#empty_text ⇒ Object
Returns the value of attribute empty_text.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def empty_text @empty_text end |
#grouped_data ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def grouped_data @grouped_data end |
#hide_if_empty ⇒ Object
Returns the value of attribute hide_if_empty.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def hide_if_empty @hide_if_empty end |
#id ⇒ Object
Returns the value of attribute id.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def id @id end |
#pivoted_data ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def pivoted_data @pivoted_data end |
#repeat_headers_for_groups ⇒ Object
Returns the value of attribute repeat_headers_for_groups.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def repeat_headers_for_groups @repeat_headers_for_groups end |
#subtotal_calculations ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def subtotal_calculations @subtotal_calculations end |
#subtotals ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def subtotals @subtotals end |
#title ⇒ Object
Returns the value of attribute title.
29 30 31 |
# File 'lib/data-table/data_table.rb', line 29 def title @title end |
#total_calculations ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def total_calculations @total_calculations end |
#totals ⇒ Object (readonly)
CONFIG
28 29 30 |
# File 'lib/data-table/data_table.rb', line 28 def totals @totals end |
Class Method Details
.default_css_styles ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/data-table/data_table.rb', line 59 def self.default_css_styles <<-CSS_STYLE .data_table {width: 100%; empty-cells: show} .data_table td, .data_table th {padding: 3px} .data_table caption {font-size: 2em; font-weight: bold} .data_table thead {} .data_table thead th {background-color: #ddd; border-bottom: 1px solid #bbb;} .data_table tbody {} .data_table tbody tr.alt {background-color: #eee;} .data_table .group_header th {text-align: left;} .data_table .subtotal {} .data_table .subtotal td {border-top: 1px solid #000;} .data_table tfoot {} .data_table tfoot td {border-top: 1px solid #000;} .empty_data_table {text-align: center; background-color: #ffc;} /* Data Types */ .data_table .number, .data_table .money {text-align: right} .data_table .text {text-align: left} CSS_STYLE end |
.render(collection) {|t| ... } ⇒ Object
GENERAL RENDERING
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/data-table/data_table.rb', line 105 def self.render(collection, &blk) # make a new table t = self.new(collection) # yield it to the block for configuration yield t # modify the data structure if necessary and do calculations t.prepare_data # render the table t.render.html_safe end |
Instance Method Details
#calculate(data, column_name, function) ⇒ Object
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/data-table/data_table.rb', line 348 def calculate(data, column_name, function) col = @columns.select { |column| column.name == column_name } if function.is_a?(Proc) case function.arity when 1; function.call(data) when 2; function.call(data, col.first) end elsif function.is_a?(Array) result = self.send("calculate_#{function[0].to_s}", data, column_name) case function[1].arity when 1; function[1].call(result) when 2; function[1].call(result, col.first) end else self.send("calculate_#{function.to_s}", data, column_name) end end |
#calculate_avg(collection, column_name) ⇒ Object
372 373 374 375 |
# File 'lib/data-table/data_table.rb', line 372 def calculate_avg(collection, column_name) sum = calculate_sum(collection, column_name) sum / collection.size end |
#calculate_max(collection, column_name) ⇒ Object
377 378 379 |
# File 'lib/data-table/data_table.rb', line 377 def calculate_max(collection, column_name) collection.collect{|r| r[column_name].to_f }.max end |
#calculate_min(collection, column_name) ⇒ Object
381 382 383 |
# File 'lib/data-table/data_table.rb', line 381 def calculate_min(collection, column_name) collection.collect{|r| r[column_name].to_f }.min end |
#calculate_subtotals! ⇒ Object
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/data-table/data_table.rb', line 331 def calculate_subtotals! @subtotal_calculations = Hash.new { |h,k| h[k] = {} } #ensure that we are dealing with a grouped results set. unless @grouped_data raise 'Subtotals only work with grouped results sets' end @collection.each do |group_name, group_data| @subtotals.each do |column_name, function| result = calculate(group_data, column_name, function) @subtotal_calculations[group_name][column_name] = result end end end |
#calculate_sum(collection, column_name) ⇒ Object
368 369 370 |
# File 'lib/data-table/data_table.rb', line 368 def calculate_sum(collection, column_name) collection.inject(0) {|sum, row| sum += row[column_name].to_f } end |
#calculate_totals! ⇒ Object
321 322 323 324 325 326 327 328 329 |
# File 'lib/data-table/data_table.rb', line 321 def calculate_totals! @total_calculations = {} @totals.each do |column_name, function| collection = @collection.is_a?(Hash) ? @collection.values.flatten : @collection result = calculate(collection, column_name, function) @total_calculations[column_name] = result end end |
#column(id, title = "", opts = {}, &b) ⇒ Object
Define a new column for the table
89 90 91 |
# File 'lib/data-table/data_table.rb', line 89 def column(id, title="", opts={}, &b) @columns << DataTableColumn.new(id, title, opts, &b) end |
#custom_header(&blk) ⇒ Object
198 199 200 |
# File 'lib/data-table/data_table.rb', line 198 def custom_header(&blk) instance_eval(&blk) end |
#default_options! ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/data-table/data_table.rb', line 42 def @id = '' @title = '' @subtitle = '' @css_class = '' @empty_text = 'No records found' @hide_if_empty = false @display_header = true @alternate_rows = true @alternate_cols = false @subtotal_title = "Subtotal:" @total_title = "Total:" @repeat_headers_for_groups = false @custom_headers = [] @row_attributes = nil end |
#group_by(group_column, &blk) ⇒ Object
TODO: allow for group column only, block only and group column and block
215 216 217 218 219 |
# File 'lib/data-table/data_table.rb', line 215 def group_by(group_column, &blk) @grouped_data = true @groupings = group_column @columns.reject!{|c| c.name == group_column} end |
#group_data! ⇒ Object
221 222 223 |
# File 'lib/data-table/data_table.rb', line 221 def group_data! @collection = @collection.group_by {|row| row[@groupings] } end |
#has_subtotals? ⇒ Boolean
300 301 302 |
# File 'lib/data-table/data_table.rb', line 300 def has_subtotals? !@subtotals.empty? end |
#has_totals? ⇒ Boolean
317 318 319 |
# File 'lib/data-table/data_table.rb', line 317 def has_totals? !@totals.empty? end |
#pivot_data! ⇒ Object
264 265 266 |
# File 'lib/data-table/data_table.rb', line 264 def pivot_data! @collection.pivot_on end |
#pivot_on(pivot_column) ⇒ Object
PIVOTING
259 260 261 262 |
# File 'lib/data-table/data_table.rb', line 259 def pivot_on(pivot_column) @pivoted_data = true @pivot_column = pivot_column end |
#prepare_data ⇒ Object
93 94 95 96 97 98 99 |
# File 'lib/data-table/data_table.rb', line 93 def prepare_data self.pivot_data! if @pivoted_data self.group_data! if @grouped_data self.calculate_subtotals! if has_subtotals? self.calculate_totals! if has_totals? end |
#render ⇒ Object
119 120 121 |
# File 'lib/data-table/data_table.rb', line 119 def render render_data_table end |
#render_custom_table_header ⇒ Object
148 149 150 151 152 153 154 |
# File 'lib/data-table/data_table.rb', line 148 def render_custom_table_header html = "<tr>" @custom_headers.each do |h| html << "<th class=\"#{h[:css]}\" colspan=\"#{h[:colspan]}\">#{h[:text]}</th>" end html << "</tr>" end |
#render_data_table ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/data-table/data_table.rb', line 123 def render_data_table html = "<table id='#{@id}' class='data_table #{@css_class}' cellspacing='0' cellpadding='0'>" html << "<caption>#{@title}</caption>" if @title html << render_data_table_header if @display_header if @collection.any? html << render_data_table_body(@collection) html << render_totals if has_totals? else html << "<tr><td class='empty_data_table' colspan='#{@columns.size}'>#{@empty_text}</td></tr>" end html << "</table>" end |
#render_data_table_body(collection) ⇒ Object
156 157 158 159 160 161 162 |
# File 'lib/data-table/data_table.rb', line 156 def render_data_table_body(collection) if @grouped_data render_grouped_data_table_body(collection) else "<tbody>#{render_rows(collection)}</tbody>" end end |
#render_data_table_header ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/data-table/data_table.rb', line 136 def render_data_table_header html = "<thead>" html << render_custom_table_header unless @custom_headers.empty? html << "<tr>" @columns.each do |col| html << col.render_column_header end html << "</tr></thead>" end |
#render_group(group_header, group_data) ⇒ Object
246 247 248 249 250 251 252 |
# File 'lib/data-table/data_table.rb', line 246 def render_group(group_header, group_data) html = "<tbody class='#{group_header.to_s.downcase.gsub(/[^A-Za-z0-9]+/, '_')}'>" #replace non-letters and numbers with '_' html << render_group_header(group_header) html << render_rows(group_data) html << render_subtotals(group_header, group_data) if has_subtotals? html << "</tbody>" end |
#render_group_header(group_header) ⇒ Object
233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/data-table/data_table.rb', line 233 def render_group_header(group_header) html = "<tr class='group_header'>" if @repeat_headers_for_groups @columns.each_with_index do |col, i| html << (i == 0 ? "<th>#{group_header}</th>" : col.render_column_header) end else html << "<th colspan='#{@columns.size}'>#{group_header}</th>" end html << "</tr>" html end |
#render_grouped_data_table_body(collection) ⇒ Object
225 226 227 228 229 230 231 |
# File 'lib/data-table/data_table.rb', line 225 def render_grouped_data_table_body(collection) html = "" collection.keys.each do |group_name| html << render_group(group_name, collection[group_name]) end html end |
#render_row(row, row_index, css_class = '', row_attributes = {}) ⇒ Object
178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/data-table/data_table.rb', line 178 def render_row(row, row_index, css_class='', row_attributes={}) if row_attributes.nil? attributes = '' else attributes = row_attributes.map {|attr, val| "#{attr}='#{val}'"}.join " " end html = "<tr class='row_#{row_index} #{css_class}' #{attributes}>" @columns.each_with_index do |col, col_index| cell = row[col.name] rescue nil html << col.render_cell(cell, row, row_index, col_index) end html << "</tr>" end |
#render_rows(collection) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/data-table/data_table.rb', line 164 def render_rows(collection) html = "" collection.each_with_index do |row, row_index| css_class = @alternate_rows && row_index % 2 == 1 ? 'alt ' : '' if @row_style && style = @row_style.call(row, row_index) css_class << style end attributes = @row_attributes.nil? ? {} : @row_attributes.call(row) html << render_row(row, row_index, css_class, attributes) end html end |
#render_subtotals(group_header, group_data) ⇒ Object
279 280 281 282 283 284 285 |
# File 'lib/data-table/data_table.rb', line 279 def render_subtotals(group_header, group_data) html = "<tr class='subtotal'>" @columns.each do |col| html << col.render_cell(@subtotal_calculations[group_header][col.name]) end html << "</tr>" end |
#render_totals ⇒ Object
TOTALS AND SUBTOTALS
271 272 273 274 275 276 277 |
# File 'lib/data-table/data_table.rb', line 271 def render_totals html = "<tfoot><tr>" @columns.each do |col| html << col.render_cell(@total_calculations[col.name]) end html << "</tr></tfoot>" end |
#row_attributes(&b) ⇒ Object
206 207 208 |
# File 'lib/data-table/data_table.rb', line 206 def row_attributes(&b) @row_attributes = b end |
#row_style(&b) ⇒ Object
define a custom block to be used to determine the css class for a row.
194 195 196 |
# File 'lib/data-table/data_table.rb', line 194 def row_style(&b) @row_style = b end |
#subtotal(column_name, function = nil, &b) ⇒ Object
define a new total column definition. total columns take the name of the column that should be totaled they also take a default aggregate function name and/or a block if only a default function is given, then it is used to calculate the total if only a block is given then only it is used to calculated the total if both a block and a function are given then the default aggregate function is called first then its result is passed into the block for further processing.
294 295 296 297 298 |
# File 'lib/data-table/data_table.rb', line 294 def subtotal(column_name, function=nil, &b) function_or_block = function || b f = function && block_given? ? [function, b] : function_or_block @subtotals.merge!({column_name => f}) end |
#th(header_text, options) ⇒ Object
202 203 204 |
# File 'lib/data-table/data_table.rb', line 202 def th(header_text, ) @custom_headers << .merge(:text => header_text) end |
#total(column_name, function = nil, &b) ⇒ Object
define a new total column definition. total columns take the name of the column that should be totaled they also take a default aggregate function name and/or a block if only a default function is given, then it is used to calculate the total if only a block is given then only it is used to calculated the total if both a block and a function are given then the default aggregate function is called first then its result is passed into the block for further processing.
311 312 313 314 315 |
# File 'lib/data-table/data_table.rb', line 311 def total(column_name, function=nil, &b) function_or_block = function || b f = function && block_given? ? [function, b] : function_or_block @totals.merge!({column_name => f}) end |