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