table_cloth 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,5 @@
1
+ Unfortunately I'm not used to making a changelog, this changelog starts at v0.4.0.
2
+
3
+ * v0.4.0
4
+
5
+ Change how the default presenter renders tables using ElementFactory. (https://github.com/bobbytables/element_factory)
data/Gemfile CHANGED
@@ -1,6 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in tablecloth.gemspec
4
- gemspec
5
-
6
- gem 'actionpack', '>= 3.0', '< 4.1', github: 'rails/rails', branch: 'master'
4
+ gemspec
data/README.md CHANGED
@@ -13,7 +13,9 @@ Follow me! [@robertoross](http://twitter.com/robertoross)
13
13
 
14
14
  Add this line to your application's Gemfile:
15
15
 
16
- gem 'table_cloth'
16
+ ```ruby
17
+ gem 'table_cloth'
18
+ ```
17
19
 
18
20
  And then execute:
19
21
 
@@ -31,7 +33,7 @@ $ rails g table User
31
33
 
32
34
  It will make this:
33
35
 
34
- ```
36
+ ```ruby
35
37
  class UserTable < TableCloth::Base
36
38
  # Define columns with the #column method
37
39
  # column :name, :email
@@ -66,14 +68,14 @@ end
66
68
  Go ahead and modify it to suit your needs, pick the columns, conditions, actions, etc...
67
69
 
68
70
  In your view, you would then use this code:
69
- ```
70
- <%= simple_table_for @users, with: UserTable %>
71
71
 
72
+ ```erb
73
+ <%= simple_table_for @users, with: UserTable %>
72
74
  ```
73
75
 
74
- The second approach to making tables with Table Cloth is in the view.
76
+ Or if you want more customization:
75
77
 
76
- ```
78
+ ```erb
77
79
  <%= simple_table_for @users do |t| %>
78
80
  <% t.column :name %>
79
81
  <% t.column :email %>
@@ -95,8 +97,9 @@ class ImageColumn < TableCloth::Column
95
97
  end
96
98
  ```
97
99
 
98
- In your table
99
- ```
100
+ In your table:
101
+
102
+ ```erb
100
103
  <%= simple_table_for @users do |table| %>
101
104
  <% table.column :name %>
102
105
  <% table.column :image, using: ImageColumn %>
@@ -105,9 +108,9 @@ In your table
105
108
 
106
109
  ## Actions
107
110
 
108
- A lot of tables have an actions column to give you the full CRUD effect. They can be painful but Table Cloth incorporates a way to easily add them to your definition.
111
+ A lot of tables have an actions column to give you the full CRUD effect. They can be painful but Table Cloth incorporates a way to easily add them to your definition:
109
112
 
110
- ```
113
+ ```ruby
111
114
  class UserTable < TableCloth::Base
112
115
  column :name
113
116
 
@@ -127,7 +130,7 @@ end
127
130
 
128
131
  Create an initializer called ```table_cloth.rb```
129
132
 
130
- Configuration looks like this:
133
+ It should look like this:
131
134
 
132
135
  ```ruby
133
136
  TableCloth::Configuration.configure do |config|
@@ -140,7 +143,7 @@ TableCloth::Configuration.configure do |config|
140
143
  end
141
144
  ```
142
145
 
143
- You can also configure specific tables separately.
146
+ You can also configure specific tables separately:
144
147
 
145
148
  ```ruby
146
149
  class UserTable < TableCloth::Base
@@ -182,7 +185,6 @@ class UserTable < TableCloth::Base
182
185
  [user.name, {class: "#{user.type}-user"}]
183
186
  end
184
187
  end
185
-
186
188
  ```
187
189
 
188
190
  This would render something alow the lines of:
data/lib/table_cloth.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "action_view"
2
+ require "element_factory"
2
3
  require "active_support/core_ext/class"
3
4
  require "table_cloth/version"
4
5
 
@@ -12,11 +12,11 @@ module TableCloth
12
12
  raise NoMethodError, "You must override the .render method"
13
13
  end
14
14
 
15
- def render_header
15
+ def thead
16
16
  raise NoMethodError, "You must override the .header method"
17
17
  end
18
18
 
19
- def render_rows
19
+ def tbody
20
20
  raise NoMethodError, "You must override the .rows method"
21
21
  end
22
22
 
@@ -45,16 +45,6 @@ module TableCloth
45
45
  end
46
46
  end
47
47
 
48
- def wrapper_tag(type, value=nil, options={}, &block)
49
- options = tag_options(type, options)
50
-
51
- if block_given?
52
- view_context.content_tag(type, options, &block)
53
- else
54
- view_context.content_tag(type, value, options)
55
- end
56
- end
57
-
58
48
  private
59
49
 
60
50
  def tag_options(type, options={})
@@ -2,24 +2,43 @@ module TableCloth
2
2
  module Presenters
3
3
  class Default < ::TableCloth::Presenter
4
4
  def render_table
5
- wrapper_tag :table do
6
- render_header + render_rows
5
+ @render_table ||= ElementFactory::Element.new(:table, tag_options(:table)).tap do |table|
6
+ table << thead
7
+ table << tbody
7
8
  end
8
9
  end
9
10
 
10
- def render_rows
11
- wrapper_tag :tbody do
12
- v.raw objects.inject("") {|r, object| r + render_row(object) }
11
+ def thead
12
+ @thead ||= ElementFactory::Element.new(:thead, tag_options(:thead)).tap do |thead|
13
+ thead << thead_row
13
14
  end
14
15
  end
15
16
 
16
- def render_row(object)
17
- wrapper_tag :tr do
18
- v.raw columns.inject("") {|tds, column| tds + render_td(column, object) }
17
+ def tbody
18
+ @tbody ||= ElementFactory::Element.new(:tbody, tag_options(:tbody)).tap do |tbody|
19
+ objects.each {|object| tbody << row_for_object(object) }
19
20
  end
20
21
  end
21
22
 
22
- def render_td(column, object)
23
+ private
24
+
25
+ def thead_row
26
+ @thead_row ||= ElementFactory::Element.new(:tr, tag_options(:tr)).tap do |row|
27
+ column_names.each do |name|
28
+ row << ElementFactory::Element.new(:th, tag_options(:th).merge(text: name))
29
+ end
30
+ end
31
+ end
32
+
33
+ def row_for_object(object)
34
+ ElementFactory::Element.new(:tr, tag_options(:tr)).tap do |row|
35
+ columns.each do |column|
36
+ row << column_for_object(column, object)
37
+ end
38
+ end
39
+ end
40
+
41
+ def column_for_object(column, object)
23
42
  td_options = column.options[:td_options] || {}
24
43
  value = column.value(object, view_context, table)
25
44
 
@@ -30,15 +49,13 @@ module TableCloth
30
49
  td_options.update(options)
31
50
  end
32
51
 
33
- wrapper_tag(:td, value, td_options)
34
- end
35
-
36
- def render_header
37
- wrapper_tag :thead do
38
- wrapper_tag :tr do
39
- v.raw column_names.inject("") {|tags, name| tags + wrapper_tag(:th, name) }
40
- end
52
+ if value.html_safe?
53
+ td_options[:inner_html] = value
54
+ else
55
+ td_options[:text] = value
41
56
  end
57
+
58
+ ElementFactory::Element.new(:td, tag_options(:td).merge(td_options))
42
59
  end
43
60
  end
44
61
  end
@@ -1,3 +1,3 @@
1
1
  module TableCloth
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -15,7 +15,6 @@ describe 'Action View Extension' do
15
15
  table.column :name, :email
16
16
  end
17
17
 
18
- doc = Nokogiri::HTML(table)
19
- expect(doc.at_xpath('//table')).to be_present
18
+ expect(table).to have_tag "table"
20
19
  end
21
20
  end
@@ -53,47 +53,4 @@ describe TableCloth::Presenter do
53
53
  expected = objects.map {|o| [o.id, o.name, o.email] }
54
54
  expect(subject.rows).to eq(expected)
55
55
  end
56
-
57
- context '.wrapper_tag' do
58
- it "creates a tag with a block" do
59
- table = subject.wrapper_tag(:table) { "Hello" }
60
- element = to_element(table, "table")
61
- expect(element).to be_present
62
- expect(element.text).to eq("Hello")
63
- end
64
-
65
- it "creates a tag without a block" do
66
- table = subject.wrapper_tag(:table, "Hello")
67
- element = to_element(table, "table")
68
- expect(element).to be_present
69
- expect(element.text).to eq("Hello")
70
- end
71
-
72
- context "config" do
73
- let(:config) { double("config", config_for: { class: "table_class" }) }
74
-
75
- it "inherits options from global config" do
76
- TableCloth.config.stub config_for: {class: "global_class"}
77
- tag = subject.wrapper_tag(:table, "Hello")
78
- element = to_element(tag, "table")
79
-
80
- expect(element[:class]).to eq("global_class")
81
- end
82
-
83
- it "includes config sent to it" do
84
- tag = subject.wrapper_tag(:table, "Hello", {class: "passed_class"})
85
- element = to_element(tag, "table")
86
-
87
- expect(element[:class]).to eq("passed_class")
88
- end
89
-
90
- it "includes config from the table instance" do
91
- dummy_table.stub config: config
92
- tag = subject.wrapper_tag(:table, "Hello", {class: "passed_class"})
93
- element = to_element(tag, "table")
94
-
95
- expect(element[:class]).to eq("table_class")
96
- end
97
- end
98
- end
99
56
  end
@@ -11,74 +11,60 @@ describe TableCloth::Presenters::Default do
11
11
  let(:view_context) { ActionView::Base.new }
12
12
  subject { TableCloth::Presenters::Default.new(objects, dummy_table, view_context) }
13
13
 
14
- context "header" do
14
+ describe "#thead" do
15
15
  let(:column_names) { ["Col1", "Col2"] }
16
+ let(:thead) { Nokogiri::HTML(subject.thead.to_s) }
16
17
 
17
18
  before(:each) do
18
19
  subject.stub column_names: column_names
19
20
  end
20
21
 
21
22
  it "creates a thead" do
22
- expect(subject.render_header).to have_tag "thead"
23
+ expect(thead).to have_tag "thead"
23
24
  end
24
25
 
25
26
  it "creates th's" do
26
- header = Nokogiri::HTML(subject.render_header)
27
- expect(header.css("th").size).to be 2
27
+ expect(thead.css("th").size).to be 2
28
28
  end
29
29
 
30
30
  it "creates th's with the correct text" do
31
- header = Nokogiri::HTML(subject.render_header)
32
- header.css("th").each_with_index {|th, i| expect(th.text).to eq(column_names[i]) }
31
+ thead.css("th").each_with_index do |th, i|
32
+ expect(th.text).to eq(column_names[i])
33
+ end
33
34
  end
34
35
  end
35
36
 
36
- context "rows" do
37
- it 'creates a tbody' do
38
- expect(subject.render_rows).to have_tag "tbody"
39
- end
37
+ describe "#render_table" do
38
+ let(:table) { Nokogiri::HTML(subject.render_table.to_s) }
40
39
 
41
- it "creates a row in the tbody" do
42
- tbody = Nokogiri::HTML(subject.render_rows)
43
- expect(tbody.css('tr').size).to be 3
40
+ it "renders a table tag" do
41
+ expect(table).to have_tag "table"
44
42
  end
45
43
  end
46
44
 
47
- context 'escaped values' do
48
- let(:objects) do
49
- FactoryGirl.build_list(:dummy_model, 1,
50
- name: "<script>alert(\"Im in your columns, snatching your main thread.\")</script>"
51
- )
52
- end
53
-
54
- it 'does not allow unescaped values in columns' do
55
- tbody = Nokogiri::HTML(subject.render_rows).at_xpath('//tbody')
56
-
57
- tbody.xpath('//td').each do |td|
58
- td.at_xpath('.//script').should_not be_present
59
- end
45
+ describe "#tbody" do
46
+ it 'creates a tbody' do
47
+ expect(subject.tbody.to_s).to have_tag "tbody"
60
48
  end
61
- end
62
49
 
63
- context "column configuration" do
64
- let(:column) { FactoryGirl.build(:column, options: {td_options: {class: "email_column"}}) }
65
- let(:model) { FactoryGirl.build(:dummy_model) }
66
-
67
- it "td has a class set" do
68
- td = Nokogiri::HTML(subject.render_td(column, model)).at_css("td")
69
- expect(td[:class]).to eq "email_column"
50
+ it "creates a row in the tbody" do
51
+ tbody = Nokogiri::HTML(subject.tbody.to_s)
52
+ expect(tbody.css('tr').size).to be 3
70
53
  end
71
54
 
72
- context "by value of row column" do
73
- before(:each) do
74
- column.stub value: ["robert@example.com", {class: "special-class"}]
55
+ context 'escaped values' do
56
+ let(:objects) do
57
+ FactoryGirl.build_list(:dummy_model, 1,
58
+ name: "<script>alert(\"Im in your columns, snatching your main thread.\")</script>"
59
+ )
75
60
  end
76
61
 
77
- specify "column has options because of value" do
78
- td = Nokogiri::HTML(subject.render_td(column, model)).at_css("td")
62
+ it 'does not allow unescaped values in columns' do
63
+ tbody = Nokogiri::HTML(subject.tbody.to_s).at_xpath('//tbody')
79
64
 
80
- expect(td.text).to include "robert@example.com"
81
- expect(td[:class]).to eq("special-class")
65
+ tbody.xpath('//td').each do |td|
66
+ td.at_xpath('.//script').should_not be_present
67
+ end
82
68
  end
83
69
  end
84
70
  end
@@ -1,6 +1,15 @@
1
+ require "nokogiri"
2
+
1
3
  RSpec::Matchers.define :have_tag do |tag|
2
4
  match do |string|
3
- document = Nokogiri::HTML(string)
4
- !!document.at_xpath(".//#{tag}")
5
+ document = Nokogiri::HTML(string.to_s)
6
+ !!document.at_css(tag)
7
+ end
8
+ end
9
+
10
+ RSpec::Matchers.define :have_xpath do |tag|
11
+ match do |string|
12
+ document = Nokogiri::HTML(string.to_s)
13
+ !!document.at_xpath(tag)
5
14
  end
6
15
  end
data/table_cloth.gemspec CHANGED
@@ -28,4 +28,5 @@ Gem::Specification.new do |gem|
28
28
  gem.add_development_dependency('rb-fsevent', '~> 0.9.1')
29
29
 
30
30
  gem.add_dependency('actionpack', '>= 3.1', '< 4.1')
31
+ gem.add_dependency('element_factory', '~> 0.1.0')
31
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: table_cloth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
12
+ date: 2013-05-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -177,6 +177,22 @@ dependencies:
177
177
  - - <
178
178
  - !ruby/object:Gem::Version
179
179
  version: '4.1'
180
+ - !ruby/object:Gem::Dependency
181
+ name: element_factory
182
+ requirement: !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ~>
186
+ - !ruby/object:Gem::Version
187
+ version: 0.1.0
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ none: false
192
+ requirements:
193
+ - - ~>
194
+ - !ruby/object:Gem::Version
195
+ version: 0.1.0
180
196
  description: Table Cloth helps you create tables easily.
181
197
  email:
182
198
  - robert@creativequeries.com
@@ -187,6 +203,7 @@ files:
187
203
  - .gitignore
188
204
  - .rspec
189
205
  - .travis.yml
206
+ - CHANGELOG
190
207
  - Gemfile
191
208
  - Guardfile
192
209
  - LICENSE.txt