diff --git a/lib/will_paginate/active_record.rb b/lib/will_paginate/active_record.rb
index 829291b36..e27c3670d 100644
--- a/lib/will_paginate/active_record.rb
+++ b/lib/will_paginate/active_record.rb
@@ -18,6 +18,8 @@ module WillPaginate
module ActiveRecord
# makes a Relation look like WillPaginate::Collection
module RelationMethods
+ include WillPaginate::CollectionMethods
+
attr_accessor :current_page
attr_writer :total_entries, :wp_count_options
@@ -92,10 +94,6 @@ def empty?
end
end
- def total_pages
- (total_entries / limit_value.to_f).ceil
- end
-
def clone
copy_will_paginate_data super
end
diff --git a/lib/will_paginate/collection.rb b/lib/will_paginate/collection.rb
index f18940780..720c722ae 100644
--- a/lib/will_paginate/collection.rb
+++ b/lib/will_paginate/collection.rb
@@ -2,6 +2,38 @@
require 'will_paginate/page_number'
module WillPaginate
+ # Any will_paginate-compatible collection should have these methods:
+ #
+ # current_page, per_page, offset, total_entries, total_pages
+ #
+ # It can also define some of these optional methods:
+ #
+ # out_of_bounds?, previous_page, next_page
+ #
+ # This module provides few of these methods.
+ module CollectionMethods
+ def total_pages
+ total_entries.zero? ? 1 : (total_entries / per_page.to_f).ceil
+ end
+
+ # current_page - 1 or nil if there is no previous page
+ def previous_page
+ current_page > 1 ? (current_page - 1) : nil
+ end
+
+ # current_page + 1 or nil if there is no next page
+ def next_page
+ current_page < total_pages ? (current_page + 1) : nil
+ end
+
+ # Helper method that is true when someone tries to fetch a page with a
+ # larger number than the last page. Can be used in combination with flashes
+ # and redirecting.
+ def out_of_bounds?
+ current_page > total_pages
+ end
+ end
+
# = The key to pagination
# Arrays returned from paginating finds are, in fact, instances of this little
# class. You may think of WillPaginate::Collection as an ordinary array with
@@ -18,7 +50,9 @@ module WillPaginate
# require 'will_paginate/collection'
# # WillPaginate::Collection is now available for use
class Collection < Array
- attr_reader :current_page, :per_page, :total_entries, :total_pages
+ include CollectionMethods
+
+ attr_reader :current_page, :per_page, :total_entries
# Arguments to the constructor are the current page number, per-page limit
# and the total number of entries. The last argument is optional because it
@@ -63,35 +97,16 @@ def self.create(page, per_page, total = nil)
pager
end
- # Helper method that is true when someone tries to fetch a page with a
- # larger number than the last page. Can be used in combination with flashes
- # and redirecting.
- def out_of_bounds?
- current_page > total_pages
- end
-
# Current offset of the paginated collection. If we're on the first page,
# it is always 0. If we're on the 2nd page and there are 30 entries per page,
# the offset is 30. This property is useful if you want to render ordinals
# side by side with records in the view: simply start with offset + 1.
def offset
- @current_page.to_offset(per_page).to_i
- end
-
- # current_page - 1 or nil if there is no previous page
- def previous_page
- current_page > 1 ? (current_page - 1) : nil
+ current_page.to_offset(per_page).to_i
end
- # current_page + 1 or nil if there is no next page
- def next_page
- current_page < total_pages ? (current_page + 1) : nil
- end
-
- # sets the total_entries property and calculates total_pages
def total_entries=(number)
@total_entries = number.to_i
- @total_pages = (@total_entries / per_page.to_f).ceil
end
# This is a magic wrapper for the original Array#replace method. It serves
diff --git a/lib/will_paginate/data_mapper.rb b/lib/will_paginate/data_mapper.rb
index 3aff3fb97..330ca5022 100644
--- a/lib/will_paginate/data_mapper.rb
+++ b/lib/will_paginate/data_mapper.rb
@@ -30,6 +30,8 @@ def paginate(options)
end
module CollectionMethods
+ include WillPaginate::CollectionMethods
+
attr_accessor :current_page
def paginated?
@@ -58,10 +60,6 @@ def total_entries
end
end
- def total_pages
- (total_entries / per_page.to_f).ceil
- end
-
def to_a
::WillPaginate::Collection.create(current_page, per_page) do |col|
col.replace super
diff --git a/lib/will_paginate/sequel.rb b/lib/will_paginate/sequel.rb
index 3fb740d1e..07f794d5e 100644
--- a/lib/will_paginate/sequel.rb
+++ b/lib/will_paginate/sequel.rb
@@ -1,10 +1,13 @@
require 'sequel'
require 'sequel/extensions/pagination'
+require 'will_paginate/collection'
module WillPaginate
# Sequel already supports pagination; we only need to make the
# resulting dataset look a bit more like WillPaginate::Collection
module SequelMethods
+ include WillPaginate::CollectionMethods
+
def total_pages
page_count
end
diff --git a/spec/collection_spec.rb b/spec/collection_spec.rb
index 98050dc7d..d561e8376 100644
--- a/spec/collection_spec.rb
+++ b/spec/collection_spec.rb
@@ -71,12 +71,20 @@
end
end
- it "should show out of bounds when page number is too high" do
- create(2, 3, 2).should be_out_of_bounds
- end
-
- it "should not show out of bounds when inside collection" do
- create(1, 3, 2).should_not be_out_of_bounds
+ describe "out of bounds" do
+ it "is out of bounds when page number is too high" do
+ create(2, 3, 2).should be_out_of_bounds
+ end
+
+ it "isn't out of bounds when inside collection" do
+ create(1, 3, 2).should_not be_out_of_bounds
+ end
+
+ it "isn't out of bounds when the collection is empty" do
+ collection = create(1, 3, 0)
+ collection.should_not be_out_of_bounds
+ collection.total_pages.should == 1
+ end
end
describe "guessing total count" do
diff --git a/spec/finders/active_record_spec.rb b/spec/finders/active_record_spec.rb
index 102af0650..f1e544720 100644
--- a/spec/finders/active_record_spec.rb
+++ b/spec/finders/active_record_spec.rb
@@ -179,6 +179,10 @@
it "should count with group" do
Developer.group(:salary).page(1).total_entries.should == 4
end
+
+ it "should not have zero total_pages when the result set is empty" do
+ Developer.where("1 = 2").page(1).total_pages.should == 1
+ end
end
it "should not ignore :select parameter when it says DISTINCT" do
diff --git a/spec/finders/data_mapper_spec.rb b/spec/finders/data_mapper_spec.rb
index c452b8e81..67929b6ec 100644
--- a/spec/finders/data_mapper_spec.rb
+++ b/spec/finders/data_mapper_spec.rb
@@ -76,4 +76,8 @@
Animal.all(:limit => 2).page(2).per_page.should == 2
end
+ it "has total_pages at 1 for empty collections" do
+ Animal.all(:conditions => ['1=2']).page(1).total_pages.should == 1
+ end
+
end if datamapper_loaded