paginater 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +127 -0
- data/Gemfile.lock.broken +78 -0
- data/Gemfile.lock.good +127 -0
- data/LICENSE.txt +22 -0
- data/README.md +268 -0
- data/Rakefile +1 -0
- data/lib/paginater.rb +31 -0
- data/lib/paginater/constants.rb +32 -0
- data/lib/paginater/core.rb +54 -0
- data/lib/paginater/formatter.rb +131 -0
- data/lib/paginater/page/base_page.rb +31 -0
- data/lib/paginater/page/page_links.rb +50 -0
- data/lib/paginater/version.rb +3 -0
- data/paginater.gemspec +36 -0
- data/spec/paginater/paginatable_array_spec.rb +122 -0
- data/spec/paginater/paginater_spec.rb +327 -0
- data/spec/paginater/paginater_with_kaminari_spec.rb +165 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/active_record_support.rb +53 -0
- data/test/config.ru +2 -0
- data/test/favicon.ico +0 -0
- data/test/rss_helper.rb +32 -0
- data/test/running_test.rb +32 -0
- metadata +233 -0
@@ -0,0 +1,327 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Formatter::Paginater do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
Class.new(Grape::API)
|
7
|
+
end
|
8
|
+
|
9
|
+
def app
|
10
|
+
subject
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#header' do
|
14
|
+
it 'is callable from within a block' do
|
15
|
+
subject.get('/hey') do
|
16
|
+
header 'X-Awesome', 'true'
|
17
|
+
"Awesome"
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/hey'
|
21
|
+
last_response.headers['X-Awesome'].should == 'true'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#headers' do
|
26
|
+
before do
|
27
|
+
subject.get('/headers') do
|
28
|
+
headers.to_json
|
29
|
+
end
|
30
|
+
end
|
31
|
+
it 'includes request headers' do
|
32
|
+
get '/headers'
|
33
|
+
JSON.parse(last_response.body).should == {
|
34
|
+
"Host" => "example.org",
|
35
|
+
"Cookie" => ""
|
36
|
+
}
|
37
|
+
end
|
38
|
+
it 'includes additional request headers' do
|
39
|
+
get '/headers', nil, { "HTTP_X_GRAPE_CLIENT" => "1" }
|
40
|
+
JSON.parse(last_response.body)["X-Grape-Client"].should == "1"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "without paginater" do
|
45
|
+
|
46
|
+
before :each do
|
47
|
+
stuff = {:stuff => 'foo bar'}
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets itself in the env upon call" do
|
51
|
+
subject.get('/') do
|
52
|
+
'Hello world.'
|
53
|
+
end
|
54
|
+
get '/'
|
55
|
+
last_request.env['api.endpoint'].should be_kind_of(Grape::Endpoint)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should work without paginater" do
|
59
|
+
subject.get('/') do
|
60
|
+
'foo bar!'
|
61
|
+
end
|
62
|
+
get '/'
|
63
|
+
last_response.body.should eq 'foo bar!'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not raise error about stuff" do
|
67
|
+
subject.format :json
|
68
|
+
subject.get '/home' do
|
69
|
+
stuff = {:stuff => 'foo bar'}
|
70
|
+
end
|
71
|
+
lambda do
|
72
|
+
get '/home'
|
73
|
+
end.should_not raise_error
|
74
|
+
get '/home'
|
75
|
+
last_response.body.should eq "{\"stuff\":\"foo bar\"}"
|
76
|
+
last_response.body.should include MultiJson.dump stuff
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context "with the route_option :paginater => :simple" do
|
82
|
+
|
83
|
+
before :each do
|
84
|
+
subject.format :json
|
85
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
86
|
+
stuff = {:stuff => 'foo bar'}
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should respond with proper content-type" do
|
90
|
+
subject.get '/home', :paginater => :simple do
|
91
|
+
stuff = {:stuff => 'foo bar'}
|
92
|
+
end
|
93
|
+
get('/home?page=1')
|
94
|
+
last_response.headers['Content-Type'].should == 'application/json'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'rescues a specific error' do
|
98
|
+
subject.rescue_from Grape::Formatter::Paginater::Constants::PaginaterError do |e|
|
99
|
+
rack_response("rescued from #{e.class.name}", 500)
|
100
|
+
end
|
101
|
+
subject.get '/home', :paginater => :simple do
|
102
|
+
raise Grape::Formatter::Paginater::Constants::PaginaterError unless params[:page]
|
103
|
+
end
|
104
|
+
subject.get '/foo' do
|
105
|
+
raise 'foo_exception'
|
106
|
+
end
|
107
|
+
get '/home'
|
108
|
+
last_response.status.should eql 500
|
109
|
+
last_response.body.should == 'rescued from Grape::Formatter::Paginater::Constants::PaginaterError'
|
110
|
+
lambda do
|
111
|
+
get '/foo'
|
112
|
+
end.should raise_error
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should understand a missing page situation' do
|
116
|
+
subject.get '/home', :paginater => :simple do
|
117
|
+
params[:page]
|
118
|
+
stuff = {:stuff => 'foo bar'}
|
119
|
+
end
|
120
|
+
lambda do
|
121
|
+
get '/home'
|
122
|
+
end.should_not raise_error
|
123
|
+
last_response.status.should eql 500
|
124
|
+
last_response.body.should eq '{"error":"missing param"}'
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'defaults the error formatter to format' do
|
128
|
+
subject.format :json
|
129
|
+
subject.rescue_from :all
|
130
|
+
subject.content_type :json, "application/json"
|
131
|
+
subject.content_type :foo, "text/foo"
|
132
|
+
subject.get '/exception' do
|
133
|
+
raise "rain!"
|
134
|
+
end
|
135
|
+
get '/exception.json'
|
136
|
+
last_response.body.should == '{"error":"rain!"}'
|
137
|
+
get '/exception.foo'
|
138
|
+
last_response.body.should == '{"error":"rain!"}'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should work with the params requested' do
|
142
|
+
subject.format :json
|
143
|
+
subject.rescue_from :all
|
144
|
+
subject.get '/stuff', :paginater => :simple do
|
145
|
+
params[:page]
|
146
|
+
stuff = {:stuff => 'foo bar'}
|
147
|
+
end
|
148
|
+
get '/stuff?page=42'
|
149
|
+
last_response.body.should eq '{"error":"invalid page 42"}'
|
150
|
+
last_response.status.should eq 500
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context "dealing with something that ... count" do
|
156
|
+
|
157
|
+
before :each do
|
158
|
+
subject.format :json
|
159
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
160
|
+
subject.get '/foo', :paginater => :simple do
|
161
|
+
numbers(42)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
it 'consider Array objects as paginable' do
|
165
|
+
get('/foo?page=11')
|
166
|
+
last_response.status.should eq 200
|
167
|
+
last_response.header.should include 'Link'
|
168
|
+
end
|
169
|
+
it 'paginate the body' do
|
170
|
+
get('/foo?page=11')
|
171
|
+
last_response.status.should eq 200
|
172
|
+
last_response.body.should include '10'
|
173
|
+
end
|
174
|
+
it 'paginate the body and understand size' do
|
175
|
+
get('/foo?page=3&size=3')
|
176
|
+
last_response.status.should eq 200
|
177
|
+
last_response.body.should_not include '5'
|
178
|
+
last_response.body.should include '6'
|
179
|
+
last_response.body.should include '8'
|
180
|
+
last_response.body.should_not include '9'
|
181
|
+
last_response.body.should include 6.upto(8).to_a.to_s.gsub(/\s/,'')
|
182
|
+
end
|
183
|
+
it 'set headers for pagination' do
|
184
|
+
get('/foo?page=3&size=3')
|
185
|
+
last_response.status.should eq 200
|
186
|
+
last_response.header.should include 'Link'
|
187
|
+
last_response.header['Link'].should include 'page=1'
|
188
|
+
last_response.header['Link'].should include 'next'
|
189
|
+
last_response.header['Link'].should include 'page=4'
|
190
|
+
last_response.header['Link'].should include 'prev'
|
191
|
+
last_response.header['Link'].should include 'page=2'
|
192
|
+
end
|
193
|
+
it 'do not mess with last pages' do
|
194
|
+
get('/foo?page=5&size=10')
|
195
|
+
last_response.status.should eq 200
|
196
|
+
last_response.header.should include 'Link'
|
197
|
+
last_response.header['Link'].should include 'prev'
|
198
|
+
last_response.header['Link'].should_not include 'next'
|
199
|
+
last_response.body.should_not include '39'
|
200
|
+
last_response.body.should include '40'
|
201
|
+
last_response.body.should include '42'
|
202
|
+
last_response.body.should_not include '43'
|
203
|
+
last_response.body.should include 41.upto(42).to_a.to_s.gsub(/[\[\s\]]/,'')
|
204
|
+
end
|
205
|
+
it 'do not mess with foo pages' do
|
206
|
+
get('/foo?page=42&size=42')
|
207
|
+
last_response.status.should eq 500
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
context "dealing with something that ... count but :txt" do
|
213
|
+
|
214
|
+
before :each do
|
215
|
+
subject.format :txt
|
216
|
+
subject.formatter :txt, Grape::Formatter::Paginater
|
217
|
+
subject.get '/foo', :paginater => :simple do
|
218
|
+
alphabet
|
219
|
+
end
|
220
|
+
end
|
221
|
+
it 'consider Array objects as paginable' do
|
222
|
+
get('/foo?page=11')
|
223
|
+
last_response.status.should eq 200
|
224
|
+
last_response.header['Link'].should include 'first'
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'understand and return a txt' do
|
228
|
+
get('/foo?page=1&size=10')
|
229
|
+
last_response.body.should include "Alpha"
|
230
|
+
last_response.body.should_not include "Kilo"
|
231
|
+
last_response.header['Link'].should include "page=1"
|
232
|
+
last_response.body.split(',').count.should eq 10
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
context "set pagination headers" do
|
238
|
+
|
239
|
+
before :each do
|
240
|
+
subject.format :json
|
241
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
242
|
+
subject.get '/foo', :paginater => :simple do
|
243
|
+
items(9)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
it 'understand the first page' do
|
247
|
+
get('/foo?page=1')
|
248
|
+
last_response.status.should eq 200
|
249
|
+
last_response.header['Link'].should include 'page=1'
|
250
|
+
last_response.header['Link'].should include 'next'
|
251
|
+
last_response.header['Link'].should_not include 'prev'
|
252
|
+
end
|
253
|
+
it 'understand the last page' do
|
254
|
+
get('/foo?page=10')
|
255
|
+
last_response.status.should eq 200
|
256
|
+
last_response.header['Link'].should include 'prev'
|
257
|
+
last_response.header['Link'].should include 'page=9'
|
258
|
+
last_response.header['Link'].should_not include 'next'
|
259
|
+
end
|
260
|
+
it 'understand the last page with size' do
|
261
|
+
get('/foo?page=5&size=2')
|
262
|
+
last_response.status.should eq 200
|
263
|
+
last_response.header['Link'].should include 'prev'
|
264
|
+
last_response.header.should_not include 'next'
|
265
|
+
last_response.body.split(',').count.should eq 2
|
266
|
+
get('/foo?page=4&size=3')
|
267
|
+
last_response.status.should eq 200
|
268
|
+
last_response.header['Link'].should include 'prev'
|
269
|
+
last_response.header['Link'].should include 'page=3'
|
270
|
+
last_response.header.should_not include 'next'
|
271
|
+
last_response.body.split(',').count.should eq 1
|
272
|
+
end
|
273
|
+
it 'paginate the body' do
|
274
|
+
get('/foo?page=1')
|
275
|
+
last_response.status.should eq 200
|
276
|
+
last_response.body.should eq '["item 000"]'
|
277
|
+
get('/foo?page=10')
|
278
|
+
last_response.body.should eq '["item 009"]'
|
279
|
+
get('/foo?page=11')
|
280
|
+
last_response.status.should eq 500
|
281
|
+
get('/foo?page=3&size=3')
|
282
|
+
last_response.body.should eq '["item 006","item 007","item 008"]'
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
context "with the wrapped object" do
|
288
|
+
|
289
|
+
before :each do
|
290
|
+
subject.format :json
|
291
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
292
|
+
subject.get '/foobar', :paginater => :wrapper do
|
293
|
+
items(42)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
it "get something paginated" do
|
297
|
+
get('/foobar?page=1')
|
298
|
+
last_response.status.should eq 200
|
299
|
+
# deprecating....
|
300
|
+
last_response.header['Link'].should include 'page', 'next'
|
301
|
+
last_response.header.should_not include 'prev'
|
302
|
+
last_response.body.should include '["item 000"]'
|
303
|
+
last_response.body.should eq "{\"content\":[\"item 000\"],\"page\":1,\"size\":1,\"links\":null}"
|
304
|
+
get('/foobar?page=3&size=3')
|
305
|
+
last_response.body.should eq "{\"content\":[\"item 006\",\"item 007\",\"item 008\"],\"page\":3,\"size\":3,\"links\":null}"
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
context "put something in the cookies" do
|
311
|
+
|
312
|
+
before :each do
|
313
|
+
subject.format :json
|
314
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
315
|
+
subject.get '/foobar', :paginater => :simple do
|
316
|
+
items(42)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
it "count total_pages and original_count" do
|
321
|
+
get('/foobar?page=7&size=3')
|
322
|
+
last_response.header['Set-Cookie'].should include "7/14/43"
|
323
|
+
end
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
end # Grape::Formatter::Paginater
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# spec/paginater/paginater_with_kaminari_spec.rb
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'support/active_record_support'
|
5
|
+
|
6
|
+
if defined? ActiveRecord
|
7
|
+
|
8
|
+
describe Grape::Formatter::Paginater do
|
9
|
+
|
10
|
+
subject do
|
11
|
+
Class.new(Grape::API)
|
12
|
+
end
|
13
|
+
|
14
|
+
def app
|
15
|
+
subject
|
16
|
+
end
|
17
|
+
|
18
|
+
shared_examples_for 'the first page' do
|
19
|
+
it { should have(25).users }
|
20
|
+
its('first.name') { should == 'user001' }
|
21
|
+
end
|
22
|
+
|
23
|
+
shared_examples_for 'blank page' do
|
24
|
+
it { should have(0).users }
|
25
|
+
end
|
26
|
+
|
27
|
+
before :each do
|
28
|
+
0.upto(999) {|i| User.create! :name => "user#{'%03d' % i}", :age => (i / 10)}
|
29
|
+
end
|
30
|
+
|
31
|
+
after :each do
|
32
|
+
User.destroy_all
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with the kaminari amazing gem" do
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
subject.format :json
|
39
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
40
|
+
subject.get '/users', :paginater => :kaminari do
|
41
|
+
User.where("age > 0")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "get something paginated" do
|
46
|
+
get('/users?page=42&size=10')
|
47
|
+
last_response.status.should eq 200
|
48
|
+
last_response.header['Link'].should include 'first', 'next'
|
49
|
+
last_response.header.should_not include 'prev'
|
50
|
+
last_response.body.should include '{"user":{"age":42,"id":425,"name":"user424"}}'
|
51
|
+
last_response.header['Link'].should include "{:url=>\"/users?page=1&size=10\", :rel=>\"first\"}"
|
52
|
+
last_response.header['Link'].should include "{:url=>\"/users?page=43&size=10\", :rel=>\"next\"}"
|
53
|
+
last_response.header['Link'].should include "{:url=>\"/users?page=41&size=10\", :rel=>\"prev\"}"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "some features with kaminari" do
|
59
|
+
|
60
|
+
# let(:all_user_count) { User.all.count }
|
61
|
+
|
62
|
+
before :each do
|
63
|
+
subject.format :json
|
64
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
65
|
+
subject.get '/users', :paginater => :kaminari do
|
66
|
+
User.where("age > -1")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "get something paginated with body, headers and cookies" do
|
71
|
+
get('/users?page=1&size=10')
|
72
|
+
last_response.status.should eq 200
|
73
|
+
last_response.body.scan(/\"user\"/).flatten.count.should == 10
|
74
|
+
last_response.header['Set-Cookie'].should include "1/100/1000" #page/pages/count
|
75
|
+
last_response.header['Link'].should include '/users?page=2&size=10'
|
76
|
+
last_response.header['Link'].should_not include 'prev'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "use the default size of 1" do
|
80
|
+
get('/users?page=1')
|
81
|
+
last_response.status.should eq 200
|
82
|
+
last_response.body.scan(/\"user\"/).flatten.count.should == 1
|
83
|
+
last_response.header['Set-Cookie'].should include "1/1000/1000"
|
84
|
+
last_response.header['Link'].should include '/users?page=2'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "manage an exceeding size as .all" do
|
88
|
+
get('/users?page=1&size=9999')
|
89
|
+
last_response.status.should eq 200
|
90
|
+
last_response.body.scan(/\"user\"/).flatten.count.should == 1000
|
91
|
+
last_response.header['Set-Cookie'].should include "1/1/1000"
|
92
|
+
last_response.header['Link'].should_not include '/users?page=2'
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
context "with kaminari and an array (PaginatableArray)" do
|
98
|
+
|
99
|
+
before :each do
|
100
|
+
subject.format :json
|
101
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
102
|
+
subject.get '/foobar', :paginater => :kaminari do
|
103
|
+
items(99)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
it "get something paginated (with default size)" do
|
107
|
+
get('/foobar?page=1')
|
108
|
+
last_response.status.should eq 200
|
109
|
+
end
|
110
|
+
it "get something paginated" do
|
111
|
+
get('/foobar?page=1&size=10')
|
112
|
+
last_response.status.should eq 200
|
113
|
+
last_response.header['Link'].should include "{:url=>\"/foobar?page=1&size=10\", :rel=>\"first\"}"
|
114
|
+
last_response.header['Link'].should include "{:url=>\"/foobar?page=2&size=10\", :rel=>\"next\"}"
|
115
|
+
last_response.body.should include "item 009"
|
116
|
+
last_response.body.should_not include "item 010"
|
117
|
+
end
|
118
|
+
it "get something paginated with default size = 1" do
|
119
|
+
get('/foobar?page=100')
|
120
|
+
last_response.body.scan(/"(.*?)"/).flatten.count.should == 1
|
121
|
+
last_response.header['Link'].should_not include "next"
|
122
|
+
end
|
123
|
+
it "get something paginated with the size param" do
|
124
|
+
get('/foobar?page=10&size=10')
|
125
|
+
last_response.body.scan(/"(.*?)"/).flatten.count.should == 10
|
126
|
+
last_response.header['Link'].should_not include "next"
|
127
|
+
end
|
128
|
+
it "understand a non existing page" do
|
129
|
+
get('/foobar?page=11&size=10')
|
130
|
+
last_response.body.scan(/"(.*?)"/).flatten.count.should == 0
|
131
|
+
last_response.body.should == '[]'
|
132
|
+
# FIXME?
|
133
|
+
# p last_response.header['Link']
|
134
|
+
# p last_response.header['Set-Cookie']
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
context "with kaminari and an hash" do
|
140
|
+
|
141
|
+
before :each do
|
142
|
+
subject.format :json
|
143
|
+
subject.formatter :json, Grape::Formatter::Paginater
|
144
|
+
subject.get '/foobar', :paginater => :kaminari do
|
145
|
+
[{:foo => 'bar'},{:bar => 'foo'}]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
it "get something paginated" do
|
149
|
+
get('/foobar?page=1')
|
150
|
+
last_response.status.should eq 200
|
151
|
+
last_response.body.should include "[{\"foo\":\"bar\"}]"
|
152
|
+
last_response.header['Link'].should include "{:url=>\"/foobar?page=1\", :rel=>\"first\"}"
|
153
|
+
end
|
154
|
+
it "discern errors and override size with 1 if necessary" do
|
155
|
+
get('/foobar?page=1&size=0')
|
156
|
+
last_response.status.should eq 200
|
157
|
+
last_response.body.should == "[{\"foo\":\"bar\"}]"
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end # Grape::Formatter::Paginater
|
163
|
+
|
164
|
+
end
|
165
|
+
|