will_paginate 3.0.pre4 → 3.0.0
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.
Potentially problematic release.
This version of will_paginate might be problematic. Click here for more details.
- data/README.md +61 -0
- data/Rakefile +19 -36
- data/lib/will_paginate.rb +16 -14
- data/lib/will_paginate/{finders/active_record.rb → active_record.rb} +66 -35
- data/lib/will_paginate/array.rb +5 -5
- data/lib/will_paginate/collection.rb +12 -36
- data/lib/will_paginate/core_ext.rb +0 -28
- data/lib/will_paginate/data_mapper.rb +91 -0
- data/lib/will_paginate/i18n.rb +22 -0
- data/lib/will_paginate/locale/en.yml +33 -0
- data/lib/will_paginate/page_number.rb +57 -0
- data/lib/will_paginate/per_page.rb +27 -0
- data/lib/will_paginate/railtie.rb +13 -4
- data/lib/will_paginate/sequel.rb +36 -0
- data/lib/will_paginate/version.rb +1 -1
- data/lib/will_paginate/view_helpers.rb +136 -22
- data/lib/will_paginate/view_helpers/action_view.rb +129 -117
- data/lib/will_paginate/view_helpers/link_renderer.rb +10 -11
- data/lib/will_paginate/view_helpers/link_renderer_base.rb +2 -8
- data/lib/will_paginate/view_helpers/merb.rb +20 -7
- data/lib/will_paginate/view_helpers/sinatra.rb +41 -0
- data/spec/ci.rb +29 -0
- data/spec/collection_spec.rb +7 -23
- data/spec/console +9 -1
- data/spec/console_fixtures.rb +1 -3
- data/spec/database.yml +10 -10
- data/spec/finders/active_record_spec.rb +82 -28
- data/spec/finders/activerecord_test_connector.rb +9 -1
- data/spec/finders/data_mapper_spec.rb +59 -48
- data/spec/finders/data_mapper_test_connector.rb +8 -1
- data/spec/finders/sequel_spec.rb +9 -3
- data/spec/fixtures/project.rb +2 -0
- data/spec/page_number_spec.rb +65 -0
- data/spec/per_page_spec.rb +41 -0
- data/spec/spec_helper.rb +5 -29
- data/spec/view_helpers/action_view_spec.rb +48 -32
- data/spec/view_helpers/base_spec.rb +59 -7
- data/spec/view_helpers/link_renderer_base_spec.rb +7 -12
- data/spec/view_helpers/view_example_group.rb +1 -0
- metadata +22 -23
- data/CHANGELOG.rdoc +0 -105
- data/README.rdoc +0 -111
- data/lib/will_paginate/deprecation.rb +0 -50
- data/lib/will_paginate/finders.rb +0 -9
- data/lib/will_paginate/finders/active_resource.rb +0 -51
- data/lib/will_paginate/finders/base.rb +0 -112
- data/lib/will_paginate/finders/data_mapper.rb +0 -30
- data/lib/will_paginate/finders/sequel.rb +0 -23
- data/lib/will_paginate/view_helpers/base.rb +0 -126
- data/spec/finders/active_resource_spec.rb +0 -52
- data/spec/finders_spec.rb +0 -76
@@ -1,112 +0,0 @@
|
|
1
|
-
require 'will_paginate/core_ext'
|
2
|
-
|
3
|
-
module WillPaginate
|
4
|
-
module Finders
|
5
|
-
# = Database-agnostic finder module
|
6
|
-
#
|
7
|
-
# Out of the box, will_paginate supports hooking in several ORMs to
|
8
|
-
# provide paginating finders based on their API. As of this writing, the
|
9
|
-
# supported libraries are:
|
10
|
-
#
|
11
|
-
# * ActiveRecord
|
12
|
-
# * DataMapper
|
13
|
-
# * Sequel
|
14
|
-
#
|
15
|
-
# It's easy to write your own adapter for anything that can load data with
|
16
|
-
# explicit limit and offset settings. DataMapper adapter is a nice and
|
17
|
-
# compact example of writing an adapter to bring the +paginate+ method to
|
18
|
-
# DataMapper models.
|
19
|
-
#
|
20
|
-
# == The importance of SQL's <tt>ORDER BY</tt>
|
21
|
-
#
|
22
|
-
# In most ORMs, <tt>:order</tt> parameter specifies columns for the
|
23
|
-
# <tt>ORDER BY</tt> clause in SQL. It is important to have it, since
|
24
|
-
# pagination only makes sense with ordered sets. Without the order clause,
|
25
|
-
# databases aren't required to do consistent ordering when performing
|
26
|
-
# <tt>SELECT</tt> queries.
|
27
|
-
#
|
28
|
-
# Ordering by a field for which many records share the same value (e.g.
|
29
|
-
# "status") can still result in incorrect ordering with some databases (MS
|
30
|
-
# SQL and Postgres for instance). With these databases it's recommend that
|
31
|
-
# you order by primary key as well. That is, instead of ordering by
|
32
|
-
# "status DESC", use the alternative "status DESC, id DESC" and this will
|
33
|
-
# yield consistent results.
|
34
|
-
#
|
35
|
-
# Therefore, make sure you are doing ordering on a column that makes the
|
36
|
-
# most sense in the current context. Make that obvious to the user, also.
|
37
|
-
# For perfomance reasons you will also want to add an index to that column.
|
38
|
-
module Base
|
39
|
-
def per_page
|
40
|
-
@per_page ||= 30
|
41
|
-
end
|
42
|
-
|
43
|
-
def per_page=(limit)
|
44
|
-
@per_page = limit.to_i
|
45
|
-
end
|
46
|
-
|
47
|
-
# This is the main paginating finder.
|
48
|
-
#
|
49
|
-
# == Special parameters for paginating finders
|
50
|
-
# * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
|
51
|
-
# * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
|
52
|
-
# * <tt>:total_entries</tt> -- use only if you manually count total entries
|
53
|
-
# * <tt>:count</tt> -- additional options that are passed on to +count+
|
54
|
-
# * <tt>:finder</tt> -- name of the finder method to use (default: "find")
|
55
|
-
#
|
56
|
-
# All other options (+conditions+, +order+, ...) are forwarded to +find+
|
57
|
-
# and +count+ calls.
|
58
|
-
def paginate(*args, &block)
|
59
|
-
options = args.pop
|
60
|
-
page, per_page, total_entries = wp_parse_options(options)
|
61
|
-
|
62
|
-
WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
|
63
|
-
query_options = options.except :page, :per_page, :total_entries
|
64
|
-
wp_query(query_options, pager, args, &block)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Iterates through all records by loading one page at a time. This is useful
|
69
|
-
# for migrations or any other use case where you don't want to load all the
|
70
|
-
# records in memory at once.
|
71
|
-
#
|
72
|
-
# It uses +paginate+ internally; therefore it accepts all of its options.
|
73
|
-
# You can specify a starting page with <tt>:page</tt> (default is 1). Default
|
74
|
-
# <tt>:order</tt> is <tt>"id"</tt>, override if necessary.
|
75
|
-
#
|
76
|
-
# {Jamis Buck describes this}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord]
|
77
|
-
# and also uses a more efficient way for MySQL.
|
78
|
-
def paginated_each(options = {}, &block)
|
79
|
-
options = { :order => 'id', :page => 1 }.merge options
|
80
|
-
options[:page] = options[:page].to_i
|
81
|
-
options[:total_entries] = 0 # skip the individual count queries
|
82
|
-
total = 0
|
83
|
-
|
84
|
-
begin
|
85
|
-
collection = paginate(options)
|
86
|
-
total += collection.each(&block).size
|
87
|
-
options[:page] += 1
|
88
|
-
end until collection.size < collection.per_page
|
89
|
-
|
90
|
-
total
|
91
|
-
end
|
92
|
-
|
93
|
-
protected
|
94
|
-
|
95
|
-
def wp_parse_options(options) #:nodoc:
|
96
|
-
raise ArgumentError, 'parameter hash expected' unless Hash === options
|
97
|
-
raise ArgumentError, ':page parameter required' unless options.key? :page
|
98
|
-
|
99
|
-
if options[:count] and options[:total_entries]
|
100
|
-
raise ArgumentError, ':count and :total_entries are mutually exclusive'
|
101
|
-
end
|
102
|
-
|
103
|
-
page = options[:page] || 1
|
104
|
-
per_page = options[:per_page] || self.per_page
|
105
|
-
total = options[:total_entries]
|
106
|
-
|
107
|
-
return [page, per_page, total]
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'will_paginate/finders/base'
|
2
|
-
require 'dm-core'
|
3
|
-
|
4
|
-
module WillPaginate::Finders
|
5
|
-
module DataMapper
|
6
|
-
include WillPaginate::Finders::Base
|
7
|
-
|
8
|
-
protected
|
9
|
-
|
10
|
-
def wp_query(options, pager, args, &block) #:nodoc
|
11
|
-
find_options = options.except(:count).update(:offset => pager.offset, :limit => pager.per_page)
|
12
|
-
|
13
|
-
pager.replace all(find_options, &block)
|
14
|
-
|
15
|
-
unless pager.total_entries
|
16
|
-
pager.total_entries = wp_count(options)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def wp_count(options) #:nodoc
|
21
|
-
count_options = options.except(:count, :order)
|
22
|
-
# merge the hash found in :count
|
23
|
-
count_options.update options[:count] if options[:count]
|
24
|
-
|
25
|
-
count_options.empty?? count() : count(count_options)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
DataMapper::Model.send(:include, WillPaginate::Finders::DataMapper)
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'will_paginate/core_ext'
|
2
|
-
require 'sequel'
|
3
|
-
require 'sequel/extensions/pagination'
|
4
|
-
|
5
|
-
existing_methods = Sequel::Dataset::Pagination.instance_methods
|
6
|
-
|
7
|
-
Sequel::Dataset::Pagination.module_eval do
|
8
|
-
# it should quack like a WillPaginate::Collection
|
9
|
-
|
10
|
-
alias :total_pages :page_count unless existing_methods.include_method? :total_pages
|
11
|
-
alias :per_page :page_size unless existing_methods.include_method? :per_page
|
12
|
-
alias :previous_page :prev_page unless existing_methods.include_method? :previous_page
|
13
|
-
alias :total_entries :pagination_record_count unless existing_methods.include_method? :total_entries
|
14
|
-
|
15
|
-
def out_of_bounds?
|
16
|
-
current_page > total_pages
|
17
|
-
end
|
18
|
-
|
19
|
-
# Current offset of the paginated collection
|
20
|
-
def offset
|
21
|
-
(current_page - 1) * per_page
|
22
|
-
end
|
23
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'will_paginate/core_ext'
|
2
|
-
require 'will_paginate/view_helpers'
|
3
|
-
|
4
|
-
module WillPaginate
|
5
|
-
module ViewHelpers
|
6
|
-
# = The main view helpers module
|
7
|
-
#
|
8
|
-
# This is the base module which provides the +will_paginate+ view helper.
|
9
|
-
module Base
|
10
|
-
# Renders Digg/Flickr-style pagination for a WillPaginate::Collection object. Nil is
|
11
|
-
# returned if there is only one page in total; pagination links aren't needed in that case.
|
12
|
-
#
|
13
|
-
# ==== Options
|
14
|
-
# * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
|
15
|
-
# * <tt>:previous_label</tt> -- default: "« Previous"
|
16
|
-
# * <tt>:next_label</tt> -- default: "Next »"
|
17
|
-
# * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
|
18
|
-
# * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
|
19
|
-
# * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
|
20
|
-
# * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
|
21
|
-
# * <tt>:params</tt> -- additional parameters when generating pagination links
|
22
|
-
# (eg. <tt>:controller => "foo", :action => nil</tt>)
|
23
|
-
# * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default:
|
24
|
-
# <tt>WillPaginate::LinkRenderer</tt>)
|
25
|
-
# * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
|
26
|
-
# * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
|
27
|
-
# false only when you are rendering your own pagination markup (default: true)
|
28
|
-
# * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID
|
29
|
-
# automatically generated from the class name of objects in collection: for example, paginating
|
30
|
-
# ArticleComment models would yield an ID of "article_comments_pagination".
|
31
|
-
#
|
32
|
-
# All options beside listed ones are passed as HTML attributes to the container
|
33
|
-
# element for pagination links (the DIV). For example:
|
34
|
-
#
|
35
|
-
# <%= will_paginate @posts, :id => 'wp_posts' %>
|
36
|
-
#
|
37
|
-
# ... will result in:
|
38
|
-
#
|
39
|
-
# <div class="pagination" id="wp_posts"> ... </div>
|
40
|
-
#
|
41
|
-
def will_paginate(collection, options = {})
|
42
|
-
# early exit if there is nothing to render
|
43
|
-
return nil unless collection.total_pages > 1
|
44
|
-
|
45
|
-
options = WillPaginate::ViewHelpers.pagination_options.merge(options)
|
46
|
-
|
47
|
-
if options[:prev_label]
|
48
|
-
WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated.")
|
49
|
-
options[:previous_label] = options.delete(:prev_label)
|
50
|
-
end
|
51
|
-
|
52
|
-
# get the renderer instance
|
53
|
-
renderer = case options[:renderer]
|
54
|
-
when String
|
55
|
-
options[:renderer].constantize.new
|
56
|
-
when Class
|
57
|
-
options[:renderer].new
|
58
|
-
else
|
59
|
-
options[:renderer]
|
60
|
-
end
|
61
|
-
# render HTML for pagination
|
62
|
-
renderer.prepare collection, options, self
|
63
|
-
renderer.to_html
|
64
|
-
end
|
65
|
-
|
66
|
-
# Renders a helpful message with numbers of displayed vs. total entries.
|
67
|
-
# You can use this as a blueprint for your own, similar helpers.
|
68
|
-
#
|
69
|
-
# <%= page_entries_info @posts %>
|
70
|
-
# #-> Displaying posts 6 - 10 of 26 in total
|
71
|
-
#
|
72
|
-
# By default, the message will use the humanized class name of objects
|
73
|
-
# in collection: for instance, "project types" for ProjectType models.
|
74
|
-
# Override this to your liking with the <tt>:entry_name</tt> parameter:
|
75
|
-
#
|
76
|
-
# <%= page_entries_info @posts, :entry_name => 'item' %>
|
77
|
-
# #-> Displaying items 6 - 10 of 26 in total
|
78
|
-
#
|
79
|
-
# Entry name is entered in singular and pluralized with
|
80
|
-
# <tt>String#pluralize</tt> method from ActiveSupport. If it isn't
|
81
|
-
# loaded, specify plural with <tt>:plural_name</tt> parameter:
|
82
|
-
#
|
83
|
-
# <%= page_entries_info @posts, :entry_name => 'item', :plural_name => 'items' %>
|
84
|
-
#
|
85
|
-
# By default, this method produces HTML output. You can trigger plain
|
86
|
-
# text output by passing <tt>:html => false</tt> in options.
|
87
|
-
def page_entries_info(collection, options = {})
|
88
|
-
entry_name = options[:entry_name] || (collection.empty?? 'entry' :
|
89
|
-
collection.first.class.name.underscore.gsub('_', ' '))
|
90
|
-
|
91
|
-
plural_name = if options[:plural_name]
|
92
|
-
options[:plural_name]
|
93
|
-
elsif entry_name == 'entry'
|
94
|
-
plural_name = 'entries'
|
95
|
-
elsif entry_name.respond_to? :pluralize
|
96
|
-
plural_name = entry_name.pluralize
|
97
|
-
else
|
98
|
-
entry_name + 's'
|
99
|
-
end
|
100
|
-
|
101
|
-
unless options[:html] == false
|
102
|
-
b = '<b>'
|
103
|
-
eb = '</b>'
|
104
|
-
sp = ' '
|
105
|
-
else
|
106
|
-
b = eb = ''
|
107
|
-
sp = ' '
|
108
|
-
end
|
109
|
-
|
110
|
-
if collection.total_pages < 2
|
111
|
-
case collection.size
|
112
|
-
when 0; "No #{plural_name} found"
|
113
|
-
when 1; "Displaying #{b}1#{eb} #{entry_name}"
|
114
|
-
else; "Displaying #{b}all #{collection.size}#{eb} #{plural_name}"
|
115
|
-
end
|
116
|
-
else
|
117
|
-
%{Displaying #{plural_name} #{b}%d#{sp}-#{sp}%d#{eb} of #{b}%d#{eb} in total} % [
|
118
|
-
collection.offset + 1,
|
119
|
-
collection.offset + collection.length,
|
120
|
-
collection.total_entries
|
121
|
-
]
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'will_paginate/finders/active_resource'
|
3
|
-
require 'active_resource/http_mock'
|
4
|
-
|
5
|
-
class AresProject < ActiveResource::Base
|
6
|
-
self.site = 'http://localhost:4000'
|
7
|
-
end
|
8
|
-
|
9
|
-
describe WillPaginate::Finders::ActiveResource do
|
10
|
-
|
11
|
-
before :all do
|
12
|
-
# ActiveResource::HttpMock.respond_to do |mock|
|
13
|
-
# mock.get "/ares_projects.xml?page=1&per_page=5", {}, [].to_xml
|
14
|
-
# end
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should integrate with ActiveResource::Base" do
|
18
|
-
ActiveResource::Base.should respond_to(:paginate)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should error when no parameters for #paginate" do
|
22
|
-
lambda { AresProject.paginate }.should raise_error(ArgumentError)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should paginate" do
|
26
|
-
AresProject.expects(:find_every).with(:params => { :page => 1, :per_page => 5 }).returns([])
|
27
|
-
AresProject.paginate(:page => 1, :per_page => 5)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should have 30 per_page as default" do
|
31
|
-
AresProject.expects(:find_every).with(:params => { :page => 1, :per_page => 30 }).returns([])
|
32
|
-
AresProject.paginate(:page => 1)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should support #paginate(:all)" do
|
36
|
-
lambda { AresProject.paginate(:all) }.should raise_error(ArgumentError)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should error #paginate(:other)" do
|
40
|
-
lambda { AresProject.paginate(:first) }.should raise_error(ArgumentError)
|
41
|
-
end
|
42
|
-
|
43
|
-
protected
|
44
|
-
|
45
|
-
def create(page = 2, limit = 5, total = nil, &block)
|
46
|
-
if block_given?
|
47
|
-
WillPaginate::Collection.create(page, limit, total, &block)
|
48
|
-
else
|
49
|
-
WillPaginate::Collection.new(page, limit, total)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/spec/finders_spec.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'will_paginate/finders/base'
|
3
|
-
|
4
|
-
class Model
|
5
|
-
extend WillPaginate::Finders::Base
|
6
|
-
end
|
7
|
-
|
8
|
-
describe WillPaginate::Finders::Base do
|
9
|
-
it "should define default per_page of 30" do
|
10
|
-
Model.per_page.should == 30
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should allow to set custom per_page" do
|
14
|
-
begin
|
15
|
-
Model.per_page = 25
|
16
|
-
Model.per_page.should == 25
|
17
|
-
ensure
|
18
|
-
Model.per_page = 30
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should result with WillPaginate::Collection" do
|
23
|
-
Model.expects(:wp_query)
|
24
|
-
Model.paginate(:page => nil).should be_instance_of(WillPaginate::Collection)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should delegate pagination to wp_query" do
|
28
|
-
Model.expects(:wp_query).with({}, instance_of(WillPaginate::Collection), [])
|
29
|
-
Model.paginate :page => nil
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should complain when no hash parameters given" do
|
33
|
-
lambda {
|
34
|
-
Model.paginate
|
35
|
-
}.should raise_error(ArgumentError, 'parameter hash expected')
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should complain when no :page parameter present" do
|
39
|
-
lambda {
|
40
|
-
Model.paginate :per_page => 6
|
41
|
-
}.should raise_error(ArgumentError, ':page parameter required')
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should complain when both :count and :total_entries are given" do
|
45
|
-
lambda {
|
46
|
-
Model.paginate :page => 1, :count => {}, :total_entries => 1
|
47
|
-
}.should raise_error(ArgumentError, ':count and :total_entries are mutually exclusive')
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should never mangle options" do
|
51
|
-
options = { :page => 1 }
|
52
|
-
options.expects(:delete).never
|
53
|
-
options_before = options.dup
|
54
|
-
|
55
|
-
Model.expects(:wp_query)
|
56
|
-
Model.paginate(options)
|
57
|
-
|
58
|
-
options.should == options_before
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should provide paginated_each functionality" do
|
62
|
-
collection = stub('collection', :size => 5, :empty? => false, :per_page => 5)
|
63
|
-
collection.expects(:each).times(2).returns(collection)
|
64
|
-
last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5)
|
65
|
-
last_collection.expects(:each).returns(last_collection)
|
66
|
-
|
67
|
-
params = { :order => 'id', :total_entries => 0 }
|
68
|
-
|
69
|
-
Model.expects(:paginate).with(params.merge(:page => 2)).returns(collection)
|
70
|
-
Model.expects(:paginate).with(params.merge(:page => 3)).returns(collection)
|
71
|
-
Model.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection)
|
72
|
-
|
73
|
-
total = Model.paginated_each(:page => '2') { }
|
74
|
-
total.should == 14
|
75
|
-
end
|
76
|
-
end
|