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 CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 3
2
+ :patch: 4
3
3
  :major: 0
4
4
  :minor: 0
@@ -1,24 +1,40 @@
1
1
  module PagedScopes
2
2
  module Controller
3
- def get_page_for(collection_name, options = {})
4
- callback_method = "get_page_for_#{collection_name}"
5
- define_method callback_method do
6
- collection = instance_variable_get("@#{collection_name.to_s.pluralize}")
7
- raise RuntimeError, "no @#{collection_name.to_s.pluralize} collection was set" unless collection
8
- object = instance_variable_get("@#{collection_name.to_s.singularize}")
9
- collection.per_page = options[:per_page] if options[:per_page]
10
- collection.page_name = options[:name] if options[:name]
11
- page = collection.pages.from_params!(params) || (object && collection.pages.find_by_object(object)) || collection.pages.first
12
- page.paginator.set_path { |pg| send(options[:path], pg) } if options[:path]
13
- instance_variable_set("@#{collection.pages.name.underscore}", page)
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.extend PagedScopes::Controller
23
- ActionController::Base.rescue_responses.update('PagedScopes::PageNotFound' => :not_found)
39
+ ActionController::Base.send :include, PagedScopes::Controller
24
40
  end
@@ -1,62 +1,39 @@
1
1
  module PagedScopes
2
2
  module Index
3
3
  def index_of(object)
4
- find_scope = scope(:find) || {}
5
- primary_key_attribute = "#{table_name}.#{primary_key}"
6
-
7
- order_attributes = find_scope[:order].to_s.split(',').map(&:strip)
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
- attribute_selects = returning([]) do |selects|
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
- order_attribute_options = { :select => attribute_selects }
25
- order_attribute_options.merge!(:offset => 0) if find_scope[:offset]
26
- object_with_order_attributes = find(object.id, order_attribute_options)
27
-
28
- object_order_attributes = {}
29
- order_attributes.each_with_index do |order_attribute, n|
30
- object_order_attributes[order_attribute] = object_with_order_attributes.send("order_attribute_#{n}")
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
- order_conditions = order_attributes.reverse.inject([ "", {}, 0 ]) do |args, order_attribute|
34
- string, hash, n = args
35
- symbol = "s#{n}".to_sym
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
- "#{order_attribute} #{order_operators[order_attribute]} #{symbol.inspect}" :
38
- "#{order_attribute} #{order_operators[order_attribute]} #{symbol.inspect} OR (#{order_attribute} = #{symbol.inspect} AND (#{string}))"
39
- hash.merge!(symbol => object_order_attributes[order_attribute])
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
- count_options = { :conditions => order_conditions, :distinct => true }
55
- count_options.merge!(:offset => 0) if find_scope[:offset]
56
- before_count = count(primary_key_attribute, count_options)
57
- if find_scope[:limit]
58
- before_count -= find_scope[:offset] if find_scope[:offset]
59
- raise ActiveRecord::RecordNotFound, "Couldn't find #{name} with ID=#{object.id}" if before_count < 0 || before_count >= find_scope[:limit]
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
@@ -138,7 +138,7 @@ module PagedScopes
138
138
  end
139
139
 
140
140
  def ==(other)
141
- number == other.number
141
+ other.is_a?(self.class) && number == other.number
142
142
  end
143
143
 
144
144
  def full?
@@ -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
- return if @page.page_count < 2
31
- if @page.number - size > 1
32
- results << yield(:first, @path.call(@page.class.first)) if extras.include? :first
33
- if extras.include?(:previous) && offset_page = @page.offset(-2 * size - 1)
34
- results << yield(:previous, @path.call(offset_page))
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
- end
37
- (-size..size).map { |offset| @page.offset(offset) }.compact.each do |page|
38
- results << yield( page, @path.call(page))
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
@@ -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 raise 404 on PagedScopes::PageNotFound" do
11
- @class.rescue_responses['PagedScopes::PageNotFound'].should == :not_found
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
- @controller = Class.new(ActionController::Base) do
33
- get_page_for :articles
34
- end.new
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 a page id in the params" do
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
- get_page_for_articles
55
- @page.should == @articles.pages.last
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 get the first page" do
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 = 3
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 = 3
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 = 3
152
+ @per_page = 2
153
153
  @articles.stub!(:per_page).and_return(@per_page)
154
154
  end
155
155
 
@@ -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
- actual_args << args
97
+ expected_args.shift.should == args
95
98
  end
96
- actual_args.should == expected_args
99
+ expected_args.should be_empty
97
100
  end
98
101
  end
99
102
 
100
- [ :first, :last ].each do |extra|
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(6)
105
+ page = @pages.find(number)
103
106
  page.paginator.set_path(&@path)
104
- page.paginator.window(:size => @size, :extras => [ extra ]) do |page, path|
105
- @received = true if extra == page && path == @path.call(@pages.send(extra))
107
+ page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
108
+ @args << args
106
109
  end
107
- @received.should be_true
110
+ @args.should include([ extra, @path.call(@pages.find(new_number)) ])
108
111
  end
109
112
  end
110
113
 
111
- [ [ :first, "1+@size" ], [ :last, "@page_count-@size" ] ].each do |extra, number|
112
- it "should not call the block with #{extra.inspect} if #{extra.inspect} is specified as an extra but the #{extra} page is within the window" do
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 |page, path|
116
- @received = true if extra == page
118
+ page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
119
+ @args << args
117
120
  end
118
- @received.should be_nil
121
+ @args.should include([ extra, nil ])
119
122
  end
120
123
  end
121
124
 
122
- [ [ :previous, 8, "8-2*@size-1" ], [ :next, 4, "4+2*@size+1" ] ].each do |extra, number, new_number|
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(number)
127
+ page = @pages.find(6)
125
128
  page.paginator.set_path(&@path)
126
- page.paginator.window(:size => @size, :extras => [ extra ]) do |page, path|
127
- @received = true if extra == page && path == @path.call(@pages.find(eval(new_number)))
129
+ page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
130
+ @args << args
128
131
  end
129
- @received.should be_true
132
+ @args.should include([ extra, @path.call(@pages.send(extra)) ])
130
133
  end
131
134
  end
132
135
 
133
- [ [ :previous, "1+2*@size" ], [ :next, "@page_count-2*@size" ] ].each do |extra, number|
134
- it "should not call the block with #{extra.inspect} if #{extra.inspect} is specified as an extra but the #{extra} window is out of range" do
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 |page, path|
138
- @received = true if extra == page
140
+ page.paginator.window(:size => @size, :extras => [ extra ]) do |*args|
141
+ @args << args
139
142
  end
140
- @received.should be_nil
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 :comments
31
- has_many :commented_articles, :through => :comments, :source => :article
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
- [ "first user", nil, "last user" ].each { |name| User.create(:name => name) }
43
- 7.times do
44
- User.all.each do |user|
45
- user.articles.create.comments << User.first.comments.new
46
- user.articles.create(:title => "%03d title" % Article.count).comments << User.first.comments.new << User.last.comments.new
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
- [ [ "a scoped ActiveRecord class", "Article.scoped({})" ],
95
- [ "a has_many association", "User.last.articles" ], # not tested for habtm!
96
- [ "a has_many, :through association", "User.first.commented_articles" ] ].each do |base_type, base|
97
- [ [ "", "" ],
98
- [ "scoped with :conditions", ".scoped(:conditions => { :title => nil })" ],
99
- [ "scoped with :include", ".scoped(:include => :comments)" ],
100
- [ "scoped with :joins", ".scoped(:joins => 'INNER JOIN users ON users.id = articles.user_id')" ],
101
- [ "scoped with :joins & :conditions", ".scoped(:joins => 'INNER JOIN users ON users.id = articles.user_id', :conditions => [ 'users.name IS NOT :nil', { :nil => nil } ])" ],
102
- [ "scoped with :joins, :conditions & :order", ".scoped(:joins => 'INNER JOIN users ON users.id = articles.user_id', :conditions => [ 'users.name IS NOT :nil', { :nil => nil } ], :order => 'users.name')" ],
103
- [ "scoped with :joins & :group", ".scoped(:joins => 'INNER JOIN comments AS article_comments ON article_comments.article_id = articles.id', :group => 'articles.id')" ],
104
- [ "scoped with :joins, :group & :limit", ".scoped(:joins => 'INNER JOIN comments AS article_comments ON article_comments.article_id = articles.id', :group => 'articles.id', :limit => 4)" ],
105
- [ "scoped with :includes, :joins & subquery", ".scoped(: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')"],
106
- [ "scoped with :limit", ".scoped(:limit => 5)" ],
107
- [ "scoped with :limit & :offset", ".scoped(:limit => 5, :offset => 7)" ],
108
- [ "scoped with :order", ".scoped(:order => 'articles.id DESC')" ] ].each do |scope_type, scope|
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.3
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-17 00:00:00 -07:00
12
+ date: 2009-06-22 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency