table_cloth 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -75,7 +75,9 @@ The second approach to making tables with Table Cloth is in the view.
75
75
  <%= simple_table_for @users do |t| %>
76
76
  <% t.column :name %>
77
77
  <% t.column :email %>
78
- <% t.action {|user| link_to "View", user %>
78
+ <% t.actions do %>
79
+ <% action {|user| link_to "View", user } %>
80
+ <% end %>
79
81
  <% end %>
80
82
  ```
81
83
 
@@ -106,8 +108,11 @@ A lot of tables have an actions column to give you the full CRUD effect. They ca
106
108
  ```
107
109
  class UserTable < TableCloth::Base
108
110
  column :name
109
- action {|object| link_to 'View', object }
110
- action(if: :admin?) {|object| link_to 'Delete', object, method: :delete }
111
+
112
+ actions do
113
+ action {|object| link_to 'View', object }
114
+ action(if: :admin?) {|object| link_to 'Delete', object, method: :delete }
115
+ end
111
116
 
112
117
  def admin?
113
118
  view.current_user.admin?
@@ -138,7 +143,10 @@ You can also configure specific tables separately.
138
143
  ```ruby
139
144
  class UserTable < TableCloth::Base
140
145
  column :name, :email
141
- action(:edit) {|object| link_to "Edit", edit_object_path(object) }
146
+
147
+ actions do
148
+ action {|object| link_to "Edit", edit_object_path(object) }
149
+ end
142
150
 
143
151
  config.table.class = ''
144
152
  config.thead.class = ''
@@ -11,12 +11,6 @@ module TableCloth
11
11
  @view = view
12
12
  end
13
13
 
14
- def column_names
15
- @column_names ||= columns.each_with_object([]) do |(column_name, column), names|
16
- names << column.human_name
17
- end
18
- end
19
-
20
14
  def columns
21
15
  @columns ||= self.class.columns.each_with_object({}) do |(column_name, column), columns|
22
16
  columns[column_name] = column if column.available?(self)
@@ -5,7 +5,7 @@ module TableCloth
5
5
  actions_html = actions.each_with_object('') do |action, links|
6
6
  if action.available?(table)
7
7
  links << "\n"
8
- links << view_context.instance_exec(object, view_context, &action.options[:proc])
8
+ links << (view_context.instance_exec(object, view_context, &action.options[:proc]) || "")
9
9
  end
10
10
  end
11
11
 
@@ -4,10 +4,10 @@ module TableCloth
4
4
  :table
5
5
 
6
6
  def initialize(objects, table, view)
7
- @view_context = view
7
+ @view_context = view
8
8
  @table_definition = table
9
- @objects = objects
10
- @table = table_definition.new(objects, view)
9
+ @objects = objects
10
+ @table = table_definition.new(objects, view)
11
11
  end
12
12
 
13
13
  # Short hand so your fingers don't hurt
@@ -28,7 +28,9 @@ module TableCloth
28
28
  end
29
29
 
30
30
  def column_names
31
- table.column_names
31
+ @column_names ||= table.columns.each_with_object([]) do |(column_name, column), names|
32
+ names << column.human_name
33
+ end
32
34
  end
33
35
 
34
36
  def row_values(object)
@@ -1,3 +1,3 @@
1
1
  module TableCloth
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :dummy_model do
3
+ sequence(:id) { |n| n }
4
+ email "robert@example.com"
5
+ name "robert"
6
+ end
7
+ end
@@ -3,14 +3,7 @@ require 'spec_helper'
3
3
  describe 'Action View Extension' do
4
4
  let(:action_view) { ActionView::Base.new }
5
5
  let(:objects) do
6
- 3.times.map do |n|
7
- num = n+1
8
- DummyModel.new.tap do |d|
9
- d.id = num # Wat
10
- d.email = "robert#{num}@example.com"
11
- d.name = "robert#{num}"
12
- end
13
- end
6
+ 3.times.map { FactoryGirl.build(:dummy_model) }
14
7
  end
15
8
 
16
9
  it 'includes to actionview' do
@@ -23,14 +16,6 @@ describe 'Action View Extension' do
23
16
  end
24
17
 
25
18
  doc = Nokogiri::HTML(table)
26
- doc.at_xpath('//table').should be_present
27
- doc.at_xpath('//tr').xpath('.//th').length.should == 2
28
-
29
- trs = doc.at_xpath('//tbody').xpath('.//tr').to_a
30
- trs.each_with_index do |tr, index|
31
- tds = tr.xpath('.//td')
32
- objects[index].name.should == tds[0].text
33
- objects[index].email.should == tds[1].text
34
- end
19
+ expect(doc.at_xpath('//table')).to be_present
35
20
  end
36
21
  end
@@ -4,26 +4,25 @@ describe TableCloth::Actions do
4
4
  subject { TableCloth::Actions }
5
5
 
6
6
  context "block syntax" do
7
-
8
7
  it "accepts a block" do
9
8
  actions = subject.new do
10
9
  action { 'Edit' }
11
10
  end
12
11
 
13
- actions.column.should have(1).actions
12
+ expect(actions.column).to have(1).actions
14
13
  end
15
14
 
16
15
  it "accepts options with a block" do
17
- expect do
18
- subject.new(class: "actions") do
19
- action { "Edit" }
20
- end
21
- end.not_to raise_error
16
+ actions = subject.new(class: "actions") do
17
+ action { "Edit" }
18
+ end
19
+
20
+ expect(actions.options[:class]).to eq("actions")
22
21
  end
23
22
 
24
23
  it ".all returns all actions for the column" do
25
24
  actions = subject.new { action { "Edit" } }
26
- actions.should have(1).all
25
+ expect(actions.all.length).to be 1
27
26
  end
28
27
  end
29
28
  end
@@ -3,17 +3,12 @@ require 'spec_helper'
3
3
  describe TableCloth::Base do
4
4
  subject { Class.new(TableCloth::Base) }
5
5
  let(:view_context) { ActionView::Base.new }
6
- let(:dummy_model) do
7
- DummyModel.new.tap do |d|
8
- d.id = 1
9
- d.email = 'robert@example.com'
10
- d.name = 'robert'
11
- end
12
- end
6
+ let(:dummy_model) { FactoryGirl.build(:dummy_model) }
7
+ let(:table_instance) { subject.new([], view_context) }
13
8
 
14
9
  context 'columns' do
15
10
  it 'has a column method' do
16
- subject.should respond_to :column
11
+ expect(subject).to respond_to :column
17
12
  end
18
13
 
19
14
  it 'column accepts a name' do
@@ -26,109 +21,34 @@ describe TableCloth::Base do
26
21
 
27
22
  it '.columns returns all columns' do
28
23
  subject.column :name
29
- subject.should have(1).columns
24
+ expect(subject).to have(1).columns
30
25
  end
31
26
 
32
- it 'excepts multiple column names' do
27
+ it 'accepts multiple column names' do
33
28
  subject.column :name, :email
34
- subject.should have(2).columns
29
+ expect(subject).to have(2).columns
35
30
  end
36
31
 
37
32
  it 'stores a proc if given in options' do
38
33
  subject.column(:name) { 'Wee' }
39
34
 
40
35
  column = subject.columns[:name]
41
- column.options[:proc].should be_present
42
- column.options[:proc].should be_kind_of(Proc)
43
- end
44
-
45
- it '.column_names returns all names' do
46
- subject.column :name, :email
47
- subject.new([], view_context).column_names.should == ['Name', 'Email']
48
- end
49
-
50
- it '.column_names includes actions when given' do
51
- subject.actions { action { } }
52
- subject.new([], view_context).column_names.should include 'Actions'
53
- end
54
-
55
- it '.column_names does not include actions if all action conditions fail' do
56
- subject.actions do
57
- action(if: :admin?) { '/' }
58
- end
59
-
60
- table = subject.new([], view_context)
61
- def table.admin?
62
- false
63
- end
64
-
65
- table.column_names.should_not include 'Actions'
66
- end
67
-
68
- it '.column_names include actions when only partial are available' do
69
- subject.actions do
70
- action(if: :admin?) { '/' }
71
- action(if: :awesome?) { '/' }
72
- end
73
-
74
- table = subject.new([], view_context)
75
- def table.admin?
76
- false
77
- end
78
-
79
- def table.awesome?
80
- true
81
- end
82
-
83
- table.column_names.should include 'Actions'
84
- end
85
-
86
- it '.column_names uses a name given to it' do
87
- subject.column :email, label: 'Email Address'
88
- subject.new([], view_context).column_names.should include 'Email Address'
89
- end
90
-
91
- it '.column can take a custom column' do
92
- email_column = Class.new(TableCloth::Column) do
93
- def value(object, view)
94
- "AN EMAIL!"
95
- end
96
- end
97
-
98
- subject.column :email, using: email_column
99
- subject.new([dummy_model], view_context)
100
-
101
- subject.columns[:email].value(dummy_model, view_context).should == "AN EMAIL!"
102
- end
103
- end
104
-
105
- context 'conditions' do
106
- context 'if' do
107
- subject { DummyTable.new([dummy_model], view_context) }
108
-
109
- it 'includes the id column when admin' do
110
- subject.column_names.should include 'Id'
111
- end
112
-
113
- it 'exclused the id column when an admin' do
114
- def subject.admin?
115
- false
116
- end
117
-
118
- subject.column_names.should_not include 'Id'
119
- end
36
+ expect(column.options[:proc]).to be_present
37
+ expect(column.options[:proc]).to be_kind_of(Proc)
120
38
  end
121
39
 
122
- context 'unless' do
123
- subject { DummyTableUnlessAdmin.new([dummy_model], view_context) }
124
- before(:each) do
125
- def subject.admin?
126
- false
40
+ context "custom" do
41
+ let(:custom_column) do
42
+ Class.new(TableCloth::Column) do
43
+ def value(object, view)
44
+ "AN EMAIL!"
45
+ end
127
46
  end
128
47
  end
129
48
 
130
- it 'includes the id when not an admin' do
131
- subject.column_names.should include 'Id'
49
+ it '.column can take a custom column' do
50
+ subject.column :email, using: custom_column
51
+ subject.columns[:email].value(dummy_model, view_context).should == "AN EMAIL!"
132
52
  end
133
53
  end
134
54
  end
@@ -146,7 +66,7 @@ describe TableCloth::Base do
146
66
  action { 'Delete' }
147
67
  end
148
68
 
149
- subject.columns[:actions].should have(2).actions
69
+ expect(subject.columns[:actions]).to be_kind_of TableCloth::Columns::Action
150
70
  end
151
71
  end
152
72
 
@@ -5,19 +5,11 @@ describe TableCloth::Builder do
5
5
  let(:view_context) { ActionView::Base.new }
6
6
 
7
7
  context '.build' do
8
- it 'can build a table on the fly with a block' do
9
- new_table = subject.build([], view_context) do |table|
10
- table.column :name
11
- table.actions do
12
- action { '/model/1/edit' }
13
- end
14
- end
15
-
16
- new_table.table.columns.length.should == 2
17
- new_table.table.columns[:actions].actions.length.should == 1
8
+ it 'builds a table on the fly with a block' do
9
+ expect {|b| subject.build([], view_context, &b) }.to yield_control
18
10
  end
19
11
 
20
- it 'can build a table from a class name' do
12
+ it 'builds a table from a class name' do
21
13
  new_table = subject.build([], view_context, with: DummyTable)
22
14
  new_table.table.should == DummyTable
23
15
  end
@@ -35,9 +27,8 @@ describe TableCloth::Builder do
35
27
 
36
28
  it '.to_s renders a table' do
37
29
  new_table = subject.build([], view_context, with: DummyTable)
38
- body = new_table.to_s
39
- doc = Nokogiri::HTML(body)
40
- doc.at_xpath('//table').should be_present
30
+ new_table.presenter.should_receive(:render_table).once
31
+ new_table.to_s
41
32
  end
42
33
  end
43
34
  end
@@ -3,51 +3,39 @@ require 'spec_helper'
3
3
  describe TableCloth::Column do
4
4
  subject { Class.new(TableCloth::Column) }
5
5
  let(:view_context) { ActionView::Base.new }
6
- let(:dummy_model) do
7
- DummyModel.new.tap do |d|
8
- d.id = 1
9
- d.email = 'robert@example.com'
10
- d.name = 'robert'
11
- end
12
- end
6
+ let(:dummy_model) { FactoryGirl.build(:dummy_model) }
13
7
 
14
8
  context 'values' do
15
- let(:name_column) do
16
- TableCloth::Column.new(:name)
9
+ let(:proc) do
10
+ lambda {|object, view| object.email.gsub("@", " at ")}
17
11
  end
18
12
 
19
- let(:email_column) do
20
- proc = lambda {|object, view|
21
- object.email
22
- }
23
-
24
- TableCloth::Column.new(:my_email, proc: proc)
25
- end
13
+ let(:name_column) { TableCloth::Column.new(:name) }
14
+ let(:email_column) { TableCloth::Column.new(:my_email, proc: proc) }
26
15
 
27
16
  it 'returns the name correctly' do
28
17
  name_column.value(dummy_model, view_context).should == 'robert'
29
18
  end
30
19
 
31
20
  it 'returns the email from a proc correctly' do
32
- email_column.value(dummy_model, view_context).should == 'robert@example.com'
21
+ email_column.value(dummy_model, view_context).should == 'robert at example.com'
33
22
  end
34
23
 
35
24
  context '.available?' do
36
- let(:dummy_table) do
37
- Class.new(TableCloth::Table) do
38
- column :name, if: :admin?
39
-
40
- def admin?
41
- view.admin?
42
- end
43
- end
44
- end
45
-
46
25
  it 'returns true on successful constraint' do
47
26
  table = Class.new(DummyTable).new([dummy_model], view_context)
48
27
  column = TableCloth::Column.new(:name, if: :admin?)
49
28
  column.available?(table).should be_true
50
29
  end
30
+
31
+ it 'returns false on failed constraints' do
32
+ table = Class.new(DummyTable).new([dummy_model], view_context)
33
+ table.stub admin?: false
34
+
35
+
36
+ column = TableCloth::Column.new(:name, if: :admin?)
37
+ column.available?(table).should be_false
38
+ end
51
39
  end
52
40
  end
53
41
  end
@@ -1,51 +1,62 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe TableCloth::Presenter do
4
+ subject { TableCloth::Presenter.new(objects, dummy_table, view_context) }
4
5
  let(:dummy_table) { Class.new(DummyTable) }
5
- let(:dummy_model) do
6
- DummyModel.new.tap do |d|
7
- d.id = 1
8
- d.email = 'robert@example.com'
9
- d.name = 'robert'
10
- end
11
- end
6
+ let(:dummy_model) { FactoryGirl.build(:dummy_model) }
12
7
 
13
- let(:objects) do
14
- 3.times.map do |n|
15
- num = n+1
16
- DummyModel.new.tap do |d|
17
- d.id = num # Wat
18
- d.email = "robert#{num}@example.com"
19
- d.name = "robert#{num}"
20
- end
21
- end
22
- end
8
+ let(:objects) { 3.times.map { FactoryGirl.build(:dummy_model) } }
23
9
 
24
10
  let(:view_context) { ActionView::Base.new }
25
11
  subject { TableCloth::Presenter.new(objects, dummy_table, view_context) }
26
12
 
13
+
14
+ context ".column_names" do
15
+ let(:table_instance) { dummy_table.new(objects, view_context) }
16
+ before(:each) { table_instance.stub admin?: false, awesome?: true }
17
+
18
+ it 'returns all names' do
19
+ dummy_table.column :name, :email
20
+ subject.column_names.should =~ ["Id", "Name", "Email"]
21
+ end
22
+
23
+ it 'includes actions when given' do
24
+ dummy_table.actions { action { } }
25
+ subject.column_names.should include 'Actions'
26
+ end
27
+
28
+ it 'include actions when only partial are available' do
29
+ dummy_table.actions do
30
+ action(if: :admin?) { '/' }
31
+ action(if: :awesome?) { '/' }
32
+ end
33
+ subject.column_names.should include 'Actions'
34
+ end
35
+
36
+ it 'uses a name given to it' do
37
+ dummy_table.column :email, label: 'Email Address'
38
+ subject.column_names.should include 'Email Address'
39
+ end
40
+ end
41
+
27
42
  it 'returns all values for a row' do
28
- subject.row_values(dummy_model).should == [1, 'robert', 'robert@example.com']
43
+ subject.row_values(dummy_model).should == [dummy_model.id, dummy_model.name, dummy_model.email]
29
44
  end
30
45
 
31
46
  it 'returns an edit link in the actions column' do
32
47
  dummy_table.actions do
33
48
  action {|object, view| link_to 'Edit', '/model/1/edit' }
34
49
  end
35
- presenter = TableCloth::Presenter.new(objects, dummy_table, view_context)
36
50
 
37
- actions_value = presenter.row_values(dummy_model).last
51
+ actions_value = subject.row_values(dummy_model).last
38
52
  column = Nokogiri::HTML(actions_value)
39
53
  column.at_xpath('//a')[:href].should == '/model/1/edit'
40
54
  column.at_xpath('//a').text.should == 'Edit'
41
55
  end
42
56
 
43
57
  it 'generates the values for all of the rows' do
44
- subject.rows.should == [
45
- [1, 'robert1', 'robert1@example.com'],
46
- [2, 'robert2', 'robert2@example.com'],
47
- [3, 'robert3', 'robert3@example.com']
48
- ]
58
+ expected = objects.map {|o| [o.id, o.name, o.email] }
59
+ expect(subject.rows).to eq(expected)
49
60
  end
50
61
 
51
62
  context 'tags' do
@@ -151,6 +151,22 @@ describe TableCloth::Presenters::Default do
151
151
  td = doc.at_css('td:last')
152
152
  td[:class].should include "actions"
153
153
  end
154
+
155
+ context "empty actions" do
156
+ let(:dummy_table) do
157
+ Class.new(TableCloth::Base) do
158
+ actions do
159
+ action { nil }
160
+ end
161
+ end
162
+ end
163
+
164
+ it "changes nil to empty string" do
165
+ doc = Nokogiri::HTML(subject.render_table)
166
+ td = doc.at_css('td:last')
167
+ expect(td.text).to eq "\n"
168
+ end
169
+ end
154
170
  end
155
171
 
156
172
  context 'by value of row column' do
@@ -1,15 +1,17 @@
1
1
  require 'table_cloth'
2
2
  require 'awesome_print'
3
3
  require 'nokogiri'
4
+ require 'factory_girl'
4
5
  require 'pry'
5
6
 
6
7
  Dir['./spec/support/**/*.rb'].each {|f| require f }
7
8
 
9
+ FactoryGirl.find_definitions
10
+
8
11
  ActionView::Base.send :include, TableClothViewMocks
9
12
 
10
13
  RSpec.configure do |config|
11
14
  config.treat_symbols_as_metadata_keys_with_true_values = true
12
15
  config.run_all_when_everything_filtered = true
13
16
  config.filter_run :focus
14
- config.include LetDeclarations
15
17
  end
@@ -1,5 +1,5 @@
1
1
  class DummyTable < TableCloth::Base
2
- column :id, if: :admin?
2
+ column :id
3
3
  column :name
4
4
  column :email
5
5
 
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency('awesome_print')
22
22
  gem.add_development_dependency('nokogiri')
23
23
  gem.add_development_dependency('pry')
24
+ gem.add_development_dependency('factory_girl')
24
25
  gem.add_development_dependency('guard-rspec')
25
26
  gem.add_development_dependency('rake')
26
27
 
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.2.2
4
+ version: 0.2.3
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: 2012-12-13 00:00:00.000000000 Z
12
+ date: 2012-12-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: factory_girl
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: guard-rspec
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -153,6 +169,7 @@ files:
153
169
  - lib/table_cloth/presenter.rb
154
170
  - lib/table_cloth/presenters/default.rb
155
171
  - lib/table_cloth/version.rb
172
+ - spec/factories/dummy_models.rb
156
173
  - spec/lib/action_view_extension_spec.rb
157
174
  - spec/lib/actions_spec.rb
158
175
  - spec/lib/base_spec.rb
@@ -167,7 +184,6 @@ files:
167
184
  - spec/support/dummy_table.rb
168
185
  - spec/support/dummy_table_with_actions.rb
169
186
  - spec/support/dummy_table_with_value_options.rb
170
- - spec/support/let_declarations.rb
171
187
  - spec/support/shared_config_examples.rb
172
188
  - spec/support/view_mocks.rb
173
189
  - table_cloth.gemspec
@@ -197,6 +213,7 @@ specification_version: 3
197
213
  summary: Table Cloth provides an easy and intuitive DSL for creating tables in rails
198
214
  views.
199
215
  test_files:
216
+ - spec/factories/dummy_models.rb
200
217
  - spec/lib/action_view_extension_spec.rb
201
218
  - spec/lib/actions_spec.rb
202
219
  - spec/lib/base_spec.rb
@@ -211,6 +228,5 @@ test_files:
211
228
  - spec/support/dummy_table.rb
212
229
  - spec/support/dummy_table_with_actions.rb
213
230
  - spec/support/dummy_table_with_value_options.rb
214
- - spec/support/let_declarations.rb
215
231
  - spec/support/shared_config_examples.rb
216
232
  - spec/support/view_mocks.rb
@@ -1,2 +0,0 @@
1
- module LetDeclarations
2
- end