mholling-paged_scopes 0.0.3 → 0.0.4
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.
- data/VERSION.yml +1 -1
- data/lib/paged_scopes/controller.rb +31 -15
- data/lib/paged_scopes/index.rb +26 -49
- data/lib/paged_scopes/pages.rb +1 -1
- data/lib/paged_scopes/paginator.rb +8 -17
- data/spec/controller_spec.rb +259 -69
- data/spec/page_spec.rb +3 -3
- data/spec/paginator_spec.rb +27 -23
- data/spec/spec_helper.rb +58 -24
- metadata +2 -2
data/VERSION.yml
CHANGED
@@ -1,24 +1,40 @@
|
|
1
1
|
module PagedScopes
|
2
2
|
module Controller
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module ClassMethods
|
4
|
+
def get_page_for(collection_name, options = {})
|
5
|
+
callback_method = "get_page_for_#{collection_name}"
|
6
|
+
define_method callback_method do
|
7
|
+
collection = instance_variable_get("@#{collection_name.to_s.pluralize}")
|
8
|
+
raise RuntimeError, "no @#{collection_name.to_s.pluralize} collection was set" unless collection
|
9
|
+
object = instance_variable_get("@#{collection_name.to_s.singularize}")
|
10
|
+
instance_variable_set("@#{collection.pages.name.underscore}", page_for(collection, object, options))
|
11
|
+
end
|
12
|
+
protected callback_method
|
13
|
+
before_filter callback_method, options.except(:per_page, :name, :path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend ClassMethods
|
19
|
+
base.rescue_responses.update('PagedScopes::PageNotFound' => :not_found)
|
20
|
+
end
|
21
|
+
|
22
|
+
def page_for(collection, *args, &block)
|
23
|
+
options = args.extract_options!
|
24
|
+
collection.per_page = options[:per_page] if options[:per_page]
|
25
|
+
collection.page_name = options[:name] if options[:name]
|
26
|
+
object = args.first
|
27
|
+
returning collection.pages.find_by_object(object) || collection.pages.from_params!(params) || collection.pages.first do |page|
|
28
|
+
if options[:path]
|
29
|
+
page.paginator.set_path { |pg| send(options[:path], pg) }
|
30
|
+
elsif block_given?
|
31
|
+
page.paginator.set_path(&block)
|
32
|
+
end
|
14
33
|
end
|
15
|
-
protected callback_method
|
16
|
-
before_filter callback_method, options.except(:per_page, :name, :path)
|
17
34
|
end
|
18
35
|
end
|
19
36
|
end
|
20
37
|
|
21
38
|
if defined? ActionController::Base
|
22
|
-
ActionController::Base.
|
23
|
-
ActionController::Base.rescue_responses.update('PagedScopes::PageNotFound' => :not_found)
|
39
|
+
ActionController::Base.send :include, PagedScopes::Controller
|
24
40
|
end
|
data/lib/paged_scopes/index.rb
CHANGED
@@ -1,62 +1,39 @@
|
|
1
1
|
module PagedScopes
|
2
2
|
module Index
|
3
3
|
def index_of(object)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
order_operators = order_attributes.inject({}) do |hash, order_attribute|
|
9
|
-
operator = order_attribute.slice!(/\s+(desc|DESC)$/) ? ">" : "<"
|
10
|
-
order_attribute.slice!(/\s+(asc|ASC)$/)
|
11
|
-
hash.merge(order_attribute => operator)
|
12
|
-
end
|
13
|
-
unless order_attributes.include? primary_key_attribute
|
14
|
-
order_operators[primary_key_attribute] = "<"
|
15
|
-
order_attributes << primary_key_attribute
|
4
|
+
columns = scope(:find, :order).to_s.split(',').map(&:strip) << "#{table_name}.#{primary_key}"
|
5
|
+
operators = columns.map do |column|
|
6
|
+
column.slice!(/\s+(asc|ASC)$/)
|
7
|
+
column.slice!(/\s+(desc|DESC)$/) ? ">" : "<"
|
16
8
|
end
|
17
9
|
|
18
|
-
|
19
|
-
order_attributes.each_with_index do |order_attribute, n|
|
20
|
-
selects << "#{order_attribute} AS order_attribute_#{n}"
|
21
|
-
end
|
22
|
-
end.join(', ')
|
10
|
+
attributes = (1..columns.size).map { |n| "attribute_#{n}" }
|
23
11
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
12
|
+
selects = [ columns, attributes ].transpose.map do |column, attribute|
|
13
|
+
"#{column} AS #{attribute}"
|
14
|
+
end.unshift("#{table_name}.*").join(', ')
|
15
|
+
|
16
|
+
options = { :select => selects }
|
17
|
+
options.merge!(:offset => 0) if scope(:find, :limit) && scope(:find, :offset)
|
18
|
+
object_with_attributes = find(object.id, options)
|
32
19
|
|
33
|
-
|
34
|
-
|
35
|
-
|
20
|
+
values = attributes.map { |attribute| object_with_attributes.send(attribute) }
|
21
|
+
|
22
|
+
string, hash = "", {}
|
23
|
+
[ columns, operators, attributes, values ].transpose.reverse.each do |column, operator, attribute, value|
|
36
24
|
string = string.blank? ?
|
37
|
-
"#{
|
38
|
-
"#{
|
39
|
-
hash.merge!(
|
40
|
-
[ string, hash, n + 1 ]
|
25
|
+
"#{column} #{operator} :#{attribute}" :
|
26
|
+
"#{column} #{operator} :#{attribute} OR (#{column} = :#{attribute} AND (#{string}))"
|
27
|
+
hash.merge!(attribute.to_sym => value)
|
41
28
|
end
|
42
|
-
order_conditions.pop
|
43
|
-
|
44
|
-
# order_conditions = order_attributes.reverse.inject([]) do |conditions, order_attribute|
|
45
|
-
# if conditions.empty?
|
46
|
-
# conditions = [ "#{order_attribute} #{order_operators[order_attribute]} ?", object_order_attributes[order_attribute] ]
|
47
|
-
# else
|
48
|
-
# conditions[0] = "#{order_attribute} #{order_operators[order_attribute]} ? OR (#{order_attribute} = ? AND (#{conditions[0]}))"
|
49
|
-
# conditions.insert 1, object_order_attributes[order_attribute]
|
50
|
-
# conditions.insert 1, object_order_attributes[order_attribute]
|
51
|
-
# end
|
52
|
-
# end
|
53
29
|
|
54
|
-
|
55
|
-
|
56
|
-
before_count = count(
|
57
|
-
|
58
|
-
|
59
|
-
|
30
|
+
options = { :conditions => [ string, hash ], :distinct => true }
|
31
|
+
options.merge!(:offset => 0) if scope(:find, :limit) && scope(:find, :offset)
|
32
|
+
before_count = count("#{table_name}.#{primary_key}", options)
|
33
|
+
|
34
|
+
if scope(:find, :limit)
|
35
|
+
before_count -= scope(:find, :offset) if scope(:find, :limit) && scope(:find, :offset)
|
36
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find #{name} with ID=#{object.id}" if before_count < 0 || before_count >= scope(:find, :limit)
|
60
37
|
end
|
61
38
|
|
62
39
|
before_count
|
data/lib/paged_scopes/pages.rb
CHANGED
@@ -23,27 +23,18 @@ module PagedScopes
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def window(options)
|
26
|
-
results = []
|
27
26
|
size = options[:size]
|
28
27
|
extras = [ options[:extras] ].flatten.compact
|
29
28
|
raise ArgumentError, "No window block supplied." unless block_given?
|
30
|
-
|
31
|
-
|
32
|
-
results << yield(:
|
33
|
-
|
34
|
-
results << yield(
|
29
|
+
returning [] do |results|
|
30
|
+
results << yield(:first, @page.first? ? nil : @path.call(@page.class.first)) if extras.include?(:first)
|
31
|
+
results << yield(:previous, @page.first? ? nil : @path.call(@page.previous)) if extras.include?(:previous)
|
32
|
+
(-size..size).map { |offset| @page.offset(offset) }.compact.each do |page|
|
33
|
+
results << yield(page, @path.call(page))
|
35
34
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
if @page.number + size < @page.page_count
|
41
|
-
if extras.include?(:next) && offset_page = @page.offset(2 * size + 1)
|
42
|
-
results << yield(:next, @path.call(offset_page))
|
43
|
-
end
|
44
|
-
results << yield(:last, @path.call(@page.class.last)) if extras.include? :last
|
45
|
-
end
|
46
|
-
results.join("\n")
|
35
|
+
results << yield(:next, @page.last? ? nil : @path.call(@page.next)) if extras.include?(:next)
|
36
|
+
results << yield(:last, @page.last? ? nil : @path.call(@page.class.last)) if extras.include?(:last)
|
37
|
+
end.join("\n")
|
47
38
|
end
|
48
39
|
end
|
49
40
|
end
|
data/spec/controller_spec.rb
CHANGED
@@ -3,12 +3,76 @@ require 'spec_helper'
|
|
3
3
|
describe "Controller" do
|
4
4
|
|
5
5
|
context "class" do
|
6
|
+
it "should raise 404 on PagedScopes::PageNotFound" do
|
7
|
+
Class.new(ActionController::Base).rescue_responses['PagedScopes::PageNotFound'].should == :not_found
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "instance using #page_for" do
|
6
12
|
before(:each) do
|
7
13
|
@class = Class.new(ActionController::Base)
|
14
|
+
@controller = @class.new
|
15
|
+
@articles = User.first.articles
|
16
|
+
@articles.per_page = 3
|
8
17
|
end
|
9
18
|
|
10
|
-
it "should
|
11
|
-
@
|
19
|
+
it "should default to the first page of the collection" do
|
20
|
+
in_controller @controller do
|
21
|
+
page_for(@articles).should == @articles.pages.first
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should find the page from a page id in the params" do
|
26
|
+
in_controller @controller do
|
27
|
+
@articles.pages.each do |page|
|
28
|
+
stub!(:params).and_return(:page_id => page.id)
|
29
|
+
page_for(@articles).should == page
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should find the page containing an object if specified" do
|
35
|
+
in_controller @controller do
|
36
|
+
@articles.each do |article|
|
37
|
+
# page_for(@articles, article).should == @articles.pages.find_by_article(article)
|
38
|
+
page_for(@articles, article).articles.all.should include(article)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should set per_page on the collection if specified" do
|
44
|
+
in_controller @controller do
|
45
|
+
page_for(@articles, :per_page => 4)
|
46
|
+
@articles.per_page.should == 4
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set the page model name on the collection if specified" do
|
51
|
+
in_controller @controller do
|
52
|
+
page_for(@articles, :name => "Group")
|
53
|
+
@articles.page_name.should == "Group"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set the pagination path proc if specified using a :path option" do
|
58
|
+
in_controller @controller do
|
59
|
+
@page = page_for(@articles, :path => :page_articles_path)
|
60
|
+
self.should_receive(:page_articles_path).with(@page.next)
|
61
|
+
@page.paginator.next
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should set the pagination path proc if specified with a block" do
|
66
|
+
in_controller @controller do
|
67
|
+
@page = page_for(@articles) { |page| "path/to/page/#{page.to_param}" }
|
68
|
+
@page.paginator.next.should == "path/to/page/#{@page.next.to_param}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "class using #get_page_for" do
|
74
|
+
before(:each) do
|
75
|
+
@class = Class.new(ActionController::Base)
|
12
76
|
end
|
13
77
|
|
14
78
|
it "should add a protected get_page_for callback as a before filter when get_page_for is called" do
|
@@ -24,54 +88,69 @@ describe "Controller" do
|
|
24
88
|
@filter.options.keys.should_not include(:per_page, :name, :path)
|
25
89
|
@filter.options.keys.should include(:only, :if)
|
26
90
|
end
|
27
|
-
|
28
91
|
end
|
29
|
-
|
30
|
-
context "instance" do
|
92
|
+
|
93
|
+
context "instance using get_page_for in the controller class" do
|
31
94
|
before(:each) do
|
32
|
-
@
|
33
|
-
|
34
|
-
|
95
|
+
@class = Class.new(ActionController::Base)
|
96
|
+
@class.get_page_for :articles, :per_page => 3
|
97
|
+
@controller = @class.new
|
35
98
|
end
|
36
|
-
|
99
|
+
|
37
100
|
it "should raise an error if no collection is set" do
|
38
101
|
in_controller @controller do
|
39
102
|
lambda { get_page_for_articles }.should raise_error(RuntimeError)
|
40
103
|
end
|
41
104
|
end
|
105
|
+
|
106
|
+
it "should pass :per_page, :name and :path options on to the call to #page_for" do
|
107
|
+
@options = { :per_page => 3, :name => "Group", :path => :page_articles_path }
|
108
|
+
@class.get_page_for :articles, @options
|
109
|
+
@controller = @class.new
|
110
|
+
in_controller @controller do
|
111
|
+
@articles = User.first.articles
|
112
|
+
self.should_receive(:page_for).with(@articles, nil, @options)
|
113
|
+
get_page_for_articles
|
114
|
+
end
|
115
|
+
end
|
42
116
|
|
43
|
-
context "when the collection is set" do
|
117
|
+
context "when the collection is set before the filter is run" do
|
44
118
|
before(:each) do
|
45
119
|
in_controller @controller do
|
46
120
|
@articles = User.first.articles
|
47
|
-
@articles.per_page = 3
|
48
121
|
end
|
49
122
|
end
|
50
123
|
|
51
|
-
it "should get the page from
|
124
|
+
it "should get the page from the collection object if set as an instance variable" do
|
52
125
|
in_controller @controller do
|
126
|
+
@articles.each do |article|
|
127
|
+
@article = article
|
128
|
+
get_page_for_articles
|
129
|
+
@page.articles.should include(@article)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should get the page from the params if a collection object is not set or is a new record" do
|
135
|
+
in_controller @controller do
|
136
|
+
@articles.per_page = 3
|
53
137
|
stub!(:params).and_return(:page_id => @articles.pages.last.id)
|
54
|
-
|
55
|
-
|
138
|
+
[ nil, Article.new ].each do |article|
|
139
|
+
@article = article
|
140
|
+
get_page_for_articles
|
141
|
+
@page.should == @articles.pages.last
|
142
|
+
end
|
56
143
|
end
|
57
144
|
end
|
58
145
|
|
59
146
|
it "should raise PageNotFound if the page id in the params is not in range" do
|
60
147
|
in_controller @controller do
|
148
|
+
@articles.per_page = 3
|
61
149
|
stub!(:params).and_return(:page_id => @articles.pages.last.id + 1)
|
62
150
|
lambda { get_page_for_articles }.should raise_error(PagedScopes::PageNotFound)
|
63
151
|
end
|
64
152
|
end
|
65
|
-
|
66
|
-
it "should otherwise get the page from the current object if no page id is present in the params" do
|
67
|
-
in_controller @controller do
|
68
|
-
@article = @articles.last
|
69
|
-
get_page_for_articles
|
70
|
-
@page.should == @articles.pages.find_by_article(@article)
|
71
|
-
@page.articles.should include(@article)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
153
|
+
|
75
154
|
it "should get the first page if the current object is a new record" do
|
76
155
|
in_controller @controller do
|
77
156
|
@article = @articles.new
|
@@ -80,7 +159,7 @@ describe "Controller" do
|
|
80
159
|
end
|
81
160
|
end
|
82
161
|
|
83
|
-
it "should otherwise
|
162
|
+
it "should otherwise default to the first page" do
|
84
163
|
in_controller @controller do
|
85
164
|
get_page_for_articles
|
86
165
|
@page.should == @articles.pages.first
|
@@ -88,48 +167,159 @@ describe "Controller" do
|
|
88
167
|
end
|
89
168
|
end
|
90
169
|
end
|
91
|
-
|
92
|
-
context "instance when :per_page is specified in the call to #get_page_for" do
|
93
|
-
it "should set per_page on the collection" do
|
94
|
-
@controller = Class.new(ActionController::Base) do
|
95
|
-
get_page_for :articles, :per_page => 3
|
96
|
-
end.new
|
97
|
-
in_controller @controller do
|
98
|
-
@articles = User.first.articles
|
99
|
-
@articles.per_page = nil
|
100
|
-
get_page_for_articles
|
101
|
-
@articles.per_page.should == 3
|
102
|
-
@articles.pages.per_page.should == 3
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context "instance when :name is specified in the call to #get_page_for" do
|
108
|
-
it "should set page_name on the collection" do
|
109
|
-
@controller = Class.new(ActionController::Base) do
|
110
|
-
get_page_for :articles, :per_page => 3, :name => "Group"
|
111
|
-
end.new
|
112
|
-
in_controller @controller do
|
113
|
-
@articles = User.first.articles
|
114
|
-
get_page_for_articles
|
115
|
-
@articles.page_name.should == "Group"
|
116
|
-
@articles.pages.name.should == "Group"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context "instance when :path is specified in the call to #get_page_for" do
|
122
|
-
it "should set page's pagination path to the specified controller method" do
|
123
|
-
@controller = Class.new(ActionController::Base) do
|
124
|
-
get_page_for :articles, :per_page => 3, :path => :page_articles_path
|
125
|
-
end.new
|
126
|
-
in_controller @controller do
|
127
|
-
@articles = User.first.articles
|
128
|
-
@article = @articles.first
|
129
|
-
get_page_for_articles
|
130
|
-
self.should_receive(:page_articles_path).with(@page.next)
|
131
|
-
@page.paginator.next
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
170
|
end
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
# require 'spec_helper'
|
192
|
+
#
|
193
|
+
# describe "Controller" do
|
194
|
+
#
|
195
|
+
# context "class" do
|
196
|
+
# before(:each) do
|
197
|
+
# @class = Class.new(ActionController::Base)
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# it "should raise 404 on PagedScopes::PageNotFound" do
|
201
|
+
# @class.rescue_responses['PagedScopes::PageNotFound'].should == :not_found
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# it "should add a protected get_page_for callback as a before filter when get_page_for is called" do
|
205
|
+
# @class.get_page_for :articles
|
206
|
+
# @class.before_filters.map(&:to_s).should include("get_page_for_articles")
|
207
|
+
# @class.protected_instance_methods.map(&:to_s).should include("get_page_for_articles")
|
208
|
+
# end
|
209
|
+
#
|
210
|
+
# it "should pass filter options except for :per_page, :name and :path on to the before filter" do
|
211
|
+
# @options = { :per_page => 3, :name => "Group", :path => :page_articles_path, :only => [ :index, :show ], :if => :test }
|
212
|
+
# @class.get_page_for :articles, @options
|
213
|
+
# @filter = @class.filter_chain.detect { |filter| filter.method.to_s == "get_page_for_articles" }
|
214
|
+
# @filter.options.keys.should_not include(:per_page, :name, :path)
|
215
|
+
# @filter.options.keys.should include(:only, :if)
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# context "instance" do
|
221
|
+
# before(:each) do
|
222
|
+
# @controller = Class.new(ActionController::Base) do
|
223
|
+
# get_page_for :articles
|
224
|
+
# end.new
|
225
|
+
# end
|
226
|
+
#
|
227
|
+
# it "should raise an error if no collection is set" do
|
228
|
+
# in_controller @controller do
|
229
|
+
# lambda { get_page_for_articles }.should raise_error(RuntimeError)
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
#
|
233
|
+
# context "when the collection is set" do
|
234
|
+
# before(:each) do
|
235
|
+
# in_controller @controller do
|
236
|
+
# @articles = User.first.articles
|
237
|
+
# @articles.per_page = 3
|
238
|
+
# end
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# it "should get the page from a page id in the params" do
|
242
|
+
# in_controller @controller do
|
243
|
+
# stub!(:params).and_return(:page_id => @articles.pages.last.id)
|
244
|
+
# get_page_for_articles
|
245
|
+
# @page.should == @articles.pages.last
|
246
|
+
# end
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# it "should raise PageNotFound if the page id in the params is not in range" do
|
250
|
+
# in_controller @controller do
|
251
|
+
# stub!(:params).and_return(:page_id => @articles.pages.last.id + 1)
|
252
|
+
# lambda { get_page_for_articles }.should raise_error(PagedScopes::PageNotFound)
|
253
|
+
# end
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
# it "should otherwise get the page from the current object if no page id is present in the params" do
|
257
|
+
# in_controller @controller do
|
258
|
+
# @article = @articles.last
|
259
|
+
# get_page_for_articles
|
260
|
+
# @page.should == @articles.pages.find_by_article(@article)
|
261
|
+
# @page.articles.should include(@article)
|
262
|
+
# end
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# it "should get the first page if the current object is a new record" do
|
266
|
+
# in_controller @controller do
|
267
|
+
# @article = @articles.new
|
268
|
+
# get_page_for_articles
|
269
|
+
# @page.should == @articles.pages.first
|
270
|
+
# end
|
271
|
+
# end
|
272
|
+
#
|
273
|
+
# it "should otherwise get the first page" do
|
274
|
+
# in_controller @controller do
|
275
|
+
# get_page_for_articles
|
276
|
+
# @page.should == @articles.pages.first
|
277
|
+
# end
|
278
|
+
# end
|
279
|
+
# end
|
280
|
+
# end
|
281
|
+
#
|
282
|
+
# context "instance when :per_page is specified in the call to #get_page_for" do
|
283
|
+
# it "should set per_page on the collection" do
|
284
|
+
# @controller = Class.new(ActionController::Base) do
|
285
|
+
# get_page_for :articles, :per_page => 3
|
286
|
+
# end.new
|
287
|
+
# in_controller @controller do
|
288
|
+
# @articles = User.first.articles
|
289
|
+
# @articles.per_page = nil
|
290
|
+
# get_page_for_articles
|
291
|
+
# @articles.per_page.should == 3
|
292
|
+
# @articles.pages.per_page.should == 3
|
293
|
+
# end
|
294
|
+
# end
|
295
|
+
# end
|
296
|
+
#
|
297
|
+
# context "instance when :name is specified in the call to #get_page_for" do
|
298
|
+
# it "should set page_name on the collection" do
|
299
|
+
# @controller = Class.new(ActionController::Base) do
|
300
|
+
# get_page_for :articles, :per_page => 3, :name => "Group"
|
301
|
+
# end.new
|
302
|
+
# in_controller @controller do
|
303
|
+
# @articles = User.first.articles
|
304
|
+
# get_page_for_articles
|
305
|
+
# @articles.page_name.should == "Group"
|
306
|
+
# @articles.pages.name.should == "Group"
|
307
|
+
# end
|
308
|
+
# end
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
# context "instance when :path is specified in the call to #get_page_for" do
|
312
|
+
# it "should set page's pagination path to the specified controller method" do
|
313
|
+
# @controller = Class.new(ActionController::Base) do
|
314
|
+
# get_page_for :articles, :per_page => 3, :path => :page_articles_path
|
315
|
+
# end.new
|
316
|
+
# in_controller @controller do
|
317
|
+
# @articles = User.first.articles
|
318
|
+
# @article = @articles.first
|
319
|
+
# get_page_for_articles
|
320
|
+
# self.should_receive(:page_articles_path).with(@page.next)
|
321
|
+
# @page.paginator.next
|
322
|
+
# end
|
323
|
+
# end
|
324
|
+
# end
|
325
|
+
# end
|
data/spec/page_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe "Pages" do
|
|
4
4
|
in_contexts do
|
5
5
|
before(:each) do
|
6
6
|
@pages = @articles.pages
|
7
|
-
@per_page =
|
7
|
+
@per_page = 2
|
8
8
|
@articles.stub!(:per_page).and_return(@per_page)
|
9
9
|
@articles.stub!(:page_name).and_return("Page")
|
10
10
|
end
|
@@ -128,7 +128,7 @@ describe "Pages" do
|
|
128
128
|
before(:each) do
|
129
129
|
@articles = Article.scoped(:conditions => { :title => "Supercalifragilisticexpialidocious" })
|
130
130
|
@articles.all.should be_empty
|
131
|
-
@articles.per_page =
|
131
|
+
@articles.per_page = 2
|
132
132
|
end
|
133
133
|
|
134
134
|
it "should have one page" do
|
@@ -149,7 +149,7 @@ describe "Page instance" do
|
|
149
149
|
in_contexts do
|
150
150
|
before(:each) do
|
151
151
|
@pages = @articles.pages
|
152
|
-
@per_page =
|
152
|
+
@per_page = 2
|
153
153
|
@articles.stub!(:per_page).and_return(@per_page)
|
154
154
|
end
|
155
155
|
|
data/spec/paginator_spec.rb
CHANGED
@@ -70,6 +70,10 @@ describe "Paginator" do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
describe "window generator" do
|
73
|
+
before(:each) do
|
74
|
+
@args = []
|
75
|
+
end
|
76
|
+
|
73
77
|
it "should raise an error if no block is provided" do
|
74
78
|
lambda { @pages.first.paginator.window({}) }.should raise_error(ArgumentError)
|
75
79
|
end
|
@@ -89,55 +93,54 @@ describe "Paginator" do
|
|
89
93
|
range.map { |nearby_number| @pages.find(nearby_number) }.each do |nearby_page|
|
90
94
|
expected_args << [ nearby_page, @path.call(nearby_page) ]
|
91
95
|
end
|
92
|
-
actual_args = []
|
93
96
|
page.paginator.window(:size => @size) do |*args|
|
94
|
-
|
97
|
+
expected_args.shift.should == args
|
95
98
|
end
|
96
|
-
|
99
|
+
expected_args.should be_empty
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
100
|
-
[ :
|
103
|
+
[ [ :previous, 2, 1 ], [ :next, 1, 2 ] ].each do |extra, number, new_number|
|
101
104
|
it "should call the block with #{extra.inspect} and the path for the #{extra} page if #{extra.inspect} is specified as an extra" do
|
102
|
-
page = @pages.find(
|
105
|
+
page = @pages.find(number)
|
103
106
|
page.paginator.set_path(&@path)
|
104
|
-
page.paginator.window(:size => @size, :extras => [ extra ]) do |
|
105
|
-
@
|
107
|
+
page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
|
108
|
+
@args << args
|
106
109
|
end
|
107
|
-
@
|
110
|
+
@args.should include([ extra, @path.call(@pages.find(new_number)) ])
|
108
111
|
end
|
109
112
|
end
|
110
113
|
|
111
|
-
[ [ :
|
112
|
-
it "should
|
114
|
+
[ [ :previous, "1" ], [ :next, "@page_count" ] ].each do |extra, number|
|
115
|
+
it "should call the block with #{extra.inspect} and a nil path if #{extra.inspect} is specified as an extra but there is no #{extra} page" do
|
113
116
|
page = @pages.find(eval(number))
|
114
117
|
page.paginator.set_path(&@path)
|
115
|
-
page.paginator.window(:size => @size, :extras => [ extra ]) do |
|
116
|
-
@
|
118
|
+
page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
|
119
|
+
@args << args
|
117
120
|
end
|
118
|
-
@
|
121
|
+
@args.should include([ extra, nil ])
|
119
122
|
end
|
120
123
|
end
|
121
124
|
|
122
|
-
[
|
125
|
+
[ :first, :last ].each do |extra|
|
123
126
|
it "should call the block with #{extra.inspect} and the path for the #{extra} page if #{extra.inspect} is specified as an extra" do
|
124
|
-
page = @pages.find(
|
127
|
+
page = @pages.find(6)
|
125
128
|
page.paginator.set_path(&@path)
|
126
|
-
page.paginator.window(:size => @size, :extras => [ extra ]) do |
|
127
|
-
@
|
129
|
+
page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
|
130
|
+
@args << args
|
128
131
|
end
|
129
|
-
@
|
132
|
+
@args.should include([ extra, @path.call(@pages.send(extra)) ])
|
130
133
|
end
|
131
134
|
end
|
132
135
|
|
133
|
-
[ [ :
|
134
|
-
it "should
|
136
|
+
[ [ :first, "1" ], [ :last, "@page_count" ] ].each do |extra, number|
|
137
|
+
it "should call the block with #{extra.inspect} and a nil path if #{extra.inspect} is specified as an extra but the current page is the #{extra} page" do
|
135
138
|
page = @pages.find(eval(number))
|
136
139
|
page.paginator.set_path(&@path)
|
137
|
-
page.paginator.window(:size => @size, :extras => [ extra ]) do |
|
138
|
-
@
|
140
|
+
page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
|
141
|
+
@args << args
|
139
142
|
end
|
140
|
-
@
|
143
|
+
@args.should include([ extra, nil ])
|
141
144
|
end
|
142
145
|
end
|
143
146
|
|
@@ -151,4 +154,5 @@ describe "Paginator" do
|
|
151
154
|
pages_in_order.should == [ :first, :previous, @pages.find(5), @pages.find(6), @pages.find(7), :next, :last ]
|
152
155
|
end
|
153
156
|
end
|
157
|
+
|
154
158
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -18,33 +18,61 @@ ActiveRecord::Schema.define do
|
|
18
18
|
create_table "articles", :force => true do |t|
|
19
19
|
t.column "user_id", :integer
|
20
20
|
t.column "title", :text
|
21
|
+
t.column "published_at", :datetime
|
21
22
|
end
|
22
23
|
create_table "comments", :force => true do |t|
|
23
24
|
t.column "article_id", :integer
|
24
25
|
t.column "user_id", :integer
|
25
26
|
end
|
27
|
+
create_table "contributions", :force => true do |t|
|
28
|
+
t.column "article_id", :integer
|
29
|
+
t.column "user_id", :integer
|
30
|
+
end
|
26
31
|
end
|
27
32
|
|
28
33
|
class ::User < ActiveRecord::Base
|
29
34
|
has_many :articles
|
30
|
-
has_many :
|
31
|
-
has_many :
|
35
|
+
has_many :recent_articles, :order => "published_at DESC", :conditions => [ "published_at IS NOT :nil", { :nil => nil } ], :class_name => "Article"
|
36
|
+
has_many :contributions
|
37
|
+
has_many :shared_articles, :through => :contributions, :source => :article
|
32
38
|
end
|
33
39
|
class ::Article < ActiveRecord::Base
|
34
40
|
belongs_to :user
|
35
41
|
has_many :comments
|
42
|
+
named_scope :untitled, :conditions => { :title => nil }
|
43
|
+
named_scope :including_user, :include => :user
|
44
|
+
named_scope :with_user, :joins => 'INNER JOIN users ON users.id = articles.user_id'
|
45
|
+
named_scope :with_named_user, :joins => 'INNER JOIN users ON users.id = articles.user_id', :conditions => [ 'users.name IS NOT :nil', { :nil => nil } ]
|
46
|
+
named_scope :ordered_by_user_name, :joins => 'INNER JOIN users ON users.id = articles.user_id', :conditions => [ 'users.name IS NOT :nil', { :nil => nil } ], :order => 'users.name'
|
47
|
+
named_scope :with_comments, :joins => 'INNER JOIN comments AS article_comments ON article_comments.article_id = articles.id', :group => 'articles.id'
|
48
|
+
named_scope :first_three_with_comments, :joins => 'INNER JOIN comments AS article_comments ON article_comments.article_id = articles.id', :group => 'articles.id', :limit => 3
|
49
|
+
named_scope :with_multiple_comments, :include => :comments, :joins => 'INNER JOIN (SELECT count(id) AS count, article_id FROM comments GROUP BY article_id) article_comments ON article_comments.article_id = articles.id', :conditions => 'article_comments.count > 1'
|
50
|
+
named_scope :first_three, :limit => 3
|
51
|
+
named_scope :two_through_four, :limit => 3, :offset => 1
|
52
|
+
named_scope :descending_id, :order => 'articles.id DESC'
|
36
53
|
end
|
37
54
|
class ::Comment < ActiveRecord::Base
|
38
55
|
belongs_to :article
|
56
|
+
end
|
57
|
+
class ::Contribution < ActiveRecord::Base
|
58
|
+
belongs_to :article
|
39
59
|
belongs_to :user
|
40
60
|
end
|
41
61
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
62
|
+
User.create(:name => "user #1")
|
63
|
+
User.create(:name => nil)
|
64
|
+
User.create(:name => "user #3")
|
65
|
+
9.times do |n|
|
66
|
+
shared_article = User.first.articles.create
|
67
|
+
User.all.each_with_index do |user, i|
|
68
|
+
user.articles.create
|
69
|
+
user.articles.create(:title => "Article #%03d" % Article.count)
|
70
|
+
published_article = user.articles.create(:title => "Article #%03d" % Article.count, :published_at => n.weeks.ago)
|
71
|
+
n.times { published_article.comments << Comment.new }
|
72
|
+
user.articles.create(:published_at => n.weeks.ago)
|
73
|
+
user.shared_articles << shared_article unless user == User.first
|
47
74
|
end
|
75
|
+
n.times { shared_article.comments << Comment.new }
|
48
76
|
end
|
49
77
|
|
50
78
|
module ControllerHelpers
|
@@ -56,6 +84,7 @@ module ControllerHelpers
|
|
56
84
|
end
|
57
85
|
|
58
86
|
def in_controller(controller, &block)
|
87
|
+
controller.copy_instance_variables_from(self)
|
59
88
|
in_instance controller do
|
60
89
|
stub!(:params).and_return({})
|
61
90
|
instance_eval(&block)
|
@@ -91,25 +120,31 @@ end
|
|
91
120
|
|
92
121
|
module Contexts
|
93
122
|
def in_contexts(&block)
|
94
|
-
[
|
95
|
-
[ "a
|
96
|
-
[ "a has_many
|
97
|
-
[
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
[ "
|
102
|
-
[ "scoped with :
|
103
|
-
[ "scoped with :
|
104
|
-
[ "scoped with :joins
|
105
|
-
[ "scoped with :
|
106
|
-
[ "scoped with :
|
107
|
-
[ "scoped with :
|
108
|
-
[ "scoped with :
|
123
|
+
[
|
124
|
+
[ "a scoped ActiveRecord class", "Article.scoped({})" ],
|
125
|
+
[ "a has_many association", "User.last.articles" ],
|
126
|
+
[ "an ordered has_many association", "User.last.recent_articles" ],
|
127
|
+
[ "a has_many, :through association", "User.last.shared_articles" ] # not tested for habtm!
|
128
|
+
].each do |base_type, base|
|
129
|
+
[
|
130
|
+
[ "", "" ],
|
131
|
+
[ "scoped with :conditions", ".untitled" ],
|
132
|
+
[ "scoped with :include", ".including_user" ],
|
133
|
+
[ "scoped with :joins", ".with_user" ],
|
134
|
+
[ "scoped with :joins & :conditions", ".with_named_user" ],
|
135
|
+
[ "scoped with :joins, :conditions & :order", ".ordered_by_user_name" ],
|
136
|
+
[ "scoped with :joins & :group", ".with_comments" ],
|
137
|
+
[ "scoped with :joins, :group & :limit", ".first_three_with_comments" ],
|
138
|
+
[ "scoped with :includes, :joins & subquery", ".with_multiple_comments" ],
|
139
|
+
[ "scoped with :limit", ".first_three" ],
|
140
|
+
[ "scoped with :limit & :offset", ".two_through_four" ],
|
141
|
+
[ "scoped with :order", ".descending_id" ]
|
142
|
+
].each do |scope_type, scope|
|
109
143
|
context "for #{base_type} #{scope_type}" do
|
110
144
|
before(:each) do
|
111
145
|
@articles = eval("#{base}#{scope}")
|
112
|
-
@articles.all.should_not be_empty
|
146
|
+
@articles.all.should_not be_empty # sanity check: make sure our collection actually has some elements!
|
147
|
+
@articles.all.should == @articles.all.uniq # don't want duplicate items in our test collection
|
113
148
|
end
|
114
149
|
instance_eval(&block)
|
115
150
|
end
|
@@ -123,4 +158,3 @@ Spec::Runner.configure do |config|
|
|
123
158
|
config.include RoutingHelpers
|
124
159
|
config.include ControllerHelpers
|
125
160
|
end
|
126
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mholling-paged_scopes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Hollingworth
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-22 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|