## # This is yet another library to convert an ActiveRecord array (or any struct) # to an HTML table. # # You get a table with a bunch of CSS classes automatically applied (or # customize it with your own classes and ids). For example, first_row (is also # a th tag), first_column, last_column, even & odd (for rows). # # Other tags like thead and tbody may be added in the future. # # Simple example with an ActiveRecord object: # # <%= TidyTable.new(@records).to_html(%w(title description created_at)) %> # # You also format the row values with a block: # # <%= TidyTable.new(@records, :table_class => "revenue_report").to_html(%w(resource visits min max)) do |row| # [ # row.resource, # number_with_delimiter(row.visit_count), # row.min, # row.max # ] # end %> # # Or in HAML: # # = TidyTable.new(@records, :table_class => "revenue_report").to_html(%w(resource visits min max)) do |row| # - [ row.resource, number_with_delimiter(row.visit_count), row.min, row.max ] class TidyTable VERSION = '0.0.5' ## # Make a new TidyTable with a data array and CSS options. # # * :table_class -- Defaults to 'tidy_table' # * :first_row_class -- Defaults to 'first_row' # * :first_column_class -- Defaults to 'first_column' # * :last_column_class -- Defaults to 'last_column' # * :title -- Title for this table. Emits an extra header row # spanning all columns. # * :title_class -- CSS class for the title th. Default: 'title' # # You also get 'even' and 'odd' for free (rows only). def initialize(array, options={}) @rows = array @options = { :table_class => "tidy_table", :first_row_class => "first_row", :first_column_class => "first_column", :last_column_class => "last_column", :title_class => "title" }.merge(options) end ## # First argument is an array of column names. # Will also be called as methods on each row object if no block is provided. # # If given, a block will be called for each row of the array. You should # return an Array with the values formatted in the format that you want to see # in the resulting cells. # # Or, return a Hash where # # :data => ['contents', 'for', 'cells'], # :id => 'id_for_this_row', # :class => 'extra_classes for_this row' def to_html(fields) output = [] output << %() # Title if @options.has_key?(:title) output << %() output << %() output << %() end # First row (header) output << %() fields.each_with_index do |field, index| output << %() end output << "" @rows.each_with_index do |row, row_index| if block_given? yield_output = yield(row) data = [] row_options = {} case yield_output when Array data = yield_output when Hash data = yield_output.delete(:data) row_options = yield_output else raise ArgumentError, "TidyTable block expects an Array or Hash, but a #{yield_output.class} was returned." end row_classes = [row_index % 2 == 0 ? 'even': 'odd', row_options[:class]].select {|i| !i.nil?}.join(' ') output << %() data.each_with_index do |item, index| output << %() end else output << %() fields.each_with_index do |field, index| output << %() end end output << "" end output << "
#{@options[:title]}
#{field}
#{item}
#{row.send(field.to_sym)}
" output.join end private ## # Returns "first_column", "last_column", or both. # # additional_class_names is a string of other class names to append to the # autogenerated classes. def column_classes(fields_array, index, additional_class_names=nil) classes = (index == 0 ? @options[:first_column_class] : '') classes += (index == fields_array.length - 1 ? @options[:last_column_class] : '') if additional_class_names classes += " " + additional_class_names end classes end end