dining-table 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d79df74fda15fcb68b6215a45dbdee28c6ddf5d3
4
- data.tar.gz: bb73bf1a0edc0fe3c0aeda71acafbc13ae337e65
3
+ metadata.gz: 5f2535c2cc619915268041c0bc43d5534172327c
4
+ data.tar.gz: d09637a314c28ba0928e3a25dd27a90aa0f7f184
5
5
  SHA512:
6
- metadata.gz: 637d781f1ec3417a01f6d1f3004ccc60e8a95b64bef354c96703760259643aab537dfcec0bacef622587fb72a7d9bba8cfa5411cb5c19685c6145ff4ea403b99
7
- data.tar.gz: 9ef097bc93ee0492e6bda519020089349da0fb552473f9c74d81da15a4bc0153308707a7a66cd472e48887b45e76ebd8d5d099aee667da1f77275655ded343a2
6
+ metadata.gz: 980abf830c3bc889c0e4b1bb31927338ad07b1f75eb4c6f83b05f97d6cac6ef791774b1c3e22b0dfb39c11bff38285b0a53eb04b0b782ee807c0c39e16ea47b0
7
+ data.tar.gz: 4a19092fd8d14c30b3823f789debb18ad15443d2001434b099271e2c27432f778e184e9352506da3262918c0112288f81be90eee9b64a67f6aa0e5f72d3edd43
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ - 2.3.0
5
+ - jruby-9.0.5.0
6
+ - rbx-2
7
+ script: bundle exec rake
8
+ before_install:
9
+ - gem install bundler
@@ -0,0 +1,9 @@
1
+ ## 0.2.0 (02/09/2016)
2
+
3
+ * No longer convert column block output to string
4
+ * Removed dependencies on ActiveSupport (try and blank?)
5
+ * Added specs
6
+
7
+ ## 0.1.0
8
+
9
+ * First Release
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ group :development do
2
2
  gem "bundler", "~> 1.0"
3
3
  gem "juwelier", "~> 2.1.0"
4
4
  end
5
+
6
+ group :test do
7
+ gem "minitest"
8
+ end
@@ -30,6 +30,7 @@ GEM
30
30
  semver
31
31
  jwt (1.5.1)
32
32
  mini_portile2 (2.0.0)
33
+ minitest (5.9.0)
33
34
  multi_json (1.12.0)
34
35
  multi_xml (0.5.5)
35
36
  multipart-post (2.0.0)
@@ -54,6 +55,7 @@ PLATFORMS
54
55
  DEPENDENCIES
55
56
  bundler (~> 1.0)
56
57
  juwelier (~> 2.1.0)
58
+ minitest
57
59
 
58
60
  BUNDLED WITH
59
61
  1.12.3
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # dining-table
2
+ [![Build Status](https://travis-ci.org/mvdamme/dining-table.png)](https://travis-ci.org/mvdamme/dining-table)
2
3
 
3
4
  dining-table was inspired by the (now unfortunately unmaintained) [table_cloth](https://github.com/bobbytables/table_cloth) gem.
4
5
  This gem is definitely not a drop-in replacement for [table-cloth](https://github.com/bobbytables/table_cloth), it aims to be less dependent on Rails
@@ -224,15 +225,15 @@ the following in a Rails controller action, for instance:
224
225
  ```ruby
225
226
  def export_csv
226
227
  collection = Car.order(:brand)
227
- csv = CarTable.new( collection, nil, :presenter => DiningTable::Presenters::CSVPresenter.new ).render
228
- send_data( csv, :filename => 'export.csv', :content_type => "text/csv" )
228
+ csv = CarTable.new( collection, nil, presenter: DiningTable::Presenters::CSVPresenter.new ).render
229
+ send_data( csv, filename: 'export.csv', content_type: "text/csv" )
229
230
  end
230
231
  ```
231
232
 
232
233
  The CSV Presenter uses the CSV class from the Ruby standard library. Options passed in through the :csv key will be passed on to `CSV.new`:
233
234
 
234
235
  ```ruby
235
- csv = CarTable.new( collection, nil, :presenter => DiningTable::Presenters::CSVPresenter.new( csv: { col_sep: ';' } ) ).render
236
+ csv = CarTable.new( collection, nil, presenter: DiningTable::Presenters::CSVPresenter.new( csv: { col_sep: ';' } ) ).render
236
237
  ```
237
238
 
238
239
  CSV options can also be set as defaults, see [Configuration](#configuration)
@@ -278,7 +279,33 @@ In order to use the Excel presenter, pass it in as a presenter and provide an ax
278
279
  ```ruby
279
280
  collection = Car.order(:brand)
280
281
  # sheet is the axlsx worksheet in which the table will be rendered
281
- CarTable.new( collection, nil, :presenter => DiningTable::Presenters::ExcelPresenter.new( sheet ) ).render
282
+ CarTable.new( collection, nil, presenter: DiningTable::Presenters::ExcelPresenter.new( sheet ) ).render
283
+ ```
284
+
285
+ ## Custom column classes
286
+
287
+ You can write your own column classes and use them for specific columns. For instance, the following column class will format a date using `I18n`:
288
+
289
+ ```ruby
290
+ class DateColumn < DiningTable::Columns::Column
291
+ def value(object)
292
+ val = super
293
+ I18n.l( val ) if val
294
+ end
295
+ end
296
+ ```
297
+
298
+ A column class has to be derived from `DiningTable::Columns::Column` and implement the `value` method. The object passed in is the object in the
299
+ collection for which the current line is being rendered. If you don't have too many custom column classes, an easy place to put the code is in an initializer
300
+ (e.g. `config/initializers/dining-table.rb`).
301
+
302
+ You can use custom column classes as follows:
303
+
304
+ ```ruby
305
+ class CarTable < DiningTable::Table
306
+ def define
307
+ column :fabrication_date, class: DateColumn
308
+ end
282
309
  ```
283
310
 
284
311
  ## Configuration <a name="configuration"></a>
@@ -289,7 +316,7 @@ You can set default options for the different presenters in an initializer (e.g.
289
316
  DiningTable.configure do |config|
290
317
  config.html_presenter.default_options = { class: 'table table-bordered table-hover',
291
318
  wrap: { tag: :div, class: 'table-responsive' } }
292
- config.csv_presenter.default_options = { :csv => { col_sep: ';' } }
319
+ config.csv_presenter.default_options = { csv: { col_sep: ';' } }
293
320
  end
294
321
  ```
295
322
 
data/Rakefile CHANGED
@@ -27,8 +27,8 @@ Juwelier::RubygemsDotOrgTasks.new
27
27
 
28
28
  require 'rake/testtask'
29
29
  Rake::TestTask.new(:test) do |test|
30
- test.libs << 'lib' << 'test'
31
- test.pattern = 'test/**/test_*.rb'
30
+ test.libs << 'lib' << 'spec'
31
+ test.pattern = 'spec/**/*_spec.rb'
32
32
  test.verbose = true
33
33
  end
34
34
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: dining-table 0.1.0 ruby lib
5
+ # stub: dining-table 0.2.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "dining-table"
9
- s.version = "0.1.0"
9
+ s.version = "0.2.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Micha\u{eb}l Van Damme"]
14
- s.date = "2016-07-31"
14
+ s.date = "2016-09-03"
15
15
  s.description = "Easily output tabular data, be it in HTML, CSV or XLSX. Create clean table classes instead of messing with views to create nice tables."
16
16
  s.email = "michael.vandamme@vub.ac.be"
17
17
  s.extra_rdoc_files = [
@@ -19,6 +19,8 @@ Gem::Specification.new do |s|
19
19
  "README.md"
20
20
  ]
21
21
  s.files = [
22
+ ".travis.yml",
23
+ "CHANGELOG.md",
22
24
  "Gemfile",
23
25
  "Gemfile.lock",
24
26
  "LICENSE",
@@ -35,7 +37,17 @@ Gem::Specification.new do |s|
35
37
  "lib/dining-table/presenters/html_presenter.rb",
36
38
  "lib/dining-table/presenters/presenter.rb",
37
39
  "lib/dining-table/presenters/spreadsheet_presenter.rb",
38
- "lib/dining-table/table.rb"
40
+ "lib/dining-table/table.rb",
41
+ "spec/collection.rb",
42
+ "spec/csv_table_spec.rb",
43
+ "spec/date_column.rb",
44
+ "spec/html_table_spec.rb",
45
+ "spec/spec_helper.rb",
46
+ "spec/tables/car_table.rb",
47
+ "spec/tables/car_table_with_actions.rb",
48
+ "spec/tables/car_table_with_footer.rb",
49
+ "spec/tables/car_table_with_header.rb",
50
+ "spec/tables/car_table_with_options.rb"
39
51
  ]
40
52
  s.homepage = "http://github.com/mvdamme/dining-table"
41
53
  s.licenses = ["MIT"]
@@ -17,7 +17,7 @@ module DiningTable
17
17
 
18
18
  def action(&block)
19
19
  action_value = yield(@current_object)
20
- @incremental_value += action_value.try(:to_s) if action_value
20
+ @incremental_value += action_value.to_s if action_value && action_value.respond_to?(:to_s)
21
21
  end
22
22
 
23
23
  # offer methods normally available on Table that could be used by the action blocks
@@ -17,7 +17,7 @@ module DiningTable
17
17
  if block
18
18
  block.call(object, self)
19
19
  else
20
- object.send(name).try(:to_s) if object.respond_to?(name)
20
+ object.send(name) if object.respond_to?(name)
21
21
  end
22
22
  end
23
23
 
@@ -25,7 +25,7 @@ module DiningTable
25
25
  @header ||= begin
26
26
  label = determine_label(:header)
27
27
  return label if label
28
- object_class = table.collection.first.try(:class)
28
+ object_class = table.collection.first.class if table.collection.first
29
29
  object_class.human_attribute_name( name ) if object_class && object_class.respond_to?( :human_attribute_name )
30
30
  end
31
31
  end
@@ -44,7 +44,8 @@ module DiningTable
44
44
  if options[ name ]
45
45
  label_ = options[ name ]
46
46
  label_ = label_.call if label_.respond_to?(:call)
47
- return label_.try(:to_s)
47
+ label_ = label_.to_s if label_.respond_to?(:to_s)
48
+ return label_
48
49
  end
49
50
  end
50
51
 
@@ -31,5 +31,3 @@ module DiningTable
31
31
  end
32
32
 
33
33
  end
34
-
35
- SuckerPunch::Backgroundable.configure {}
@@ -1,3 +1,5 @@
1
+ require 'csv'
2
+
1
3
  module DiningTable
2
4
 
3
5
  module Presenters
@@ -57,7 +57,7 @@ module DiningTable
57
57
 
58
58
  def render_footer
59
59
  footers = columns.each.map(&:footer)
60
- if footers.map(&:blank?).uniq != [ true ]
60
+ if footers.map { |s| blank?(s) }.uniq != [ true ]
61
61
  add_tag(:start, :tfoot)
62
62
  add_tag(:start, :tr)
63
63
  columns.each_with_index do |column, index|
@@ -70,7 +70,7 @@ module DiningTable
70
70
  end
71
71
 
72
72
  def output
73
- @output.html_safe
73
+ @output.respond_to?(:html_safe) ? @output.html_safe : @output
74
74
  end
75
75
 
76
76
  private
@@ -87,7 +87,7 @@ module DiningTable
87
87
  end
88
88
 
89
89
  def start_tag(tag, options = {})
90
- "<#{ tag.to_s } #{ options_string(options) }>"
90
+ "<#{ tag.to_s }#{ options_string(options) }>"
91
91
  end
92
92
 
93
93
  def end_tag(tag, options = {})
@@ -44,6 +44,11 @@ module DiningTable
44
44
  end
45
45
  end
46
46
 
47
+ # implementation adapted from ActiveSupport
48
+ def blank?( string )
49
+ string.respond_to?(:empty?) ? !!string.empty? : !string
50
+ end
51
+
47
52
  end
48
53
 
49
54
  end
@@ -19,7 +19,7 @@ module DiningTable
19
19
 
20
20
  def render_footer
21
21
  footers = footer_strings
22
- if footers.map(&:blank?).uniq != [ true ]
22
+ if footers.map { |s| blank?(s) }.uniq != [ true ]
23
23
  add_row( footers )
24
24
  end
25
25
  end
@@ -21,10 +21,12 @@ module DiningTable
21
21
  def render
22
22
  presenter.start_table
23
23
  presenter.render_header unless no_header
24
+ presenter.start_body
24
25
  collection.each_with_index do |object, index_|
25
26
  self.index = index_
26
27
  presenter.render_row( object )
27
28
  end
29
+ presenter.end_body
28
30
  presenter.render_footer
29
31
  presenter.end_table
30
32
  presenter.output
@@ -0,0 +1,23 @@
1
+ class Car < Struct.new(:brand, :type, :number_of_doors, :stock, :launch_date)
2
+
3
+ COLLECTION = [
4
+ [ 'Audi', 'A4', 3, 100, Date.new(2016, 1, 1) ],
5
+ [ 'Citroën', 'C4 Picasso', 5, 150, Date.new(2016, 2, 1) ],
6
+ [ 'Ferrari', 'F12', 3, 2, Date.new(2016, 3, 1) ]
7
+ ]
8
+
9
+ def self.collection
10
+ COLLECTION.map do |data|
11
+ self.new( *data )
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ class CarWithHumanAttributeName < Car
18
+
19
+ def self.human_attribute_name(attribute)
20
+ attribute.to_s.gsub('_', ' ').capitalize
21
+ end
22
+
23
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'collection'
3
+ require 'rexml/document'
4
+ Dir["#{File.dirname(__FILE__)}/tables/**/*.rb"].each {|file| require file }
5
+
6
+
7
+ describe 'CSVTableSpec' do
8
+ before do
9
+ @cars = CarWithHumanAttributeName.collection
10
+ @presenter = DiningTable::Presenters::CSVPresenter.new
11
+ end
12
+
13
+ it "correctly renders a basic table" do
14
+ csv = CarTable.new(@cars, nil, :presenter => @presenter).render
15
+ data = CSV.parse(csv)
16
+ check_data( data )
17
+ end
18
+
19
+ it "respects csv options" do
20
+ @presenter = DiningTable::Presenters::CSVPresenter.new( :csv => { :col_sep => ';' } )
21
+ csv = CarTable.new(@cars, nil, :presenter => @presenter).render
22
+ data = CSV.parse(csv)
23
+ data.first.length.must_equal 1 # wrongly parsed due to using comma as a separator
24
+ data = CSV.parse(csv, :col_sep => ';')
25
+ check_data( data )
26
+ end
27
+
28
+ it "respects global csv options" do
29
+ DiningTable.configure do |config|
30
+ config.csv_presenter.default_options = { :csv => { :col_sep => ';' } }
31
+ end
32
+ @presenter = DiningTable::Presenters::CSVPresenter.new
33
+ csv = CarTable.new(@cars, nil, :presenter => @presenter).render
34
+ data = CSV.parse(csv)
35
+ data.first.length.must_equal 1 # wrongly parsed due to using comma as a separator
36
+ data = CSV.parse(csv, :col_sep => ';')
37
+ check_data( data )
38
+ # reset configuration for other specs
39
+ DiningTable.configure do |config|
40
+ config.csv_presenter.default_options = { }
41
+ end
42
+ end
43
+
44
+ def check_data( data )
45
+ data.first.must_equal ["Brand", "Type", "Number of doors", "Stock"]
46
+ @cars.each_with_index do |car, index|
47
+ line = [ :brand, :type, :number_of_doors, :stock ].map do |item|
48
+ car.send(item).to_s
49
+ end
50
+ data[index + 1].must_equal line
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,12 @@
1
+ # note that this custom class is specific for testing (value contains minitest assertions)
2
+ class DateColumn < DiningTable::Columns::Column
3
+ def value(object)
4
+ val = super
5
+ val.class.name.must_equal 'Date' # make sure an actual object is returned, not a string representation
6
+ self.class.localize( val ) if val
7
+ end
8
+
9
+ def self.localize(date)
10
+ "#{ date.day }/#{ date.month }/#{ date.year }"
11
+ end
12
+ end
@@ -0,0 +1,212 @@
1
+ require 'spec_helper'
2
+ require 'collection'
3
+ require 'date_column'
4
+ require 'rexml/document'
5
+ Dir["#{File.dirname(__FILE__)}/tables/**/*.rb"].each {|file| require file }
6
+
7
+ describe 'HTMLTableSpec' do
8
+ before do
9
+ @cars = Car.collection
10
+ @view_context = ViewContext.new
11
+ end
12
+
13
+ it "correctly renders a basic table's body" do
14
+ html = CarTable.new(@cars, nil).render
15
+ doc = document( html )
16
+ @cars.each_with_index do |car, index|
17
+ [ :brand, :number_of_doors, :stock ].each_with_index do |column, col_index|
18
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[#{ col_index + 1 }]"
19
+ check_not_empty(doc.elements, xpath)
20
+ doc.elements.each(xpath) do |element|
21
+ element.text.must_equal car.send( column ).to_s
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ it "correctly renders a table's header when no explicit headers are defined" do
28
+ @cars = CarWithHumanAttributeName.collection
29
+ html = CarTable.new(@cars, nil).render
30
+ doc = document( html )
31
+ [ 'Brand', 'Number of doors', 'Stock' ].each_with_index do |header, col_index|
32
+ xpath = "/table/thead/tr[1]/th[#{ col_index + 1 }]"
33
+ check_not_empty(doc.elements, xpath)
34
+ doc.elements.each(xpath) do |element|
35
+ element.text.must_equal header
36
+ end
37
+ end
38
+ end
39
+
40
+ it "correctly renders a table's header when explicit headers are defined" do
41
+ @cars = CarWithHumanAttributeName.collection
42
+ html = CarTableWithHeader.new(@cars, @view_context).render
43
+ doc = document( html )
44
+ [ 'The brand', 'The number of doors' ].each_with_index do |header, col_index|
45
+ xpath = "/table/thead/tr[1]/th[#{ col_index + 1 }]"
46
+ check_not_empty(doc.elements, xpath)
47
+ doc.elements.each(xpath) do |element|
48
+ element.text.must_equal header
49
+ end
50
+ end
51
+ # last header has link
52
+ doc.elements.each("/table/thead/tr[1]/th[3]/a") do |element|
53
+ element.text.must_equal 'Stock'
54
+ element.attributes.get_attribute('href').value.must_equal "http://www.google.com"
55
+ end
56
+ end
57
+
58
+ it "correctly renders a table's footer when footers are defined" do
59
+ @cars = CarWithHumanAttributeName.collection
60
+ html = CarTableWithFooter.new(@cars, @view_context).render
61
+ doc = document( html )
62
+ [ nil, 'Total' ].each_with_index do |footer, col_index|
63
+ xpath = "/table/tfoot/tr[1]/td[#{ col_index + 1 }]"
64
+ check_not_empty(doc.elements, xpath)
65
+ doc.elements.each(xpath) do |element|
66
+ element.text.must_equal footer
67
+ end
68
+ end
69
+ # last footer has link
70
+ doc.elements.each("/table/tfoot/tr[1]/th[3]/a") do |element|
71
+ element.text.must_equal "Total: #{ 150 }"
72
+ element.attributes.get_attribute('href').value.must_equal "#"
73
+ end
74
+ end
75
+
76
+ it "correctly renders a table with column options and column blocks" do
77
+ html = CarTableWithOptions.new(@cars, nil).render
78
+ doc = document( html )
79
+ @cars.each_with_index do |car, index|
80
+ [ :brand, :stock ].each_with_index do |column, col_index|
81
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[#{ col_index + 1 }]"
82
+ check_not_empty(doc.elements, xpath)
83
+ doc.elements.each(xpath) do |element|
84
+ element.text.must_equal car.send( column ).to_s.upcase
85
+ class_ = col_index == 0 ? 'center' : 'left'
86
+ element.attributes.get_attribute('class').value.must_equal class_
87
+ end
88
+ end
89
+ end
90
+ # also check header
91
+ [ 1, 2 ].each do |index|
92
+ doc.elements.each("/table/thead/tr[1]/th[#{ index }]") do |element|
93
+ class_ = index == 1 ? 'center' : 'left'
94
+ element.attributes.get_attribute('class').value.must_equal class_
95
+ end
96
+ end
97
+ end
98
+
99
+ it "correctly renders a table with actions" do
100
+ html = CarTableWithActions.new(@cars, @view_context).render
101
+ doc = document( html )
102
+ @cars.each_with_index do |car, index|
103
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[3]/a"
104
+ check_not_empty(doc.elements, xpath)
105
+ doc.elements.each_with_index(xpath) do |element, idx|
106
+ text = (idx == 0 ? 'Show' : 'Edit')
107
+ link = (idx == 0 ? '#show' : '#edit')
108
+ element.text.must_equal text
109
+ element.attributes.get_attribute('href').value.must_equal link
110
+ end
111
+ # check options
112
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[3]"
113
+ doc.elements.each(xpath) do |element|
114
+ element.attributes.get_attribute('class').value.must_equal 'left'
115
+ end
116
+ end
117
+ end
118
+
119
+ it "respects custom columns when specified" do
120
+ # first without custom column
121
+ html = CarTableWithOptions.new(@cars, nil, :with_normal_launch_date => true).render
122
+ doc = document( html )
123
+ @cars.each_with_index do |car, index|
124
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[3]"
125
+ check_not_empty(doc.elements, xpath)
126
+ doc.elements.each(xpath) do |element|
127
+ element.text.must_equal car.launch_date.to_s
128
+ end
129
+ end
130
+ # now with custom date column
131
+ html = CarTableWithOptions.new(@cars, nil, :with_date_column_launch_date => true).render
132
+ doc = document( html )
133
+ @cars.each_with_index do |car, index|
134
+ xpath = "/table/tbody/tr[#{ index + 1 }]/td[3]"
135
+ check_not_empty(doc.elements, xpath)
136
+ doc.elements.each(xpath) do |element|
137
+ element.text.must_equal DateColumn.localize( car.launch_date )
138
+ end
139
+ end
140
+ end
141
+
142
+ it "respects presenter options" do
143
+ html = CarTable.new(@cars, nil,
144
+ :presenter => DiningTable::Presenters::HTMLPresenter.new( :class => 'table table-bordered' ) ).render
145
+ doc = document( html )
146
+ doc.elements.first.attributes.get_attribute('class').value.must_equal 'table table-bordered'
147
+ end
148
+
149
+ it "correctly wraps the table" do
150
+ html = CarTable.new(@cars, nil,
151
+ :presenter => DiningTable::Presenters::HTMLPresenter.new( :wrap => { :tag => :div, :class => 'table-responsive' } ) ).render
152
+ doc = REXML::Document.new( html )
153
+ doc.elements.first.name.must_equal 'div'
154
+ doc.elements.first.attributes.get_attribute('class').value.must_equal 'table-responsive'
155
+ end
156
+
157
+ it "respects global html options" do
158
+ DiningTable.configure do |config|
159
+ config.html_presenter.default_options = { :class => 'table-hover',
160
+ :wrap => { :tag => :div, :class => 'table-responsive' } }
161
+ end
162
+ html = CarTable.new(@cars, nil).render
163
+ doc = REXML::Document.new( html )
164
+ doc.elements.first.name.must_equal 'div'
165
+ doc.elements.first.attributes.get_attribute('class').value.must_equal 'table-responsive'
166
+ table = doc.elements.first.elements.first
167
+ table.attributes.get_attribute('class').value.must_equal 'table-hover'
168
+ # reset configuration for other specs
169
+ DiningTable.configure do |config|
170
+ config.html_presenter.default_options = { }
171
+ end
172
+ end
173
+
174
+ def document( html )
175
+ doc = REXML::Document.new( html )
176
+ check_table_structure( doc )
177
+ doc
178
+ end
179
+
180
+ def check_table_structure( document )
181
+ document.elements.size.must_equal 1
182
+ table = document.elements.first
183
+ table.name.must_equal 'table'
184
+ (table.elements.size >= 2).must_equal true
185
+ header = table.elements.first
186
+ header.name.must_equal 'thead'
187
+ body = table.elements[2] # 2 = second element (not third) in REXML
188
+ body.name.must_equal 'tbody'
189
+ if table.elements.size == 3
190
+ footer = table.elements[3]
191
+ footer.name.must_equal 'tfoot'
192
+ end
193
+ end
194
+
195
+ def not_empty?(node, xpath)
196
+ node.each(xpath) do
197
+ return true
198
+ end
199
+ false
200
+ end
201
+
202
+ def check_not_empty(node, xpath)
203
+ not_empty?(node, xpath).must_equal true
204
+ end
205
+
206
+ class ViewContext
207
+ def link_to(text, url)
208
+ "<a href=\"#{ url }\">#{ text }</a>"
209
+ end
210
+ end
211
+
212
+ end
@@ -0,0 +1,2 @@
1
+ require 'dining-table'
2
+ require 'minitest/autorun'
@@ -0,0 +1,8 @@
1
+ class CarTable < DiningTable::Table
2
+ def define
3
+ column :brand
4
+ column :type if presenter.type?(:csv)
5
+ column :number_of_doors
6
+ column :stock
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class CarTableWithActions < DiningTable::Table
2
+ def define
3
+ column :brand
4
+ column :number_of_doors
5
+ actions :header => 'Action', :html => { :td_options => { class: 'left' }, :th_options => { class: :left } } do |object|
6
+ action { |object| h.link_to( 'Show', '#show' ) }
7
+ action { |object| h.link_to( 'Edit', '#edit' ) }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ class CarTableWithFooter < DiningTable::Table
2
+ def define
3
+ column :brand
4
+ column :number_of_doors, :footer => 'Total'
5
+ column :stock, :footer => lambda { h.link_to("Total: #{ collection.map(&:stock).inject(&:+) }", '#') }
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class CarTableWithHeader < DiningTable::Table
2
+ def define
3
+ column :brand, :header => 'The brand'
4
+ column :number_of_doors, :header => lambda { 'The number of doors' }
5
+ column :stock, :header => lambda { h.link_to('Stock', 'http://www.google.com') }
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ class CarTableWithOptions < DiningTable::Table
2
+ def define
3
+ column :brand, :html => { :td_options => { class: 'center' }, :th_options => { class: :center } } do |object|
4
+ object.brand.upcase
5
+ end
6
+ column :stock, :html => { :td_options => { class: 'left' }, :th_options => { class: :left } }
7
+ column :launch_date if options[:with_normal_launch_date]
8
+ column :launch_date, :class => DateColumn if options[:with_date_column_launch_date]
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dining-table
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michaël Van Damme
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-31 00:00:00.000000000 Z
11
+ date: 2016-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -47,6 +47,8 @@ extra_rdoc_files:
47
47
  - LICENSE
48
48
  - README.md
49
49
  files:
50
+ - ".travis.yml"
51
+ - CHANGELOG.md
50
52
  - Gemfile
51
53
  - Gemfile.lock
52
54
  - LICENSE
@@ -64,6 +66,16 @@ files:
64
66
  - lib/dining-table/presenters/presenter.rb
65
67
  - lib/dining-table/presenters/spreadsheet_presenter.rb
66
68
  - lib/dining-table/table.rb
69
+ - spec/collection.rb
70
+ - spec/csv_table_spec.rb
71
+ - spec/date_column.rb
72
+ - spec/html_table_spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/tables/car_table.rb
75
+ - spec/tables/car_table_with_actions.rb
76
+ - spec/tables/car_table_with_footer.rb
77
+ - spec/tables/car_table_with_header.rb
78
+ - spec/tables/car_table_with_options.rb
67
79
  homepage: http://github.com/mvdamme/dining-table
68
80
  licenses:
69
81
  - MIT