dining-table 0.1.0 → 0.2.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.
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