tabletastic 0.1.3 → 0.2.0.pre

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.
@@ -1,3 +1,6 @@
1
+ Git
2
+ * Updating to Rails3 API and idioms
3
+
1
4
  v0.1.3 (Dec 28, 2009)
2
5
  * Changing destroy action to have confirmation by default
3
6
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Joshua Davey
1
+ Copyright (c) 2010 Joshua Davey
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -24,18 +24,33 @@ This is my attempt to simplify this (the default scaffold):
24
24
 
25
25
  into this:
26
26
 
27
- <% table_for(@posts) do |t| %>
28
- <%= t.data :actions => :all %>
29
- <% end %>
27
+ <%= table_for(@posts) do |t|
28
+ t.data :actions => :all
29
+ end %>
30
30
 
31
31
  and still output the same effective results, but with all the semantic
32
32
  goodness that tabular data should have, i.e. a +thead+ and +tbody+ element.
33
33
 
34
34
 
35
+ == NOTICE: Rails 3 only!
36
+
37
+ As of version 0.2.0, this project is <strong>no longer compatible with Rails 2</strong>.
38
+ To use, make sure you're using the latest release of Rails 3 (beta 2 at this time).
39
+
40
+ Also, the new Rails 3 idiom is for blocks in erb templates to be use <%= %>, so if you're
41
+ upgrading, you MUST now use the <%= %> erb helpers when you call +table_for+.
42
+
43
+ For example:
44
+
45
+ <%= table_for(@people) do |t|
46
+ t.data
47
+ end %>
48
+
49
+
35
50
  == Installation
36
51
 
37
- In your Rails project, as a gem:
38
- config.gem "tabletastic", :source => "http://gemcutter.org"
52
+ In your Rails project, Gemfile:
53
+ gem "tabletastic"
39
54
 
40
55
  Or, for if you're behind the times, as a plugin:
41
56
  script/plugin install git://github.com/jgdavey/tabletastic.git
@@ -49,9 +64,9 @@ you can just use the helper. It will try to detect all content fields and belong
49
64
 
50
65
  In your view, simply calling:
51
66
 
52
- <% table_for(@posts) do |t| %>
53
- <%= t.data %>
54
- <% end %>
67
+ <%= table_for(@posts) do |t|
68
+ t.data
69
+ end %>
55
70
 
56
71
  will produce html like this:
57
72
 
@@ -86,9 +101,9 @@ will produce html like this:
86
101
  To limit the fields, change the order, or to include fields that are excluded by default (such as created_at),
87
102
  You can list methods to call on each resource:
88
103
 
89
- <% table_for(@posts) do |t| %>
90
- <%= t.data :author, :title, :created_at %>
91
- <% end %>
104
+ <%= table_for(@posts) do |t|
105
+ t.data :author, :title, :created_at
106
+ end %>
92
107
 
93
108
  will produce html like:
94
109
 
@@ -121,13 +136,13 @@ will produce html like:
121
136
 
122
137
  For even greater flexibility, you can pass +data+ a block:
123
138
 
124
- <% table_for(@posts) do |t| %>
125
- <% t.data :actions => :all do %>
126
- <%= t.cell(:title, :cell_html => {:class => "titlestring"}) %>
127
- <%= t.cell(:body, :heading => "Content") {|p| truncate(p.body, 30)} %>
128
- <%= t.cell(:author) {|p| p.author && link_to(p.author.name, p.author) } %>
129
- <% end -%>
130
- <% end %>
139
+ <%= table_for(@posts) do |t|
140
+ t.data :actions => :all do
141
+ t.cell(:title, :cell_html => {:class => "titlestring"})
142
+ t.cell(:body, :heading => "Content") {|p| truncate(p.body, 30)}
143
+ t.cell(:author) {|p| p.author && link_to(p.author.name, p.author) }
144
+ end
145
+ end %>
131
146
 
132
147
  will product html like:
133
148
 
@@ -206,4 +221,4 @@ If it _still_ isn't flexible enough for your needs, it might be time to return t
206
221
 
207
222
  == Copyright
208
223
 
209
- Copyright (c) 2009 Joshua Davey. See LICENSE for details.
224
+ Copyright (c) 2010 Joshua Davey. See LICENSE for details.
@@ -1,14 +1,15 @@
1
- module Tabletastic
1
+ require 'tabletastic/table_builder'
2
2
 
3
+ module Tabletastic
3
4
  # returns and outputs a table for the given active record collection
4
- def table_for(collection, *args)
5
+ def table_for(collection, *args, &block)
6
+ raise ArgumentError, "you must provide a block" unless block_given?
5
7
  klass = default_class_for(collection)
6
8
  options = args.extract_options!
7
9
  options[:html] ||= {}
8
10
  options[:html][:id] ||= get_id_for(klass)
9
- concat(tag(:table, options[:html], true))
10
- yield TableBuilder.new(collection, klass, self)
11
- concat("</table>")
11
+ result = block.call(TableBuilder.new(collection, klass, self))
12
+ content_tag(:table, result, options[:html])
12
13
  end
13
14
 
14
15
  private
@@ -22,185 +23,6 @@ module Tabletastic
22
23
  end
23
24
 
24
25
  def get_id_for(klass)
25
- klass.to_s.tableize
26
- end
27
-
28
- class TableBuilder
29
- @@association_methods = %w[display_name full_name name title username login value to_s]
30
- @@default_hidden_columns = %w[created_at updated_at created_on updated_on lock_version version]
31
- @@destroy_confirm_message = "Are you sure?"
32
-
33
- attr_accessor :field_labels
34
- attr_reader :collection, :klass, :fields
35
-
36
- def initialize(collection, klass, template)
37
- @collection, @klass, @template = collection, klass, template
38
- @field_labels = []
39
- end
40
-
41
- # builds up the fields that the table will include,
42
- # returns table head and body with all data
43
- #
44
- # Can be used one of three ways:
45
- #
46
- # * Alone, which will try to detect all content columns on the resource
47
- # * With an array of methods to call on each element in the collection
48
- # * With a block, which assumes you will use +cell+ method to build up
49
- # the table
50
- #
51
- #
52
- def data(*args, &block) # :yields: tablebody
53
- options = args.extract_options!
54
- if block_given?
55
- @fields = []
56
- yield self
57
- action_cells(options[:actions], options[:action_prefix])
58
- @template.concat(head)
59
- @template.concat(body)
60
- else
61
- @fields = args.empty? ? active_record_fields : args
62
- @field_labels = fields.map { |f| f.to_s.humanize }
63
- action_cells(options[:actions], options[:action_prefix])
64
- [head, body].join("")
65
- end
66
- end
67
-
68
- # individually specify a column, which will build up the header,
69
- # and method or block to call on each resource in the array
70
- #
71
- # Should always be called within the block of +data+
72
- #
73
- # For example:
74
- #
75
- # t.cell :blah
76
- #
77
- # will simply call +blah+ on each resource
78
- #
79
- # You can also provide a block, which allows for other helpers
80
- # or custom formatting. Since by default erb will just call +to_s+
81
- # on an any element output, you can more greatly control the output:
82
- #
83
- # t.cell(:price) {|resource| number_to_currency(resource)}
84
- #
85
- # would output something like:
86
- #
87
- # <td>$1.50</td>
88
- #
89
- def cell(*args, &proc)
90
- options = args.extract_options!
91
- method = args.first.to_sym
92
- method_or_proc = block_given? ? proc : method
93
-
94
- @fields << [method_or_proc, options.delete(:cell_html)]
95
-
96
- @field_labels << (options.delete(:heading) || method.to_s.humanize)
97
- # Since this will likely be called with <%= %> (aka 'concat'), explicitly return an empty string
98
- # This suppresses unwanted output
99
- return ""
100
- end
101
-
102
- def head
103
- content_tag(:thead) do
104
- content_tag(:tr) do
105
- self.field_labels.inject("") do |result,field|
106
- result += content_tag(:th, field)
107
- end
108
- end
109
- end
110
- end
111
-
112
- def body
113
- content_tag(:tbody) do
114
- @collection.inject("") do |rows, record|
115
- rowclass = @template.cycle("odd","even")
116
- rows += @template.content_tag_for(:tr, record, :class => rowclass) do
117
- cells_for_row(record)
118
- end
119
- end
120
- end
121
- end
122
-
123
- def cells_for_row(record)
124
- fields.inject("") do |cells, field_or_array|
125
- field = field_or_array
126
- if field_or_array.is_a?(Array)
127
- field = field_or_array.first
128
- html_options = field_or_array.last
129
- end
130
- cells += content_tag(:td, cell_data(record, field), html_options)
131
- end
132
- end
133
-
134
- def cell_data(record, method_or_attribute_or_proc)
135
- # Get the attribute or association in question
136
- result = send_or_call(record, method_or_attribute_or_proc)
137
- # If we already have a string, just return it
138
- return result if result.is_a?(String)
139
-
140
- # If we don't have a string, its likely an association
141
- # Try to detect which method to use for stringifying the attribute
142
- to_string = detect_string_method(result)
143
- result.send(to_string) if to_string
144
- end
145
-
146
- # Used internally to build up cells for common CRUD actions
147
- def action_cells(actions, prefix = nil)
148
- return if actions.blank?
149
- actions = [actions] if !actions.respond_to?(:each)
150
- actions = [:show, :edit, :destroy] if actions == [:all]
151
- actions.each do |action|
152
- action_link(action.to_sym, prefix)
153
- end
154
- end
155
-
156
- # Dynamically builds links for the action
157
- def action_link(action, prefix)
158
- html_class = "actions #{action.to_s}_link"
159
- self.cell(action, :heading => "", :cell_html => {:class => html_class}) do |resource|
160
- compound_resource = [prefix, resource].compact
161
- case action
162
- when :show
163
- @template.link_to("Show", compound_resource)
164
- when :destroy
165
- @template.link_to("Destroy", compound_resource, :method => :delete, :confirm => @@destroy_confirm_message)
166
- else # edit, other resource GET actions
167
- @template.link_to(action.to_s.titleize, @template.polymorphic_path(compound_resource, :action => action))
168
- end
169
- end
170
- end
171
-
172
- protected
173
-
174
- def detect_string_method(association)
175
- @@association_methods.detect { |method| association.respond_to?(method) }
176
- end
177
-
178
-
179
- def active_record_fields
180
- return [] if klass.blank?
181
- fields = klass.content_columns.map(&:name)
182
- fields += active_record_association_reflections
183
- fields -= @@default_hidden_columns
184
- fields = fields.map(&:to_sym)
185
- end
186
-
187
- def active_record_association_reflections
188
- return [] unless klass.respond_to?(:reflect_on_all_associations)
189
- associations = klass.reflect_on_all_associations(:belongs_to).map(&:name)
190
- end
191
-
192
- private
193
-
194
- def content_tag(name, content = nil, options = nil, escape = true, &block)
195
- @template.content_tag(name, content, options, escape, &block)
196
- end
197
-
198
- def send_or_call(object, duck)
199
- if duck.respond_to?(:call)
200
- duck.call(object)
201
- else
202
- object.send(duck)
203
- end
204
- end
26
+ klass ? klass.model_name.collection : ""
205
27
  end
206
28
  end
@@ -0,0 +1,143 @@
1
+ require File.join(File.dirname(__FILE__), 'table_field')
2
+
3
+ module Tabletastic
4
+ class TableBuilder
5
+ @@default_hidden_columns = %w[created_at updated_at created_on updated_on lock_version version]
6
+ @@destroy_confirm_message = "Are you sure?"
7
+
8
+ attr_reader :collection, :klass, :table_fields
9
+
10
+ def initialize(collection, klass, template)
11
+ @collection, @klass, @template = collection, klass, template
12
+ @table_fields = []
13
+ end
14
+
15
+ # builds up the fields that the table will include,
16
+ # returns table head and body with all data
17
+ #
18
+ # Can be used one of three ways:
19
+ #
20
+ # * Alone, which will try to detect all content columns on the resource
21
+ # * With an array of methods to call on each element in the collection
22
+ # * With a block, which assumes you will use +cell+ method to build up
23
+ # the table
24
+ #
25
+ #
26
+ def data(*args, &block) # :yields: tablebody
27
+ options = args.extract_options!
28
+ if block_given?
29
+ yield self
30
+ else
31
+ @table_fields = args.empty? ? active_record_fields : args.collect {|f| TableField.new(f.to_sym)}
32
+ end
33
+ action_cells(options[:actions], options[:action_prefix])
34
+ [head, body].join("").html_safe
35
+ end
36
+
37
+ # individually specify a column, which will build up the header,
38
+ # and method or block to call on each resource in the array
39
+ #
40
+ # Should always be called within the block of +data+
41
+ #
42
+ # For example:
43
+ #
44
+ # t.cell :blah
45
+ #
46
+ # will simply call +blah+ on each resource
47
+ #
48
+ # You can also provide a block, which allows for other helpers
49
+ # or custom formatting. Since by default erb will just call +to_s+
50
+ # on an any element output, you can more greatly control the output:
51
+ #
52
+ # t.cell(:price) {|resource| number_to_currency(resource)}
53
+ #
54
+ # would output something like:
55
+ #
56
+ # <td>$1.50</td>
57
+ #
58
+ def cell(*args, &proc)
59
+ options = args.extract_options!
60
+ options.merge!(:klass => klass)
61
+ args << options
62
+ @table_fields << TableField.new(*args, &proc)
63
+ # Since this will likely be called with <%= %> (aka 'concat'), explicitly return an empty string
64
+ # This suppresses unwanted output
65
+ return ""
66
+ end
67
+
68
+ def head
69
+ content_tag(:thead) do
70
+ content_tag(:tr) do
71
+ @table_fields.inject("") do |result,field|
72
+ result += content_tag(:th, field.heading)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def body
79
+ content_tag(:tbody) do
80
+ @collection.inject("") do |rows, record|
81
+ rowclass = @template.cycle("odd","even")
82
+ rows += @template.content_tag_for(:tr, record, :class => rowclass) do
83
+ cells_for_row(record)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def cells_for_row(record)
90
+ @table_fields.inject("") do |cells, field|
91
+ cells + content_tag(:td, field.cell_data(record), field.cell_html)
92
+ end
93
+ end
94
+
95
+ # Used internally to build up cells for common CRUD actions
96
+ def action_cells(actions, prefix = nil)
97
+ return if actions.blank?
98
+ actions = [actions] if !actions.respond_to?(:each)
99
+ actions = [:show, :edit, :destroy] if actions == [:all]
100
+ actions.each do |action|
101
+ action_link(action.to_sym, prefix)
102
+ end
103
+ end
104
+
105
+ # Dynamically builds links for the action
106
+ def action_link(action, prefix)
107
+ html_class = "actions #{action.to_s}_link"
108
+ proc = lambda do |resource|
109
+ compound_resource = [prefix, resource].compact
110
+ case action
111
+ when :show
112
+ @template.link_to("Show", compound_resource)
113
+ when :destroy
114
+ @template.link_to("Destroy", compound_resource, :method => :delete, :confirm => @@destroy_confirm_message)
115
+ else # edit, other resource GET actions
116
+ @template.link_to(action.to_s.titleize, @template.polymorphic_path(compound_resource, :action => action))
117
+ end
118
+ end
119
+ self.cell(action, :heading => "", :cell_html => {:class => html_class}, &proc)
120
+ end
121
+
122
+ protected
123
+
124
+ def active_record_fields
125
+ return [] if klass.blank?
126
+ fields = klass.content_columns.map(&:name)
127
+ fields += active_record_association_reflections
128
+ fields -= @@default_hidden_columns
129
+ fields.collect {|f| TableField.new(f.to_sym)}
130
+ end
131
+
132
+ private
133
+
134
+ def active_record_association_reflections
135
+ return [] unless klass.respond_to?(:reflect_on_all_associations)
136
+ associations = klass.reflect_on_all_associations(:belongs_to).map(&:name)
137
+ end
138
+
139
+ def content_tag(name, content = nil, options = nil, escape = true, &block)
140
+ @template.content_tag(name, content, options, escape, &block)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,44 @@
1
+ require 'active_support/core_ext/object'
2
+
3
+ module Tabletastic
4
+ class TableField
5
+ @@association_methods = %w[to_label display_name full_name name title username login value to_str to_s]
6
+
7
+ attr_accessor :heading, :method_or_proc, :cell_html
8
+
9
+ def initialize(*args, &proc)
10
+ options = args.extract_options!
11
+ method = args.first.to_sym
12
+ @method_or_proc = block_given? ? proc : method
13
+ @cell_html = options[:cell_html]
14
+ @klass = options.delete(:klass)
15
+ @heading = options.delete(:heading) || @klass.try(:human_attribute_name, method.to_s) || method.to_s.humanize
16
+ end
17
+
18
+ def cell_data(record)
19
+ # Get the attribute or association in question
20
+ result = send_or_call(record, method_or_proc)
21
+ # If we already have a string, just return it
22
+ return result if result.is_a?(String)
23
+
24
+ # If we don't have a string, its likely an association
25
+ # Try to detect which method to use for stringifying the attribute
26
+ to_string = detect_string_method(result)
27
+ result.send(to_string) if to_string
28
+ end
29
+
30
+ private
31
+
32
+ def detect_string_method(association)
33
+ @@association_methods.detect { |method| association.respond_to?(method) }
34
+ end
35
+
36
+ def send_or_call(object, duck)
37
+ if duck.respond_to?(:call)
38
+ duck.call(object)
39
+ else
40
+ object.send(duck)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Tabletastic
2
+ VERSION = "0.2.0.pre"
3
+ end
@@ -1,7 +1,8 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  require 'rubygems'
3
3
 
4
- def smart_require(lib_name, gem_name, gem_version = '>= 0.0.0')
4
+ def smart_require(gem_name, gem_version = '>= 0.0.0', lib_name = nil)
5
+ lib_name ||= gem_name
5
6
  begin
6
7
  require lib_name if lib_name
7
8
  rescue LoadError
@@ -12,43 +13,44 @@ def smart_require(lib_name, gem_name, gem_version = '>= 0.0.0')
12
13
  end
13
14
  end
14
15
 
15
- smart_require 'spec', 'spec', '>= 1.2.8'
16
+ smart_require 'rspec', '>= 1.3.0', 'spec'
16
17
  require 'spec/autorun'
17
- smart_require false, 'rspec-rails', '>= 1.2.7.1'
18
- smart_require 'hpricot', 'hpricot', '>= 0.6.1'
19
- smart_require 'rspec_hpricot_matchers', 'rspec_hpricot_matchers', '>= 1.0.0'
20
- smart_require 'active_support', 'activesupport', '>= 2.3.4'
21
- smart_require 'action_controller', 'actionpack', '>= 2.3.4'
22
- smart_require 'action_view', 'actionpack', '>= 2.3.4'
23
-
18
+ smart_require 'nokogiri'
19
+ smart_require 'rspec_tag_matchers', '>= 1.0.0'
20
+ smart_require 'activesupport', '>= 3.0.0.beta2', 'active_support'
21
+ smart_require 'actionpack', '>= 3.0.0.beta2', 'action_pack'
22
+ smart_require 'activerecord', '>= 3.0.0.beta2', 'active_record'
23
+ require 'action_controller'
24
+ require 'action_view/base'
25
+ require 'action_view/template'
26
+ require 'action_view/helpers'
24
27
  Spec::Runner.configure do |config|
25
- config.include(RspecHpricotMatchers)
28
+ config.include(RspecTagMatchers)
26
29
  end
27
30
 
28
31
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
29
32
  require 'tabletastic'
30
33
 
31
34
  module TabletasticSpecHelper
35
+ include ActiveSupport
36
+ include ActionView
32
37
  include ActionView::Helpers::UrlHelper
33
38
  include ActionView::Helpers::TagHelper
34
39
  include ActionView::Helpers::TextHelper
35
- include ActionView::Helpers::ActiveRecordHelper
40
+ include ActionView::Helpers::ActiveModelHelper
36
41
  include ActionView::Helpers::RecordIdentificationHelper
37
42
  include ActionView::Helpers::RecordTagHelper
38
43
  include ActionView::Helpers::CaptureHelper
39
- include ActiveSupport
44
+ include ActionView::Helpers::RawOutputHelper
40
45
  include ActionController::PolymorphicRoutes
41
46
 
42
47
  def self.included(base)
43
48
  base.class_eval do
44
49
  attr_accessor :output_buffer
45
- def protect_against_forgery?
46
- false
47
- end
48
50
  end
49
51
  end
50
52
 
51
- module ::RspecHpricotMatchers
53
+ module ::RspecTagMatchers
52
54
  def have_table_with_tag(selector, inner_text_or_options = nil, options = {}, &block)
53
55
  HaveTag.new("table", nil, {}) &&
54
56
  HaveTag.new(selector, inner_text_or_options, options, &block)
@@ -73,8 +75,9 @@ module TabletasticSpecHelper
73
75
  @post.stub!(:class).and_return(::Post)
74
76
  @post.stub!(:id).and_return(nil)
75
77
  @post.stub!(:author)
78
+ @post.stub!(:to_key).and_return([2])
76
79
  ::Post.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
77
- ::Post.stub!(:human_name).and_return('Post')
80
+ ::Post.stub!(:model_name).and_return(ActiveModel::Name.new(::Post))
78
81
 
79
82
  @fred = mock('user')
80
83
  @fred.stub!(:class).and_return(::Author)
@@ -84,6 +87,7 @@ module TabletasticSpecHelper
84
87
  ::Author.stub!(:find).and_return([@fred])
85
88
  ::Author.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
86
89
  ::Author.stub!(:human_name).and_return('Author')
90
+ ::Author.stub!(:model_name).and_return(ActiveModel::Name.new(::Author))
87
91
  ::Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Post, :macro => :has_many) if column_name == :posts }
88
92
 
89
93
  @freds_post = mock('post')
@@ -91,6 +95,7 @@ module TabletasticSpecHelper
91
95
  @freds_post.stub!(:title).and_return('Fred\'s Post')
92
96
  @freds_post.stub!(:body)
93
97
  @freds_post.stub!(:id).and_return(19)
98
+ @freds_post.stub!(:to_key).and_return([19])
94
99
  @freds_post.stub!(:author).and_return(@fred)
95
100
  @freds_post.stub!(:author_id).and_return(@fred.id)
96
101
  @fred.stub!(:posts).and_return([@freds_post])
@@ -105,3 +110,6 @@ module TabletasticSpecHelper
105
110
  ::Post.stub!(:reflect_on_all_associations).with(:belongs_to).and_return([])
106
111
  end
107
112
  end
113
+
114
+ include TabletasticSpecHelper
115
+ include Tabletastic
@@ -1,12 +1,9 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- include TabletasticSpecHelper
3
- include Tabletastic
4
-
1
+ require 'spec_helper'
5
2
 
6
3
  describe "Tabletastic#table_for" do
7
4
 
8
5
  before do
9
- @output_buffer = ''
6
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
7
  end
11
8
 
12
9
  describe "basics" do
@@ -15,327 +12,15 @@ describe "Tabletastic#table_for" do
15
12
  end
16
13
 
17
14
  it "should build a basic table" do
18
- table_for([]) do |t|
19
- end
15
+ concat(table_for([]) {})
20
16
  output_buffer.should have_tag("table")
21
17
  end
22
18
 
23
- context "head and table body" do
24
- before do
25
- table_for([]) do |t|
26
- concat(t.head)
27
- concat(t.body)
28
- end
29
- end
30
-
31
- it "should build a basic table and head" do
32
- output_buffer.should have_table_with_tag("thead")
33
- end
34
-
35
- it "should build a basic table and body" do
36
- output_buffer.should have_table_with_tag("tbody")
37
- end
38
- end
39
-
40
19
  context "with options" do
41
20
  it "should pass along html options" do
42
- table_for([], :html => {:class => 'special'}) do |t|
43
- end
21
+ concat(table_for([], :html => {:class => 'special'}){})
44
22
  output_buffer.should have_tag("table.special")
45
23
  end
46
24
  end
47
25
  end
48
-
49
- describe "#data" do
50
- before do
51
- mock_everything
52
- ::Post.stub!(:content_columns).and_return([mock('column', :name => 'title'), mock('column', :name => 'body'), mock('column', :name => 'created_at')])
53
- @post.stub!(:title).and_return("The title of the post")
54
- @post.stub!(:body).and_return("Lorem ipsum")
55
- @post.stub!(:created_at).and_return(Time.now)
56
- @post.stub!(:id).and_return(2)
57
- @posts = [@post]
58
- end
59
-
60
- context "without a block" do
61
- context "with no other arguments" do
62
- before do
63
- table_for(@posts) do |t|
64
- concat(t.data)
65
- end
66
- end
67
-
68
- it "should output table with id of the class of the collection" do
69
- output_buffer.should have_tag("table#posts")
70
- end
71
-
72
- it "should output head" do
73
- output_buffer.should have_table_with_tag("thead")
74
- end
75
-
76
- it "should have a <th> for each attribute" do
77
- # title and body
78
- output_buffer.should have_table_with_tag("th", :count => 2)
79
- end
80
-
81
- it "should include header for Title" do
82
- output_buffer.should have_table_with_tag("th", "Title")
83
- end
84
-
85
- it "should include header for Body" do
86
- output_buffer.should have_table_with_tag("th", "Body")
87
- end
88
-
89
- it "should output body" do
90
- output_buffer.should have_table_with_tag("tbody")
91
- end
92
-
93
- it "should include a row for each record" do
94
- output_buffer.should have_table_with_tag("tbody") do |tbody|
95
- tbody.should have_tag("tr", :count => 1)
96
- end
97
- end
98
-
99
- it "should have data for each field" do
100
- output_buffer.should have_table_with_tag("td", "The title of the post")
101
- output_buffer.should have_table_with_tag("td", "Lorem ipsum")
102
- end
103
-
104
- it "should include the id for the <tr> for each record" do
105
- output_buffer.should have_table_with_tag("tr#post_#{@post.id}")
106
- end
107
-
108
- it "should cycle row classes" do
109
- @output_buffer = ""
110
- @posts = [@post, @post]
111
- table_for(@posts) do |t|
112
- concat(t.data)
113
- end
114
- output_buffer.should have_table_with_tag("tr.odd")
115
- output_buffer.should have_table_with_tag("tr.even")
116
- end
117
-
118
- context "when collection has associations" do
119
- it "should handle belongs_to associations" do
120
- ::Post.stub!(:reflect_on_all_associations).with(:belongs_to).and_return([@mock_reflection_belongs_to_author])
121
- @posts = [@freds_post]
122
- @output_buffer = ""
123
- table_for(@posts) do |t|
124
- concat(t.data)
125
- end
126
- output_buffer.should have_table_with_tag("th", "Author")
127
- output_buffer.should have_table_with_tag("td", "Fred Smith")
128
- end
129
- end
130
- end
131
-
132
- context "with options[:actions]" do
133
- it "includes path to post for :show" do
134
- table_for(@posts) do |t|
135
- concat(t.data(:actions => :show))
136
- end
137
- output_buffer.should have_table_with_tag("a[@href=/posts/#{@post.id}]")
138
- output_buffer.should have_table_with_tag("th", "")
139
- end
140
-
141
- it "should have a cell with default class 'actions' and the action name" do
142
- table_for(@posts) do |t|
143
- concat(t.data(:actions => :show))
144
- end
145
- output_buffer.should have_tag("td.actions.show_link") do |td|
146
- td.should have_tag("a")
147
- end
148
- end
149
-
150
- it "includes path to post for :edit" do
151
- table_for(@posts) do |t|
152
- concat(t.data(:actions => :edit))
153
- end
154
- output_buffer.should have_tag("a[@href=/posts/#{@post.id}/edit]", "Edit")
155
- end
156
-
157
- it "includes path to post for :destroy" do
158
- table_for(@posts) do |t|
159
- concat(t.data(:actions => :destroy))
160
- end
161
- output_buffer.should have_table_with_tag("a[@href=/posts/#{@post.id}]")
162
- output_buffer.should have_table_with_tag("th", "")
163
- end
164
-
165
- it "includes path to post for :show and :edit" do
166
- table_for(@posts) do |t|
167
- concat(t.data(:actions => [:show, :edit]))
168
- end
169
- output_buffer.should have_tag("td:nth-child(3) a[@href=/posts/#{@post.id}]", "Show")
170
- output_buffer.should have_tag("td:nth-child(4) a[@href=/posts/#{@post.id}/edit]", "Edit")
171
- end
172
-
173
- it "includes path to post for :all" do
174
- table_for(@posts) do |t|
175
- concat(t.data(:actions => :all))
176
- end
177
- output_buffer.should have_tag("td:nth-child(3) a[@href=/posts/#{@post.id}]", "Show")
178
- output_buffer.should have_tag("td:nth-child(4) a[@href=/posts/#{@post.id}/edit]", "Edit")
179
- output_buffer.should have_tag("td:nth-child(5) a[@href=/posts/#{@post.id}]", "Destroy")
180
- end
181
-
182
- context "with options[:actions_prefix]" do
183
- it "includes path to admin post for :show" do
184
- table_for(@posts) do |t|
185
- concat(t.data(:actions => :show, :action_prefix => :admin))
186
- end
187
- output_buffer.should have_tag("td:nth-child(3) a[@href=/admin/posts/#{@post.id}]", "Show")
188
- end
189
-
190
- it "includes path to admin post for :edit" do
191
- table_for(@posts) do |t|
192
- concat(t.data(:actions => :edit, :action_prefix => :admin))
193
- end
194
- output_buffer.should have_tag("td:nth-child(3) a[@href=/admin/posts/#{@post.id}/edit]", "Edit")
195
- end
196
-
197
- it "includes path to admin post for :destroy" do
198
- table_for(@posts) do |t|
199
- concat(t.data(:actions => :destroy, :action_prefix => :admin))
200
- end
201
- output_buffer.should have_tag("td:nth-child(3) a[@href=/admin/posts/#{@post.id}]", "Destroy")
202
- end
203
-
204
- it "includes path to admin for all actions" do
205
- table_for(@posts) do |t|
206
- concat(t.data(:actions => :all, :action_prefix => :admin))
207
- end
208
- output_buffer.should have_tag("td:nth-child(3) a[@href=/admin/posts/#{@post.id}]", "Show")
209
- output_buffer.should have_tag("td:nth-child(4) a[@href=/admin/posts/#{@post.id}/edit]", "Edit")
210
- output_buffer.should have_tag("td:nth-child(5) a[@href=/admin/posts/#{@post.id}]", "Destroy")
211
- end
212
- end
213
- end
214
-
215
- context "with a list of attributes" do
216
- before do
217
- table_for(@posts) do |t|
218
- concat(t.data(:title, :created_at))
219
- end
220
- end
221
-
222
- it "should call each method passed in, and only those methods" do
223
- output_buffer.should have_table_with_tag("th", "Title")
224
- output_buffer.should have_table_with_tag("th", "Created at")
225
- output_buffer.should_not have_table_with_tag("th", "Body")
226
- end
227
- end
228
-
229
- context "with a list of attributes and options[:actions]" do
230
- it "includes path to post for :show" do
231
- table_for(@posts) do |t|
232
- concat(t.data(:title, :created_at, :actions => :show))
233
- end
234
- output_buffer.should have_tag("th:nth-child(1)", "Title")
235
- output_buffer.should have_tag("th:nth-child(2)", "Created at")
236
- output_buffer.should have_tag("th:nth-child(3)", "")
237
- output_buffer.should_not have_tag("th", "Body")
238
-
239
- output_buffer.should have_tag("td:nth-child(3) a[@href=/posts/#{@post.id}]")
240
- end
241
- end
242
- end
243
-
244
- context "with a block" do
245
- context "and normal columns" do
246
- before do
247
- table_for(@posts) do |t|
248
- t.data do
249
- concat(t.cell(:title))
250
- concat(t.cell(:body))
251
- end
252
- end
253
- end
254
-
255
- it "should include the data for the fields passed in" do
256
- output_buffer.should have_table_with_tag("th", "Title")
257
- output_buffer.should have_tag("td", "The title of the post")
258
- output_buffer.should have_tag("td", "Lorem ipsum")
259
- end
260
- end
261
-
262
- context "with custom cell options" do
263
- before do
264
- table_for(@posts) do |t|
265
- t.data do
266
- concat(t.cell(:title, :heading => "FooBar"))
267
- concat(t.cell(:body, :cell_html => {:class => "batquux"}))
268
- end
269
- end
270
- end
271
-
272
- it "should change the heading label for :heading option" do
273
- output_buffer.should have_table_with_tag("th", "FooBar")
274
- output_buffer.should have_table_with_tag("th", "Body")
275
- end
276
-
277
- it "should pass :cell_html to the cell" do
278
- output_buffer.should have_table_with_tag("td.batquux")
279
- end
280
- end
281
-
282
- context "with custom cell options" do
283
- before do
284
- table_for(@posts) do |t|
285
- t.data do
286
- concat(t.cell(:title) {|p| link_to p.title, "/" })
287
- concat(t.cell(:body, :heading => "Content") {|p| p.body })
288
- end
289
- end
290
- end
291
-
292
- it "accepts a block as a lazy attribute" do
293
- output_buffer.should have_table_with_tag("th:nth-child(1)", "Title")
294
- output_buffer.should have_table_with_tag("td:nth-child(1)") do |td|
295
- td.should have_tag("a", "The title of the post")
296
- end
297
- end
298
-
299
- it "accepts a block as a lazy attribute (2)" do
300
- output_buffer.should have_table_with_tag("th:nth-child(2)", "Content")
301
- output_buffer.should have_table_with_tag("td:nth-child(2)", "Lorem ipsum")
302
- end
303
- end
304
-
305
- context "with options[:actions]" do
306
- it "includes path to post for :show" do
307
- table_for(@posts) do |t|
308
- t.data(:actions => :show) do
309
- concat(t.cell(:title))
310
- concat(t.cell(:body))
311
- end
312
- end
313
- output_buffer.should have_table_with_tag("td:nth-child(3) a[@href=/posts/#{@post.id}]")
314
- end
315
- end
316
-
317
- context "and normal/association columns" do
318
- before do
319
- ::Post.stub!(:reflect_on_all_associations).with(:belongs_to).and_return([@mock_reflection_belongs_to_author])
320
- @posts = [@freds_post]
321
- table_for(@posts) do |t|
322
- t.data do
323
- concat(t.cell(:title))
324
- concat(t.cell(:author))
325
- end
326
- end
327
- end
328
-
329
- it "should include normal columns" do
330
- output_buffer.should have_table_with_tag("th:nth-child(1)", "Title")
331
- output_buffer.should have_table_with_tag("td:nth-child(1)", "Fred's Post")
332
- end
333
-
334
- it "should include belongs_to associations" do
335
- output_buffer.should have_table_with_tag("th:nth-child(2)", "Author")
336
- output_buffer.should have_table_with_tag("td:nth-child(2)", "Fred Smith")
337
- end
338
- end
339
- end
340
- end
341
26
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabletastic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ prerelease: true
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ - pre
10
+ version: 0.2.0.pre
5
11
  platform: ruby
6
12
  authors:
7
13
  - Joshua Davey
@@ -9,19 +15,21 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-12-28 00:00:00 -06:00
18
+ date: 2010-04-10 00:00:00 -05:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
23
- version: 1.2.9
24
- version:
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
25
33
  description: A table builder for active record collections that produces semantically rich and accessible markup
26
34
  email: josh@joshuadavey.com
27
35
  executables: []
@@ -29,47 +37,45 @@ executables: []
29
37
  extensions: []
30
38
 
31
39
  extra_rdoc_files:
32
- - LICENSE
33
40
  - README.rdoc
41
+ - LICENSE
34
42
  files:
35
- - .document
36
- - .gitignore
37
- - CHANGELOG.rdoc
43
+ - lib/tabletastic/table_builder.rb
44
+ - lib/tabletastic/table_field.rb
45
+ - lib/tabletastic/version.rb
46
+ - lib/tabletastic.rb
38
47
  - LICENSE
39
48
  - README.rdoc
40
- - Rakefile
41
- - VERSION
42
- - lib/tabletastic.rb
43
- - rails/init.rb
44
- - spec/spec.opts
45
- - spec/spec_helper.rb
46
- - spec/tabletastic_spec.rb
47
- - tabletastic.gemspec
49
+ - CHANGELOG.rdoc
48
50
  has_rdoc: true
49
51
  homepage: http://github.com/jgdavey/tabletastic
50
52
  licenses: []
51
53
 
52
54
  post_install_message:
53
- rdoc_options:
54
- - --charset=UTF-8
55
+ rdoc_options: []
56
+
55
57
  require_paths:
56
58
  - lib
57
59
  required_ruby_version: !ruby/object:Gem::Requirement
58
60
  requirements:
59
61
  - - ">="
60
62
  - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
61
65
  version: "0"
62
- version:
63
66
  required_rubygems_version: !ruby/object:Gem::Requirement
64
67
  requirements:
65
68
  - - ">="
66
69
  - !ruby/object:Gem::Version
67
- version: "0"
68
- version:
70
+ segments:
71
+ - 1
72
+ - 3
73
+ - 5
74
+ version: 1.3.5
69
75
  requirements: []
70
76
 
71
77
  rubyforge_project:
72
- rubygems_version: 1.3.5
78
+ rubygems_version: 1.3.6
73
79
  signing_key:
74
80
  specification_version: 3
75
81
  summary: A smarter table builder for Rails collections
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/.gitignore DELETED
@@ -1,22 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
22
- doc/
data/Rakefile DELETED
@@ -1,59 +0,0 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- GEM = "tabletastic"
5
- LONGDESCRIPTION = %Q{A table builder for active record collections \
6
- that produces semantically rich and accessible markup}
7
-
8
- begin
9
- require 'jeweler'
10
- Jeweler::Tasks.new do |s|
11
- s.name = GEM
12
- s.summary = %Q{A smarter table builder for Rails collections}
13
- s.description = LONGDESCRIPTION
14
- s.email = "josh@joshuadavey.com"
15
- s.homepage = "http://github.com/jgdavey/tabletastic"
16
- s.authors = ["Joshua Davey"]
17
- s.require_path = 'lib'
18
-
19
- s.add_development_dependency "rspec", ">= 1.2.9"
20
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
- end
22
- Jeweler::GemcutterTasks.new
23
- rescue LoadError
24
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
- end
26
-
27
- require 'spec/rake/spectask'
28
- Spec::Rake::SpecTask.new(:spec) do |spec|
29
- spec.libs << 'lib' << 'spec'
30
- spec.spec_files = FileList['spec/**/*_spec.rb']
31
- end
32
-
33
- desc 'Test the tabletastic plugin with specdoc formatting and colors'
34
- Spec::Rake::SpecTask.new('specdoc') do |t|
35
- t.spec_files = FileList['spec/**/*_spec.rb']
36
- t.spec_opts = ["--format specdoc", "-c"]
37
- end
38
-
39
- desc 'Test the tabletastic plugin with rcov'
40
- Spec::Rake::SpecTask.new(:rcov) do |spec|
41
- spec.libs << 'lib' << 'spec'
42
- spec.pattern = 'spec/**/*_spec.rb'
43
- spec.rcov = true
44
- spec.rcov_opts = ['--exclude', 'spec,Library']
45
- end
46
-
47
- task :spec => :check_dependencies
48
-
49
- task :default => :spec
50
-
51
- require 'rake/rdoctask'
52
- Rake::RDocTask.new do |rdoc|
53
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
54
-
55
- rdoc.rdoc_dir = 'rdoc'
56
- rdoc.title = "Tabletastic #{version}"
57
- rdoc.rdoc_files.include('README*')
58
- rdoc.rdoc_files.include('lib/**/*.rb')
59
- end
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.3
@@ -1,3 +0,0 @@
1
- # Include hook code here
2
- require File.join(File.dirname(__FILE__), *%w[.. lib tabletastic])
3
- ActionView::Base.send :include, Tabletastic
@@ -1,2 +0,0 @@
1
- --diff
2
- --color
@@ -1,57 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{tabletastic}
8
- s.version = "0.1.3"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Joshua Davey"]
12
- s.date = %q{2009-12-28}
13
- s.description = %q{A table builder for active record collections that produces semantically rich and accessible markup}
14
- s.email = %q{josh@joshuadavey.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "CHANGELOG.rdoc",
23
- "LICENSE",
24
- "README.rdoc",
25
- "Rakefile",
26
- "VERSION",
27
- "lib/tabletastic.rb",
28
- "rails/init.rb",
29
- "spec/spec.opts",
30
- "spec/spec_helper.rb",
31
- "spec/tabletastic_spec.rb",
32
- "tabletastic.gemspec"
33
- ]
34
- s.homepage = %q{http://github.com/jgdavey/tabletastic}
35
- s.rdoc_options = ["--charset=UTF-8"]
36
- s.require_paths = ["lib"]
37
- s.rubygems_version = %q{1.3.5}
38
- s.summary = %q{A smarter table builder for Rails collections}
39
- s.test_files = [
40
- "spec/spec_helper.rb",
41
- "spec/tabletastic_spec.rb"
42
- ]
43
-
44
- if s.respond_to? :specification_version then
45
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
- s.specification_version = 3
47
-
48
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
- s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
50
- else
51
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
52
- end
53
- else
54
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
55
- end
56
- end
57
-