table_cloth 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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