will_paginate-3.0.5/0000755000004100000410000000000012261225505014366 5ustar www-datawww-datawill_paginate-3.0.5/spec/0000755000004100000410000000000012261225505015320 5ustar www-datawww-datawill_paginate-3.0.5/spec/fake_rubygems.rb0000644000004100000410000000073012261225505020470 0ustar www-datawww-data# Makes the test suite compatible with Bundler standalone mode (used in CI) # because Active Record uses `gem` for loading adapters. Kernel.module_eval do remove_method :gem if 'method' == defined? gem def gem(*args) return if $VERBOSE.nil? $stderr << "warning: gem(#{args.map {|o| o.inspect }.join(', ')}) ignored" $stderr << "; called from:\n " << caller[0,5].join("\n ") if $DEBUG $stderr << "\n" end private :gem end $" << "rubygems.rb" will_paginate-3.0.5/spec/spec_helper.rb0000644000004100000410000000252212261225505020137 0ustar www-datawww-datarequire 'rspec' require 'view_helpers/view_example_group' begin require 'ruby-debug' rescue LoadError # no debugger available end RSpec.configure do |config| config.include Module.new { protected def include_phrase(string) PhraseMatcher.new(string) end def have_deprecation(msg) DeprecationMatcher.new(msg) end } config.mock_with :mocha config.backtrace_clean_patterns << /view_example_group/ end class PhraseMatcher def initialize(string) @string = string @pattern = /\b#{Regexp.escape string}\b/ end def matches?(actual) @actual = actual.to_s @actual =~ @pattern end def failure_message "expected #{@actual.inspect} to contain phrase #{@string.inspect}" end def negative_failure_message "expected #{@actual.inspect} not to contain phrase #{@string.inspect}" end end require 'stringio' class DeprecationMatcher def initialize(message) @message = message end def matches?(block) @actual = hijack_stderr(&block) PhraseMatcher.new("DEPRECATION WARNING: #{@message}").matches?(@actual) end def failure_message "expected deprecation warning #{@message.inspect}, got #{@actual.inspect}" end private def hijack_stderr err = $stderr $stderr = StringIO.new yield $stderr.string.rstrip ensure $stderr = err end end will_paginate-3.0.5/spec/per_page_spec.rb0000644000004100000410000000142012261225505020436 0ustar www-datawww-datarequire 'spec_helper' require 'will_paginate/per_page' describe WillPaginate::PerPage do class MyModel extend WillPaginate::PerPage end it "has the default value" do MyModel.per_page.should == 30 WillPaginate.per_page = 10 begin MyModel.per_page.should == 10 ensure WillPaginate.per_page = 30 end end it "casts values to int" do WillPaginate.per_page = '10' begin MyModel.per_page.should == 10 ensure WillPaginate.per_page = 30 end end it "has an explicit value" do MyModel.per_page = 12 begin MyModel.per_page.should == 12 subclass = Class.new(MyModel) subclass.per_page.should == 12 ensure MyModel.send(:remove_instance_variable, '@per_page') end end end will_paginate-3.0.5/spec/finders/0000755000004100000410000000000012261225505016752 5ustar www-datawww-datawill_paginate-3.0.5/spec/finders/active_record_spec.rb0000644000004100000410000004053012261225505023124 0ustar www-datawww-datarequire 'spec_helper' require 'will_paginate/active_record' require File.expand_path('../activerecord_test_connector', __FILE__) ActiverecordTestConnector.setup abort unless ActiverecordTestConnector.able_to_connect describe WillPaginate::ActiveRecord do extend ActiverecordTestConnector::FixtureSetup fixtures :topics, :replies, :users, :projects, :developers_projects it "should integrate with ActiveRecord::Base" do ActiveRecord::Base.should respond_to(:paginate) end it "should paginate" do lambda { users = User.paginate(:page => 1, :per_page => 5).to_a users.length.should == 5 }.should run_queries(2) end it "should fail when encountering unknown params" do lambda { User.paginate :foo => 'bar', :page => 1, :per_page => 4 }.should raise_error(ArgumentError) end describe "relation" do it "should return a relation" do rel = nil lambda { rel = Developer.paginate(:page => 1) rel.per_page.should == 10 rel.current_page.should == 1 }.should run_queries(0) lambda { rel.total_pages.should == 2 }.should run_queries(1) end it "should keep per-class per_page number" do rel = Developer.order('id').paginate(:page => 1) rel.per_page.should == 10 end it "should be able to change per_page number" do rel = Developer.order('id').paginate(:page => 1).limit(5) rel.per_page.should == 5 end it "remembers pagination in sub-relations" do rel = Topic.paginate(:page => 2, :per_page => 3) lambda { rel.total_entries.should == 4 }.should run_queries(1) rel = rel.mentions_activerecord rel.current_page.should == 2 rel.per_page.should == 3 lambda { rel.total_entries.should == 1 }.should run_queries(1) end it "supports the page() method" do rel = Developer.page('1').order('id') rel.current_page.should == 1 rel.per_page.should == 10 rel.offset.should == 0 rel = rel.limit(5).page(2) rel.per_page.should == 5 rel.offset.should == 5 end it "raises on invalid page number" do lambda { Developer.page('foo') }.should raise_error(ArgumentError) end it "supports first limit() then page()" do rel = Developer.limit(3).page(3) rel.offset.should == 6 end it "supports first page() then limit()" do rel = Developer.page(3).limit(3) rel.offset.should == 6 end it "supports #first" do rel = Developer.order('id').page(2).per_page(4) rel.first.should == users(:dev_5) rel.first(2).should == users(:dev_5, :dev_6) end it "supports #last" do rel = Developer.order('id').page(2).per_page(4) rel.last.should == users(:dev_8) rel.last(2).should == users(:dev_7, :dev_8) rel.page(3).last.should == users(:poor_jamis) end it "keeps pagination data after 'scoped'" do rel = Developer.page(2).scoped rel.per_page.should == 10 rel.offset.should == 10 rel.current_page.should == 2 end end describe "counting" do it "should guess the total count" do lambda { topics = Topic.paginate :page => 2, :per_page => 3 topics.total_entries.should == 4 }.should run_queries(1) end it "should guess that there are no records" do lambda { topics = Topic.where(:project_id => 999).paginate :page => 1, :per_page => 3 topics.total_entries.should == 0 }.should run_queries(1) end it "forgets count in sub-relations" do lambda { topics = Topic.paginate :page => 1, :per_page => 3 topics.total_entries.should == 4 topics.where('1 = 1').total_entries.should == 4 }.should run_queries(2) end it "remembers custom count options in sub-relations" do topics = Topic.paginate :page => 1, :per_page => 3, :count => {:conditions => "title LIKE '%futurama%'"} topics.total_entries.should == 1 topics.length.should == 3 lambda { topics.order('id').total_entries.should == 1 }.should run_queries(1) end it "supports empty? method" do topics = Topic.paginate :page => 1, :per_page => 3 lambda { topics.should_not be_empty }.should run_queries(1) end it "support empty? for grouped queries" do topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3 lambda { topics.should_not be_empty }.should run_queries(1) end it "supports `size` for grouped queries" do topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3 lambda { topics.size.should == {nil=>2, 1=>2} }.should run_queries(1) end it "overrides total_entries count with a fixed value" do lambda { topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => 999 topics.total_entries.should == 999 # value is kept even in sub-relations topics.where('1 = 1').total_entries.should == 999 }.should run_queries(0) end it "supports a non-int for total_entries" do topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => "999" topics.total_entries.should == 999 end it "removes :include for count" do lambda { developers = Developer.paginate(:page => 1, :per_page => 1).includes(:projects) developers.total_entries.should == 11 $query_sql.last.should_not =~ /\bJOIN\b/ }.should run_queries(1) end it "keeps :include for count when they are referenced in :conditions" do developers = Developer.paginate(:page => 1, :per_page => 1).includes(:projects) with_condition = developers.where('projects.id > 1') with_condition.total_entries.should == 1 $query_sql.last.should =~ /\bJOIN\b/ end it "should count with group" do Developer.group(:salary).page(1).total_entries.should == 4 end it "removes :reorder for count with group" do Project.group(:id).reorder(:id).page(1).total_entries $query_sql.last.should_not =~ /\ORDER\b/ 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 users = User.select('DISTINCT salary').paginate :page => 2 users.total_entries.should == 5 end describe "paginate_by_sql" do it "should respond" do User.should respond_to(:paginate_by_sql) end it "should paginate" do lambda { sql = "select content from topics where content like '%futurama%'" topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1 topics.total_entries.should == 1 topics.first.attributes.has_key?('title').should be_false }.should run_queries(2) end it "should respect total_entries setting" do lambda { sql = "select content from topics" topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1, :total_entries => 999 topics.total_entries.should == 999 }.should run_queries(1) end it "defaults to page 1" do sql = "select content from topics" topics = Topic.paginate_by_sql sql, :page => nil, :per_page => 1 topics.current_page.should == 1 topics.size.should == 1 end it "should strip the order when counting" do lambda { sql = "select id, title, content from topics order by topics.title" topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 2 topics.first.should == topics(:ar) }.should run_queries(2) $query_sql.last.should include('COUNT') $query_sql.last.should_not include('order by topics.title') end it "shouldn't change the original query string" do query = 'select * from topics where 1 = 2' original_query = query.dup Topic.paginate_by_sql(query, :page => 1) query.should == original_query end end it "doesn't mangle options" do options = { :page => 1 } options.expects(:delete).never options_before = options.dup Topic.paginate(options) options.should == options_before end it "should get first page of Topics with a single query" do lambda { result = Topic.paginate :page => nil result.to_a # trigger loading of records result.current_page.should == 1 result.total_pages.should == 1 result.size.should == 4 }.should run_queries(1) end it "should get second (inexistent) page of Topics, requiring 2 queries" do lambda { result = Topic.paginate :page => 2 result.total_pages.should == 1 result.should be_empty }.should run_queries(2) end it "should paginate with :order" do result = Topic.paginate :page => 1, :order => 'created_at DESC' result.should == topics(:futurama, :harvey_birdman, :rails, :ar).reverse result.total_pages.should == 1 end it "should paginate with :conditions" do result = Topic.paginate :page => 1, :order => 'id ASC', :conditions => ["created_at > ?", 30.minutes.ago] result.should == topics(:rails, :ar) result.total_pages.should == 1 end it "should paginate with :include and :conditions" do result = Topic.paginate \ :page => 1, :include => :replies, :conditions => "replies.content LIKE 'Bird%' ", :per_page => 10 expected = Topic.find :all, :include => 'replies', :conditions => "replies.content LIKE 'Bird%' ", :limit => 10 result.should == expected result.total_entries.should == 1 end it "should paginate with :include and :order" do result = nil lambda { result = Topic.paginate(:page => 1, :include => :replies, :per_page => 10, :order => 'replies.created_at asc, topics.created_at asc').to_a }.should run_queries(2) expected = Topic.find :all, :include => 'replies', :order => 'replies.created_at asc, topics.created_at asc', :limit => 10 result.should == expected result.total_entries.should == 4 end describe "associations" do it "should paginate with include" do project = projects(:active_record) result = project.topics.paginate \ :page => 1, :include => :replies, :conditions => ["replies.content LIKE ?", 'Nice%'], :per_page => 10 expected = Topic.find :all, :include => 'replies', :conditions => ["project_id = ? AND replies.content LIKE ?", project.id, 'Nice%'], :limit => 10 result.should == expected end it "should paginate" do dhh = users(:david) expected_name_ordered = projects(:action_controller, :active_record) expected_id_ordered = projects(:active_record, :action_controller) lambda { # with association-specified order result = ignore_deprecation { dhh.projects.paginate(:page => 1) } result.should == expected_name_ordered result.total_entries.should == 2 }.should run_queries(2) # with explicit order result = dhh.projects.paginate(:page => 1).reorder('projects.id') result.should == expected_id_ordered result.total_entries.should == 2 lambda { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) }.should_not raise_error result = dhh.projects.paginate(:page => 1, :per_page => 4).reorder('projects.id') result.should == expected_id_ordered # has_many with implicit order topic = Topic.find(1) expected = replies(:spam, :witty_retort) # FIXME: wow, this is ugly topic.replies.paginate(:page => 1).map(&:id).sort.should == expected.map(&:id).sort topic.replies.paginate(:page => 1).reorder('replies.id ASC').should == expected.reverse end it "should paginate through association extension" do project = Project.order('id').first expected = [replies(:brave)] lambda { result = project.replies.only_recent.paginate(:page => 1) result.should == expected }.should run_queries(1) end end it "should paginate with joins" do result = nil join_sql = 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id' lambda { result = Developer.paginate(:page => 1, :joins => join_sql, :conditions => 'project_id = 1') result.to_a # trigger loading of records result.size.should == 2 developer_names = result.map(&:name) developer_names.should include('David') developer_names.should include('Jamis') }.should run_queries(1) lambda { expected = result.to_a result = Developer.paginate(:page => 1, :joins => join_sql, :conditions => 'project_id = 1', :count => { :select => "users.id" }).to_a result.should == expected result.total_entries.should == 2 }.should run_queries(1) end it "should paginate with group" do result = nil lambda { result = Developer.paginate(:page => 1, :per_page => 10, :group => 'salary', :select => 'salary', :order => 'salary').to_a }.should run_queries(1) expected = users(:david, :jamis, :dev_10, :poor_jamis).map(&:salary).sort result.map(&:salary).should == expected end it "should not paginate with dynamic finder" do lambda { Developer.paginate_by_salary(100000, :page => 1, :per_page => 5) }.should raise_error(NoMethodError) end it "should paginate with_scope" do result = Developer.with_poor_ones { Developer.paginate :page => 1 } result.size.should == 2 result.total_entries.should == 2 end describe "scopes" do it "should paginate" do result = Developer.poor.paginate :page => 1, :per_page => 1 result.size.should == 1 result.total_entries.should == 2 end it "should paginate on habtm association" do project = projects(:active_record) lambda { result = ignore_deprecation { project.developers.poor.paginate :page => 1, :per_page => 1 } result.size.should == 1 result.total_entries.should == 1 }.should run_queries(2) end it "should paginate on hmt association" do project = projects(:active_record) expected = [replies(:brave)] lambda { result = project.replies.recent.paginate :page => 1, :per_page => 1 result.should == expected result.total_entries.should == 1 }.should run_queries(2) end it "should paginate on has_many association" do project = projects(:active_record) expected = [topics(:ar)] lambda { result = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1 result.should == expected result.total_entries.should == 1 }.should run_queries(2) end end it "should paginate with :readonly option" do lambda { Developer.paginate :readonly => true, :page => 1 }.should_not raise_error end it "should not paginate an array of IDs" do lambda { Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id') }.should raise_error(ArgumentError) end it "errors out for invalid values" do |variable| lambda { # page that results in an offset larger than BIGINT Project.page(307445734561825862) }.should raise_error(WillPaginate::InvalidPage, "invalid offset: 9223372036854775830") end protected def ignore_deprecation ActiveSupport::Deprecation.silence { yield } end def run_queries(num) QueryCountMatcher.new(num) end def show_queries(&block) counter = QueryCountMatcher.new(nil) counter.run block ensure queries = counter.performed_queries if queries.any? puts queries else puts "no queries" end end end class QueryCountMatcher def initialize(num) @expected_count = num end def matches?(block) run(block) if @expected_count.respond_to? :include? @expected_count.include? @count else @count == @expected_count end end def run(block) $query_count = 0 $query_sql = [] block.call ensure @queries = $query_sql.dup @count = $query_count end def performed_queries @queries end def failure_message "expected #{@expected_count} queries, got #{@count}\n#{@queries.join("\n")}" end def negative_failure_message "expected query count not to be #{@expected_count}" end end will_paginate-3.0.5/spec/finders/sequel_spec.rb0000644000004100000410000000345112261225505021612 0ustar www-datawww-datarequire 'spec_helper' begin require 'will_paginate/sequel' require File.expand_path('../sequel_test_connector', __FILE__) rescue LoadError, ArgumentError => error warn "Error running Sequel specs: #{error.message}" sequel_loaded = false else sequel_loaded = true end describe Sequel::Dataset::Pagination, 'extension' do class Car < Sequel::Model end it "should have the #paginate method" do Car.should respond_to(:paginate) end it "should NOT have the #paginate_by_sql method" do Car.should_not respond_to(:paginate_by_sql) end describe 'pagination' do before(:all) do Car.create(:name => 'Shelby', :notes => "Man's best friend") Car.create(:name => 'Aston Martin', :notes => "Woman's best friend") Car.create(:name => 'Corvette', :notes => 'King of the Jungle') end it "should imitate WillPaginate::Collection" do result = Car.paginate(1, 2) result.should_not be_empty result.size.should == 2 result.length.should == 2 result.total_entries.should == 3 result.total_pages.should == 2 result.per_page.should == 2 result.current_page.should == 1 end it "should perform" do Car.paginate(1, 2).all.should == [Car[1], Car[2]] end it "should be empty" do result = Car.paginate(3, 2) result.should be_empty end it "should perform with #select and #order" do result = Car.select("name as foo".lit).order(:name).paginate(1, 2).all result.size.should == 2 result.first.values[:foo].should == "Aston Martin" end it "should perform with #filter" do results = Car.filter(:name => 'Shelby').paginate(1, 2).all results.size.should == 1 results.first.should == Car.find(:name => 'Shelby') end end end if sequel_loaded will_paginate-3.0.5/spec/finders/data_mapper_spec.rb0000644000004100000410000000543612261225505022576 0ustar www-datawww-datarequire 'spec_helper' begin require 'will_paginate/data_mapper' require File.expand_path('../data_mapper_test_connector', __FILE__) rescue LoadError => error warn "Error running DataMapper specs: #{error.message}" datamapper_loaded = false else datamapper_loaded = true end describe WillPaginate::DataMapper do it "has per_page" do Animal.per_page.should == 30 begin Animal.per_page = 10 Animal.per_page.should == 10 subclass = Class.new(Animal) subclass.per_page.should == 10 ensure Animal.per_page = 30 end end it "doesn't make normal collections appear paginated" do Animal.all.should_not be_paginated end it "paginates to first page by default" do animals = Animal.paginate(:page => nil) animals.should be_paginated animals.current_page.should == 1 animals.per_page.should == 30 animals.offset.should == 0 animals.total_entries.should == 3 animals.total_pages.should == 1 end it "paginates to first page, explicit limit" do animals = Animal.paginate(:page => 1, :per_page => 2) animals.current_page.should == 1 animals.per_page.should == 2 animals.total_entries.should == 3 animals.total_pages.should == 2 animals.map {|a| a.name }.should == %w[ Dog Cat ] end it "paginates to second page" do animals = Animal.paginate(:page => 2, :per_page => 2) animals.current_page.should == 2 animals.offset.should == 2 animals.map {|a| a.name }.should == %w[ Lion ] end it "paginates a collection" do friends = Animal.all(:notes.like => '%friend%') friends.paginate(:page => 1).per_page.should == 30 friends.paginate(:page => 1, :per_page => 1).total_entries.should == 2 end it "paginates a limited collection" do animals = Animal.all(:limit => 2).paginate(:page => 1) animals.per_page.should == 2 end it "has page() method" do Animal.page(2).per_page.should == 30 Animal.page(2).offset.should == 30 Animal.page(2).current_page.should == 2 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 it "can iterate and then call WP methods" do animals = Animal.all(:limit => 2).page(1) animals.each { |a| } animals.total_entries.should == 3 end it "augments to_a to return a WP::Collection" do animals = Animal.all(:limit => 2).page(1) array = animals.to_a array.size.should == 2 array.should be_kind_of(WillPaginate::Collection) array.current_page.should == 1 array.per_page.should == 2 end it "doesn't have a problem assigning has-one-through relationship" do human = Human.create :name => "Mislav" human.pet = Animal.first end end if datamapper_loaded will_paginate-3.0.5/spec/finders/activerecord_test_connector.rb0000644000004100000410000000660112261225505025065 0ustar www-datawww-datarequire 'active_record' require 'active_record/fixtures' require 'active_support/multibyte' # needed for Ruby 1.9.1 $query_count = 0 $query_sql = [] ignore_sql = / ^( PRAGMA | SHOW\ max_identifier_length | SELECT\ (currval|CAST|@@IDENTITY|@@ROWCOUNT) | SHOW\ (FIELDS|TABLES) )\b | \bFROM\ (sqlite_master|pg_tables|pg_attribute)\b /x ActiveSupport::Notifications.subscribe(/^sql\./) do |*args| payload = args.last unless payload[:name] =~ /^Fixture/ or payload[:sql] =~ ignore_sql $query_count += 1 $query_sql << payload[:sql] end end module ActiverecordTestConnector extend self attr_accessor :able_to_connect attr_accessor :connected FIXTURES_PATH = File.expand_path('../../fixtures', __FILE__) Fixtures = defined?(ActiveRecord::FixtureSet) ? ActiveRecord::FixtureSet : defined?(ActiveRecord::Fixtures) ? ActiveRecord::Fixtures : ::Fixtures # Set our defaults self.connected = false self.able_to_connect = true def setup unless self.connected || !self.able_to_connect setup_connection load_schema add_load_path FIXTURES_PATH self.connected = true end rescue Exception => e # errors from ActiveRecord setup $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n" self.able_to_connect = false end private def add_load_path(path) dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies dep.autoload_paths.unshift path end def setup_connection db = ENV['DB'].blank?? 'sqlite3' : ENV['DB'] configurations = YAML.load_file(File.expand_path('../../database.yml', __FILE__)) raise "no configuration for '#{db}'" unless configurations.key? db configuration = configurations[db] # ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb' puts "using #{configuration['adapter']} adapter" ActiveRecord::Base.configurations = { db => configuration } ActiveRecord::Base.establish_connection(db) ActiveRecord::Base.default_timezone = :utc end def load_schema silencer = ActiveRecord::Base.method(:silence) silence_args = [] silence_args << :stdout if silencer.arity != 0 silencer.call(*silence_args) do ActiveRecord::Migration.verbose = false load File.join(FIXTURES_PATH, 'schema.rb') end end module FixtureSetup def fixtures(*tables) table_names = tables.map { |t| t.to_s } fixtures = Fixtures.create_fixtures ActiverecordTestConnector::FIXTURES_PATH, table_names @@loaded_fixtures = {} @@fixture_cache = {} unless fixtures.nil? if fixtures.instance_of?(Fixtures) @@loaded_fixtures[fixtures.table_name] = fixtures else fixtures.each { |f| @@loaded_fixtures[f.table_name] = f } end end table_names.each do |table_name| define_method(table_name) do |*fixtures| @@fixture_cache[table_name] ||= {} instances = fixtures.map do |fixture| if @@loaded_fixtures[table_name][fixture.to_s] @@fixture_cache[table_name][fixture] ||= @@loaded_fixtures[table_name][fixture.to_s].find else raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'" end end instances.size == 1 ? instances.first : instances end end end end end will_paginate-3.0.5/spec/finders/sequel_test_connector.rb0000644000004100000410000000056612261225505023715 0ustar www-datawww-datarequire 'sequel' Symbol.class_eval do # Active Record calculations tries `as` on some objects but chokes when that # object was a Symbol and it gets a Sequel::SQL::AliasedExpression. undef as if method_defined? :as end db = Sequel.sqlite db.create_table :cars do primary_key :id, :integer, :auto_increment => true column :name, :text column :notes, :text end will_paginate-3.0.5/spec/finders/data_mapper_test_connector.rb0000644000004100000410000000205512261225505024667 0ustar www-datawww-datarequire 'sqlite3' require 'dm-core' require 'dm-core/support/logger' require 'dm-migrations' DataMapper.setup :default, 'sqlite3::memory:' # Define models class Animal include DataMapper::Resource property :id, Serial property :name, String property :notes, Text def self.setup Animal.create(:name => 'Dog', :notes => "Man's best friend") Animal.create(:name => 'Cat', :notes => "Woman's best friend") Animal.create(:name => 'Lion', :notes => 'King of the Jungle') end end class Ownership include DataMapper::Resource belongs_to :animal, :key => true belongs_to :human, :key => true def self.setup end end class Human include DataMapper::Resource property :id, Serial property :name, String has n, :ownerships has 1, :pet, :model => 'Animal', :through => :ownerships, :via => :animal def self.setup end end # Load fixtures [Animal, Ownership, Human].each do |klass| klass.auto_migrate! klass.setup end if 'irb' == $0 DataMapper.logger.set_log($stdout, :debug) DataMapper.logger.auto_flush = true end will_paginate-3.0.5/spec/fixtures/0000755000004100000410000000000012261225505017171 5ustar www-datawww-datawill_paginate-3.0.5/spec/fixtures/replies.yml0000644000004100000410000000106012261225505021354 0ustar www-datawww-datawitty_retort: id: 1 topic_id: 1 content: Birdman is better! created_at: <%= 6.hours.ago.utc.to_s(:db) %> another: id: 2 topic_id: 2 content: Nuh uh! created_at: <%= 1.hour.ago.utc.to_s(:db) %> spam: id: 3 topic_id: 1 content: Nice site! created_at: <%= 1.hour.ago.utc.to_s(:db) %> decisive: id: 4 topic_id: 4 content: "I'm getting to the bottom of this" created_at: <%= 30.minutes.ago.utc.to_s(:db) %> brave: id: 5 topic_id: 4 content: "AR doesn't scare me a bit" created_at: <%= 10.minutes.ago.utc.to_s(:db) %> will_paginate-3.0.5/spec/fixtures/project.rb0000644000004100000410000000106012261225505021161 0ustar www-datawww-dataclass Project < ActiveRecord::Base has_and_belongs_to_many :developers, :uniq => true, :join_table => 'developers_projects' has_many :topics # :finder_sql => 'SELECT * FROM topics WHERE (topics.project_id = #{id})', # :counter_sql => 'SELECT COUNT(*) FROM topics WHERE (topics.project_id = #{id})' has_many :replies, :through => :topics do def only_recent(params = {}) scoped.where(['replies.created_at > ?', 15.minutes.ago]) end end has_many :unique_replies, :through => :topics, :source => :replies, :uniq => true end will_paginate-3.0.5/spec/fixtures/admin.rb0000644000004100000410000000012712261225505020606 0ustar www-datawww-dataclass Admin < User has_many :companies, :finder_sql => 'SELECT * FROM companies' end will_paginate-3.0.5/spec/fixtures/topic.rb0000644000004100000410000000046612261225505020642 0ustar www-datawww-dataclass Topic < ActiveRecord::Base has_many :replies, :dependent => :destroy, :order => 'replies.created_at DESC' belongs_to :project scope :mentions_activerecord, lambda { where(['topics.title LIKE ?', '%ActiveRecord%']) } scope :distinct, lambda { select("DISTINCT #{table_name}.*") } end will_paginate-3.0.5/spec/fixtures/schema.rb0000644000004100000410000000212612261225505020757 0ustar www-datawww-dataActiveRecord::Schema.define do create_table "users", :force => true do |t| t.column "name", :text t.column "salary", :integer, :default => 70000 t.column "created_at", :datetime t.column "updated_at", :datetime t.column "type", :text end create_table "projects", :force => true do |t| t.column "name", :text end create_table "developers_projects", :id => false, :force => true do |t| t.column "developer_id", :integer, :null => false t.column "project_id", :integer, :null => false t.column "joined_on", :date t.column "access_level", :integer, :default => 1 end create_table "topics", :force => true do |t| t.column "project_id", :integer t.column "title", :string t.column "subtitle", :string t.column "content", :text t.column "created_at", :datetime t.column "updated_at", :datetime end create_table "replies", :force => true do |t| t.column "content", :text t.column "created_at", :datetime t.column "updated_at", :datetime t.column "topic_id", :integer end end will_paginate-3.0.5/spec/fixtures/reply.rb0000644000004100000410000000036012261225505020650 0ustar www-datawww-dataclass Reply < ActiveRecord::Base belongs_to :topic, :include => [:replies] scope :recent, lambda { where(['replies.created_at > ?', 15.minutes.ago]). order('replies.created_at DESC') } validates_presence_of :content end will_paginate-3.0.5/spec/fixtures/developer.rb0000644000004100000410000000063012261225505021502 0ustar www-datawww-dataclass Developer < User has_and_belongs_to_many :projects, :include => :topics, :order => 'projects.name', :join_table => 'developers_projects' def self.with_poor_ones(&block) with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do yield end end scope :poor, lambda { where(['salary <= ?', 80000]).order('salary') } def self.per_page() 10 end end will_paginate-3.0.5/spec/fixtures/projects.yml0000644000004100000410000000014212261225505021542 0ustar www-datawww-dataactive_record: id: 1 name: Active Record action_controller: id: 2 name: Action Controller will_paginate-3.0.5/spec/fixtures/user.rb0000644000004100000410000000004412261225505020472 0ustar www-datawww-dataclass User < ActiveRecord::Base end will_paginate-3.0.5/spec/fixtures/users.yml0000644000004100000410000000065012261225505021056 0ustar www-datawww-datadavid: id: 1 name: David salary: 80000 type: Developer jamis: id: 2 name: Jamis salary: 150000 type: Developer <% for digit in 3..10 %> dev_<%= digit %>: id: <%= digit %> name: fixture_<%= digit %> salary: 100000 type: Developer <% end %> poor_jamis: id: 11 name: Jamis salary: 9000 type: Developer admin: id: 12 name: admin type: Admin goofy: id: 13 name: Goofy type: Admin will_paginate-3.0.5/spec/fixtures/topics.yml0000644000004100000410000000135412261225505021220 0ustar www-datawww-datafuturama: id: 1 title: Isnt futurama awesome? subtitle: It really is, isnt it. content: I like futurama created_at: <%= 1.day.ago.utc.to_s(:db) %> updated_at: harvey_birdman: id: 2 title: Harvey Birdman is the king of all men subtitle: yup content: He really is created_at: <%= 2.hours.ago.utc.to_s(:db) %> updated_at: rails: id: 3 project_id: 1 title: Rails is nice subtitle: It makes me happy content: except when I have to hack internals to fix pagination. even then really. created_at: <%= 20.minutes.ago.utc.to_s(:db) %> ar: id: 4 project_id: 1 title: ActiveRecord sometimes freaks me out content: "I mean, what's the deal with eager loading?" created_at: <%= 15.minutes.ago.utc.to_s(:db) %> will_paginate-3.0.5/spec/fixtures/developers_projects.yml0000644000004100000410000000033212261225505023773 0ustar www-datawww-datadavid_action_controller: developer_id: 1 project_id: 2 joined_on: 2004-10-10 david_active_record: developer_id: 1 project_id: 1 joined_on: 2004-10-10 jamis_active_record: developer_id: 2 project_id: 1will_paginate-3.0.5/spec/page_number_spec.rb0000644000004100000410000000373112261225505021147 0ustar www-datawww-datarequire 'spec_helper' require 'will_paginate/page_number' describe WillPaginate::PageNumber do describe "valid" do subject { described_class.new('12', 'page') } it { should eq(12) } its(:inspect) { should eq('page 12') } it { should be_a(WillPaginate::PageNumber) } it { should be_instance_of(WillPaginate::PageNumber) } it { should be_a(Numeric) } it { should be_a(Fixnum) } it { should_not be_instance_of(Fixnum) } it "passes the PageNumber=== type check" do |variable| (WillPaginate::PageNumber === subject).should be end it "passes the Numeric=== type check" do |variable| (Numeric === subject).should be (Fixnum === subject).should be end end describe "invalid" do def create(value, name = 'page') described_class.new(value, name) end it "errors out on non-int values" do lambda { create(nil) }.should raise_error(WillPaginate::InvalidPage) lambda { create('') }.should raise_error(WillPaginate::InvalidPage) lambda { create('Schnitzel') }.should raise_error(WillPaginate::InvalidPage) end it "errors out on zero or less" do lambda { create(0) }.should raise_error(WillPaginate::InvalidPage) lambda { create(-1) }.should raise_error(WillPaginate::InvalidPage) end it "doesn't error out on zero for 'offset'" do lambda { create(0, 'offset') }.should_not raise_error lambda { create(-1, 'offset') }.should raise_error(WillPaginate::InvalidPage) end end describe "coercion method" do it "defaults to 'page' name" do num = WillPaginate::PageNumber(12) num.inspect.should eq('page 12') end it "accepts a custom name" do num = WillPaginate::PageNumber(12, 'monkeys') num.inspect.should eq('monkeys 12') end it "doesn't affect PageNumber instances" do num = WillPaginate::PageNumber(12) num2 = WillPaginate::PageNumber(num) num2.object_id.should eq(num.object_id) end end end will_paginate-3.0.5/spec/database.yml0000644000004100000410000000051612261225505017611 0ustar www-datawww-datasqlite3: database: ":memory:" adapter: sqlite3 timeout: 500 mysql: adapter: mysql database: will_paginate username: encoding: utf8 mysql2: adapter: mysql2 database: will_paginate username: encoding: utf8 postgres: adapter: postgresql database: will_paginate username: postgres min_messages: warning will_paginate-3.0.5/spec/view_helpers/0000755000004100000410000000000012261225505020014 5ustar www-datawww-datawill_paginate-3.0.5/spec/view_helpers/link_renderer_base_spec.rb0000644000004100000410000000523412261225505025174 0ustar www-datawww-datarequire 'spec_helper' require 'will_paginate/view_helpers/link_renderer_base' require 'will_paginate/collection' describe WillPaginate::ViewHelpers::LinkRendererBase do before do @renderer = described_class.new end it "should raise error when unprepared" do lambda { @renderer.pagination }.should raise_error end it "should prepare with collection and options" do prepare({}) @renderer.send(:current_page).should == 1 end it "should have total_pages accessor" do prepare :total_pages => 42 @renderer.send(:total_pages).should == 42 end it "should clear old cached values when prepared" do prepare(:total_pages => 1) @renderer.send(:total_pages).should == 1 # prepare with different object: prepare(:total_pages => 2) @renderer.send(:total_pages).should == 2 end it "should have pagination definition" do prepare({ :total_pages => 1 }, :page_links => true) @renderer.pagination.should == [:previous_page, 1, :next_page] end describe "visible page numbers" do it "should calculate windowed visible links" do prepare({ :page => 6, :total_pages => 11 }, :inner_window => 1, :outer_window => 1) showing_pages 1, 2, :gap, 5, 6, 7, :gap, 10, 11 end it "should eliminate small gaps" do prepare({ :page => 6, :total_pages => 11 }, :inner_window => 2, :outer_window => 1) # pages 4 and 8 appear instead of the gap showing_pages 1..11 end it "should support having no windows at all" do prepare({ :page => 4, :total_pages => 7 }, :inner_window => 0, :outer_window => 0) showing_pages 1, :gap, 4, :gap, 7 end it "should adjust upper limit if lower is out of bounds" do prepare({ :page => 1, :total_pages => 10 }, :inner_window => 2, :outer_window => 1) showing_pages 1, 2, 3, 4, 5, :gap, 9, 10 end it "should adjust lower limit if upper is out of bounds" do prepare({ :page => 10, :total_pages => 10 }, :inner_window => 2, :outer_window => 1) showing_pages 1, 2, :gap, 6, 7, 8, 9, 10 end def showing_pages(*pages) pages = pages.first.to_a if Array === pages.first or Range === pages.first @renderer.send(:windowed_page_numbers).should == pages end end protected def collection(params = {}) if params[:total_pages] params[:per_page] = 1 params[:total_entries] = params[:total_pages] end WillPaginate::Collection.new(params[:page] || 1, params[:per_page] || 30, params[:total_entries]) end def prepare(collection_options, options = {}) @renderer.prepare(collection(collection_options), options) end end will_paginate-3.0.5/spec/view_helpers/base_spec.rb0000644000004100000410000001106012261225505022263 0ustar www-datawww-datarequire 'spec_helper' require 'will_paginate/view_helpers' require 'will_paginate/array' require 'active_support' require 'active_support/core_ext/string/inflections' require 'active_support/inflections' describe WillPaginate::ViewHelpers do before(:all) do # make sure default translations aren't loaded I18n.load_path.clear end before(:each) do I18n.reload! end include WillPaginate::ViewHelpers describe "will_paginate" do it "should render" do collection = WillPaginate::Collection.new(1, 2, 4) renderer = mock 'Renderer' renderer.expects(:prepare).with(collection, instance_of(Hash), self) renderer.expects(:to_html).returns('') will_paginate(collection, :renderer => renderer).should == '' end it "should return nil for single-page collections" do collection = mock 'Collection', :total_pages => 1 will_paginate(collection).should be_nil end it "should call html_safe on result" do collection = WillPaginate::Collection.new(1, 2, 4) html = mock 'HTML' html.expects(:html_safe).returns(html) renderer = mock 'Renderer' renderer.stubs(:prepare) renderer.expects(:to_html).returns(html) will_paginate(collection, :renderer => renderer).should eql(html) end end describe "pagination_options" do let(:pagination_options) { WillPaginate::ViewHelpers.pagination_options } it "deprecates setting :renderer" do begin lambda { pagination_options[:renderer] = 'test' }.should have_deprecation("pagination_options[:renderer] shouldn't be set") ensure pagination_options.delete :renderer end end end describe "page_entries_info" do before :all do @array = ('a'..'z').to_a end def info(params, options = {}) collection = Hash === params ? @array.paginate(params) : params page_entries_info collection, {:html => false}.merge(options) end it "should display middle results and total count" do info(:page => 2, :per_page => 5).should == "Displaying strings 6 - 10 of 26 in total" end it "uses translation if available" do translation :will_paginate => { :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'} } info(:page => 2, :per_page => 5).should == "Showing 6 - 10" end it "uses specific translation if available" do translation :will_paginate => { :page_entries_info => {:multi_page => 'Showing %{from} - %{to}'}, :string => { :page_entries_info => {:multi_page => 'Strings %{from} to %{to}'} } } info(:page => 2, :per_page => 5).should == "Strings 6 to 10" end it "should output HTML by default" do info({ :page => 2, :per_page => 5 }, :html => true).should == "Displaying strings 6 - 10 of 26 in total" end it "should display shortened end results" do info(:page => 7, :per_page => 4).should include_phrase('strings 25 - 26') end it "should handle longer class names" do collection = @array.paginate(:page => 2, :per_page => 5) model = stub('Class', :name => 'ProjectType', :to_s => 'ProjectType') collection.first.stubs(:class).returns(model) info(collection).should include_phrase('project types') end it "should adjust output for single-page collections" do info(('a'..'d').to_a.paginate(:page => 1, :per_page => 5)).should == "Displaying all 4 strings" info(['a'].paginate(:page => 1, :per_page => 5)).should == "Displaying 1 string" end it "should display 'no entries found' for empty collections" do info([].paginate(:page => 1, :per_page => 5)).should == "No entries found" end it "uses model_name.human when available" do name = stub('model name', :i18n_key => :flower_key) name.expects(:human).with(:count => 1).returns('flower') model = stub('Class', :model_name => name) collection = [1].paginate(:page => 1) info(collection, :model => model).should == "Displaying 1 flower" end it "uses custom translation instead of model_name.human" do name = stub('model name', :i18n_key => :flower_key) name.expects(:human).never model = stub('Class', :model_name => name) translation :will_paginate => {:models => {:flower_key => 'tulip'}} collection = [1].paginate(:page => 1) info(collection, :model => model).should == "Displaying 1 tulip" end private def translation(data) I18n.backend.store_translations(:en, data) end end end will_paginate-3.0.5/spec/view_helpers/action_view_spec.rb0000644000004100000410000002773212261225505023675 0ustar www-datawww-datarequire 'spec_helper' require 'active_support/rescuable' # needed for Ruby 1.9.1 require 'action_controller' require 'will_paginate/view_helpers/action_view' require 'will_paginate/collection' Routes = ActionDispatch::Routing::RouteSet.new Routes.draw do get 'dummy/page/:page' => 'dummy#index' get 'dummy/dots/page.:page' => 'dummy#dots' get 'ibocorp(/:page)' => 'ibocorp#index', :constraints => { :page => /\d+/ }, :defaults => { :page => 1 } get ':controller(/:action(/:id(.:format)))' end describe WillPaginate::ActionView do before(:all) do I18n.load_path.concat WillPaginate::I18n.load_path end before(:each) do I18n.reload! end before(:each) do @assigns = {} @controller = DummyController.new @request = @controller.request @template = '<%= will_paginate collection, options %>' end attr_reader :assigns, :controller, :request def render(locals) @view = ActionView::Base.new([], @assigns, @controller) @view.request = @request @view.singleton_class.send(:include, @controller._routes.url_helpers) @view.render(:inline => @template, :locals => locals) end ## basic pagination ## it "should render" do paginate do |pagination| assert_select 'a[href]', 3 do |elements| validate_page_numbers [2,3,2], elements assert_select elements.last, ':last-child', "Next →" end assert_select 'span', 1 assert_select 'span.disabled:first-child', '← Previous' assert_select 'em.current', '1' pagination.first.inner_text.should == '← Previous 1 2 3 Next →' end end it "should override existing page param value" do request.params :page => 1 paginate do |pagination| assert_select 'a[href]', 3 do |elements| validate_page_numbers [2,3,2], elements end end end it "should render nothing when there is only 1 page" do paginate(:per_page => 30).should be_empty end it "should paginate with options" do paginate({ :page => 2 }, :class => 'will_paginate', :previous_label => 'Prev', :next_label => 'Next') do assert_select 'a[href]', 4 do |elements| validate_page_numbers [1,1,3,3], elements # test rel attribute values: assert_select elements[1], 'a', '1' do |link| link.first['rel'].should == 'prev start' end assert_select elements.first, 'a', "Prev" do |link| link.first['rel'].should == 'prev start' end assert_select elements.last, 'a', "Next" do |link| link.first['rel'].should == 'next' end end assert_select '.current', '2' end end it "should paginate using a custom renderer class" do paginate({}, :renderer => AdditionalLinkAttributesRenderer) do assert_select 'a[default=true]', 3 end end it "should paginate using a custom renderer instance" do renderer = WillPaginate::ActionView::LinkRenderer.new def renderer.gap() '~~' end paginate({ :per_page => 2 }, :inner_window => 0, :outer_window => 0, :renderer => renderer) do assert_select 'span.my-gap', '~~' end renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered') paginate({}, :renderer => renderer) do assert_select 'a[title=rendered]', 3 end end it "should have classnames on previous/next links" do paginate do |pagination| assert_select 'span.disabled.previous_page:first-child' assert_select 'a.next_page[href]:last-child' end end it "should match expected markup" do paginate expected = <<-HTML HTML expected.strip!.gsub!(/\s{2,}/, ' ') expected_dom = HTML::Document.new(expected).root html_document.root.should == expected_dom end it "should output escaped URLs" do paginate({:page => 1, :per_page => 1, :total_entries => 2}, :page_links => false, :params => { :tag => '
' }) assert_select 'a[href]', 1 do |links| query = links.first['href'].split('?', 2)[1] query.split('&').sort.should == %w(page=2 tag=%3Cbr%3E) end end ## advanced options for pagination ## it "should be able to render without container" do paginate({}, :container => false) assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t' assert_select 'a[href]', 3 end it "should be able to render without page links" do paginate({ :page => 2 }, :page_links => false) do assert_select 'a[href]', 2 do |elements| validate_page_numbers [1,3], elements end end end ## other helpers ## it "should render a paginated section" do @template = <<-ERB <%= paginated_section collection, options do %> <%= content_tag :div, '', :id => "developers" %> <% end %> ERB paginate assert_select 'div.pagination', 2 assert_select 'div.pagination + div#developers', 1 end it "should not render a paginated section with a single page" do @template = <<-ERB <%= paginated_section collection, options do %> <%= content_tag :div, '', :id => "developers" %> <% end %> ERB paginate(:total_entries => 1) assert_select 'div.pagination', 0 assert_select 'div#developers', 1 end ## parameter handling in page links ## it "should preserve parameters on GET" do request.params :foo => { :bar => 'baz' } paginate assert_links_match /foo\[bar\]=baz/ end it "doesn't allow tampering with host, port, protocol" do request.params :host => 'disney.com', :port => '99', :protocol => 'ftp' paginate assert_links_match %r{^/foo/bar} assert_no_links_match /disney/ assert_no_links_match /99/ assert_no_links_match /ftp/ end it "should not preserve parameters on POST" do request.post request.params :foo => 'bar' paginate assert_no_links_match /foo=bar/ end it "should add additional parameters to links" do paginate({}, :params => { :foo => 'bar' }) assert_links_match /foo=bar/ end it "should add anchor parameter" do paginate({}, :params => { :anchor => 'anchor' }) assert_links_match /#anchor$/ end it "should remove arbitrary parameters" do request.params :foo => 'bar' paginate({}, :params => { :foo => nil }) assert_no_links_match /foo=bar/ end it "should override default route parameters" do paginate({}, :params => { :controller => 'baz', :action => 'list' }) assert_links_match %r{\Wbaz/list\W} end it "should paginate with custom page parameter" do paginate({ :page => 2 }, :param_name => :developers_page) do assert_select 'a[href]', 4 do |elements| validate_page_numbers [1,1,3,3], elements, :developers_page end end end it "should paginate with complex custom page parameter" do request.params :developers => { :page => 2 } paginate({ :page => 2 }, :param_name => 'developers[page]') do assert_select 'a[href]', 4 do |links| assert_links_match /\?developers\[page\]=\d+$/, links validate_page_numbers [1,1,3,3], links, 'developers[page]' end end end it "should paginate with custom route page parameter" do request.symbolized_path_parameters.update :controller => 'dummy', :action => nil paginate :per_page => 2 do assert_select 'a[href]', 6 do |links| assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2] end end end it "should paginate with custom route with dot separator page parameter" do request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots' paginate :per_page => 2 do assert_select 'a[href]', 6 do |links| assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2] end end end it "should paginate with custom route and first page number implicit" do request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil paginate :page => 2, :per_page => 2 do assert_select 'a[href]', 7 do |links| assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3] end end # Routes.recognize_path('/ibocorp/2').should == {:page=>'2', :action=>'index', :controller=>'ibocorp'} # Routes.recognize_path('/ibocorp/foo').should == {:action=>'foo', :controller=>'ibocorp'} end ## internal hardcore stuff ## it "should be able to guess the collection name" do collection = mock collection.expects(:total_pages).returns(1) @template = '<%= will_paginate options %>' controller.controller_name = 'developers' assigns['developers'] = collection paginate(nil) end it "should fail if the inferred collection is nil" do @template = '<%= will_paginate options %>' controller.controller_name = 'developers' lambda { paginate(nil) }.should raise_error(ActionView::TemplateError, /@developers/) end ## i18n it "is able to translate previous/next labels" do translation :will_paginate => { :previous_label => 'Go back', :next_label => 'Load more' } paginate do |pagination| assert_select 'span.disabled:first-child', 'Go back' assert_select 'a[rel=next]', 'Load more' end end it "renders using ActionView helpers on a custom object" do helper = Object.new class << helper attr_reader :controller include ActionView::Helpers::UrlHelper include Routes.url_helpers include WillPaginate::ActionView end helper.default_url_options[:controller] = 'dummy' collection = WillPaginate::Collection.new(2, 1, 3) @render_output = helper.will_paginate(collection) assert_select 'a[href]', 4 do |links| urls = links.map {|l| l['href'] }.uniq urls.should == ['/dummy/page/1', '/dummy/page/3'] end end it "renders using ActionDispatch helper on a custom object" do helper = Object.new class << helper include ActionDispatch::Routing::UrlFor include Routes.url_helpers include WillPaginate::ActionView end helper.default_url_options.update \ :only_path => true, :controller => 'dummy' collection = WillPaginate::Collection.new(2, 1, 3) @render_output = helper.will_paginate(collection) assert_select 'a[href]', 4 do |links| urls = links.map {|l| l['href'] }.uniq urls.should == ['/dummy/page/1', '/dummy/page/3'] end end private def translation(data) I18n.available_locales # triggers loading existing translations I18n.backend.store_translations(:en, data) end end class AdditionalLinkAttributesRenderer < WillPaginate::ActionView::LinkRenderer def initialize(link_attributes = nil) super() @additional_link_attributes = link_attributes || { :default => 'true' } end def link(text, target, attributes = {}) super(text, target, attributes.merge(@additional_link_attributes)) end end class DummyController attr_reader :request attr_accessor :controller_name include ActionController::UrlFor include Routes.url_helpers def initialize @request = DummyRequest.new end def params @request.params end def env {} end def _prefixes [] end end class IbocorpController < DummyController end class DummyRequest attr_accessor :symbolized_path_parameters def initialize @get = true @params = {} @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' } end def get? @get end def post @get = false end def relative_url_root '' end def script_name '' end def params(more = nil) @params.update(more) if more @params end def host_with_port 'example.com' end alias host host_with_port def optional_port '' end def protocol 'http:' end end will_paginate-3.0.5/spec/view_helpers/view_example_group.rb0000644000004100000410000000542112261225505024244 0ustar www-datawww-datarequire 'active_support' begin require 'minitest/unit' rescue LoadError # Fails on Ruby 1.8, but it's OK since we only need MiniTest::Assertions # on Rails 4 which doesn't support 1.8 anyway. end require 'action_dispatch/testing/assertions' require 'will_paginate/array' module ViewExampleGroup include ActionDispatch::Assertions::SelectorAssertions include MiniTest::Assertions if defined? MiniTest def assert(value, message) message = message.call if message.respond_to?(:call) raise message unless value end def paginate(collection = {}, options = {}, &block) if collection.instance_of? Hash page_options = { :page => 1, :total_entries => 11, :per_page => 4 }.merge(collection) collection = [1].paginate(page_options) end locals = { :collection => collection, :options => options } @render_output = render(locals) @html_document = nil if block_given? classname = options[:class] || WillPaginate::ViewHelpers.pagination_options[:class] assert_select("div.#{classname}", 1, 'no main DIV', &block) end @render_output end def html_document @html_document ||= HTML::Document.new(@render_output, true, false) end def response_from_page_or_rjs html_document.root end def validate_page_numbers(expected, links, param_name = :page) param_pattern = /\W#{Regexp.escape(param_name.to_s)}=([^&]*)/ links.map { |el| unescape_href(el) =~ param_pattern $1 ? $1.to_i : $1 }.should == expected end def assert_links_match(pattern, links = nil, numbers = nil) links ||= assert_select 'div.pagination a[href]' do |elements| elements end pages = [] if numbers links.each do |el| href = unescape_href(el) href.should =~ pattern if numbers href =~ pattern pages << ($1.nil?? nil : $1.to_i) end end pages.should == numbers if numbers end def assert_no_links_match(pattern) assert_select 'div.pagination a[href]' do |elements| elements.each do |el| unescape_href(el).should_not =~ pattern end end end def unescape_href(el) CGI.unescape CGI.unescapeHTML(el['href']) end def build_message(message, pattern, *args) built_message = pattern.dup for value in args built_message.sub! '?', value.inspect end built_message end end RSpec.configure do |config| config.include ViewExampleGroup, :type => :view, :example_group => { :file_path => %r{spec/view_helpers/} } end module HTML Node.class_eval do def inner_text children.map(&:inner_text).join('') end end Text.class_eval do def inner_text self.to_s end end Tag.class_eval do def inner_text childless?? '' : super end end end will_paginate-3.0.5/spec/console0000755000004100000410000000064412261225505016714 0ustar www-datawww-data#!/usr/bin/env ruby irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' opts = %w[ --simple-prompt -rirb/completion ] if ARGV.include? '-dm' opts << '-rwill_paginate/data_mapper' << '-rfinders/data_mapper_test_connector' elsif ARGV.include? '-seq' opts << '-rwill_paginate/sequel' << '-rfinders/sequel_test_connector' else opts << '-rconsole_fixtures' end exec 'bundle', 'exec', irb, '-Ilib:spec', *opts will_paginate-3.0.5/spec/collection_spec.rb0000644000004100000410000001000412261225505021005 0ustar www-datawww-datarequire 'will_paginate/array' require 'spec_helper' describe WillPaginate::Collection do before :all do @simple = ('a'..'e').to_a end it "should be a subset of original collection" do @simple.paginate(:page => 1, :per_page => 3).should == %w( a b c ) end it "can be shorter than per_page if on last page" do @simple.paginate(:page => 2, :per_page => 3).should == %w( d e ) end it "should include whole collection if per_page permits" do @simple.paginate(:page => 1, :per_page => 5).should == @simple end it "should be empty if out of bounds" do @simple.paginate(:page => 2, :per_page => 5).should be_empty end it "should default to 1 as current page and 30 per-page" do result = (1..50).to_a.paginate result.current_page.should == 1 result.size.should == 30 end it "should give total_entries precedence over actual size" do %w(a b c).paginate(:total_entries => 5).total_entries.should == 5 end it "should be an augmented Array" do entries = %w(a b c) collection = create(2, 3, 10) do |pager| pager.replace(entries).should == entries end collection.should == entries for method in %w(total_pages each offset size current_page per_page total_entries) collection.should respond_to(method) end collection.should be_kind_of(Array) collection.entries.should be_instance_of(Array) # TODO: move to another expectation: collection.offset.should == 3 collection.total_pages.should == 4 collection.should_not be_out_of_bounds end describe "previous/next pages" do it "should have previous_page nil when on first page" do collection = create(1, 1, 3) collection.previous_page.should be_nil collection.next_page.should == 2 end it "should have both prev/next pages" do collection = create(2, 1, 3) collection.previous_page.should == 1 collection.next_page.should == 3 end it "should have next_page nil when on last page" do collection = create(3, 1, 3) collection.previous_page.should == 2 collection.next_page.should be_nil end end 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 it "can guess when collection is shorter than limit" do collection = create { |p| p.replace array } collection.total_entries.should == 8 end it "should allow explicit total count to override guessed" do collection = create(2, 5, 10) { |p| p.replace array } collection.total_entries.should == 10 end it "should not be able to guess when collection is same as limit" do collection = create { |p| p.replace array(5) } collection.total_entries.should be_nil end it "should not be able to guess when collection is empty" do collection = create { |p| p.replace array(0) } collection.total_entries.should be_nil end it "should be able to guess when collection is empty and this is the first page" do collection = create(1) { |p| p.replace array(0) } collection.total_entries.should == 0 end end it "should not respond to page_count anymore" do Proc.new { create.page_count }.should raise_error(NoMethodError) end it "inherits per_page from global value" do collection = described_class.new(1) collection.per_page.should == 30 end private def create(page = 2, limit = 5, total = nil, &block) if block_given? described_class.create(page, limit, total, &block) else described_class.new(page, limit, total) end end def array(size = 3) Array.new(size) end end will_paginate-3.0.5/spec/console_fixtures.rb0000644000004100000410000000143412261225505021242 0ustar www-datawww-datarequire 'bundler' Bundler.setup require 'will_paginate/active_record' require 'finders/activerecord_test_connector' ActiverecordTestConnector.setup windows = RUBY_PLATFORM =~ /(:?mswin|mingw)/ # used just for the `color` method log_subscriber = ActiveSupport::LogSubscriber.log_subscribers.first IGNORE_SQL = /\b(sqlite_master|sqlite_version)\b|^(CREATE TABLE|PRAGMA)\b/ ActiveSupport::Notifications.subscribe(/^sql\./) do |*args| data = args.last unless data[:name] =~ /^Fixture/ or data[:sql] =~ IGNORE_SQL if windows puts data[:sql] else puts log_subscriber.send(:color, data[:sql], :cyan) end end end # load all fixtures ActiverecordTestConnector::Fixtures.create_fixtures \ ActiverecordTestConnector::FIXTURES_PATH, ActiveRecord::Base.connection.tables will_paginate-3.0.5/lib/0000755000004100000410000000000012261225505015134 5ustar www-datawww-datawill_paginate-3.0.5/lib/will_paginate/0000755000004100000410000000000012261225505017753 5ustar www-datawww-datawill_paginate-3.0.5/lib/will_paginate/core_ext.rb0000644000004100000410000000134112261225505022107 0ustar www-datawww-datarequire 'set' # copied from ActiveSupport so we don't depend on it unless Hash.method_defined? :except Hash.class_eval do # Returns a new hash without the given keys. def except(*keys) rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) reject { |key,| rejected.include?(key) } end # Replaces the hash without only the given keys. def except!(*keys) replace(except(*keys)) end end end unless String.method_defined? :underscore String.class_eval do def underscore self.to_s.gsub(/::/, '/'). gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). tr("-", "_"). downcase end end end will_paginate-3.0.5/lib/will_paginate/active_record.rb0000644000004100000410000001701312261225505023113 0ustar www-datawww-datarequire 'will_paginate/per_page' require 'will_paginate/page_number' require 'will_paginate/collection' require 'active_record' module WillPaginate # = Paginating finders for ActiveRecord models # # WillPaginate adds +paginate+, +per_page+ and other methods to # ActiveRecord::Base class methods and associations. # # In short, paginating finders are equivalent to ActiveRecord finders; the # only difference is that we start with "paginate" instead of "find" and # that :page is required parameter: # # @posts = Post.paginate :all, :page => params[:page], :order => 'created_at DESC' # 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 def per_page(value = nil) if value.nil? then limit_value else limit(value) end end # TODO: solve with less relation clones and code dups def limit(num) rel = super if rel.current_page rel.offset rel.current_page.to_offset(rel.limit_value).to_i else rel end end # dirty hack to enable `first` after `limit` behavior above def first(*args) if current_page rel = clone rel.current_page = nil rel.first(*args) else super end end # fix for Rails 3.0 def find_last if !loaded? and offset_value || limit_value @last ||= to_a.last else super end end def offset(value = nil) if value.nil? then offset_value else super(value) end end def total_entries @total_entries ||= begin if loaded? and size < limit_value and (current_page == 1 or size > 0) offset_value + size else @total_entries_queried = true result = count result = result.size if result.respond_to?(:size) and !result.is_a?(Integer) result end end end def count if limit_value excluded = [:order, :limit, :offset, :reorder] excluded << :includes unless eager_loading? rel = self.except(*excluded) # TODO: hack. decide whether to keep rel = rel.apply_finder_options(@wp_count_options) if defined? @wp_count_options rel.count else super end end # workaround for Active Record 3.0 def size if !loaded? and limit_value and group_values.empty? [super, limit_value].min else super end end # overloaded to be pagination-aware def empty? if !loaded? and offset_value result = count result = result.size if result.respond_to?(:size) and !result.is_a?(Integer) result <= offset_value else super end end def clone copy_will_paginate_data super end # workaround for Active Record 3.0 def scoped(options = nil) copy_will_paginate_data super end def to_a if current_page.nil? then super # workaround for Active Record 3.0 else ::WillPaginate::Collection.create(current_page, limit_value) do |col| col.replace super col.total_entries ||= total_entries end end end private def copy_will_paginate_data(other) other.current_page = current_page unless other.current_page other.total_entries = nil if defined? @total_entries_queried other.wp_count_options = @wp_count_options if defined? @wp_count_options other end end module Pagination def paginate(options) options = options.dup pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } per_page = options.delete(:per_page) || self.per_page total = options.delete(:total_entries) count_options = options.delete(:count) options.delete(:page) rel = limit(per_page.to_i).page(pagenum) rel = rel.apply_finder_options(options) if options.any? rel.wp_count_options = count_options if count_options rel.total_entries = total.to_i unless total.blank? rel end def page(num) rel = if ::ActiveRecord::Relation === self self elsif !defined?(::ActiveRecord::Scoping) or ::ActiveRecord::Scoping::ClassMethods.method_defined? :with_scope # Active Record 3 scoped else # Active Record 4 all end rel = rel.extending(RelationMethods) pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num) per_page = rel.limit_value || self.per_page rel = rel.offset(pagenum.to_offset(per_page).to_i) rel = rel.limit(per_page) unless rel.limit_value rel.current_page = pagenum rel end end module BaseMethods # Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string # based on the params otherwise used by paginating finds: +page+ and # +per_page+. # # Example: # # @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000], # :page => params[:page], :per_page => 3 # # A query for counting rows will automatically be generated if you don't # supply :total_entries. If you experience problems with this # generated SQL, you might want to perform the count manually in your # application. # def paginate_by_sql(sql, options) pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } || 1 per_page = options[:per_page] || self.per_page total = options[:total_entries] WillPaginate::Collection.create(pagenum, per_page, total) do |pager| query = sanitize_sql(sql.dup) original_query = query.dup oracle = self.connection.adapter_name =~ /^(oracle|oci$)/i # add limit, offset if oracle query = <<-SQL SELECT * FROM ( SELECT rownum rnum, a.* FROM (#{query}) a WHERE rownum <= #{pager.offset + pager.per_page} ) WHERE rnum >= #{pager.offset} SQL else query << " LIMIT #{pager.per_page} OFFSET #{pager.offset}" end # perfom the find pager.replace find_by_sql(query) unless pager.total_entries count_query = original_query.sub /\bORDER\s+BY\s+[\w`,\s.]+$/mi, '' count_query = "SELECT COUNT(*) FROM (#{count_query})" count_query << ' AS count_table' unless oracle # perform the count query pager.total_entries = count_by_sql(count_query) end end end end # mix everything into Active Record ::ActiveRecord::Base.extend PerPage ::ActiveRecord::Base.extend Pagination ::ActiveRecord::Base.extend BaseMethods klasses = [::ActiveRecord::Relation] if defined? ::ActiveRecord::Associations::CollectionProxy klasses << ::ActiveRecord::Associations::CollectionProxy else klasses << ::ActiveRecord::Associations::AssociationCollection end # support pagination on associations and scopes klasses.each { |klass| klass.send(:include, Pagination) } end end will_paginate-3.0.5/lib/will_paginate/deprecation.rb0000644000004100000410000000231612261225505022577 0ustar www-datawww-datamodule WillPaginate::Deprecation class << self def warn(message, stack = caller) offending_line = origin_of_call(stack) full_message = "DEPRECATION WARNING: #{message} (called from #{offending_line})" logger = rails_logger || Kernel logger.warn full_message end private def rails_logger defined?(Rails) && Rails.logger end def origin_of_call(stack) lib_root = File.expand_path('../../..', __FILE__) stack.find { |line| line.index(lib_root) != 0 } || stack.first end end class Hash < ::Hash def initialize(values = {}) super() update values @deprecated = {} end def []=(key, value) check_deprecated(key, value) super end def deprecate_key(*keys) message = block_given? ? Proc.new : keys.pop Array(keys).each { |key| @deprecated[key] = message } end def merge(another) to_hash.update(another) end def to_hash ::Hash.new.update(self) end private def check_deprecated(key, value) if msg = @deprecated[key] and (!msg.respond_to?(:call) or (msg = msg.call(key, value))) WillPaginate::Deprecation.warn(msg) end end end end will_paginate-3.0.5/lib/will_paginate/sequel.rb0000644000004100000410000000141612261225505021600 0ustar www-datawww-datarequire '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 def per_page page_size end def size current_page_record_count end alias length size def total_entries pagination_record_count end def out_of_bounds? current_page > total_pages end # Current offset of the paginated collection def offset (current_page - 1) * per_page end end Sequel::Dataset::Pagination.send(:include, SequelMethods) end will_paginate-3.0.5/lib/will_paginate/version.rb0000644000004100000410000000023012261225505021760 0ustar www-datawww-datamodule WillPaginate #:nodoc: module VERSION #:nodoc: MAJOR = 3 MINOR = 0 TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end end will_paginate-3.0.5/lib/will_paginate/view_helpers.rb0000644000004100000410000001526412261225505023004 0ustar www-datawww-data# encoding: utf-8 require 'will_paginate/core_ext' require 'will_paginate/i18n' require 'will_paginate/deprecation' module WillPaginate # = Will Paginate view helpers # # The main view helper is +will_paginate+. It renders the pagination links # for the given collection. The helper itself is lightweight and serves only # as a wrapper around LinkRenderer instantiation; the renderer then does # all the hard work of generating the HTML. module ViewHelpers class << self # Write to this hash to override default options on the global level: # # WillPaginate::ViewHelpers.pagination_options[:page_links] = false # attr_accessor :pagination_options end # default view options self.pagination_options = Deprecation::Hash.new \ :class => 'pagination', :previous_label => nil, :next_label => nil, :inner_window => 4, # links around the current page :outer_window => 1, # links around beginning and end :link_separator => ' ', # single space is friendly to spiders and non-graphic browsers :param_name => :page, :params => nil, :page_links => true, :container => true label_deprecation = Proc.new { |key, value| "set the 'will_paginate.#{key}' key in your i18n locale instead of editing pagination_options" if defined? Rails } pagination_options.deprecate_key(:previous_label, :next_label, &label_deprecation) pagination_options.deprecate_key(:renderer) { |key, _| "pagination_options[#{key.inspect}] shouldn't be set globally" } include WillPaginate::I18n # Returns HTML representing page links for a WillPaginate::Collection-like object. # In case there is no more than one page in total, nil is returned. # # ==== Options # * :class -- CSS class name for the generated DIV (default: "pagination") # * :previous_label -- default: "« Previous" # * :next_label -- default: "Next »" # * :inner_window -- how many links are shown around the current page (default: 4) # * :outer_window -- how many links are around the first and the last page (default: 1) # * :link_separator -- string separator for page HTML elements (default: single space) # * :param_name -- parameter name for page number in URLs (default: :page) # * :params -- additional parameters when generating pagination links # (eg. :controller => "foo", :action => nil) # * :renderer -- class name, class or instance of a link renderer (default in Rails: # WillPaginate::ActionView::LinkRenderer) # * :page_links -- when false, only previous/next links are rendered (default: true) # * :container -- toggles rendering of the DIV container for pagination links, set to # false only when you are rendering your own pagination markup (default: true) # # All options not recognized by will_paginate will become HTML attributes on the container # element for pagination links (the DIV). For example: # # <%= will_paginate @posts, :style => 'color:blue' %> # # will result in: # # # def will_paginate(collection, options = {}) # early exit if there is nothing to render return nil unless collection.total_pages > 1 options = WillPaginate::ViewHelpers.pagination_options.merge(options) options[:previous_label] ||= will_paginate_translate(:previous_label) { '← Previous' } options[:next_label] ||= will_paginate_translate(:next_label) { 'Next →' } # get the renderer instance renderer = case options[:renderer] when nil raise ArgumentError, ":renderer not specified" when String klass = if options[:renderer].respond_to? :constantize then options[:renderer].constantize else Object.const_get(options[:renderer]) # poor man's constantize end klass.new when Class then options[:renderer].new else options[:renderer] end # render HTML for pagination renderer.prepare collection, options, self output = renderer.to_html output = output.html_safe if output.respond_to?(:html_safe) output end # Renders a message containing number of displayed vs. total entries. # # <%= page_entries_info @posts %> # #-> Displaying posts 6 - 12 of 26 in total # # The default output contains HTML. Use ":html => false" for plain text. def page_entries_info(collection, options = {}) model = options[:model] model = collection.first.class unless model or collection.empty? model ||= 'entry' model_key = if model.respond_to? :model_name model.model_name.i18n_key # ActiveModel::Naming else model.to_s.underscore end if options.fetch(:html, true) b, eb = '', '' sp = ' ' html_key = '_html' else b = eb = html_key = '' sp = ' ' end model_count = collection.total_pages > 1 ? 5 : collection.size defaults = ["models.#{model_key}"] defaults << Proc.new { |_, opts| if model.respond_to? :model_name model.model_name.human(:count => opts[:count]) else name = model_key.to_s.tr('_', ' ') raise "can't pluralize model name: #{model.inspect}" unless name.respond_to? :pluralize opts[:count] == 1 ? name : name.pluralize end } model_name = will_paginate_translate defaults, :count => model_count if collection.total_pages < 2 i18n_key = :"page_entries_info.single_page#{html_key}" keys = [:"#{model_key}.#{i18n_key}", i18n_key] will_paginate_translate keys, :count => collection.total_entries, :model => model_name do |_, opts| case opts[:count] when 0; "No #{opts[:model]} found" when 1; "Displaying #{b}1#{eb} #{opts[:model]}" else "Displaying #{b}all#{sp}#{opts[:count]}#{eb} #{opts[:model]}" end end else i18n_key = :"page_entries_info.multi_page#{html_key}" keys = [:"#{model_key}.#{i18n_key}", i18n_key] params = { :model => model_name, :count => collection.total_entries, :from => collection.offset + 1, :to => collection.offset + collection.length } will_paginate_translate keys, params do |_, opts| %{Displaying %s #{b}%d#{sp}-#{sp}%d#{eb} of #{b}%d#{eb} in total} % [ opts[:model], opts[:from], opts[:to], opts[:count] ] end end end end end will_paginate-3.0.5/lib/will_paginate/array.rb0000644000004100000410000000242212261225505021416 0ustar www-datawww-datarequire 'will_paginate/collection' class Array # Paginates a static array (extracting a subset of it). The result is a # WillPaginate::Collection instance, which is an array with a few more # properties about its paginated state. # # Parameters: # * :page - current page, defaults to 1 # * :per_page - limit of items per page, defaults to 30 # * :total_entries - total number of items in the array, defaults to # array.length (obviously) # # Example: # arr = ['a', 'b', 'c', 'd', 'e'] # paged = arr.paginate(:per_page => 2) #-> ['a', 'b'] # paged.total_entries #-> 5 # arr.paginate(:page => 2, :per_page => 2) #-> ['c', 'd'] # arr.paginate(:page => 3, :per_page => 2) #-> ['e'] # # This method was originally {suggested by Desi # McAdam}[http://www.desimcadam.com/archives/8] and later proved to be the # most useful method of will_paginate library. def paginate(options = {}) page = options[:page] || 1 per_page = options[:per_page] || WillPaginate.per_page total = options[:total_entries] || self.length WillPaginate::Collection.create(page, per_page, total) do |pager| pager.replace self[pager.offset, pager.per_page].to_a end end end will_paginate-3.0.5/lib/will_paginate/i18n.rb0000644000004100000410000000105712261225505021062 0ustar www-datawww-datamodule WillPaginate module I18n def self.locale_dir File.expand_path('../locale', __FILE__) end def self.load_path Dir["#{locale_dir}/*.{rb,yml}"] end def will_paginate_translate(keys, options = {}) if defined? ::I18n defaults = Array(keys).dup defaults << Proc.new if block_given? ::I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => :will_paginate)) else key = Array === keys ? keys.first : keys yield key, options end end end end will_paginate-3.0.5/lib/will_paginate/collection.rb0000644000004100000410000001205412261225505022435 0ustar www-datawww-datarequire 'will_paginate/per_page' 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 # some extra properties. Those properties are used by view helpers to generate # correct page links. # # WillPaginate::Collection also assists in rolling out your own pagination # solutions: see +create+. # # If you are writing a library that provides a collection which you would like # to conform to this API, you don't have to copy these methods over; simply # make your plugin/gem dependant on this library and do: # # require 'will_paginate/collection' # # WillPaginate::Collection is now available for use class Collection < Array 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 # is best to do lazy counting; in other words, count *conditionally* after # populating the collection using the +replace+ method. def initialize(page, per_page = WillPaginate.per_page, total = nil) @current_page = WillPaginate::PageNumber(page) @per_page = per_page.to_i self.total_entries = total if total end # Just like +new+, but yields the object after instantiation and returns it # afterwards. This is very useful for manual pagination: # # @entries = WillPaginate::Collection.create(1, 10) do |pager| # result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset) # # inject the result array into the paginated collection: # pager.replace(result) # # unless pager.total_entries # # the pager didn't manage to guess the total count, do it manually # pager.total_entries = Post.count # end # end # # The possibilities with this are endless. For another example, here is how # WillPaginate used to define pagination for Array instances: # # Array.class_eval do # def paginate(page = 1, per_page = 15) # WillPaginate::Collection.create(page, per_page, size) do |pager| # pager.replace self[pager.offset, pager.per_page].to_a # end # end # end # # The Array#paginate API has since then changed, but this still serves as a # fine example of WillPaginate::Collection usage. def self.create(page, per_page, total = nil) pager = new(page, per_page, total) yield pager pager 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 def total_entries=(number) @total_entries = number.to_i end # This is a magic wrapper for the original Array#replace method. It serves # for populating the paginated collection after initialization. # # Why magic? Because it tries to guess the total number of entries judging # by the size of given array. If it is shorter than +per_page+ limit, then we # know we're on the last page. This trick is very useful for avoiding # unnecessary hits to the database to do the counting after we fetched the # data for the current page. # # However, after using +replace+ you should always test the value of # +total_entries+ and set it to a proper value if it's +nil+. See the example # in +create+. def replace(array) result = super # The collection is shorter then page limit? Rejoice, because # then we know that we are on the last page! if total_entries.nil? and length < per_page and (current_page == 1 or length > 0) self.total_entries = offset + length end result end end end will_paginate-3.0.5/lib/will_paginate/per_page.rb0000644000004100000410000000075112261225505022065 0ustar www-datawww-datamodule WillPaginate module PerPage def per_page defined?(@per_page) ? @per_page : WillPaginate.per_page end def per_page=(limit) @per_page = limit.to_i end def self.extended(base) base.extend Inheritance if base.is_a? Class end module Inheritance def inherited(subclass) super subclass.per_page = self.per_page end end end extend PerPage # default number of items per page self.per_page = 30 end will_paginate-3.0.5/lib/will_paginate/view_helpers/0000755000004100000410000000000012261225505022447 5ustar www-datawww-datawill_paginate-3.0.5/lib/will_paginate/view_helpers/sinatra.rb0000644000004100000410000000172512261225505024442 0ustar www-datawww-datarequire 'sinatra/base' require 'will_paginate/view_helpers' require 'will_paginate/view_helpers/link_renderer' module WillPaginate module Sinatra module Helpers include ViewHelpers def will_paginate(collection, options = {}) #:nodoc: options = options.merge(:renderer => LinkRenderer) unless options[:renderer] super(collection, options) end end class LinkRenderer < ViewHelpers::LinkRenderer protected def url(page) str = File.join(request.script_name.to_s, request.path_info) params = request.GET.merge(param_name.to_s => page.to_s) params.update @options[:params] if @options[:params] str << '?' << build_query(params) end def request @template.request end def build_query(params) Rack::Utils.build_nested_query params end end def self.registered(app) app.helpers Helpers end ::Sinatra.register self end end will_paginate-3.0.5/lib/will_paginate/view_helpers/merb.rb0000644000004100000410000000123312261225505023720 0ustar www-datawww-datarequire 'will_paginate/core_ext' require 'will_paginate/view_helpers' require 'will_paginate/view_helpers/link_renderer' module WillPaginate module Merb include ViewHelpers def will_paginate(collection, options = {}) #:nodoc: options = options.merge(:renderer => LinkRenderer) unless options[:renderer] super(collection, options) end class LinkRenderer < ViewHelpers::LinkRenderer protected def url(page) params = @template.request.params.except(:action, :controller).merge(param_name => page) @template.url(:this, params) end end ::Merb::AbstractController.send(:include, self) end end will_paginate-3.0.5/lib/will_paginate/view_helpers/action_view.rb0000644000004100000410000001050212261225505025301 0ustar www-datawww-datarequire 'will_paginate/view_helpers' require 'will_paginate/view_helpers/link_renderer' module WillPaginate # = ActionView helpers # # This module serves for availability in ActionView templates. It also adds a new # view helper: +paginated_section+. # # == Using the helper without arguments # If the helper is called without passing in the collection object, it will # try to read from the instance variable inferred by the controller name. # For example, calling +will_paginate+ while the current controller is # PostsController will result in trying to read from the @posts # variable. Example: # # <%= will_paginate :id => true %> # # ... will result in @post collection getting paginated: # # # module ActionView include ViewHelpers def will_paginate(collection = nil, options = {}) #:nodoc: options, collection = collection, nil if collection.is_a? Hash collection ||= infer_collection_from_controller options = options.symbolize_keys options[:renderer] ||= LinkRenderer super(collection, options) end def page_entries_info(collection = nil, options = {}) #:nodoc: options, collection = collection, nil if collection.is_a? Hash collection ||= infer_collection_from_controller super(collection, options.symbolize_keys) end # Wrapper for rendering pagination links at both top and bottom of a block # of content. # # <% paginated_section @posts do %> #
    # <% for post in @posts %> #
  1. ...
  2. # <% end %> #
# <% end %> # # will result in: # # #
    # ... #
# # # Arguments are passed to a will_paginate call, so the same options # apply. Don't use the :id option; otherwise you'll finish with two # blocks of pagination links sharing the same ID (which is invalid HTML). def paginated_section(*args, &block) pagination = will_paginate(*args) if pagination pagination + capture(&block) + pagination else capture(&block) end end def will_paginate_translate(keys, options = {}) if respond_to? :translate if Array === keys defaults = keys.dup key = defaults.shift else defaults = nil key = keys end translate(key, options.merge(:default => defaults, :scope => :will_paginate)) else super end end protected def infer_collection_from_controller collection_name = "@#{controller.controller_name}" collection = instance_variable_get(collection_name) raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " + "forget to pass the collection object for will_paginate?" if collection.nil? collection end class LinkRenderer < ViewHelpers::LinkRenderer protected def default_url_params {} end def url(page) @base_url_params ||= begin url_params = merge_get_params(default_url_params) url_params[:only_path] = true merge_optional_params(url_params) end url_params = @base_url_params.dup add_current_page_param(url_params, page) @template.url_for(url_params) end def merge_get_params(url_params) if @template.respond_to? :request and @template.request and @template.request.get? symbolized_update(url_params, @template.params) end url_params end def merge_optional_params(url_params) symbolized_update(url_params, @options[:params]) if @options[:params] url_params end def add_current_page_param(url_params, page) unless param_name.index(/[^\w-]/) url_params[param_name.to_sym] = page else page_param = parse_query_parameters("#{param_name}=#{page}") symbolized_update(url_params, page_param) end end private def parse_query_parameters(params) Rack::Utils.parse_nested_query(params) end end ::ActionView::Base.send :include, self end end will_paginate-3.0.5/lib/will_paginate/view_helpers/link_renderer_base.rb0000644000004100000410000000445412261225505026620 0ustar www-datawww-datamodule WillPaginate module ViewHelpers # This class does the heavy lifting of actually building the pagination # links. It is used by +will_paginate+ helper internally. class LinkRendererBase # * +collection+ is a WillPaginate::Collection instance or any other object # that conforms to that API # * +options+ are forwarded from +will_paginate+ view helper def prepare(collection, options) @collection = collection @options = options # reset values in case we're re-using this instance @total_pages = nil end def pagination items = @options[:page_links] ? windowed_page_numbers : [] items.unshift :previous_page items.push :next_page end protected # Calculates visible page numbers using the :inner_window and # :outer_window options. def windowed_page_numbers inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i window_from = current_page - inner_window window_to = current_page + inner_window # adjust lower or upper limit if other is out of bounds if window_to > total_pages window_from -= window_to - total_pages window_to = total_pages end if window_from < 1 window_to += 1 - window_from window_from = 1 window_to = total_pages if window_to > total_pages end # these are always visible middle = window_from..window_to # left window if outer_window + 3 < middle.first # there's a gap left = (1..(outer_window + 1)).to_a left << :gap else # runs into visible pages left = 1...middle.first end # right window if total_pages - outer_window - 2 > middle.last # again, gap right = ((total_pages - outer_window)..total_pages).to_a right.unshift :gap else # runs into visible pages right = (middle.last + 1)..total_pages end left.to_a + middle.to_a + right.to_a end private def current_page @collection.current_page end def total_pages @total_pages ||= @collection.total_pages end end end end will_paginate-3.0.5/lib/will_paginate/view_helpers/link_renderer.rb0000644000004100000410000001005412261225505025617 0ustar www-datawww-datarequire 'cgi' require 'will_paginate/core_ext' require 'will_paginate/view_helpers' require 'will_paginate/view_helpers/link_renderer_base' module WillPaginate module ViewHelpers # This class does the heavy lifting of actually building the pagination # links. It is used by +will_paginate+ helper internally. class LinkRenderer < LinkRendererBase # * +collection+ is a WillPaginate::Collection instance or any other object # that conforms to that API # * +options+ are forwarded from +will_paginate+ view helper # * +template+ is the reference to the template being rendered def prepare(collection, options, template) super(collection, options) @template = template @container_attributes = @base_url_params = nil end # Process it! This method returns the complete HTML string which contains # pagination links. Feel free to subclass LinkRenderer and change this # method as you see fit. def to_html html = pagination.map do |item| item.is_a?(Fixnum) ? page_number(item) : send(item) end.join(@options[:link_separator]) @options[:container] ? html_container(html) : html end # Returns the subset of +options+ this instance was initialized with that # represent HTML attributes for the container element of pagination links. def container_attributes @container_attributes ||= @options.except(*(ViewHelpers.pagination_options.keys + [:renderer] - [:class])) end protected def page_number(page) unless page == current_page link(page, page, :rel => rel_value(page)) else tag(:em, page, :class => 'current') end end def gap text = @template.will_paginate_translate(:page_gap) { '…' } %(#{text}) end def previous_page num = @collection.current_page > 1 && @collection.current_page - 1 previous_or_next_page(num, @options[:previous_label], 'previous_page') end def next_page num = @collection.current_page < total_pages && @collection.current_page + 1 previous_or_next_page(num, @options[:next_label], 'next_page') end def previous_or_next_page(page, text, classname) if page link(text, page, :class => classname) else tag(:span, text, :class => classname + ' disabled') end end def html_container(html) tag(:div, html, container_attributes) end # Returns URL params for +page_link_or_span+, taking the current GET params # and :params option into account. def url(page) raise NotImplementedError end private def param_name @options[:param_name].to_s end def link(text, target, attributes = {}) if target.is_a? Fixnum attributes[:rel] = rel_value(target) target = url(target) end attributes[:href] = target tag(:a, text, attributes) end def tag(name, value, attributes = {}) string_attributes = attributes.inject('') do |attrs, pair| unless pair.last.nil? attrs << %( #{pair.first}="#{CGI::escapeHTML(pair.last.to_s)}") end attrs end "<#{name}#{string_attributes}>#{value}" end def rel_value(page) case page when @collection.current_page - 1; 'prev' + (page == 1 ? ' start' : '') when @collection.current_page + 1; 'next' when 1; 'start' end end def symbolized_update(target, other) other.each do |key, value| key = key.to_sym existing = target[key] if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?) symbolized_update(existing || (target[key] = {}), value) else target[key] = value end end end end end end will_paginate-3.0.5/lib/will_paginate/data_mapper.rb0000644000004100000410000000475612261225505022571 0ustar www-datawww-datarequire 'dm-core' require 'dm-aggregates' require 'will_paginate/per_page' require 'will_paginate/page_number' require 'will_paginate/collection' module WillPaginate module DataMapper module Pagination def page(num) pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num) per_page = query.limit || self.per_page options = {:offset => pagenum.to_offset(per_page).to_i} options[:limit] = per_page unless query.limit col = new_collection(query.merge(options)) col.current_page = pagenum col end def paginate(options) options = options.dup pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" } per_page = options.delete(:per_page) || self.per_page options.delete(:page) options[:limit] = per_page.to_i all(options).page(pagenum) end end module CollectionMethods include WillPaginate::CollectionMethods attr_accessor :current_page def paginated? !current_page.nil? end def per_page query.limit || model.per_page end def offset query.offset end def total_entries @total_entries ||= begin if loaded? and @array.size < per_page and (current_page == 1 or @array.size > 0) offset + @array.size else # :reload prevents Collection.filter from being run, which # would cause a stack overflow clean_query = query.merge(:reload => true) # seems like the only way clean_query.instance_variable_set('@limit', nil) clean_query.instance_variable_set('@offset', 0) new_collection(clean_query).count end end end def to_a if paginated? ::WillPaginate::Collection.create(current_page, per_page) do |col| col.replace super col.total_entries ||= total_entries end else super end end private def new_collection(query, resources = nil) col = super col.current_page = self.current_page col end def initialize_copy(original) super @total_entries = nil end end ::DataMapper::Model.append_extensions PerPage ::DataMapper::Model.append_extensions Pagination ::DataMapper::Collection.send(:include, Pagination) ::DataMapper::Collection.send(:include, CollectionMethods) end end will_paginate-3.0.5/lib/will_paginate/page_number.rb0000644000004100000410000000246212261225505022570 0ustar www-datawww-datarequire 'delegate' require 'forwardable' module WillPaginate # a module that page number exceptions are tagged with module InvalidPage; end # integer representing a page number class PageNumber < DelegateClass(Integer) # a value larger than this is not supported in SQL queries BIGINT = 9223372036854775807 extend Forwardable def initialize(value, name) value = Integer(value) if 'offset' == name ? (value < 0 or value > BIGINT) : value < 1 raise RangeError, "invalid #{name}: #{value.inspect}" end @name = name super(value) rescue ArgumentError, TypeError, RangeError => error error.extend InvalidPage raise error end alias_method :to_i, :__getobj__ def inspect "#{@name} #{to_i}" end def to_offset(per_page) PageNumber.new((to_i - 1) * per_page.to_i, 'offset') end def kind_of?(klass) super || to_i.kind_of?(klass) end alias is_a? kind_of? end # Ultrahax: makes `Fixnum === current_page` checks pass Numeric.extend Module.new { def ===(obj) obj.instance_of? PageNumber or super end } # An idemptotent coercion method def self.PageNumber(value, name = 'page') case value when PageNumber then value else PageNumber.new(value, name) end end end will_paginate-3.0.5/lib/will_paginate/railtie.rb0000644000004100000410000000414512261225505021735 0ustar www-datawww-datarequire 'will_paginate' require 'will_paginate/page_number' require 'will_paginate/collection' require 'will_paginate/i18n' module WillPaginate class Railtie < Rails::Railtie initializer "will_paginate" do |app| ActiveSupport.on_load :active_record do require 'will_paginate/active_record' end ActiveSupport.on_load :action_controller do WillPaginate::Railtie.setup_actioncontroller end ActiveSupport.on_load :action_view do require 'will_paginate/view_helpers/action_view' end self.class.add_locale_path config # early access to ViewHelpers.pagination_options require 'will_paginate/view_helpers' end def self.setup_actioncontroller ( defined?(ActionDispatch::ExceptionWrapper) ? ActionDispatch::ExceptionWrapper : ActionDispatch::ShowExceptions ).send :include, ShowExceptionsPatch ActionController::Base.extend ControllerRescuePatch end def self.add_locale_path(config) config.i18n.railties_load_path.unshift(*WillPaginate::I18n.load_path) end # Extending the exception handler middleware so it properly detects # WillPaginate::InvalidPage regardless of it being a tag module. module ShowExceptionsPatch extend ActiveSupport::Concern included { alias_method_chain :status_code, :paginate } def status_code_with_paginate(exception = @exception) if exception.is_a?(WillPaginate::InvalidPage) or (exception.respond_to?(:original_exception) && exception.original_exception.is_a?(WillPaginate::InvalidPage)) Rack::Utils.status_code(:not_found) else original_method = method(:status_code_without_paginate) if original_method.arity != 0 original_method.call(exception) else original_method.call() end end end end module ControllerRescuePatch def rescue_from(*args, &block) if idx = args.index(WillPaginate::InvalidPage) args[idx] = args[idx].name end super(*args, &block) end end end end will_paginate-3.0.5/lib/will_paginate/locale/0000755000004100000410000000000012261225505021212 5ustar www-datawww-datawill_paginate-3.0.5/lib/will_paginate/locale/en.yml0000644000004100000410000000204612261225505022341 0ustar www-datawww-dataen: will_paginate: previous_label: "← Previous" next_label: "Next →" page_gap: "…" page_entries_info: single_page: zero: "No %{model} found" one: "Displaying 1 %{model}" other: "Displaying all %{count} %{model}" single_page_html: zero: "No %{model} found" one: "Displaying 1 %{model}" other: "Displaying all %{count} %{model}" multi_page: "Displaying %{model} %{from} - %{to} of %{count} in total" multi_page_html: "Displaying %{model} %{from} - %{to} of %{count} in total" # models: # entry: # zero: entries # one: entry # few: entries # other: entries # line_item: # page_entries_info: # single_page: # zero: "Your shopping cart is empty" # one: "Displaying one item in your cart" # other: "Displaying all %{count} items" # multi_page: "Displaying items %{from} - %{to} of %{count} in total" will_paginate-3.0.5/lib/will_paginate.rb0000644000004100000410000000125312261225505020301 0ustar www-datawww-data# You will paginate! module WillPaginate end if defined?(Rails::Railtie) require 'will_paginate/railtie' elsif defined?(Rails::Initializer) raise "will_paginate 3.0 is not compatible with Rails 2.3 or older" end if defined?(Merb::AbstractController) require 'will_paginate/view_helpers/merb' Merb::BootLoader.before_app_loads do adapters = { :datamapper => 'data_mapper', :activerecord => 'active_record', :sequel => 'sequel' } # auto-load the right ORM adapter if adapter = adapters[Merb.orm] require "will_paginate/#{adapter}" end end end if defined?(Sinatra) and Sinatra.respond_to? :register require 'will_paginate/view_helpers/sinatra' end will_paginate-3.0.5/metadata.yml0000644000004100000410000000550712261225505016700 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: will_paginate version: !ruby/object:Gem::Version prerelease: version: 3.0.5 platform: ruby authors: - Mislav Marohnić autorequire: bindir: bin cert_chain: [] date: 2013-09-18 00:00:00.000000000 Z dependencies: [] description: will_paginate provides a simple API for performing paginated queries with Active Record, DataMapper and Sequel, and includes helpers for rendering pagination links in Rails, Sinatra and Merb web apps. email: mislav.marohnic@gmail.com executables: [] extensions: [] extra_rdoc_files: - README.md - LICENSE files: - lib/will_paginate/active_record.rb - lib/will_paginate/array.rb - lib/will_paginate/collection.rb - lib/will_paginate/core_ext.rb - lib/will_paginate/data_mapper.rb - lib/will_paginate/deprecation.rb - lib/will_paginate/i18n.rb - lib/will_paginate/locale/en.yml - lib/will_paginate/page_number.rb - lib/will_paginate/per_page.rb - lib/will_paginate/railtie.rb - lib/will_paginate/sequel.rb - lib/will_paginate/version.rb - lib/will_paginate/view_helpers/action_view.rb - lib/will_paginate/view_helpers/link_renderer.rb - lib/will_paginate/view_helpers/link_renderer_base.rb - lib/will_paginate/view_helpers/merb.rb - lib/will_paginate/view_helpers/sinatra.rb - lib/will_paginate/view_helpers.rb - lib/will_paginate.rb - spec/collection_spec.rb - spec/console - spec/console_fixtures.rb - spec/database.yml - spec/fake_rubygems.rb - spec/finders/active_record_spec.rb - spec/finders/activerecord_test_connector.rb - spec/finders/data_mapper_spec.rb - spec/finders/data_mapper_test_connector.rb - spec/finders/sequel_spec.rb - spec/finders/sequel_test_connector.rb - spec/fixtures/admin.rb - spec/fixtures/developer.rb - spec/fixtures/developers_projects.yml - spec/fixtures/project.rb - spec/fixtures/projects.yml - spec/fixtures/replies.yml - spec/fixtures/reply.rb - spec/fixtures/schema.rb - spec/fixtures/topic.rb - spec/fixtures/topics.yml - spec/fixtures/user.rb - spec/fixtures/users.yml - spec/page_number_spec.rb - spec/per_page_spec.rb - spec/spec_helper.rb - spec/view_helpers/action_view_spec.rb - spec/view_helpers/base_spec.rb - spec/view_helpers/link_renderer_base_spec.rb - spec/view_helpers/view_example_group.rb - README.md - LICENSE homepage: https://github.com/mislav/will_paginate/wiki licenses: - MIT post_install_message: rdoc_options: - --main - README.md - --charset=UTF-8 require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: Pagination plugin for web frameworks and other apps test_files: [] will_paginate-3.0.5/LICENSE0000644000004100000410000000205712261225505015377 0ustar www-datawww-dataCopyright (c) 2009 Mislav Marohnić Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. will_paginate-3.0.5/README.md0000644000004100000410000000313612261225505015650 0ustar www-datawww-data# will_paginate will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Merb, DataMapper and Sequel. Installation: ``` ruby ## Gemfile for Rails 3, Sinatra, and Merb gem 'will_paginate', '~> 3.0' ``` See [installation instructions][install] on the wiki for more info. ## Basic will_paginate use ``` ruby ## perform a paginated query: @posts = Post.paginate(:page => params[:page]) # or, use an explicit "per page" limit: Post.paginate(:page => params[:page], :per_page => 30) ## render page links in the view: <%= will_paginate @posts %> ``` And that's it! You're done. You just need to add some CSS styles to [make those pagination links prettier][css]. You can customize the default "per_page" value: ``` ruby # for the Post model class Post self.per_page = 10 end # set per_page globally WillPaginate.per_page = 10 ``` New in Active Record 3: ``` ruby # paginate in Active Record now returns a Relation Post.where(:published => true).paginate(:page => params[:page]).order('id DESC') # the new, shorter page() method Post.page(params[:page]).order('created_at DESC') ``` See [the wiki][wiki] for more documentation. [Ask on the group][group] if you have usage questions. [Report bugs][issues] on GitHub. Happy paginating. [wiki]: https://github.com/mislav/will_paginate/wiki [install]: https://github.com/mislav/will_paginate/wiki/Installation "will_paginate installation" [group]: http://groups.google.com/group/will_paginate "will_paginate discussion and support group" [issues]: https://github.com/mislav/will_paginate/issues [css]: http://mislav.uniqpath.com/will_paginate/