grid_fu 0.0.1 → 0.0.2

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.
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # GridFu
2
2
 
3
- https://github.com/evilmartians/slashadmin/issues/3
3
+ Inspired by discussion at: https://github.com/evilmartians/slashadmin/issues/3.
4
+ Rails table renderer that tries to be flexible.
4
5
 
5
6
  ## Installation
6
7
 
@@ -18,25 +19,143 @@ Or install it yourself as:
18
19
 
19
20
  ## Usage
20
21
 
21
- Do not forget to describe config options.
22
+ Somwhere in your app:
23
+
24
+ ```ruby
25
+ short_table = GridFu.define do
26
+ cell :id
27
+ cell :name
28
+ end
29
+
30
+ puts short_table.to_html(collection, User)
31
+ ```
32
+
33
+ You will see following:
34
+
35
+ ```html
36
+ # <table>
37
+ # <thead><tr><th>Id</th><th>User name</th></tr></thead>
38
+ # <tbody>
39
+ # <tr><td>1</td><td>John Doe</td></tr>
40
+ # <tr>...</tr>
41
+ # </tbody>
42
+ # </table>
43
+ ```
44
+
45
+ ## Full definition
46
+
47
+ ```ruby
48
+ table = GridFu.define do
49
+ html_options class: 'table'
50
+
51
+ header do
52
+ row do
53
+ cell 'Id', html_options: { colspan: 5 }
54
+ cell do
55
+ 'Doctor strangelove'
56
+ end
57
+ end
58
+ end
59
+
60
+ body do
61
+ html_options class: 'sortable'
62
+ row do
63
+ html_options do |member, index|
64
+ { data: { id: member.id, index: index } }
65
+ end
66
+
67
+ cell html_options: ->(member, _) { { data: { value: member.id } } } do |_, index|
68
+ index
69
+ end
70
+ cell :id
71
+ cell :age do |member, _|
72
+ "Dead at #{member.age}"
73
+ end
74
+ cell do |_, index|
75
+ sample_helper_function(index)
76
+ end
77
+ end
78
+
79
+ row html_options: { class: 'small' } do
80
+ tag 'overriden_tr'
81
+
82
+ cell :test do
83
+ "test"
84
+ end
85
+
86
+ cell :age, formatter: :sample_formatter
87
+ end
88
+ end
89
+
90
+ footer do
91
+ row do
92
+ cell html_options: { rowspan: 3 } do
93
+ "On foot"
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ puts table.to_html(collection)
100
+ ```
101
+
102
+ Every element accepts:
103
+ * html_options - to customize default options.
104
+ * override_html_options - to completely override default html options.
105
+ * tag - to change tag name.
106
+
107
+ Default HTML options are:
108
+ * data-id - for tbody/tr.
109
+ * data-key - for tbody/tr/td.
110
+
111
+ Options which are set by blocks accepts:
112
+ * |member, index| - for row and cell inside body element.
113
+ * |collection, klass = nil| - for table, header and footer (and all nested elements)
114
+ * Same for body.
115
+
116
+ Method called with :formatter option accepts value, member and index.
117
+
118
+ You can override default html options for an element with :override_html_options
119
+ option.
120
+
121
+ You can specify two or more rows in body section. All of this rows will be
122
+ rendered for every collection item.
123
+
124
+ ## Global configuration
125
+
126
+ Table elements can be customized at application level.
127
+
128
+ Somewhere in initializer:
129
+
130
+ ```ruby
131
+ GridFu::Table.config.html_options = { class: 'table' }
132
+ GridFu::HeaderRow.config.html_options = proc { |_, resource_class = nil|
133
+ { class: resource_class.name.underscore }
134
+ }
135
+ ```
136
+
137
+ You can use: Table, Header, Body, Footer, HeaderRow, BodyRow, FooterRow,
138
+ HeaderCell, BodyCell, FooterCell.
139
+
140
+ So, you can replace table with ordered list or something you need.
141
+
142
+ ## Partial rendering
143
+
144
+ Could be useful for twitter-style pagination:
145
+
146
+ ```ruby
147
+ table.element_to_html(:header, collection, User)
148
+ table.element_to_html(:body, collection, User)
149
+ table.element_to_html(:footer, collection, User)
150
+ ```
22
151
 
23
152
  ## TODO
24
153
 
25
- 1. Default header & footer if none present.
26
- 2. Render body, footer and header separately
27
- 3. Specs.
28
- 4. Sort?
29
- 5. Nice output.
30
- 6. Default data attrs for everything.
31
- 7. Rowspan
32
- 8. :span
33
- 9. Footer
34
- 10. Header
35
- 11. Base class for footer, header and tbody.
36
- 12. Avoid body block if there's no header/footer.
37
- 13. value: :function cell param
38
- 14. merge_html_options?
39
- 15. Bypass :value param.
154
+ 1. Think about sorting.
155
+ 2. Formatted output.
156
+ 3. Data attrs for everything.
157
+ 4. Authospan.
158
+ 5. :row as parameter.
40
159
 
41
160
  ## Contributing
42
161
 
@@ -17,8 +17,9 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_dependency 'active_support', '~> 3'
20
+ gem.add_dependency 'activesupport', '~> 3'
21
21
 
22
22
  gem.add_development_dependency 'rspec'
23
23
  gem.add_development_dependency 'rake'
24
+ gem.add_development_dependency 'rspec-html-matchers'
24
25
  end
@@ -1,15 +1,21 @@
1
- require 'active_support/core_ext/class/attribute_accessors'
2
1
  require 'active_support/core_ext/object/blank'
2
+ require 'active_support/core_ext/object/inclusion'
3
+ require 'active_support/core_ext/string/inflections'
4
+ require 'active_support/core_ext/object/try'
3
5
  require 'active_support/configurable'
4
6
 
5
7
  require 'grid_fu/version'
6
8
  require 'grid_fu/element'
9
+ require 'grid_fu/element/configuration'
10
+ require 'grid_fu/element/rendering'
11
+ require 'grid_fu/element/nesting'
12
+ require 'grid_fu/cells'
13
+ require 'grid_fu/rows'
14
+ require 'grid_fu/sections'
7
15
  require 'grid_fu/table'
8
- require 'grid_fu/row'
9
- require 'grid_fu/body'
10
- require 'grid_fu/cell'
11
16
 
12
17
  module GridFu
18
+ # TODO: Custom table class
13
19
  def define(*args, &block)
14
20
  Table.new(*args, &block)
15
21
  end
@@ -0,0 +1,54 @@
1
+ module GridFu
2
+ class Cell < Element
3
+ def initialize(*args, &block)
4
+ self.value = block
5
+ self.key = args.first if args.first.is_a?(String) or args.first.is_a?(Symbol)
6
+
7
+ # Bypass block evaling: in this case it's not a config but a value formatter
8
+ super(*args, &nil)
9
+ end
10
+
11
+ protected
12
+ attr_accessor :key, :value
13
+ end
14
+
15
+ class BodyCell < Cell
16
+ config.tag = 'td'
17
+
18
+ protected
19
+ def html_content(member, index)
20
+ value = self.value.call(member, index) if self.value.present?
21
+ value ||= member.send(key) if key.present? and member.respond_to?(key)
22
+
23
+ if config.formatter.present?
24
+ value ||= send(config.formatter, key, member, index)
25
+ end
26
+
27
+ value
28
+ end
29
+ end
30
+
31
+ class HeaderCell < Cell
32
+ config.tag = 'th'
33
+
34
+ protected
35
+ def html_content(collection, resource_class = nil)
36
+ return value.call(collection, resource_class) if value.is_a?(Proc)
37
+ if resource_class.respond_to?(:human_attribute_name)
38
+ resource_class.human_attribute_name(key)
39
+ else
40
+ key
41
+ end
42
+ end
43
+ end
44
+
45
+ class FooterCell < Cell
46
+ config.tag = 'td'
47
+
48
+ protected
49
+ def html_content(*args)
50
+ return value.call(*args) if value.is_a?(Proc)
51
+ key
52
+ end
53
+ end
54
+ end
@@ -2,77 +2,10 @@ module GridFu
2
2
  class Element
3
3
  include ActiveSupport::Configurable
4
4
 
5
- def initialize(*args, &block)
6
- instance_exec(&block) if block_given?
7
-
8
- config.html_options ||= {}
9
-
10
- set_options([:tag, :html_options], *args)
11
- end
12
-
13
- def to_html(*args, &block)
14
- tag, html_options = get_options([:tag, :html_options], *args)
15
-
16
- html_options = _to_html_args(html_options)
17
-
18
- html = []
19
- html << "<#{tag}"
20
- if html_options.present?
21
- html << " #{html_options}"
22
- end
23
- html << '>'
24
- if block_given?
25
- html << yield(*args)
26
- else
27
- html << html_content(*args).to_s
28
- end
29
- html << "</#{tag}>"
30
-
31
- html.join
32
- end
33
-
34
- protected
35
- def html_content(*args)
36
- raise NotImplementedError, "Must implement #html_content for #{self.class.name} or pass a block for #to_html"
37
- end
38
-
39
- def set_options(expected, *args)
5
+ def initialize(*args, &definition)
6
+ instance_exec(&definition) if block_given?
40
7
  options = args.extract_options!
41
-
42
- expected.each do |name|
43
- config[name] = options.delete(name) if options.key?(name)
44
- end
45
- end
46
-
47
- def get_options(expected, *args)
48
- expected.map do |name|
49
- config[name].is_a?(Proc) ? config[name].call(*args) : config[name]
50
- end
51
- end
52
-
53
- def self.option_setter(name)
54
- define_method name do |value = nil, &block|
55
- if value.present? || block.present?
56
- config[name] = value || block
57
- end
58
- end
59
- end
60
-
61
- option_setter :tag
62
- option_setter :html_options
63
-
64
- private
65
- def _to_html_args(options, prepend = nil)
66
- options = options || {}
67
- html_args = options.map do |key, value|
68
- if value.is_a?(Hash)
69
- _to_html_args(value, key)
70
- else
71
- key = "#{prepend}-#{key}" if prepend.present?
72
- %{#{key}="#{value}"}
73
- end
74
- end
75
- html_args.join(' ')
8
+ config.merge!(options)
76
9
  end
77
10
  end
78
- end
11
+ end
@@ -0,0 +1,32 @@
1
+ module GridFu
2
+ class Element
3
+ protected
4
+ # Catches a call to configuration option setter.
5
+ #
6
+ # Example:
7
+ # body do
8
+ # html_options { class: 'test' } # Holds such calls
9
+ # end
10
+ def method_missing(method_name, *args, &block)
11
+ return super unless method_name.to_s.in?(config.allowed_configuration_options)
12
+ config[method_name] = args.first || block
13
+
14
+ class_eval do
15
+ define_method method_name do |value|
16
+ config[method_name] = value
17
+ end
18
+ protected method_name
19
+ end
20
+
21
+ config[method_name]
22
+ end
23
+
24
+ config.allowed_configuration_options = %w(
25
+ tag html_options override_html_options
26
+ )
27
+ config.html_options = {}
28
+ config.override_html_options = {}
29
+ config.render_nested_elements = []
30
+ config.tag = nil
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ module GridFu
2
+ class Element
3
+ class << self
4
+ protected
5
+ # Defines DSL method for configuring nested element.
6
+ # If no args/block passed - returns currently defined elements as array.
7
+ #
8
+ # Example:
9
+ # class Table < Element
10
+ # nest :body, Body
11
+ # end
12
+ #
13
+ # table = Table.new do
14
+ # body do
15
+ # (...)
16
+ # end
17
+ # end
18
+ #
19
+ # table.body.first.to_html # <tbody>...</tbody>
20
+ def nest(accessor_name, klass)
21
+ define_method accessor_name do |*args, &block|
22
+ items = instance_variable_get("@#{accessor_name}") || []
23
+ return items if args.blank? && block.blank?
24
+
25
+ value = klass.new(*args, &block)
26
+ items.push(value)
27
+ instance_variable_set("@#{accessor_name}", items)
28
+ value
29
+ end
30
+ protected accessor_name
31
+ end
32
+
33
+ # Defines top-level shortcut DSL method.
34
+ #
35
+ # Example:
36
+ # class Body < Element
37
+ # nest :row, BodyRow
38
+ # end
39
+ #
40
+ # class Table < Element
41
+ # nest_through :body, :row, :cell # Table#cell calls .body.row.cell
42
+ # end
43
+ #
44
+ # table = Table.new do
45
+ # cell :id
46
+ # end
47
+ #
48
+ # table.body.first.row.first.cell.first.to_html # <td data-name="id">...</td>
49
+ def nest_through(*chain)
50
+ nested_method = chain.last
51
+
52
+ define_method nested_method do |*args, &block|
53
+ _get_chained(self, chain.dup, *args, &block)
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+ def _get_chained(context, chain, *args, &block)
60
+ key = chain.shift
61
+ if chain.empty?
62
+ context.send(key, *args, &block)
63
+ else
64
+ # Get last defined element, or define new blank
65
+ nested_item = context.send(key).last || context.send(key) { }
66
+ _get_chained(nested_item, chain, *args, &block)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,73 @@
1
+ module GridFu
2
+ class Element
3
+ # Translates element to html tag.
4
+ def to_html(*args)
5
+ tag, override_html_options, html_options =
6
+ get_options([:tag, :override_html_options, :html_options], *args)
7
+
8
+ raise "Set tag option for #{self.class.name}" if tag.blank?
9
+
10
+ html_options = override_html_options.merge(html_options)
11
+ html_options = _to_html_args(html_options)
12
+
13
+ html = []
14
+
15
+ html << "<#{tag}"
16
+ html << " #{html_options}" if html_options.present?
17
+ html << '>'
18
+
19
+ html << html_content(*args).to_s
20
+
21
+ html << "</#{tag}>"
22
+ html.join
23
+ end
24
+
25
+ def element_to_html(element, *args)
26
+ send(element).map { |item| item.to_html(*args) }.join
27
+ end
28
+
29
+ protected
30
+ # HTML content for element. Renders elements set by :render_nested_elements
31
+ # wrapped by :tag.
32
+ def html_content(*args)
33
+ nested = get_options(:render_nested_elements, *args).first
34
+
35
+ if nested.blank?
36
+ raise "Set render_nested_elements options or override #html_content/#to_html for #{self.class.name}"
37
+ end
38
+
39
+ html = nested.map do |element|
40
+ self.send(element).map { |element| element.to_html(*args) }.join
41
+ end
42
+ html.join
43
+ end
44
+
45
+ private
46
+ # Translates html_options to HTML attributes string. Accepts nested
47
+ # data-attributes.
48
+ #
49
+ # Example:
50
+ # _to_html_args(ref: true, data: { id: 1 }) # ref="true" data-id="1"
51
+ def _to_html_args(options, prepend = nil)
52
+ options = options || {}
53
+ html_args = options.map do |key, value|
54
+ if value.is_a?(Hash)
55
+ _to_html_args(value, key)
56
+ else
57
+ key = "#{prepend}-#{key}" if prepend.present?
58
+ %{#{key}="#{value}"}
59
+ end
60
+ end
61
+ html_args.join(' ')
62
+ end
63
+
64
+ # Gets given option values. If an option is a block - yields it and
65
+ # returns value.
66
+ def get_options(keys, *args)
67
+ keys = Array.wrap(keys)
68
+ keys.map do |name|
69
+ config[name].is_a?(Proc) ? config[name].call(*args) : config[name]
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,32 @@
1
+ module GridFu
2
+ class Row < Element
3
+ attr_reader :cells
4
+
5
+ config.tag = 'tr'
6
+ config.render_nested_elements = %w(cell)
7
+ end
8
+
9
+ class BodyRow < Row
10
+ config.override_html_options = proc { |member, index|
11
+ { data: { id: member.try(:id) } }
12
+ }
13
+
14
+ nest :cell, BodyCell
15
+
16
+ protected
17
+ def html_content(member, index)
18
+ html = cell.map do |cell|
19
+ cell.to_html(member, index)
20
+ end
21
+ html.join
22
+ end
23
+ end
24
+
25
+ class HeaderRow < Row
26
+ nest :cell, HeaderCell
27
+ end
28
+
29
+ class FooterRow < Row
30
+ nest :cell, FooterCell
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module GridFu
2
+ class Section < Element
3
+ config.render_nested_elements = %w(row)
4
+ end
5
+
6
+ class Body < Section
7
+ config.tag = 'tbody'
8
+
9
+ nest :row, BodyRow
10
+ nest_through :row, :cell
11
+
12
+ protected
13
+ def html_content(collection, resource_class = nil)
14
+ html = collection.map.with_index do |member, index|
15
+ row.map { |row| row.to_html(member, index) }.join(' ')
16
+ end
17
+ html.join
18
+ end
19
+ end
20
+
21
+ class Header < Section
22
+ config.tag = 'thead'
23
+
24
+ nest :row, HeaderRow
25
+ nest_through :row, :cell
26
+ end
27
+
28
+ class Footer < Section
29
+ config.tag = 'tfoot'
30
+
31
+ nest :row, FooterRow
32
+ nest_through :row, :cell
33
+ end
34
+ end
@@ -1,22 +1,13 @@
1
1
  module GridFu
2
2
  class Table < Element
3
- attr_reader :header_content, :body_content, :footer_content
3
+ config.tag = 'table'
4
+ config.render_nested_elements = %w(header body footer)
5
+ config.allowed_configuration_options = %w(tag html_options)
4
6
 
5
- def initialize(*args, &block)
6
- config.tag ||= 'table'
7
+ nest :header, Header
8
+ nest :body, Body
9
+ nest :footer, Footer
7
10
 
8
- super
9
- end
10
-
11
- protected
12
- def html_content(collection, resource_class = nil)
13
- body_content.to_html(collection, resource_class)
14
- end
15
-
16
- def body(*args, &block)
17
- self.body_content = Body.new(*args, &block)
18
- end
19
-
20
- attr_writer :header_content, :body_content, :footer_content
11
+ nest_through :body, :row, :cell
21
12
  end
22
- end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module GridFu
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,15 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Configuration' do
4
- subject { sample_table }
3
+ describe 'Grid' do
4
+ context 'defined fully' do
5
+ subject { sample_table_full_described }
5
6
 
6
- it 'should set provided html options correctly' do
7
- #subject.config.tag.should == 'table'
8
- #subject.config.html_options.should == {}
9
- #subject.body_content.config.tag.should == 'tbody'
10
- #subject.body_content.rows.first.config.html_options.should == { class: 'odd' }
11
- #subject.body_content.rows.last.config.html_options.should be_kind_of(Proc)
7
+ it 'should render correctly' do
8
+ subject.should have_tag 'table', with: { class: 'table' }, count: 1 do
9
+ with_tag 'thead', count: 1 do
10
+ with_tag 'th', text: 'Doctor strangelove', count: 1
11
+ with_tag 'th', text: 'Id', count: 1
12
+ end
12
13
 
13
- # puts subject.to_html(sample_collection)
14
+ with_tag 'tbody', with: { class: 'sortable' }, count: 1 do
15
+ sample_collection.each_with_index do |member, index|
16
+ with_tag "tr[data-id='#{member.id}'][data-index='#{index}']"
17
+
18
+ with_tag 'td', with: { 'data-value' => member.id }, text: index, count: 1
19
+ with_tag 'td', text: member.id, count: 1
20
+ with_tag 'td', text: "Dead at #{member.age}", count: 1
21
+ with_tag 'td', text: "I hope this helps #{index}", count: 1
22
+
23
+ with_tag 'overriden_tr'
24
+
25
+ with_tag 'td', text: member.age
26
+ end
27
+ end
28
+
29
+ with_tag 'tfoot', count: 1 do
30
+ with_tag 'td', text: 'On foot', count: 1
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'partial rendering' do
37
+ subject do
38
+ sample_table_full_described_definition.element_to_html(:body, sample_collection)
39
+ end
40
+
41
+ it 'should render header, footer, body separately' do
42
+ subject.should_not have_tag 'thead'
43
+ subject.should_not have_tag 'tfoot'
44
+
45
+ subject.should have_tag 'tbody'
46
+ subject.should have_tag 'tr'
47
+ subject.should have_tag 'td'
48
+ end
49
+ end
50
+
51
+ context 'defined shortly' do
52
+ subject { sample_table_short }
53
+
54
+ it 'should render correctly' do
55
+ subject.should have_tag 'table', count: 1 do
56
+ with_tag 'tbody', count: 1
57
+ with_tag 'thead', count: 1
58
+ with_tag 'tr', count: 4
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'with active record objects' do
64
+ subject { sample_table_active_record }
65
+
66
+ it 'should get right headings from active record' do
67
+ subject.should have_tag 'thead', count: 1 do
68
+ with_tag 'th', text: 'Humanized id', count: 1
69
+ with_tag 'th', text: 'Humanized age', count: 1
70
+ end
71
+
72
+ subject.should_not have_tag 'tfoot'
73
+ end
14
74
  end
15
75
  end
@@ -3,7 +3,7 @@ require 'bundler/setup'
3
3
 
4
4
  require 'grid_fu'
5
5
  require 'support/sample_table'
6
+ require 'rspec-html-matchers'
6
7
 
7
8
  RSpec.configure do |config|
8
- # some (optional) config here
9
9
  end
@@ -1,41 +1,109 @@
1
1
  require 'ostruct'
2
2
 
3
+ class ActiveRecordMock
4
+ def self.human_attribute_name(name)
5
+ "Humanized #{name.to_s}"
6
+ end
7
+ end
8
+
3
9
  def sample_collection
4
10
  [
5
- OpenStruct.new(id: 1, age: 27, value: 'Jim Morrison'),
6
- OpenStruct.new(id: 1, age: 70, value: 'William Blake'),
7
- OpenStruct.new(id: 1, age: 89, value: 'Robert Lee Frost')
11
+ OpenStruct.new(id: 10, age: 27, value: 'Jim Morrison'),
12
+ OpenStruct.new(id: 20, age: 70, value: 'William Blake'),
13
+ OpenStruct.new(id: 30, age: 89, value: 'Robert Lee Frost')
8
14
  ]
9
15
  end
10
16
 
11
- def sample_helper_function
12
- "I hope this helps"
17
+ def sample_helper_function(arg)
18
+ "I hope this helps #{arg}"
19
+ end
20
+
21
+ def sample_formatter(key, member, index)
22
+ "Formatter for #{member[key]}"
13
23
  end
14
24
 
15
- def sample_table
25
+ def sample_table_full_described_definition
16
26
  GridFu.define do
27
+ html_options class: 'table'
28
+
29
+ header do
30
+ row do
31
+ cell 'Id', html_options: { colspan: 5 }
32
+ cell do
33
+ 'Doctor strangelove'
34
+ end
35
+ end
36
+ end
37
+
17
38
  body do
18
39
  html_options class: 'sortable'
19
40
  row do
20
41
  html_options do |member, index|
21
- { data: { id: member.id } }
42
+ { data: { id: member.id, index: index } }
22
43
  end
23
44
 
24
- cell html_options: ->(value, _, _) { { data: { value: value } } } do |_, _, index|
45
+ cell html_options: ->(member, _) { { data: { value: member.id } } } do |_, index|
25
46
  index
26
47
  end
27
48
  cell :id
28
- cell :age do |value, _, _|
29
- "Dead at #{value}"
49
+ cell :age do |member, _|
50
+ "Dead at #{member.age}"
30
51
  end
31
- cell do
32
- sample_helper_function
52
+ cell do |_, index|
53
+ sample_helper_function(index)
33
54
  end
34
55
  end
35
56
 
36
57
  row html_options: { class: 'small' } do
37
- tag 'div'
58
+ tag 'overriden_tr'
59
+
60
+ cell :test do
61
+ "test"
62
+ end
63
+
64
+ cell :age, formatter: :sample_formatter
65
+ end
66
+ end
67
+
68
+ footer do
69
+ row do
70
+ cell html_options: { rowspan: 3 } do
71
+ "On foot"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def sample_table_full_described
79
+ sample_table_full_described_definition.to_html(sample_collection)
80
+ end
81
+
82
+ def sample_table_short
83
+ table = GridFu.define do
84
+ header do
85
+ cell 'Id'
86
+ cell 'Age'
87
+ end
88
+
89
+ cell :id
90
+ cell :age
91
+ end
92
+ table.to_html(sample_collection)
93
+ end
94
+
95
+ def sample_table_active_record
96
+ table = GridFu.define do
97
+ header do
98
+ cell :id
99
+ cell :age
100
+ cell "Custom string"
101
+ cell do
102
+ "Custom block"
38
103
  end
39
104
  end
105
+ cell :id
106
+ cell :age
40
107
  end
108
+ table.to_html(sample_collection, ActiveRecordMock)
41
109
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grid_fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-04 00:00:00.000000000 Z
12
+ date: 2013-03-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: active_support
15
+ name: activesupport
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec-html-matchers
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
62
78
  description: HTML table generator
63
79
  email:
64
80
  - gzigzigzeo@gmail.com
@@ -68,16 +84,20 @@ extra_rdoc_files: []
68
84
  files:
69
85
  - .gitignore
70
86
  - .rspec
87
+ - .travis.yml
71
88
  - Gemfile
72
89
  - LICENSE.txt
73
90
  - README.md
74
91
  - Rakefile
75
92
  - grid_fu.gemspec
76
93
  - lib/grid_fu.rb
77
- - lib/grid_fu/body.rb
78
- - lib/grid_fu/cell.rb
94
+ - lib/grid_fu/cells.rb
79
95
  - lib/grid_fu/element.rb
80
- - lib/grid_fu/row.rb
96
+ - lib/grid_fu/element/configuration.rb
97
+ - lib/grid_fu/element/nesting.rb
98
+ - lib/grid_fu/element/rendering.rb
99
+ - lib/grid_fu/rows.rb
100
+ - lib/grid_fu/sections.rb
81
101
  - lib/grid_fu/table.rb
82
102
  - lib/grid_fu/version.rb
83
103
  - spec/grid_spec.rb
@@ -97,7 +117,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
117
  version: '0'
98
118
  segments:
99
119
  - 0
100
- hash: 4608333944381045103
120
+ hash: -31517031954940795
101
121
  required_rubygems_version: !ruby/object:Gem::Requirement
102
122
  none: false
103
123
  requirements:
@@ -106,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
126
  version: '0'
107
127
  segments:
108
128
  - 0
109
- hash: 4608333944381045103
129
+ hash: -31517031954940795
110
130
  requirements: []
111
131
  rubyforge_project:
112
132
  rubygems_version: 1.8.25
@@ -1,28 +0,0 @@
1
- module GridFu
2
- class Body < Element
3
- attr_reader :rows
4
-
5
- def initialize(*args, &block)
6
- self.rows = []
7
-
8
- config.tag ||= 'tbody'
9
-
10
- super
11
- end
12
-
13
- protected
14
- def html_content(collection, resource_class)
15
- html = collection.map do |member|
16
- rows.map.with_index { |row, index| row.to_html(member, index) }.join(' ')
17
- end
18
- html.join
19
- end
20
-
21
- protected
22
- def row(*args, &block)
23
- self.rows << Row.new(&block)
24
- end
25
-
26
- attr_writer :rows
27
- end
28
- end
@@ -1,32 +0,0 @@
1
- module GridFu
2
- class Cell < Element
3
- def initialize(*args, &block)
4
- self.value = block
5
- self.key = args.first if args.first.is_a?(String) or args.first.is_a?(Symbol)
6
-
7
- config.tag = 'td'
8
- super(*args, &nil) # Bypass block evaling: in this case it's a value formatter
9
- end
10
-
11
- attr_reader :key, :value
12
-
13
- def to_html(member, index, &block)
14
- member_value = member.send(key) if key.present? and member.respond_to?(key)
15
- member_value = if value.is_a?(Proc)
16
- value.call(member_value, member, index)
17
- else
18
- member_value.to_s
19
- end
20
-
21
- super(*[member_value, member, index], &block)
22
- end
23
-
24
- protected
25
- def html_content(value, member, index)
26
- value
27
- end
28
-
29
- attr_writer :value
30
- attr_writer :key
31
- end
32
- end
@@ -1,26 +0,0 @@
1
- module GridFu
2
- class Row < Element
3
- attr_reader :cells
4
-
5
- def initialize(*args, &block)
6
- self.cells = []
7
- config.tag = 'tr'
8
-
9
- super
10
- end
11
-
12
- protected
13
- def html_content(member, index)
14
- html = cells.map do |cell|
15
- cell.to_html(member, index)
16
- end
17
- html.join
18
- end
19
-
20
- def cell(*args, &block)
21
- self.cells << Cell.new(*args, &block)
22
- end
23
-
24
- attr_writer :cells
25
- end
26
- end