will_paginate_seo 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +18 -0
  3. data/README.md +61 -0
  4. data/lib/will_paginate.rb +25 -0
  5. data/lib/will_paginate/active_record.rb +261 -0
  6. data/lib/will_paginate/array.rb +33 -0
  7. data/lib/will_paginate/collection.rb +136 -0
  8. data/lib/will_paginate/core_ext.rb +30 -0
  9. data/lib/will_paginate/data_mapper.rb +100 -0
  10. data/lib/will_paginate/deprecation.rb +55 -0
  11. data/lib/will_paginate/i18n.rb +22 -0
  12. data/lib/will_paginate/locale/en.yml +33 -0
  13. data/lib/will_paginate/mongoid.rb +46 -0
  14. data/lib/will_paginate/page_number.rb +57 -0
  15. data/lib/will_paginate/per_page.rb +27 -0
  16. data/lib/will_paginate/railtie.rb +68 -0
  17. data/lib/will_paginate/sequel.rb +39 -0
  18. data/lib/will_paginate/version.rb +9 -0
  19. data/lib/will_paginate/view_helpers.rb +162 -0
  20. data/lib/will_paginate/view_helpers/action_view.rb +152 -0
  21. data/lib/will_paginate/view_helpers/link_renderer.rb +131 -0
  22. data/lib/will_paginate/view_helpers/link_renderer_base.rb +77 -0
  23. data/lib/will_paginate/view_helpers/merb.rb +26 -0
  24. data/lib/will_paginate/view_helpers/sinatra.rb +41 -0
  25. data/spec/collection_spec.rb +139 -0
  26. data/spec/console +12 -0
  27. data/spec/console_fixtures.rb +28 -0
  28. data/spec/database.yml +22 -0
  29. data/spec/fake_rubygems.rb +18 -0
  30. data/spec/finders/active_record_spec.rb +517 -0
  31. data/spec/finders/activerecord_test_connector.rb +119 -0
  32. data/spec/finders/data_mapper_spec.rb +116 -0
  33. data/spec/finders/data_mapper_test_connector.rb +54 -0
  34. data/spec/finders/mongoid_spec.rb +140 -0
  35. data/spec/finders/sequel_spec.rb +67 -0
  36. data/spec/finders/sequel_test_connector.rb +15 -0
  37. data/spec/fixtures/admin.rb +3 -0
  38. data/spec/fixtures/developer.rb +16 -0
  39. data/spec/fixtures/developers_projects.yml +13 -0
  40. data/spec/fixtures/project.rb +13 -0
  41. data/spec/fixtures/projects.yml +6 -0
  42. data/spec/fixtures/replies.yml +29 -0
  43. data/spec/fixtures/reply.rb +8 -0
  44. data/spec/fixtures/schema.rb +38 -0
  45. data/spec/fixtures/topic.rb +8 -0
  46. data/spec/fixtures/topics.yml +30 -0
  47. data/spec/fixtures/user.rb +2 -0
  48. data/spec/fixtures/users.yml +35 -0
  49. data/spec/matchers/deprecation_matcher.rb +27 -0
  50. data/spec/matchers/phrase_matcher.rb +19 -0
  51. data/spec/matchers/query_count_matcher.rb +36 -0
  52. data/spec/page_number_spec.rb +65 -0
  53. data/spec/per_page_spec.rb +41 -0
  54. data/spec/spec_helper.rb +46 -0
  55. data/spec/view_helpers/action_view_spec.rb +441 -0
  56. data/spec/view_helpers/base_spec.rb +142 -0
  57. data/spec/view_helpers/link_renderer_base_spec.rb +87 -0
  58. data/spec/view_helpers/view_example_group.rb +125 -0
  59. metadata +106 -0
@@ -0,0 +1,441 @@
1
+ require 'spec_helper'
2
+ require 'active_support/rescuable' # needed for Ruby 1.9.1
3
+ require 'action_controller'
4
+ require 'action_view'
5
+ require 'will_paginate/view_helpers/action_view'
6
+ require 'will_paginate/collection'
7
+
8
+ Routes = ActionDispatch::Routing::RouteSet.new
9
+
10
+ Routes.draw do
11
+ get 'dummy/page/:page' => 'dummy#index'
12
+ get 'dummy/dots/page.:page' => 'dummy#dots'
13
+ get 'ibocorp(/:page)' => 'ibocorp#index',
14
+ :constraints => { :page => /\d+/ }, :defaults => { :page => 1 }
15
+
16
+ get ':controller(/:action(/:id(.:format)))'
17
+ end
18
+
19
+ describe WillPaginate::ActionView do
20
+
21
+ before(:all) do
22
+ I18n.load_path.concat WillPaginate::I18n.load_path
23
+ end
24
+
25
+ before(:each) do
26
+ I18n.reload!
27
+ end
28
+
29
+ before(:each) do
30
+ @assigns = {}
31
+ @controller = DummyController.new
32
+ @request = @controller.request
33
+ @template = '<%= will_paginate collection, options %>'
34
+ end
35
+
36
+ attr_reader :assigns, :controller, :request
37
+
38
+ def render(locals)
39
+ @view = ActionView::Base.new([], @assigns, @controller)
40
+ @view.request = @request
41
+ @view.singleton_class.send(:include, @controller._routes.url_helpers)
42
+ @view.render(:inline => @template, :locals => locals)
43
+ end
44
+
45
+ ## basic pagination ##
46
+
47
+ it "should render" do
48
+ paginate do |pagination|
49
+ assert_select 'a[href]', 3 do |elements|
50
+ validate_page_numbers [2,3,2], elements
51
+ assert_select elements.last, ':last-child', "Next &#8594;"
52
+ end
53
+ assert_select 'span', 1
54
+ assert_select 'span.disabled:first-child', '&#8592; Previous'
55
+ assert_select 'em.current', '1'
56
+ pagination.first.inner_text.should == '&#8592; Previous 1 2 3 Next &#8594;'
57
+ end
58
+ end
59
+
60
+ it "should override existing page param value" do
61
+ request.params :page => 1
62
+ paginate do |pagination|
63
+ assert_select 'a[href]', 3 do |elements|
64
+ validate_page_numbers [2,3,2], elements
65
+ end
66
+ end
67
+ end
68
+
69
+ it "should render nothing when there is only 1 page" do
70
+ paginate(:per_page => 30).should be_empty
71
+ end
72
+
73
+ it "should paginate with options" do
74
+ paginate({ :page => 2 }, :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do
75
+ assert_select 'a[href]', 4 do |elements|
76
+ validate_page_numbers [1,1,3,3], elements
77
+ # test rel attribute values:
78
+ assert_select elements[1], 'a', '1' do |link|
79
+ link.first['rel'].should == 'prev start'
80
+ end
81
+ assert_select elements.first, 'a', "Prev" do |link|
82
+ link.first['rel'].should == 'prev start'
83
+ end
84
+ assert_select elements.last, 'a', "Next" do |link|
85
+ link.first['rel'].should == 'next'
86
+ end
87
+ end
88
+ assert_select '.current', '2'
89
+ end
90
+ end
91
+
92
+ it "should paginate using a custom renderer class" do
93
+ paginate({}, :renderer => AdditionalLinkAttributesRenderer) do
94
+ assert_select 'a[default=true]', 3
95
+ end
96
+ end
97
+
98
+ it "should paginate using a custom renderer instance" do
99
+ renderer = WillPaginate::ActionView::LinkRenderer.new
100
+ def renderer.gap() '<span class="my-gap">~~</span>' end
101
+
102
+ paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do
103
+ assert_select 'span.my-gap', '~~'
104
+ end
105
+
106
+ renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered')
107
+ paginate({}, :renderer => renderer) do
108
+ assert_select 'a[title=rendered]', 3
109
+ end
110
+ end
111
+
112
+ it "should have classnames on previous/next links" do
113
+ paginate do |pagination|
114
+ assert_select 'span.disabled.previous_page:first-child'
115
+ assert_select 'a.next_page[href]:last-child'
116
+ end
117
+ end
118
+
119
+ it "should match expected markup" do
120
+ paginate
121
+ expected = <<-HTML
122
+ <div class="pagination"><span class="previous_page disabled">&#8592; Previous</span>
123
+ <em class="current">1</em>
124
+ <a href="/foo/bar?page=2" rel="next">2</a>
125
+ <a href="/foo/bar?page=3">3</a>
126
+ <a href="/foo/bar?page=2" class="next_page" rel="next">Next &#8594;</a></div>
127
+ HTML
128
+ expected.strip!.gsub!(/\s{2,}/, ' ')
129
+ expected_dom = HTML::Document.new(expected).root
130
+
131
+ html_document.root.should == expected_dom
132
+ end
133
+
134
+ it "should output escaped URLs" do
135
+ paginate({:page => 1, :per_page => 1, :total_entries => 2},
136
+ :page_links => false, :params => { :tag => '<br>' })
137
+
138
+ assert_select 'a[href]', 1 do |links|
139
+ query = links.first['href'].split('?', 2)[1]
140
+ query.split('&amp;').sort.should == %w(page=2 tag=%3Cbr%3E)
141
+ end
142
+ end
143
+
144
+ ## advanced options for pagination ##
145
+
146
+ it "should be able to render without container" do
147
+ paginate({}, :container => false)
148
+ assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t'
149
+ assert_select 'a[href]', 3
150
+ end
151
+
152
+ it "should be able to render without page links" do
153
+ paginate({ :page => 2 }, :page_links => false) do
154
+ assert_select 'a[href]', 2 do |elements|
155
+ validate_page_numbers [1,3], elements
156
+ end
157
+ end
158
+ end
159
+
160
+ ## other helpers ##
161
+
162
+ it "should render a paginated section" do
163
+ @template = <<-ERB
164
+ <%= paginated_section collection, options do %>
165
+ <%= content_tag :div, '', :id => "developers" %>
166
+ <% end %>
167
+ ERB
168
+
169
+ paginate
170
+ assert_select 'div.pagination', 2
171
+ assert_select 'div.pagination + div#developers', 1
172
+ end
173
+
174
+ it "should not render a paginated section with a single page" do
175
+ @template = <<-ERB
176
+ <%= paginated_section collection, options do %>
177
+ <%= content_tag :div, '', :id => "developers" %>
178
+ <% end %>
179
+ ERB
180
+
181
+ paginate(:total_entries => 1)
182
+ assert_select 'div.pagination', 0
183
+ assert_select 'div#developers', 1
184
+ end
185
+
186
+ ## parameter handling in page links ##
187
+
188
+ it "should preserve parameters on GET" do
189
+ request.params :foo => { :bar => 'baz' }
190
+ paginate
191
+ assert_links_match /foo\[bar\]=baz/
192
+ end
193
+
194
+ it "doesn't allow tampering with host, port, protocol" do
195
+ request.params :host => 'disney.com', :port => '99', :protocol => 'ftp'
196
+ paginate
197
+ assert_links_match %r{^/foo/bar}
198
+ assert_no_links_match /disney/
199
+ assert_no_links_match /99/
200
+ assert_no_links_match /ftp/
201
+ end
202
+
203
+ it "should not preserve parameters on POST" do
204
+ request.post
205
+ request.params :foo => 'bar'
206
+ paginate
207
+ assert_no_links_match /foo=bar/
208
+ end
209
+
210
+ it "should add additional parameters to links" do
211
+ paginate({}, :params => { :foo => 'bar' })
212
+ assert_links_match /foo=bar/
213
+ end
214
+
215
+ it "should add anchor parameter" do
216
+ paginate({}, :params => { :anchor => 'anchor' })
217
+ assert_links_match /#anchor$/
218
+ end
219
+
220
+ it "should remove arbitrary parameters" do
221
+ request.params :foo => 'bar'
222
+ paginate({}, :params => { :foo => nil })
223
+ assert_no_links_match /foo=bar/
224
+ end
225
+
226
+ it "should override default route parameters" do
227
+ paginate({}, :params => { :controller => 'baz', :action => 'list' })
228
+ assert_links_match %r{\Wbaz/list\W}
229
+ end
230
+
231
+ it "should paginate with custom page parameter" do
232
+ paginate({ :page => 2 }, :param_name => :developers_page) do
233
+ assert_select 'a[href]', 4 do |elements|
234
+ validate_page_numbers [1,1,3,3], elements, :developers_page
235
+ end
236
+ end
237
+ end
238
+
239
+ it "should paginate with complex custom page parameter" do
240
+ request.params :developers => { :page => 2 }
241
+
242
+ paginate({ :page => 2 }, :param_name => 'developers[page]') do
243
+ assert_select 'a[href]', 4 do |links|
244
+ assert_links_match /\?developers\[page\]=\d+$/, links
245
+ validate_page_numbers [1,1,3,3], links, 'developers[page]'
246
+ end
247
+ end
248
+ end
249
+
250
+ it "should paginate with custom route page parameter" do
251
+ request.symbolized_path_parameters.update :controller => 'dummy', :action => nil
252
+ paginate :per_page => 2 do
253
+ assert_select 'a[href]', 6 do |links|
254
+ assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2]
255
+ end
256
+ end
257
+ end
258
+
259
+ it "should paginate with custom route with dot separator page parameter" do
260
+ request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots'
261
+ paginate :per_page => 2 do
262
+ assert_select 'a[href]', 6 do |links|
263
+ assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2]
264
+ end
265
+ end
266
+ end
267
+
268
+ it "should paginate with custom route and first page number implicit" do
269
+ request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil
270
+ paginate :page => 2, :per_page => 2 do
271
+ assert_select 'a[href]', 7 do |links|
272
+ assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3]
273
+ end
274
+ end
275
+ # Routes.recognize_path('/ibocorp/2').should == {:page=>'2', :action=>'index', :controller=>'ibocorp'}
276
+ # Routes.recognize_path('/ibocorp/foo').should == {:action=>'foo', :controller=>'ibocorp'}
277
+ end
278
+
279
+ ## internal hardcore stuff ##
280
+
281
+ it "should be able to guess the collection name" do
282
+ collection = mock
283
+ collection.expects(:total_pages).returns(1)
284
+
285
+ @template = '<%= will_paginate options %>'
286
+ controller.controller_name = 'developers'
287
+ assigns['developers'] = collection
288
+
289
+ paginate(nil)
290
+ end
291
+
292
+ it "should fail if the inferred collection is nil" do
293
+ @template = '<%= will_paginate options %>'
294
+ controller.controller_name = 'developers'
295
+
296
+ lambda {
297
+ paginate(nil)
298
+ }.should raise_error(ActionView::TemplateError, /@developers/)
299
+ end
300
+
301
+ ## i18n
302
+
303
+ it "is able to translate previous/next labels" do
304
+ translation :will_paginate => {
305
+ :previous_label => 'Go back',
306
+ :next_label => 'Load more'
307
+ }
308
+
309
+ paginate do |pagination|
310
+ assert_select 'span.disabled:first-child', 'Go back'
311
+ assert_select 'a[rel=next]', 'Load more'
312
+ end
313
+ end
314
+
315
+ it "renders using ActionView helpers on a custom object" do
316
+ helper = Class.new {
317
+ attr_reader :controller
318
+ include ActionView::Helpers::UrlHelper
319
+ include Routes.url_helpers
320
+ include WillPaginate::ActionView
321
+ }.new
322
+ helper.default_url_options[:controller] = 'dummy'
323
+
324
+ collection = WillPaginate::Collection.new(2, 1, 3)
325
+ @render_output = helper.will_paginate(collection)
326
+
327
+ assert_select 'a[href]', 4 do |links|
328
+ urls = links.map {|l| l['href'] }.uniq
329
+ urls.should == ['/dummy/page/1', '/dummy/page/3']
330
+ end
331
+ end
332
+
333
+ it "renders using ActionDispatch helper on a custom object" do
334
+ helper = Class.new {
335
+ include ActionDispatch::Routing::UrlFor
336
+ include Routes.url_helpers
337
+ include WillPaginate::ActionView
338
+ }.new
339
+ helper.default_url_options.update \
340
+ :only_path => true,
341
+ :controller => 'dummy'
342
+
343
+ collection = WillPaginate::Collection.new(2, 1, 3)
344
+ @render_output = helper.will_paginate(collection)
345
+
346
+ assert_select 'a[href]', 4 do |links|
347
+ urls = links.map {|l| l['href'] }.uniq
348
+ urls.should == ['/dummy/page/1', '/dummy/page/3']
349
+ end
350
+ end
351
+
352
+ private
353
+
354
+ def translation(data)
355
+ I18n.available_locales # triggers loading existing translations
356
+ I18n.backend.store_translations(:en, data)
357
+ end
358
+ end
359
+
360
+ class AdditionalLinkAttributesRenderer < WillPaginate::ActionView::LinkRenderer
361
+ def initialize(link_attributes = nil)
362
+ super()
363
+ @additional_link_attributes = link_attributes || { :default => 'true' }
364
+ end
365
+
366
+ def link(text, target, attributes = {})
367
+ super(text, target, attributes.merge(@additional_link_attributes))
368
+ end
369
+ end
370
+
371
+ class DummyController
372
+ attr_reader :request
373
+ attr_accessor :controller_name
374
+
375
+ include ActionController::UrlFor
376
+ include Routes.url_helpers
377
+
378
+ def initialize
379
+ @request = DummyRequest.new
380
+ end
381
+
382
+ def params
383
+ @request.params
384
+ end
385
+
386
+ def env
387
+ {}
388
+ end
389
+
390
+ def _prefixes
391
+ []
392
+ end
393
+ end
394
+
395
+ class IbocorpController < DummyController
396
+ end
397
+
398
+ class DummyRequest
399
+ attr_accessor :symbolized_path_parameters
400
+ alias :path_parameters :symbolized_path_parameters
401
+
402
+ def initialize
403
+ @get = true
404
+ @params = {}
405
+ @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
406
+ end
407
+
408
+ def get?
409
+ @get
410
+ end
411
+
412
+ def post
413
+ @get = false
414
+ end
415
+
416
+ def relative_url_root
417
+ ''
418
+ end
419
+
420
+ def script_name
421
+ ''
422
+ end
423
+
424
+ def params(more = nil)
425
+ @params.update(more) if more
426
+ @params
427
+ end
428
+
429
+ def host_with_port
430
+ 'example.com'
431
+ end
432
+ alias host host_with_port
433
+
434
+ def optional_port
435
+ ''
436
+ end
437
+
438
+ def protocol
439
+ 'http:'
440
+ end
441
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'will_paginate/view_helpers'
3
+ require 'will_paginate/array'
4
+ require 'active_support'
5
+ require 'active_support/core_ext/string/inflections'
6
+ require 'active_support/inflections'
7
+
8
+ describe WillPaginate::ViewHelpers do
9
+
10
+ before(:all) do
11
+ # make sure default translations aren't loaded
12
+ I18n.load_path.clear
13
+ end
14
+
15
+ before(:each) do
16
+ I18n.reload!
17
+ end
18
+
19
+ include WillPaginate::ViewHelpers
20
+
21
+ describe "will_paginate" do
22
+ it "should render" do
23
+ collection = WillPaginate::Collection.new(1, 2, 4)
24
+ renderer = mock 'Renderer'
25
+ renderer.expects(:prepare).with(collection, instance_of(Hash), self)
26
+ renderer.expects(:to_html).returns('<PAGES>')
27
+
28
+ will_paginate(collection, :renderer => renderer).should == '<PAGES>'
29
+ end
30
+
31
+ it "should return nil for single-page collections" do
32
+ collection = mock 'Collection', :total_pages => 1
33
+ will_paginate(collection).should be_nil
34
+ end
35
+
36
+ it "should call html_safe on result" do
37
+ collection = WillPaginate::Collection.new(1, 2, 4)
38
+
39
+ html = mock 'HTML'
40
+ html.expects(:html_safe).returns(html)
41
+ renderer = mock 'Renderer'
42
+ renderer.stubs(:prepare)
43
+ renderer.expects(:to_html).returns(html)
44
+
45
+ will_paginate(collection, :renderer => renderer).should eql(html)
46
+ end
47
+ end
48
+
49
+ describe "pagination_options" do
50
+ let(:pagination_options) { WillPaginate::ViewHelpers.pagination_options }
51
+
52
+ it "deprecates setting :renderer" do
53
+ begin
54
+ lambda {
55
+ pagination_options[:renderer] = 'test'
56
+ }.should have_deprecation("pagination_options[:renderer] shouldn't be set")
57
+ ensure
58
+ pagination_options.delete :renderer
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "page_entries_info" do
64
+ before :all do
65
+ @array = ('a'..'z').to_a
66
+ end
67
+
68
+ def info(params, options = {})
69
+ collection = Hash === params ? @array.paginate(params) : params
70
+ page_entries_info collection, {:html => false}.merge(options)
71
+ end
72
+
73
+ it "should display middle results and total count" do
74
+ info(:page => 2, :per_page => 5).should == "Displaying strings 6 - 10 of 26 in total"
75
+ end
76
+
77
+ it "uses translation if available" do
78
+ translation :will_paginate => {
79
+ :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'}
80
+ }
81
+ info(:page => 2, :per_page => 5).should == "Showing 6 - 10"
82
+ end
83
+
84
+ it "uses specific translation if available" do
85
+ translation :will_paginate => {
86
+ :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'},
87
+ :string => { :page_entries_info => {:multi_page => 'Strings %{from} to %{to}'} }
88
+ }
89
+ info(:page => 2, :per_page => 5).should == "Strings 6 to 10"
90
+ end
91
+
92
+ it "should output HTML by default" do
93
+ info({ :page => 2, :per_page => 5 }, :html => true).should ==
94
+ "Displaying strings <b>6&nbsp;-&nbsp;10</b> of <b>26</b> in total"
95
+ end
96
+
97
+ it "should display shortened end results" do
98
+ info(:page => 7, :per_page => 4).should include_phrase('strings 25 - 26')
99
+ end
100
+
101
+ it "should handle longer class names" do
102
+ collection = @array.paginate(:page => 2, :per_page => 5)
103
+ model = stub('Class', :name => 'ProjectType', :to_s => 'ProjectType')
104
+ collection.first.stubs(:class).returns(model)
105
+ info(collection).should include_phrase('project types')
106
+ end
107
+
108
+ it "should adjust output for single-page collections" do
109
+ info(('a'..'d').to_a.paginate(:page => 1, :per_page => 5)).should == "Displaying all 4 strings"
110
+ info(['a'].paginate(:page => 1, :per_page => 5)).should == "Displaying 1 string"
111
+ end
112
+
113
+ it "should display 'no entries found' for empty collections" do
114
+ info([].paginate(:page => 1, :per_page => 5)).should == "No entries found"
115
+ end
116
+
117
+ it "uses model_name.human when available" do
118
+ name = stub('model name', :i18n_key => :flower_key)
119
+ name.expects(:human).with(:count => 1).returns('flower')
120
+ model = stub('Class', :model_name => name)
121
+ collection = [1].paginate(:page => 1)
122
+
123
+ info(collection, :model => model).should == "Displaying 1 flower"
124
+ end
125
+
126
+ it "uses custom translation instead of model_name.human" do
127
+ name = stub('model name', :i18n_key => :flower_key)
128
+ name.expects(:human).never
129
+ model = stub('Class', :model_name => name)
130
+ translation :will_paginate => {:models => {:flower_key => 'tulip'}}
131
+ collection = [1].paginate(:page => 1)
132
+
133
+ info(collection, :model => model).should == "Displaying 1 tulip"
134
+ end
135
+
136
+ private
137
+
138
+ def translation(data)
139
+ I18n.backend.store_translations(:en, data)
140
+ end
141
+ end
142
+ end