tabletastic 0.1.3 → 0.2.0.pre

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