mholling-paged_scopes 0.0.4 → 0.0.5
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/pages.rb +1 -1
- data/lib/paged_scopes/paginator.rb +37 -9
- data/spec/page_spec.rb +9 -1
- data/spec/paginator_spec.rb +145 -47
- metadata +2 -2
data/VERSION.yml
CHANGED
data/lib/paged_scopes/pages.rb
CHANGED
@@ -21,19 +21,47 @@ module PagedScopes
|
|
21
21
|
def next
|
22
22
|
path.call(@page.next) unless @page.last?
|
23
23
|
end
|
24
|
+
|
25
|
+
def first
|
26
|
+
path.call(@page.class.first)
|
27
|
+
end
|
28
|
+
|
29
|
+
def last
|
30
|
+
path.call(@page.class.last)
|
31
|
+
end
|
24
32
|
|
25
33
|
def window(options)
|
26
|
-
size = options[:size]
|
27
|
-
extras = [ options[:extras] ].flatten.compact
|
28
34
|
raise ArgumentError, "No window block supplied." unless block_given?
|
35
|
+
raise ArgumentError, "please specify a :inner option" unless inner = options[:inner]
|
36
|
+
return if @page.page_count < 2
|
37
|
+
outer = options[:outer] || 0
|
38
|
+
extras = [ options[:extras] ].flatten.compact
|
39
|
+
numbers = case
|
40
|
+
when @page.number <= inner + 1
|
41
|
+
1 .. 1 + 2 * inner
|
42
|
+
when @page.number >= @page.page_count - inner
|
43
|
+
@page.page_count - 2 * inner .. @page.page_count
|
44
|
+
else
|
45
|
+
@page.number - inner .. @page.number + inner
|
46
|
+
end.to_a
|
47
|
+
1.upto(outer) { |n| numbers << n << @page.page_count-n+1 }
|
48
|
+
numbers.uniq!
|
49
|
+
numbers.sort!
|
50
|
+
numbers.reject! { |number| !number.between?(1, @page.page_count) }
|
29
51
|
returning [] do |results|
|
30
|
-
results << yield(:first, @page.first? ? nil :
|
31
|
-
results << yield(:previous,
|
32
|
-
(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
52
|
+
results << yield(:first, @page.first? ? nil : first, []) if extras.include?(:first)
|
53
|
+
results << yield(:previous, previous, []) if extras.include?(:previous)
|
54
|
+
numbers.zip([nil]+numbers, numbers[1..-1]) do |number, prev_number, next_number|
|
55
|
+
page = @page.class.find(number)
|
56
|
+
path = page == @page ? nil : @path.call(page)
|
57
|
+
classes = []
|
58
|
+
classes << :selected if page == @page
|
59
|
+
classes << :gap_before if prev_number && prev_number < number - 1
|
60
|
+
classes << :gap_after if next_number && next_number > number + 1
|
61
|
+
results << yield(page, path, classes)
|
62
|
+
end
|
63
|
+
results << yield(:next, self.next, []) if extras.include?(:next)
|
64
|
+
results << yield(:last, @page.last? ? nil : last, []) if extras.include?(:last)
|
37
65
|
end.join("\n")
|
38
66
|
end
|
39
67
|
end
|
data/spec/page_spec.rb
CHANGED
@@ -44,7 +44,7 @@ describe "Pages" do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should find pages with valid numbers" do
|
47
|
-
(
|
47
|
+
1.upto(@pages.count) do |number|
|
48
48
|
lambda { @pages.find(number) }.should_not raise_error
|
49
49
|
end
|
50
50
|
end
|
@@ -107,6 +107,14 @@ describe "Pages" do
|
|
107
107
|
lambda { @pages.find_by_article!(article) }.should raise_error(PagedScopes::PageNotFound)
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
it "should not find the page of an object if the object is a new record" do
|
112
|
+
lambda { @pages.find_by_article!(Article.new) }.should raise_error(PagedScopes::PageNotFound)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should not find the page of an object if the object is not an ActiveRecord::Base instance" do
|
116
|
+
lambda { @pages.find_by_article!(Object.new) }.should raise_error(PagedScopes::PageNotFound)
|
117
|
+
end
|
110
118
|
|
111
119
|
it "should find a page from a params hash with a pages name as an id in the key" do
|
112
120
|
@pages.stub!(:name).and_return("Page")
|
data/spec/paginator_spec.rb
CHANGED
@@ -3,17 +3,32 @@ require 'spec_helper'
|
|
3
3
|
describe "Paginator" do
|
4
4
|
before(:each) do
|
5
5
|
@articles = Article.scoped({})
|
6
|
-
@articles.per_page =
|
6
|
+
@articles.per_page = 2
|
7
7
|
@pages = @articles.pages
|
8
|
-
@size = 2 # window size
|
9
|
-
@page_count = @pages.count
|
10
|
-
(@page_count >= 14).should be_true # window specs won't work otherwise
|
11
8
|
@path = lambda { |page| "/path/to/page/#{page.to_param}" }
|
12
9
|
end
|
13
10
|
|
14
11
|
it "should raise an error if the paginator path is not set" do
|
15
12
|
lambda { @pages.first.paginator.next }.should raise_error(RuntimeError)
|
16
13
|
end
|
14
|
+
|
15
|
+
it "should call the path proc with the last page when #last is called" do
|
16
|
+
@pages.each do |page|
|
17
|
+
path = lambda { |page| }
|
18
|
+
page.paginator.set_path(&path)
|
19
|
+
path.should_receive(:call).with(@pages.last).and_return("/path")
|
20
|
+
page.paginator.last.should == "/path"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should call the path proc with the first page when #first is called" do
|
25
|
+
@pages.each do |page|
|
26
|
+
path = lambda { |page| }
|
27
|
+
page.paginator.set_path(&path)
|
28
|
+
path.should_receive(:call).with(@pages.first).and_return "/path"
|
29
|
+
page.paginator.first.should == "/path"
|
30
|
+
end
|
31
|
+
end
|
17
32
|
|
18
33
|
context "for the first page" do
|
19
34
|
before(:each) do
|
@@ -23,8 +38,8 @@ describe "Paginator" do
|
|
23
38
|
end
|
24
39
|
|
25
40
|
it "should call the path proc with the next page when #next is called" do
|
26
|
-
@path.should_receive(:call).with(@page.next)
|
27
|
-
@paginator.next
|
41
|
+
@path.should_receive(:call).with(@page.next).and_return("/path")
|
42
|
+
@paginator.next.should == "/path"
|
28
43
|
end
|
29
44
|
|
30
45
|
it "should not call the path proc when #previous is called" do
|
@@ -35,19 +50,19 @@ describe "Paginator" do
|
|
35
50
|
|
36
51
|
context "for the last page" do
|
37
52
|
before(:each) do
|
38
|
-
@page = @pages.
|
53
|
+
@page = @pages.last
|
39
54
|
@paginator = @page.paginator
|
40
55
|
@paginator.set_path(&@path)
|
41
56
|
end
|
42
57
|
|
43
|
-
it "should call the path proc with the
|
44
|
-
@path.should_receive(:call).with(@page.
|
45
|
-
@paginator.
|
58
|
+
it "should call the path proc with the previous page when #previous is called" do
|
59
|
+
@path.should_receive(:call).with(@page.previous).and_return("/path")
|
60
|
+
@paginator.previous.should == "/path"
|
46
61
|
end
|
47
62
|
|
48
|
-
it "should not call the path proc when #
|
63
|
+
it "should not call the path proc when #next is called" do
|
49
64
|
@path.should_not_receive(:call)
|
50
|
-
@paginator.
|
65
|
+
@paginator.next.should be_nil
|
51
66
|
end
|
52
67
|
end
|
53
68
|
|
@@ -59,44 +74,89 @@ describe "Paginator" do
|
|
59
74
|
end
|
60
75
|
|
61
76
|
it "should call the path proc with the next page when #next is called" do
|
62
|
-
@path.should_receive(:call).with(@page.next)
|
63
|
-
@paginator.next
|
77
|
+
@path.should_receive(:call).with(@page.next).and_return("/path")
|
78
|
+
@paginator.next.should == "/path"
|
64
79
|
end
|
65
80
|
|
66
81
|
it "should call the path proc with the previous page when #previous is called" do
|
67
|
-
@path.should_receive(:call).with(@page.previous)
|
68
|
-
@paginator.previous
|
82
|
+
@path.should_receive(:call).with(@page.previous).and_return("/path")
|
83
|
+
@paginator.previous.should == "/path"
|
69
84
|
end
|
70
85
|
end
|
71
86
|
|
72
87
|
describe "window generator" do
|
73
88
|
before(:each) do
|
74
|
-
@
|
89
|
+
@pages.stub!(:count).and_return(14)
|
90
|
+
@count = @pages.count
|
75
91
|
end
|
76
92
|
|
77
93
|
it "should raise an error if no block is provided" do
|
78
|
-
lambda { @pages.first.paginator.window(
|
94
|
+
lambda { @pages.first.paginator.window(:inner => 2) }.should raise_error(ArgumentError)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should raise an error if no inner size is provided" do
|
98
|
+
lambda { @pages.first.paginator.window({}) { |page, path| } }.should raise_error(ArgumentError)
|
79
99
|
end
|
80
100
|
|
81
101
|
it "should concatenate all the block return values into a string" do
|
82
102
|
page = @pages.find(6)
|
83
103
|
page.paginator.set_path { |page| }
|
84
|
-
links = (
|
85
|
-
links.join("\n").should == page.paginator.window(:
|
104
|
+
links = (4..8).map { |n| "<li><a href='/path/to/page/#{6+n}'>#{6+n}</a></li>" }
|
105
|
+
links.join("\n").should == page.paginator.window(:inner => 2) { |page, path| links.shift }
|
86
106
|
end
|
87
|
-
|
107
|
+
|
88
108
|
it "should call the block with the page and the path for each page in a window surrounding the page" do
|
89
|
-
[
|
109
|
+
[
|
110
|
+
[ 6, 4..8 ],
|
111
|
+
[ 3, 1..5 ],
|
112
|
+
[ 1, 1..5 ],
|
113
|
+
[ @count-2, @count-4..@count ],
|
114
|
+
[ @count, @count-4..@count ]
|
115
|
+
].each do |number, range|
|
90
116
|
page = @pages.find(number)
|
91
117
|
page.paginator.set_path(&@path)
|
92
|
-
|
93
|
-
range.
|
94
|
-
|
118
|
+
pages, paths = [], []
|
119
|
+
range.each do |n|
|
120
|
+
pages << @pages.find(n)
|
121
|
+
paths << (n == page.number ? nil : @path.call(@pages.find(n)))
|
95
122
|
end
|
96
|
-
page.paginator.window(:
|
97
|
-
|
123
|
+
page.paginator.window(:inner => 2) do |pg, path, classes|
|
124
|
+
pg.should == pages.shift
|
125
|
+
path.should == paths.shift
|
126
|
+
pg == page ? classes.should(include(:selected)) : classes.should_not(include(:selected))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "with an outer window" do
|
132
|
+
it "should also call the block for each page in a window from the first and last pages, and include separators between the windws if necessary" do
|
133
|
+
[
|
134
|
+
[ 6, 1..2, 6-2..6+2, @count-1..@count ],
|
135
|
+
[ 5, 1..5+2, @count-1..@count ],
|
136
|
+
[ 3, 1..5, @count-1..@count ],
|
137
|
+
[ 1, 1..5, @count-1..@count ],
|
138
|
+
[ @count-4, 1..2, @count-4-2..@count ],
|
139
|
+
[ @count-2, 1..2, @count-4..@count ],
|
140
|
+
[ @count, 1..2, @count-4..@count ]
|
141
|
+
].each do |number, *ranges|
|
142
|
+
page = @pages.find(number)
|
143
|
+
page.paginator.set_path(&@path)
|
144
|
+
pages, paths, gaps_before, gaps_after = [], [], [], []
|
145
|
+
ranges.each do |range|
|
146
|
+
range.each do |n|
|
147
|
+
pages << @pages.find(n)
|
148
|
+
paths << (n == page.number ? nil : @path.call(@pages.find(n)))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
pages.each_with_index { |pg, n| gaps_before << (pages[n-1] ? pages[n-1].number < pg.number - 1 : false) }
|
152
|
+
pages.each_with_index { |pg, n| gaps_after << (pages[n+1] ? pages[n+1].number > pg.number + 1 : false) }
|
153
|
+
page.paginator.window(:inner => 2, :outer => 2) do |pg, path, classes|
|
154
|
+
pg.should == pages.shift
|
155
|
+
path.should == paths.shift
|
156
|
+
gaps_before.shift ? classes.should(include(:gap_before)) : classes.should_not(include(:gap_before))
|
157
|
+
gaps_after.shift ? classes.should(include(:gap_after)) : classes.should_not(include(:gap_after))
|
158
|
+
end
|
98
159
|
end
|
99
|
-
expected_args.should be_empty
|
100
160
|
end
|
101
161
|
end
|
102
162
|
|
@@ -104,21 +164,23 @@ describe "Paginator" do
|
|
104
164
|
it "should call the block with #{extra.inspect} and the path for the #{extra} page if #{extra.inspect} is specified as an extra" do
|
105
165
|
page = @pages.find(number)
|
106
166
|
page.paginator.set_path(&@path)
|
107
|
-
|
108
|
-
|
167
|
+
pages_paths = []
|
168
|
+
page.paginator.window(:inner => 2, :extras => [ extra ]) do |page, path, classes|
|
169
|
+
pages_paths << [ page, path ]
|
109
170
|
end
|
110
|
-
|
171
|
+
pages_paths.should include([ extra, @path.call(@pages.find(new_number)) ])
|
111
172
|
end
|
112
173
|
end
|
113
174
|
|
114
|
-
[ [ :previous, "1" ], [ :next, "@
|
175
|
+
[ [ :previous, "1" ], [ :next, "@count" ] ].each do |extra, number|
|
115
176
|
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
|
116
177
|
page = @pages.find(eval(number))
|
117
178
|
page.paginator.set_path(&@path)
|
118
|
-
|
119
|
-
|
179
|
+
pages_paths = []
|
180
|
+
page.paginator.window(:inner => 2, :extras => [ extra ]) do |page, path, classes|
|
181
|
+
pages_paths << [ page, path ]
|
120
182
|
end
|
121
|
-
|
183
|
+
pages_paths.should include([ extra, nil ])
|
122
184
|
end
|
123
185
|
end
|
124
186
|
|
@@ -126,33 +188,69 @@ describe "Paginator" do
|
|
126
188
|
it "should call the block with #{extra.inspect} and the path for the #{extra} page if #{extra.inspect} is specified as an extra" do
|
127
189
|
page = @pages.find(6)
|
128
190
|
page.paginator.set_path(&@path)
|
129
|
-
|
130
|
-
|
191
|
+
pages_paths = []
|
192
|
+
page.paginator.window(:inner => 2, :extras => [ extra ]) do |page, path, classes|
|
193
|
+
pages_paths << [ page, path ]
|
131
194
|
end
|
132
|
-
|
195
|
+
pages_paths.should include([ extra, @path.call(@pages.send(extra)) ])
|
133
196
|
end
|
134
197
|
end
|
135
198
|
|
136
|
-
[ [ :first, "1" ], [ :last, "@
|
199
|
+
[ [ :first, "1" ], [ :last, "@count" ] ].each do |extra, number|
|
137
200
|
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
|
138
201
|
page = @pages.find(eval(number))
|
139
202
|
page.paginator.set_path(&@path)
|
140
|
-
|
141
|
-
|
203
|
+
pages_paths = []
|
204
|
+
page.paginator.window(:inner => 2, :extras => [ extra ]) do |page, path, classes|
|
205
|
+
pages_paths << [ page, path ]
|
142
206
|
end
|
143
|
-
|
207
|
+
pages_paths.should include([ extra, nil ])
|
144
208
|
end
|
145
209
|
end
|
146
210
|
|
147
211
|
it "should call the block with :first, :previous, pages, :next, :last in that order" do
|
148
212
|
page = @pages.find(6)
|
149
213
|
page.paginator.set_path(&@path)
|
150
|
-
|
151
|
-
page.paginator.window(:
|
152
|
-
|
214
|
+
pages = []
|
215
|
+
page.paginator.window(:inner => 1, :extras => [ :first, :previous, :next, :last ]) do |page, path, classes|
|
216
|
+
pages << page
|
153
217
|
end
|
154
|
-
|
218
|
+
pages.should == [ :first, :previous, @pages.find(5), @pages.find(6), @pages.find(7), :next, :last ]
|
155
219
|
end
|
156
220
|
end
|
157
221
|
|
158
|
-
|
222
|
+
describe "window generator for a collection with fewer pages than the window size" do
|
223
|
+
it "should list all the page" do
|
224
|
+
@pages.stub!(:count).and_return(5)
|
225
|
+
@pages.each do |page|
|
226
|
+
page.paginator.set_path(&@path)
|
227
|
+
pages = @pages.all
|
228
|
+
page.paginator.window(:inner => 2) do |pg, path, classes|
|
229
|
+
pg.should == pages.shift
|
230
|
+
if pg == page
|
231
|
+
path.should be_nil
|
232
|
+
classes.should include(:selected)
|
233
|
+
else
|
234
|
+
path.should_not be_nil
|
235
|
+
classes.should_not include(:selected)
|
236
|
+
end
|
237
|
+
classes.should_not include(:gap_before, :gap_after)
|
238
|
+
end
|
239
|
+
pages.should be_empty
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "window generator for a collection with only one page" do
|
245
|
+
it "should not generate any links" do
|
246
|
+
@pages.stub!(:count).and_return(1)
|
247
|
+
page = @pages.first
|
248
|
+
page.paginator.set_path(&@path)
|
249
|
+
@path.should_not_receive(:call)
|
250
|
+
page.paginator.window(:inner => 2) do |pg, path, classes|
|
251
|
+
fail "expected block not to be called"
|
252
|
+
"<a>some link</a>"
|
253
|
+
end.should be_blank
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
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.5
|
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-26 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|