Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First import from gem.

  • Loading branch information...
commit 371124c9025d7e67d07229ddc514b6d3b7340809 0 parents
@topfunky authored
21 History.txt
@@ -0,0 +1,21 @@
+== 0.0.5 / 2007-11-14
+
+* Added :title option in initializer. Emits header row spanning all columns.
+
+== 0.0.4 / 2007-06-27
+
+* Changed default table class name to 'tidy_table' for consistency.
+* Added ability to return a Hash from the block passed to TidyTable#to_html.
+ This allows the :id or :class of the row to be set along with the :data.
+
+== 0.0.3 / 2007-06-24
+
+* Added automatic last_column_class to header row also
+
+== 0.0.2 / 2007-06-24
+
+* Added automatic last_column_class and related options
+
+== 0.0.1 / 2007-06-20
+
+* Initial release
7 Manifest.txt
@@ -0,0 +1,7 @@
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+lib/tidy_table.rb
+spec/spec_helper.rb
+spec/tidy_table_spec.rb
46 README.txt
@@ -0,0 +1,46 @@
+TidyTable
+ by Geoffrey Grosenbach
+ http://topfunky.com
+
+== DESCRIPTION:
+
+Yet another library to convert an array of structs (such as an ActiveRecord
+object) into an HTML table. Simple, with a few options. Includes automatic
+tags for first_column, first_row, even, odd, etc.
+
+== FEATURES/PROBLEMS:
+
+* First release
+
+== REQUIREMENTS:
+
+* None
+
+== INSTALL:
+
+* sudo gem install tidy_table
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2007 Geoffrey Grosenbach
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 Rakefile
@@ -0,0 +1,19 @@
+
+require 'rubygems'
+require 'hoe'
+require './lib/tidy_table.rb'
+
+Hoe.new('tidy_table', TidyTable::VERSION) do |p|
+ p.rubyforge_name = 'seattlerb'
+ p.author = 'Geoffrey Grosenbach'
+ p.email = 'boss AT topfunky.com'
+ p.summary = 'Yet another library for converting a struct into an HTML table.'
+ p.description = p.paragraphs_of('README.txt', 0..1).join("\n\n")
+ p.url = "http://rubyforge.org/projects/seattlerb"
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
+end
+
+desc "Test task (actually runs specs)"
+task "test" do
+ system "spec --format specdoc --color spec"
+end
141 lib/tidy_table.rb
@@ -0,0 +1,141 @@
+##
+# 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 << %(<table class="#{@options[:table_class]}">)
+
+ # Title
+ if @options.has_key?(:title)
+ output << %(<tr class="#{@options[:first_row_class]}">)
+ output << %(<th class="#{@options[:title_class]} #{@options[:first_row_class]} #{@options[:first_column_class]}" colspan="#{fields.length}">#{@options[:title]}</th>)
+ output << %(</tr>)
+ end
+
+ # First row (header)
+ output << %(<tr class="#{@options[:first_row_class]}">)
+ fields.each_with_index do |field, index|
+ output << %(<th class="#{@options[:first_row_class]} #{column_classes(fields, index)}">#{field}</th>)
+ end
+ output << "</tr>"
+
+ @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 << %(<tr class="#{row_classes}" #{"id=\"#{row_options[:id]}\"" if row_options.has_key?(:id)}>)
+ data.each_with_index do |item, index|
+ output << %(<td class="#{column_classes(data, index)}">#{item}</td>)
+ end
+ else
+ output << %(<tr class="#{row_index % 2 == 0 ? 'even': 'odd'}">)
+ fields.each_with_index do |field, index|
+ output << %(<td class="#{column_classes(fields, index)}">#{row.send(field.to_sym)}</td>)
+ end
+ end
+ output << "</tr>"
+ end
+ output << "</table>"
+ 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
5 spec/spec_helper.rb
@@ -0,0 +1,5 @@
+
+require 'rubygems'
+require 'spec'
+
+require File.dirname(__FILE__) + "/../lib/tidy_table"
67 spec/tidy_table_spec.rb
@@ -0,0 +1,67 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+class RecordStruct < Struct.new(:title, :description); end
+
+describe TidyTable do
+
+ before do
+ @records = [RecordStruct.new("Cheese", "A sample of fine cheeses")]
+ end
+
+ it "should initialize with defaults" do
+ t = TidyTable.new(@records)
+ t.to_html([:title, :description]) {|row| [row.title, row.description]}.should match(/Cheese/)
+ end
+
+ it "should run without block" do
+ t = TidyTable.new(@records)
+ t.to_html([:title, :description]).should match(/Cheese/)
+ end
+
+ it "should merge options" do
+ t = TidyTable.new(@records, :table_class => "cheese_table_class")
+ t.to_html([:title, :description]).should match(/cheese_table_class/)
+ end
+
+ it "should tag with last_column CSS class" do
+ t = TidyTable.new(@records)
+ t.to_html([:title, :description]).should match(/last_column/)
+ end
+
+ it "should tag with custom last_column CSS class" do
+ t = TidyTable.new(@records, :last_column_class => "the_end_my_friend")
+ content = t.to_html([:title, :description])
+ content.should_not match(/last_column/)
+ content.should match(/the_end_my_friend/)
+ end
+
+ it "should set row title" do
+ t = TidyTable.new(@records)
+ t.to_html([:title, :description]) do |record|
+ {:id => "cheese_1", :data => [record.title, record.description]}
+ end.should match(/tr class="even" id="cheese_1"/)
+ end
+
+ it "should set row class" do
+ t = TidyTable.new(@records)
+ t.to_html([:title, :description]) do |record|
+ {:class => "cheese_class", :data => [record.title, record.description]}
+ end.should match(/tr class="even cheese_class"/)
+ end
+
+ it "should raise if wrong argument passed from block" do
+ t = TidyTable.new(@records)
+ lambda {
+ t.to_html([:title, :description]) do |record|
+ Date.new
+ end
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should show title" do
+ t = TidyTable.new(@records, :title => "Report of Doom")
+ output = t.to_html([:title, :description])
+ output.should match(/Report of Doom/)
+ end
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.