table_for_collection 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog ADDED
@@ -0,0 +1,7 @@
1
+ == v.0.2
2
+
3
+ Packaged as a gem.
4
+
5
+ == v.0.1
6
+
7
+ Initial version: table_for method added.
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source :gemcutter
2
+
3
+ gem "rails"
4
+
5
+ group :development, :test do
6
+ gem "rspec", ">=2.0.0"
7
+ gem "autotest"
8
+ gem "webrat"
9
+
10
+ case RUBY_VERSION
11
+ when /^1\.9/
12
+ gem 'ruby-debug19'
13
+ when /^1\.8/
14
+ gem 'ruby-debug'
15
+ end
16
+ end
data/README.rdoc ADDED
@@ -0,0 +1,99 @@
1
+ == Description
2
+
3
+ table_for_collection is a simple gem used to render tables based on the given collection.
4
+
5
+ === Simplest examle
6
+
7
+ <%= table_for @users do -%>
8
+ <% columns :name, :email, :address %>
9
+ <% end %>
10
+
11
+ In this case you just put fields list to the :columns method.
12
+ This ruby code will produce following HTML:
13
+
14
+ <table>
15
+ <thead>
16
+ <tr>
17
+ <th>Name</th>
18
+ <th>Email</th>
19
+ <th>Address</th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <tr>
24
+ <td>John Smith</td>
25
+ <td>john.smith@example.com</td>
26
+ <td>100 Spear St., NY, USA</td>
27
+ </tr>
28
+ </tbody>
29
+ </table>
30
+
31
+ === Simple examle
32
+
33
+ <%= table_for @users, :html => {
34
+ :class => "simple-table",
35
+ :id => "users",
36
+ :width => "100%",
37
+ :tr => {
38
+ :class => "simple-row"
39
+ }
40
+ } do -%>
41
+ <% column :name %>
42
+ <% column :email %>
43
+ <% column :address, :title => "Home" %>
44
+ <% end %>
45
+
46
+ You can put :html hash to the options list. In this case table will be created with
47
+ given html attributes. Also :title value in the :column method will be used as column's
48
+ title. It will produce HTML similar to:
49
+
50
+ <table class="simple-table" id="users" width="100%">
51
+ <thead>
52
+ <tr>
53
+ <td>Name</td>
54
+ <td>Email</td>
55
+ <td>Home</td>
56
+ </tr>
57
+ </thead>
58
+ <tbody>
59
+ <tr class="simple-row"
60
+ ...
61
+ </tr>
62
+ </tbody>
63
+ </table>
64
+
65
+ === More complex example
66
+
67
+ <%= table_for @users do -%>
68
+ <% column :login, :title => "User name" %>
69
+ <% column :email %>
70
+ <% column :title => "Full name" do |user| %>
71
+ <% [user.first_name, user.last_name].join(" ") %>
72
+ <% end %>
73
+ <% column :title => "Actions" do |user| %>
74
+ <% [link_to("Show", user), link_to("Delete", user, :method => :delete)].join(" | ") %>
75
+ <% end %>
76
+ <% end %>
77
+
78
+ === Example with colorized rows
79
+
80
+ <%= table_for @users, :html => { :tr => { :class => "row" } }, :stripes => %w{even odd} do %>
81
+ <% column :name %>
82
+ <% column :email %>
83
+ <% column :address %>
84
+ <% end %>
85
+
86
+ Also class given by :stripe option will be merged with options[:html][:tr] so this code will produce following HTML:
87
+
88
+ <tr class="row even">...
89
+ <tr class="row odd">...
90
+ <tr class="row even">...
91
+ <tr class="row odd">...
92
+
93
+ == Known issues
94
+
95
+ Unfortunately it works incorrect if there is no "-" before %> in this code:
96
+
97
+ <%= table_for @users do -%>
98
+
99
+ We hope it will be fixed soon.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ desc "Test the table_for plugin."
4
+ RSpec::Core::RakeTask.new('spec')
5
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'table_for'
@@ -0,0 +1,13 @@
1
+ module CoreEx
2
+ module ArrayIterator
3
+ def next
4
+ unless self.size.zero?
5
+ res = (@current ||= 0)
6
+ if self.size == (@current += 1)
7
+ @current = 0
8
+ end
9
+ self[res]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module TableHelper
2
+ class CallbackColumn < Column # :nodoc:
3
+ def initialize(template, obj, ops)
4
+ super
5
+ @title = @options.delete(:title) || "&nbsp;"
6
+ end
7
+ def content_for(record)
8
+ @attr.call(record)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module TableHelper
2
+ class Column # :nodoc:
3
+ attr_reader :title
4
+ def initialize(template, obj, ops)
5
+ @template, @options, @attr, @title = template, ops, obj, ""
6
+ end
7
+
8
+ def content_for
9
+ raise NoMethodError, "Use SimpleColumn or CallbackColumn"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ module TableHelper
2
+ # Simplest examle:
3
+ #
4
+ # <%= table_for @users do -%>
5
+ # <% columns :name, :email, :address %>
6
+ # <% end %>
7
+ #
8
+ # Simple examle:
9
+ #
10
+ # <%= table_for @users, :http => { :class => "simple-table", :id => "users" } do -%>
11
+ # <% column :name %>
12
+ # <% column :email %>
13
+ # <% column :address %>
14
+ # <% end %>
15
+ #
16
+ # More complex example:
17
+ #
18
+ # <%= table_for @users do -%>
19
+ # <% column :login, :title => "User name" %>
20
+ # <% column :email %>
21
+ # <% column :title => "Full name" do |user| %>
22
+ # <% [user.first_name, user.last_name].join(" ") %>
23
+ # <% end %>
24
+ # <% column :title => "Actions" do |user| %>
25
+ # <% link_to "Show", user %>
26
+ # <% link_to "Delete", user, :method => :delete %>
27
+ # <% end %>
28
+ # <% end %>
29
+ #
30
+ def table_for(records, *args, &proc)
31
+ raise ArgumentError, "Missing block" unless block_given?
32
+ options = args.extract_options!
33
+ raise ArgumentError, "Records should be array" unless records.is_a? Enumerable
34
+ t = Table.new(self, records, options)
35
+ t.instance_eval(&proc)
36
+ t.draw
37
+ end
38
+ end
39
+
40
+ ActionView::Base.class_eval {
41
+ include TableHelper
42
+ }
@@ -0,0 +1,11 @@
1
+ module TableHelper
2
+ class SimpleColumn < Column # :nodoc:
3
+ def initialize(template, obj, ops)
4
+ super
5
+ @title = @options.delete(:title) || @attr.to_s.humanize || "&nbsp;"
6
+ end
7
+ def content_for(record)
8
+ record.send(@attr)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ require "core_ex/array"
2
+
3
+ module TableHelper
4
+ class Table # :nodoc:
5
+ delegate :content_tag, :to => :@template
6
+
7
+ def initialize(template, records, options = {})
8
+ @template, @records, @columns = template, records, []
9
+ # table's html options
10
+ @table_html_options = options.delete(:html) || {}
11
+ # trs' html options
12
+ @tr_html_options = @table_html_options.delete(:tr) || {}
13
+ # stripes (cycling)
14
+ @stripes = options.delete(:stripes) || []
15
+ @stripes.extend CoreEx::ArrayIterator
16
+ end
17
+
18
+ def columns(*args)
19
+ unless args.blank?
20
+ args.each do |arg|
21
+ self.column(arg)
22
+ end
23
+ else
24
+ raise ArgumentError, "At least one attribute name should be given"
25
+ end
26
+ end
27
+
28
+ def column(*args, &block)
29
+ col_options = args.extract_options!
30
+ unless args.blank?
31
+ attr = args.shift
32
+ @columns << SimpleColumn.new(@template, attr, col_options)
33
+ else
34
+ if block_given?
35
+ @columns << CallbackColumn.new(@template, block, col_options)
36
+ else
37
+ raise ArgumentError, "Attribute name or block should be given"
38
+ end
39
+ end
40
+ end
41
+
42
+ def draw
43
+ content_tag :table, @table_html_options do
44
+ head + body
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def method_missing(method, *args, &proc)
51
+ @template.send(method, *args, &proc)
52
+ end
53
+
54
+ private
55
+
56
+ def head
57
+ content_tag :thead do
58
+ content_tag :tr do
59
+ @columns.map do |col|
60
+ content_tag :th do
61
+ col.title
62
+ end
63
+ end.join
64
+ end
65
+ end
66
+ end
67
+
68
+ def body
69
+ content_tag :tbody do
70
+ @records.map do |rec|
71
+ content_tag(:tr, tr_options) do
72
+ @columns.map do |col|
73
+ content_tag :td do
74
+ col.content_for(rec).to_s
75
+ end
76
+ end.join
77
+ end
78
+ end.join
79
+ end
80
+ end
81
+
82
+ def tr_options
83
+ res = @tr_html_options.nil? ? {} : @tr_html_options.clone
84
+ html_class = @stripes.next
85
+ unless html_class.nil?
86
+ if res.has_key?(:class)
87
+ res[:class] += " " + html_class
88
+ else
89
+ res.merge!({ :class => html_class })
90
+ end
91
+ end
92
+ res
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,4 @@
1
+ module TableHelper
2
+ GEM_NAME = "table_for_collection"
3
+ VERSION = "1.0"
4
+ end
@@ -0,0 +1,10 @@
1
+ require "action_view"
2
+ require "table_for/helper"
3
+
4
+ module TableHelper
5
+ private
6
+ autoload :Column, "table_for/column"
7
+ autoload :SimpleColumn, "table_for/simple_column"
8
+ autoload :CallbackColumn, "table_for/callback_column"
9
+ autoload :Table, "table_for/table"
10
+ end
@@ -0,0 +1,39 @@
1
+ require 'core_ex/array'
2
+
3
+ describe Array do
4
+ describe "when non-empty" do
5
+ let(:array) do
6
+ [1, 2, 3]
7
+ end
8
+ before(:each) do
9
+ array.extend CoreEx::ArrayIterator
10
+ end
11
+ it "should have :next method" do
12
+ array.should respond_to(:next)
13
+ end
14
+ describe "method :next" do
15
+ it "should return valid values" do
16
+ array.next.should == 1
17
+ array.next.should == 2
18
+ array.next.should == 3
19
+ array.next.should == 1
20
+ end
21
+ end
22
+ end
23
+ describe "when empty" do
24
+ let(:array) do
25
+ []
26
+ end
27
+ before(:each) do
28
+ array.extend CoreEx::ArrayIterator
29
+ end
30
+ it "should have :next method" do
31
+ array.should respond_to(:next)
32
+ end
33
+ it "should return nil" do
34
+ array.next.should be_nil
35
+ array.next.should be_nil
36
+ array.next.should be_nil
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ require "table_for"
2
+ require "webrat"
3
+
4
+ RSpec.configure do |config|
5
+ config.include(Webrat::Matchers)
6
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ describe TableHelper::Table do
4
+ # ActionView::Base instance
5
+ let(:template) do
6
+ ActionView::Base.new
7
+ end
8
+ # users list (stubbed data)
9
+ let(:users) do
10
+ [
11
+ mock({
12
+ :name => "John Smith",
13
+ :email => "tester@example.com",
14
+ :address => "100, Spear Street, NY, USA",
15
+ })
16
+ ]
17
+ end
18
+ # table instance
19
+ let(:table) do
20
+ TableHelper::Table.new(template, users)
21
+ end
22
+ # check are methods available
23
+ describe "should respond_to" do
24
+ [:columns, :column, :draw, :content_tag].each do |method|
25
+ it "#{method}" do
26
+ table.should respond_to(method)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,203 @@
1
+ require "spec_helper"
2
+
3
+ describe ActionView::Base do
4
+ # ActionView::Base instance
5
+ let(:template) do
6
+ ActionView::Base.new
7
+ end
8
+ # users list (stubbed data)
9
+ let(:users) do
10
+ [
11
+ mock({
12
+ :id => 1209,
13
+ :name => "John Smith",
14
+ :email => "smith@matrix.net",
15
+ :address => "100, Spear Street, NY, USA",
16
+ }),
17
+ mock({
18
+ :id => 2123,
19
+ :name => "Thomas Anderson",
20
+ :email => "neo@matrix.net",
21
+ :address => "200, Spear Street, NY, USA",
22
+ }),
23
+ mock({
24
+ :id => 3323,
25
+ :name => "Trinity",
26
+ :email => "trinity@matrix.net",
27
+ :address => "300, Spear Street, NY, USA",
28
+ }),
29
+ mock({
30
+ :id => 4912,
31
+ :name => "Morpheus",
32
+ :email => "morpheus@matrix.net",
33
+ :address => "400, Spear Street, NY, USA",
34
+ })
35
+ ]
36
+ end
37
+ # check if method available
38
+ it "should respond to :table_for" do
39
+ template.should respond_to(:table_for)
40
+ end
41
+
42
+ # main method
43
+ describe ":table_for method" do
44
+ # <%= table_for @users %>
45
+ it "should raise if no block given" do
46
+ lambda do
47
+ template.table_for(users)
48
+ end.should raise_error(ArgumentError)
49
+ end
50
+ # <%= table_for @users do %>
51
+ # <% column :name %>
52
+ # <% end %>
53
+ describe "with simple column" do
54
+ before(:each) do
55
+ @html = template.table_for(users) do
56
+ column :name
57
+ end
58
+ end
59
+ it "should render valid HTML" do
60
+ @html.should have_selector("table") do |table|
61
+ table.should have_selector("thead/tr/th") do |th|
62
+ th.should contain("Name")
63
+ end
64
+ table.should have_selector("tbody/tr") do |tr|
65
+ users.each do |user|
66
+ tr.should have_selector("td") do |td|
67
+ td.should contain(user.name)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ # <%= table_for @users do %>
75
+ # <% columns :name, :email, :address %>
76
+ # <% end %>
77
+ describe "with columns" do
78
+ before(:each) do
79
+ @html = template.table_for(users) do
80
+ columns :id, :name, :email, :address
81
+ end
82
+ end
83
+ it "should render valid HTML" do
84
+ @html.should have_selector("table") do |table|
85
+ table.should have_selector("thead/tr") do |tr|
86
+ ["Id", "Name", "Email", "Address"].each do |field|
87
+ tr.should have_selector("th") do |th|
88
+ th.should contain(field)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ # <%= table_for @users, :html => { :id => "users", :class => "simple-table" } do %>
97
+ # <% column :name %>
98
+ # <% end %>
99
+ describe "with given :html options" do
100
+ before(:each) do
101
+ @html = template.table_for(users, :html => { :id => "users", :class => "simple-table" }) do
102
+ column :name
103
+ end
104
+ end
105
+ it "should render specialized table" do
106
+ @html.should have_selector("table#users.simple-table")
107
+ end
108
+ end
109
+ # <%= table_for @users do %>
110
+ # <% column :name, :title => "User's name" %>
111
+ # <% end %>
112
+ describe "with titled column" do
113
+ before(:each) do
114
+ @html = template.table_for(users) do
115
+ column :email, :title => "Email address"
116
+ end
117
+ end
118
+ it "should render valid HTML" do
119
+ @html.should have_selector("table") do |table|
120
+ table.should have_selector("thead/tr/th") do |th|
121
+ th.should contain("Email address")
122
+ end
123
+ table.should have_selector("tbody/tr") do |tr|
124
+ users.each do |user|
125
+ tr.should have_selector("td") do |td|
126
+ td.should contain(user.email)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ # <%= table_for @users do %>
134
+ # <% column :title => "User's name" do |user| %>
135
+ # <% content_tag :div do %>
136
+ # <% [user.first_name, user.last_name].join(" ") %>
137
+ # <% end %>
138
+ # <% end %>
139
+ # <% end %>
140
+ describe "with callback column" do
141
+ before(:each) do
142
+ @html = template.table_for(users) do
143
+ column :id
144
+ column :title => "Addr" do |user|
145
+ content_tag :div do
146
+ user.address[0,10]
147
+ end
148
+ end
149
+ end
150
+ end
151
+ it "should render valid HTML" do
152
+ @html.should have_selector("table") do |table|
153
+ table.should have_selector("thead/tr/th") do |th|
154
+ th.should contain("Addr")
155
+ end
156
+ table.should have_selector("tbody/tr") do |tr|
157
+ users.each do |user|
158
+ tr.should have_selector("td") do |td|
159
+ td.should contain(user.id.to_s)
160
+ end
161
+ tr.should have_selector("td/div") do |td|
162
+ td.should contain(user.address[0,10])
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # <%= table_for @users, :stripes => ["odd", "even"] do %>
171
+ # <% column :name %>
172
+ # <% end %>
173
+ describe "with cycling stripes" do
174
+ before(:each) do
175
+ @html = template.table_for(users, :stripes => %w{s-one s-two s-three}) do
176
+ column :name
177
+ end
178
+ end
179
+
180
+ it "should have valid classes" do
181
+ @html.should have_selector("tr.s-one", :count => 2)
182
+ @html.should have_selector("tr.s-two", :count => 1)
183
+ @html.should have_selector("tr.s-three", :count => 1)
184
+ end
185
+ end
186
+
187
+ # <%= table_for @users, :stripes => ["odd", "even"], :html => { :tr => { :class => "table-row" } } do %>
188
+ # <% column :name %>
189
+ # <% end %>
190
+ describe "with tr html" do
191
+ before(:each) do
192
+ @html = template.table_for(users, :stripes => ["odd", "even"], :html => { :tr => { :class => "table-row" } }) do
193
+ column :name
194
+ end
195
+ end
196
+
197
+ it "should have valid classes" do
198
+ @html.should have_selector("tr.odd.table-row", :count => 2)
199
+ @html.should have_selector("tr.even.table-row", :count => 2)
200
+ end
201
+ end
202
+ end
203
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: table_for_collection
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ version: "1.0"
10
+ platform: ruby
11
+ authors:
12
+ - Dima Lunich
13
+ - Andrey Savchenko
14
+ - Dmitry Shaposhnik
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-10-24 00:00:00 +03:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rspec
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rails
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description: This gem builds HTML-table using given array
51
+ email:
52
+ - dima.lunich@gmail.com
53
+ - andrey@aejis.eu
54
+ - dmitry@shaposhnik.name
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - README.rdoc
61
+ files:
62
+ - lib/core_ex/array.rb
63
+ - lib/table_for/callback_column.rb
64
+ - lib/table_for/column.rb
65
+ - lib/table_for/helper.rb
66
+ - lib/table_for/simple_column.rb
67
+ - lib/table_for/table.rb
68
+ - lib/table_for/version.rb
69
+ - lib/table_for_collection.rb
70
+ - spec/core_ex/array_spec.rb
71
+ - spec/spec_helper.rb
72
+ - spec/table_for_collection/table_spec.rb
73
+ - spec/table_for_collection_spec.rb
74
+ - README.rdoc
75
+ - Rakefile
76
+ - Changelog
77
+ - Gemfile
78
+ - init.rb
79
+ has_rdoc: true
80
+ homepage: http://github.com/lunich/table_for
81
+ licenses: []
82
+
83
+ post_install_message:
84
+ rdoc_options:
85
+ - --main
86
+ - README.rdoc
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project: ""
110
+ rubygems_version: 1.3.7
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: table_for_collection-1.0
114
+ test_files:
115
+ - spec/core_ex/array_spec.rb
116
+ - spec/spec_helper.rb
117
+ - spec/table_for_collection/table_spec.rb
118
+ - spec/table_for_collection_spec.rb