table_for_collection 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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