pax_global_header 0000666 0000000 0000000 00000000064 14105170370 0014510 g ustar 00root root 0000000 0000000 52 comment=c0f1f470203e1b311bc559c057d8518da3b2967d
will_paginate-3.3.1/ 0000775 0000000 0000000 00000000000 14105170370 0014333 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/.envrc 0000664 0000000 0000000 00000000376 14105170370 0015457 0 ustar 00root root 0000000 0000000 # shellcheck shell=bash
export MYSQL_HOST=127.0.0.1
export MYSQL_PORT=3307
export POSTGRES_HOST=localhost
export POSTGRES_PORT=5433
export POSTGRES_USER=postgres
export POSTGRES_PASSWORD=postgres
export MONGODB_HOST=localhost
export MONGODB_PORT=27018
will_paginate-3.3.1/.github/ 0000775 0000000 0000000 00000000000 14105170370 0015673 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14105170370 0017730 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/.github/workflows/test.yml 0000664 0000000 0000000 00000005770 14105170370 0021443 0 ustar 00root root 0000000 0000000 ---
name: Test Suite
'on':
- push
- pull_request
jobs:
test-rails:
strategy:
fail-fast: false
matrix:
ruby:
- '2.4'
- '2.5'
- '2.6'
- '2.7'
- '3.0'
gemfile:
- Gemfile
- environments/Gemfile.rails5.0.rb
- environments/Gemfile.rails5.1.rb
- environments/Gemfile.rails5.2.rb
- environments/Gemfile.rails6.0.rb
- environments/Gemfile.rails-edge.rb
exclude:
- ruby: '2.4'
gemfile: Gemfile
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.0.rb
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.1.rb
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.2.rb
- ruby: '2.4'
gemfile: environments/Gemfile.rails6.0.rb
- ruby: '2.4'
gemfile: environments/Gemfile.rails-edge.rb
- ruby: '2.5'
gemfile: environments/Gemfile.rails-edge.rb
- ruby: '2.6'
gemfile: environments/Gemfile.rails-edge.rb
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
services:
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE: will_paginate
MYSQL_ALLOW_EMPTY_PASSWORD: true
ports:
- 3306:3306
postgres:
image: postgres:11
env:
POSTGRES_DB: will_paginate
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: "${{ matrix.ruby }}"
bundler-cache: true
- name: Run tests
env:
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3306
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
run: |
docker-wait() {
local container
container="$(docker ps -q -f ancestor=$1)"
timeout 90s bash -c "until docker exec $container $2; do sleep 5; done"
}
docker-wait postgres:11 "pg_isready"
docker-wait mysql:5.7 "mysqladmin ping"
bundler binstubs rspec-core
script/test_all
test-nonrails:
strategy:
fail-fast: false
matrix:
ruby:
- '2.4'
- '2.5'
- '2.6'
- '2.7'
- '3.0'
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: environments/Gemfile.non-rails.rb
services:
mongodb:
image: mongo:4.2
ports:
- 27017:27017
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: "${{ matrix.ruby }}"
bundler-cache: true
- name: Run tests
run: |
docker-wait() {
local container
container="$(docker ps -q -f ancestor=$1)"
timeout 90s bash -c "until docker exec $container $2; do sleep 5; done"
}
docker-wait mongo:4.2 "mongo --quiet"
bundler binstubs rspec-core
script/test_all
will_paginate-3.3.1/.gitignore 0000664 0000000 0000000 00000000142 14105170370 0016320 0 ustar 00root root 0000000 0000000 Gemfile*.lock
Brewfile.lock.json
.bundle
doc
*.gem
coverage
/bin
vendor/bundle
tags
.ruby-version
will_paginate-3.3.1/.rspec 0000664 0000000 0000000 00000000010 14105170370 0015437 0 ustar 00root root 0000000 0000000 --color
will_paginate-3.3.1/Brewfile 0000664 0000000 0000000 00000000224 14105170370 0016013 0 ustar 00root root 0000000 0000000 # brew 'mongodb/brew/mongodb-community@4.0', restart_service: true
brew 'mysql@5.7', restart_service: true
brew 'postgresql', restart_service: true
will_paginate-3.3.1/CONTRIBUTING.md 0000664 0000000 0000000 00000000565 14105170370 0016572 0 ustar 00root root 0000000 0000000 How to set up your environment for running tests:
1. Run `script/bootstrap`
**Note:** on systems without Homebrew, you must ensure that MySQL 5.7, PostgreSQL 12, and MongoDB 4.x Community Edition are up and running.
2. Run `script/test_all`
This ensures that the Active Record part of the suite is run across `sqlite3`, `mysql`, and `postgres` database adapters.
will_paginate-3.3.1/Gemfile 0000664 0000000 0000000 00000000530 14105170370 0015624 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# We test against other Rails versions, too. See `environments/`
rails_version = '~> 6.1.2'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
will_paginate-3.3.1/LICENSE 0000664 0000000 0000000 00000002057 14105170370 0015344 0 ustar 00root root 0000000 0000000 Copyright (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.3.1/README.md 0000664 0000000 0000000 00000003063 14105170370 0015614 0 ustar 00root root 0000000 0000000 # will_paginate
will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Hanami::View, Merb, DataMapper and Sequel.
``` ruby
gem 'will_paginate', '~> 3.1.0'
```
See [installation instructions][install] on the wiki for more info.
ℹ️ will_paginate is now in _maintenance mode_ and it will not be receiving new features. [See alternatives](https://www.ruby-toolbox.com/categories/pagination)
## 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. [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"
[issues]: https://github.com/mislav/will_paginate/issues
[css]: http://mislav.github.io/will_paginate/
will_paginate-3.3.1/docker-compose.yml 0000664 0000000 0000000 00000000576 14105170370 0020000 0 ustar 00root root 0000000 0000000 ---
version: '2.1'
services:
mysql:
image: mysql:5.7
environment:
- MYSQL_DATABASE=will_paginate
- MYSQL_ALLOW_EMPTY_PASSWORD=true
ports:
- 3307:3306
postgres:
image: postgres:11
environment:
- POSTGRES_DB=will_paginate
- POSTGRES_PASSWORD=postgres
ports:
- 5433:5432
mongodb:
image: mongo:4.2
ports:
- 27018:27017
will_paginate-3.3.1/environments/ 0000775 0000000 0000000 00000000000 14105170370 0017062 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/environments/Gemfile.non-rails.rb 0000664 0000000 0000000 00000000352 14105170370 0022660 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.4.0'
gem 'sequel', '~> 5.29'
gem 'dm-core'
gem 'dm-aggregates'
gem 'dm-migrations'
gem 'dm-sqlite-adapter'
gem 'mongoid', '~> 7.2.0'
will_paginate-3.3.1/environments/Gemfile.rails-edge.rb 0000664 0000000 0000000 00000000547 14105170370 0023000 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gem 'activerecord', git: 'https://github.com/rails/rails.git', branch: 'main'
gem 'actionpack', git: 'https://github.com/rails/rails.git', branch: 'main'
gem 'thread_safe'
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
will_paginate-3.3.1/environments/Gemfile.rails5.0.rb 0000664 0000000 0000000 00000000462 14105170370 0022315 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
rails_version = '~> 5.0.7'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rails-dom-testing'
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
will_paginate-3.3.1/environments/Gemfile.rails5.1.rb 0000664 0000000 0000000 00000000432 14105170370 0022313 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
rails_version = '~> 5.1.7'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
will_paginate-3.3.1/environments/Gemfile.rails5.2.rb 0000664 0000000 0000000 00000000431 14105170370 0022313 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
rails_version = '~> 5.2.4'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
will_paginate-3.3.1/environments/Gemfile.rails6.0.rb 0000664 0000000 0000000 00000000430 14105170370 0022311 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
rails_version = '~> 6.0.0'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 2.99'
gem 'mocha', '~> 0.9.8'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
will_paginate-3.3.1/init.rb 0000664 0000000 0000000 00000000727 14105170370 0015631 0 ustar 00root root 0000000 0000000 require 'will_paginate'
# This is all duplication of what Railtie does, but is necessary because
# the initializer defined by the Railtie won't ever run when loaded as plugin.
if defined? ActiveRecord::Base
require 'will_paginate/active_record'
end
if defined? ActionController::Base
WillPaginate::Railtie.setup_actioncontroller
end
if defined? ActionView::Base
require 'will_paginate/view_helpers/action_view'
end
WillPaginate::Railtie.add_locale_path config
will_paginate-3.3.1/lib/ 0000775 0000000 0000000 00000000000 14105170370 0015101 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/lib/will_paginate.rb 0000664 0000000 0000000 00000001253 14105170370 0020246 0 ustar 00root root 0000000 0000000 # 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.3.1/lib/will_paginate/ 0000775 0000000 0000000 00000000000 14105170370 0017720 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/lib/will_paginate/active_record.rb 0000664 0000000 0000000 00000016746 14105170370 0023074 0 ustar 00root root 0000000 0000000 require '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
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(*args)
if !loaded? && args.empty? && (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(*args)
if limit_value
excluded = [:order, :limit, :offset, :reorder]
excluded << :includes unless eager_loading?
rel = self.except(*excluded)
column_name = if rel.select_values.present?
select = rel.select_values.join(", ")
select if select !~ /[,*]/
end || :all
rel.count(column_name)
else
super(*args)
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
total_entries <= 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
end
end
module Pagination
def paginate(options)
options = options.dup
pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
options.delete(:page)
per_page = options.delete(:per_page) || self.per_page
total = options.delete(:total_entries)
if options.any?
raise ArgumentError, "unsupported parameters: %p" % options.keys
end
rel = limit(per_page.to_i).page(pagenum)
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
elsif (self.connection.adapter_name =~ /^sqlserver/i)
query << " OFFSET #{pager.offset} ROWS FETCH NEXT #{pager.per_page} ROWS ONLY"
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.3.1/lib/will_paginate/array.rb 0000664 0000000 0000000 00000002422 14105170370 0021363 0 ustar 00root root 0000000 0000000 require '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.3.1/lib/will_paginate/collection.rb 0000664 0000000 0000000 00000012054 14105170370 0022402 0 ustar 00root root 0000000 0000000 require '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.3.1/lib/will_paginate/core_ext.rb 0000664 0000000 0000000 00000001341 14105170370 0022054 0 ustar 00root root 0000000 0000000 require '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.3.1/lib/will_paginate/data_mapper.rb 0000664 0000000 0000000 00000005277 14105170370 0022535 0 ustar 00root root 0000000 0000000 require '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
total = options.delete(:total_entries)
options.delete(:page)
options[:limit] = per_page.to_i
col = all(options).page(pagenum)
col.total_entries = total.to_i unless total.nil? || (total.kind_of?(String) && total.strip.empty?)
col
end
end
module CollectionMethods
include WillPaginate::CollectionMethods
attr_accessor :current_page
attr_writer :total_entries
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.3.1/lib/will_paginate/deprecation.rb 0000664 0000000 0000000 00000002332 14105170370 0022542 0 ustar 00root root 0000000 0000000 module 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.logger) && 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, &block)
message = block_given? ? block : 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.3.1/lib/will_paginate/i18n.rb 0000664 0000000 0000000 00000001066 14105170370 0021027 0 ustar 00root root 0000000 0000000 module 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 = {}, &block)
if defined? ::I18n
defaults = Array(keys).dup
defaults << block 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.3.1/lib/will_paginate/locale/ 0000775 0000000 0000000 00000000000 14105170370 0021157 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/lib/will_paginate/locale/en.yml 0000664 0000000 0000000 00000002161 14105170370 0022304 0 ustar 00root root 0000000 0000000 en:
will_paginate:
previous_label: "← Previous"
next_label: "Next →"
page_gap: "…"
container_aria_label: "Pagination"
page_aria_label: "Page %{page}"
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.3.1/lib/will_paginate/mongoid.rb 0000664 0000000 0000000 00000002207 14105170370 0021702 0 ustar 00root root 0000000 0000000 require 'mongoid'
require 'will_paginate/collection'
module WillPaginate
module Mongoid
module CriteriaMethods
def paginate(options = {})
extend CollectionMethods
@current_page = WillPaginate::PageNumber(options[:page] || @current_page || 1)
@page_multiplier = current_page - 1
@total_entries = options.delete(:total_entries)
pp = (options[:per_page] || per_page || WillPaginate.per_page).to_i
limit(pp).skip(@page_multiplier * pp)
end
def per_page(value = :non_given)
if value == :non_given
options[:limit] == 0 ? nil : options[:limit] # in new Mongoid versions a nil limit is saved as 0
else
limit(value)
end
end
def page(page)
paginate(:page => page)
end
end
module CollectionMethods
attr_reader :current_page
def total_entries
@total_entries ||= count
end
def total_pages
(total_entries / per_page.to_f).ceil
end
def offset
@page_multiplier * per_page
end
end
::Mongoid::Criteria.send(:include, CriteriaMethods)
end
end
will_paginate-3.3.1/lib/will_paginate/page_number.rb 0000664 0000000 0000000 00000002300 14105170370 0022524 0 ustar 00root root 0000000 0000000 require 'forwardable'
module WillPaginate
# a module that page number exceptions are tagged with
module InvalidPage; end
# integer representing a page number
class PageNumber < Numeric
# 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
@value = value
rescue ArgumentError, TypeError, RangeError => error
error.extend InvalidPage
raise error
end
def to_i
@value
end
def_delegators :@value, :coerce, :==, :<=>, :to_s, :+, :-, :*, :/, :to_json
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
# 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.3.1/lib/will_paginate/per_page.rb 0000664 0000000 0000000 00000000751 14105170370 0022032 0 ustar 00root root 0000000 0000000 module 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.3.1/lib/will_paginate/railtie.rb 0000664 0000000 0000000 00000004342 14105170370 0021701 0 ustar 00root root 0000000 0000000 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
# 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
# Extending the exception handler middleware so it properly detects
# WillPaginate::InvalidPage regardless of it being a tag module.
module ShowExceptionsPatch
extend ActiveSupport::Concern
included do
alias_method :status_code_without_paginate, :status_code
alias_method :status_code, :status_code_with_paginate
end
def status_code_with_paginate(exception = @exception)
actual_exception = if exception.respond_to?(:cause)
exception.cause || exception
elsif exception.respond_to?(:original_exception)
exception.original_exception
else
exception
end
if actual_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, **kwargs, &block)
if idx = args.index(WillPaginate::InvalidPage)
args[idx] = args[idx].name
end
super(*args, **kwargs, &block)
end
end
end
end
ActiveSupport.on_load :i18n do
I18n.load_path.concat(WillPaginate::I18n.load_path)
end
will_paginate-3.3.1/lib/will_paginate/sequel.rb 0000664 0000000 0000000 00000001416 14105170370 0021545 0 ustar 00root root 0000000 0000000 require 'sequel'
require 'sequel/extensions/pagination'
require 'will_paginate/collection'
module WillPaginate
# Sequel already supports pagination; we only need to make the
# resulting dataset look a bit more like WillPaginate::Collection
module SequelMethods
include WillPaginate::CollectionMethods
def total_pages
page_count
end
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.3.1/lib/will_paginate/version.rb 0000664 0000000 0000000 00000000230 14105170370 0021725 0 ustar 00root root 0000000 0000000 module WillPaginate #:nodoc:
module VERSION #:nodoc:
MAJOR = 3
MINOR = 3
TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
end
will_paginate-3.3.1/lib/will_paginate/view_helpers.rb 0000664 0000000 0000000 00000015264 14105170370 0022751 0 ustar 00root root 0000000 0000000 # 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.3.1/lib/will_paginate/view_helpers/ 0000775 0000000 0000000 00000000000 14105170370 0022414 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/lib/will_paginate/view_helpers/action_view.rb 0000664 0000000 0000000 00000010637 14105170370 0025257 0 ustar 00root root 0000000 0000000 require '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 %>
# - ...
# <% 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
GET_PARAMS_BLACKLIST = [:script_name, :original_script_name]
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, GET_PARAMS_BLACKLIST)
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.3.1/lib/will_paginate/view_helpers/hanami.rb 0000664 0000000 0000000 00000002005 14105170370 0024173 0 ustar 00root root 0000000 0000000 require 'hanami/view'
require 'will_paginate/view_helpers'
require 'will_paginate/view_helpers/link_renderer'
module WillPaginate
module Hanami
module Helpers
include ViewHelpers
def will_paginate(collection, options = {}) #:nodoc:
options = options.merge(:renderer => LinkRenderer) unless options[:renderer]
str = super(collection, options)
str && raw(str)
end
end
class LinkRenderer < ViewHelpers::LinkRenderer
protected
def url(page)
str = File.join(request_env['SCRIPT_NAME'].to_s, request_env['PATH_INFO'])
params = request_env['rack.request.query_hash'].merge(param_name.to_s => page.to_s)
params.update @options[:params] if @options[:params]
str << '?' << build_query(params)
end
def request_env
@template.params.env
end
def build_query(params)
Rack::Utils.build_nested_query params
end
end
def self.included(base)
base.include Helpers
end
end
end
will_paginate-3.3.1/lib/will_paginate/view_helpers/link_renderer.rb 0000664 0000000 0000000 00000010674 14105170370 0025574 0 ustar 00root root 0000000 0000000 require '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?(Integer) ?
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 ||= {
:role => 'navigation',
:"aria-label" => @template.will_paginate_translate(:container_aria_label) { 'Pagination' }
}.update @options.except(*(ViewHelpers.pagination_options.keys + [:renderer] - [:class]))
end
protected
def page_number(page)
aria_label = @template.will_paginate_translate(:page_aria_label, :page => page.to_i) { "Page #{page}" }
if page == current_page
tag(:em, page, :class => 'current', :"aria-label" => aria_label, :"aria-current" => 'page')
else
link(page, page, :rel => rel_value(page), :"aria-label" => aria_label)
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', :"aria-disabled" => true)
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?(Integer)
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}#{name}>"
end
def rel_value(page)
case page
when @collection.current_page - 1; 'prev'
when @collection.current_page + 1; 'next'
end
end
def symbolized_update(target, other, blacklist = nil)
other.each_pair do |key, value|
key = key.to_sym
existing = target[key]
next if blacklist && blacklist.include?(key)
if value.respond_to?(:each_pair) 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.3.1/lib/will_paginate/view_helpers/link_renderer_base.rb 0000664 0000000 0000000 00000004455 14105170370 0026566 0 ustar 00root root 0000000 0000000 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 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 either 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.3.1/lib/will_paginate/view_helpers/merb.rb 0000664 0000000 0000000 00000001233 14105170370 0023665 0 ustar 00root root 0000000 0000000 require '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.3.1/lib/will_paginate/view_helpers/sinatra.rb 0000664 0000000 0000000 00000001725 14105170370 0024407 0 ustar 00root root 0000000 0000000 require '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.3.1/script/ 0000775 0000000 0000000 00000000000 14105170370 0015637 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/script/bootstrap 0000775 0000000 0000000 00000001266 14105170370 0017607 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vi:ft=sh:
set -e
if type -p brew >/dev/null; then
brew bundle --no-upgrade
mysql_prefix="$(brew --prefix mysql@5.7)"
openssl_prefix="$(brew --prefix openssl@1.1)"
bundle config set --local build.mysql2 --with-mysql-config="${mysql_prefix}/bin/mysql_config" --with-ldflags="-L${openssl_prefix}/lib"
while [ ! -e /tmp/mysql.sock ] && [ ! -e /var/run/mysql5/mysqld.sock ]; do
echo "Waiting for mysql to start up ..." >&2
sleep 1
done
fi
mysql -u root -e 'CREATE DATABASE IF NOT EXISTS will_paginate;'
psql --dbname will_paginate -c '' 2>/dev/null || createdb will_paginate
bundle config set path "$PWD/vendor/bundle"
bundle install
bundle binstubs rspec-core
will_paginate-3.3.1/script/ci-matrix 0000775 0000000 0000000 00000002343 14105170370 0017464 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
require "yaml"
ci_config = File.expand_path('../../.github/workflows/test.yml', __FILE__)
data = YAML.load(File.read(ci_config))
matrix = data.dig('jobs', 'test-rails', 'strategy', 'matrix')
ruby_versions = matrix.fetch('ruby')
gemfiles = matrix.fetch('gemfile')
requirements = {
'environments/Gemfile.rails5.0.rb' => ['>= 2.2', '< 3.0'],
'environments/Gemfile.rails5.1.rb' => ['>= 2.2', '< 3.0'],
'environments/Gemfile.rails5.2.rb' => ['>= 2.2', '< 3.0'],
'environments/Gemfile.rails6.0.rb' => '>= 2.5',
'Gemfile' => '>= 2.5',
'environments/Gemfile.rails-edge.rb' => '>= 2.7',
}
commands = {}
commands['excludes'] = -> {
excludes = []
gemfiles.each do |gemfile|
req = Gem::Requirement.new(requirements.fetch(gemfile))
ruby_versions.each do |version|
unless req.satisfied_by?(Gem::Version.new(version))
excludes << { 'ruby' => version, 'gemfile' => gemfile }
end
end
end
matrix['exclude'] = excludes
File.open(ci_config, 'w') do |file|
yaml_str = YAML.dump(data)
file.write(yaml_str)
end
}
cmd = commands.fetch(ARGV[0]) do
$stderr.puts "available commands: #{commands.keys.join(', ')}"
exit 1
end
cmd.(*ARGV[1..-1])
will_paginate-3.3.1/script/release 0000775 0000000 0000000 00000001216 14105170370 0017205 0 ustar 00root root 0000000 0000000 #!/bin/sh
set -euo pipefail
bin/rspec spec
BUNDLE_GEMFILE=environments/Gemfile.non-rails.rb bin/rspec spec-non-rails
changelog() {
local previous_tag="$(git describe --tags HEAD^ --abbrev=0)"
git log --first-parent --format='* %s%n%w(0,2,2)%+b' --reverse "${previous_tag}..HEAD^" "$@"
}
eval "$(gem build *.gemspec | awk '/(Name|Version|File): /{print tolower($1) $2}' | sed 's/:/=/')"
git commit -m "${name} ${version}" -- lib/will_paginate/version.rb
git tag "v${version}"
git push origin HEAD "v${version}"
gem push "$file"
rm -rf "$file"
{ echo "${name} ${version}"
echo
changelog -- lib
} | hub release create -F- --edit "v${version}"
will_paginate-3.3.1/script/test_all 0000775 0000000 0000000 00000000710 14105170370 0017372 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
set -e
binstubs_path="bin"
if [[ -n $CI && $BUNDLE_GEMFILE == */* ]]; then
binstubs_path="${BUNDLE_GEMFILE%/*}/bin"
fi
export PATH="${binstubs_path}:$PATH"
if [[ $BUNDLE_GEMFILE == *non-rails* ]]; then
echo "bin/rspec spec-non-rails"
exec rspec spec-non-rails
fi
status=0
for db in sqlite3 mysql postgres; do
printf "\e[1;33m[DB] %s\e[m\n" "$db"
echo "bin/rspec spec"
DB="$db" rspec spec || status="$?"
done
exit $status
will_paginate-3.3.1/spec-non-rails/ 0000775 0000000 0000000 00000000000 14105170370 0017165 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec-non-rails/data_mapper_spec.rb 0000664 0000000 0000000 00000006441 14105170370 0023006 0 ustar 00root root 0000000 0000000 require_relative './spec_helper'
require 'will_paginate/data_mapper'
require_relative './data_mapper_test_connector'
describe "WillPaginate::DataMapper" do
before(:all) do
DataMapper.setup :default, 'sqlite3::memory:'
[Animal, Ownership, Human].each do |klass|
klass.auto_migrate!
end
Animal.create(:name => 'Dog', :notes => 'a friend of all')
Animal.create(:name => 'Cat', :notes => 'a friend or foe')
Animal.create(:name => 'Lion', :notes => 'some roar')
end
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 "overrides total_entries count with a fixed value" do
animals = Animal.paginate :page => 1, :per_page => 3, :total_entries => 999
animals.total_entries.should == 999
end
it "supports a non-int for total_entries" do
topics = Animal.paginate :page => 1, :per_page => 3, :total_entries => "999"
topics.total_entries.should == 999
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
will_paginate-3.3.1/spec-non-rails/data_mapper_test_connector.rb 0000664 0000000 0000000 00000001173 14105170370 0025102 0 ustar 00root root 0000000 0000000 require 'sqlite3'
require 'dm-core'
require 'dm-core/support/logger'
require 'dm-migrations'
class Animal
include DataMapper::Resource
property :id, Serial
property :name, String
property :notes, Text
end
class Ownership
include DataMapper::Resource
belongs_to :animal, :key => true
belongs_to :human, :key => true
end
class Human
include DataMapper::Resource
property :id, Serial
property :name, String
has n, :ownerships
has 1, :pet, :model => 'Animal', :through => :ownerships, :via => :animal
end
if 'irb' == $0
DataMapper.logger.set_log($stdout, :debug)
DataMapper.logger.auto_flush = true
end
will_paginate-3.3.1/spec-non-rails/mongoid_spec.rb 0000664 0000000 0000000 00000010606 14105170370 0022163 0 ustar 00root root 0000000 0000000 require_relative './spec_helper'
require 'will_paginate/mongoid'
describe WillPaginate::Mongoid do
class MongoidModel
include Mongoid::Document
end
before(:all) do
Mongoid.configure do |config|
mongodb_host = ENV["MONGODB_HOST"] || "localhost"
mongodb_port = ENV["MONGODB_PORT"] || "27017"
config.clients.default = {
hosts: ["#{mongodb_host}:#{mongodb_port}"],
database: "will_paginate_test",
}
config.log_level = :warn
end
MongoidModel.delete_all
4.times { MongoidModel.create! }
end
let(:criteria) { MongoidModel.criteria }
describe "#page" do
it "should forward to the paginate method" do
criteria.expects(:paginate).with(:page => 2).returns("itself")
criteria.page(2).should == "itself"
end
it "should not override per_page if set earlier in the chain" do
criteria.paginate(:per_page => 10).page(1).per_page.should == 10
criteria.paginate(:per_page => 20).page(1).per_page.should == 20
end
end
describe "#per_page" do
it "should set the limit if given an argument" do
criteria.per_page(10).options[:limit].should == 10
end
it "should return the current limit if no argument is given" do
criteria.per_page.should == nil
criteria.per_page(10).per_page.should == 10
end
it "should be interchangable with limit" do
criteria.limit(15).per_page.should == 15
end
it "should be nil'able" do
criteria.per_page(nil).per_page.should be_nil
end
end
describe "#paginate" do
it "should use criteria" do
criteria.paginate.should be_instance_of(::Mongoid::Criteria)
end
it "should not override page number if set earlier in the chain" do
criteria.page(3).paginate.current_page.should == 3
end
it "should limit according to per_page parameter" do
criteria.paginate(:per_page => 10).options.should include(:limit => 10)
end
it "should skip according to page and per_page parameters" do
criteria.paginate(:page => 2, :per_page => 5).options.should include(:skip => 5)
end
specify "first fallback value for per_page option is the current limit" do
criteria.limit(12).paginate.options.should include(:limit => 12)
end
specify "second fallback value for per_page option is WillPaginate.per_page" do
criteria.paginate.options.should include(:limit => WillPaginate.per_page)
end
specify "page should default to 1" do
criteria.paginate.options.should include(:skip => 0)
end
it "should convert strings to integers" do
criteria.paginate(:page => "2", :per_page => "3").options.should include(:limit => 3)
end
describe "collection compatibility" do
describe "#total_count" do
it "should be calculated correctly" do
criteria.paginate(:per_page => 1).total_entries.should == 4
criteria.paginate(:per_page => 3).total_entries.should == 4
end
it "should be cached" do
criteria.expects(:count).once.returns(123)
criteria.paginate
2.times { criteria.total_entries.should == 123 }
end
end
it "should calculate total_pages" do
criteria.paginate(:per_page => 1).total_pages.should == 4
criteria.paginate(:per_page => 3).total_pages.should == 2
criteria.paginate(:per_page => 10).total_pages.should == 1
end
it "should return per_page" do
criteria.paginate(:per_page => 1).per_page.should == 1
criteria.paginate(:per_page => 5).per_page.should == 5
end
describe "#current_page" do
it "should return current_page" do
criteria.paginate(:page => 1).current_page.should == 1
criteria.paginate(:page => 3).current_page.should == 3
end
it "should be casted to PageNumber" do
page = criteria.paginate(:page => 1).current_page
(page.instance_of? WillPaginate::PageNumber).should be
end
end
it "should return offset" do
criteria.paginate(:page => 1).offset.should == 0
criteria.paginate(:page => 2, :per_page => 5).offset.should == 5
criteria.paginate(:page => 3, :per_page => 10).offset.should == 20
end
it "should not pollute plain mongoid criterias" do
%w(total_entries total_pages current_page).each do |method|
criteria.should_not respond_to(method)
end
end
end
end
end
will_paginate-3.3.1/spec-non-rails/sequel_spec.rb 0000664 0000000 0000000 00000003476 14105170370 0022034 0 ustar 00root root 0000000 0000000 require_relative './spec_helper'
require 'sequel'
require 'will_paginate/sequel'
Sequel.sqlite.create_table :cars do
primary_key :id, :integer, :auto_increment => true
column :name, :text
column :notes, :text
end
describe Sequel::Dataset::Pagination, 'extension' do
class Car < Sequel::Model
self.dataset = dataset.extension(:pagination)
end
it "should have the #paginate method" do
Car.dataset.should respond_to(:paginate)
end
it "should NOT have the #paginate_by_sql method" do
Car.dataset.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.dataset.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.dataset.paginate(1, 2).all.should == [Car[1], Car[2]]
end
it "should be empty" do
result = Car.dataset.paginate(3, 2)
result.should be_empty
end
it "should perform with #select and #order" do
result = Car.select(Sequel.lit("name as foo")).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
will_paginate-3.3.1/spec-non-rails/spec_helper.rb 0000664 0000000 0000000 00000000113 14105170370 0021776 0 ustar 00root root 0000000 0000000 require 'rspec'
RSpec.configure do |config|
config.mock_with :mocha
end
will_paginate-3.3.1/spec/ 0000775 0000000 0000000 00000000000 14105170370 0015265 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec/collection_spec.rb 0000664 0000000 0000000 00000010004 14105170370 0020752 0 ustar 00root root 0000000 0000000 require '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.3.1/spec/console 0000775 0000000 0000000 00000000644 14105170370 0016661 0 ustar 00root root 0000000 0000000 #!/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.3.1/spec/console_fixtures.rb 0000664 0000000 0000000 00000001434 14105170370 0021207 0 ustar 00root root 0000000 0000000 require '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.3.1/spec/database.yml 0000664 0000000 0000000 00000001321 14105170370 0017551 0 ustar 00root root 0000000 0000000 sqlite3:
database: ":memory:"
adapter: sqlite3
timeout: 500
mysql:
adapter: mysql2
database: will_paginate
username: <%= ENV["MYSQL_USER"] || "root" %>
encoding: utf8
<% if ENV["MYSQL_PORT"] %>
host: <%= ENV["MYSQL_HOST"] %>
port: <%= ENV["MYSQL_PORT"] %>
<% elsif File.exist?("/var/run/mysql5/mysqld.sock") %>
host: localhost
socket: /var/run/mysql5/mysqld.sock
<% elsif File.exist? "/tmp/mysql.sock" %>
host: localhost
socket: /tmp/mysql.sock
<% end %>
postgres:
adapter: postgresql
database: will_paginate
min_messages: warning
username: <%= ENV["POSTGRES_USER"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
host: <%= ENV["POSTGRES_HOST"] %>
port: <%= ENV["POSTGRES_PORT"] %>
will_paginate-3.3.1/spec/finders/ 0000775 0000000 0000000 00000000000 14105170370 0016717 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec/finders/active_record_spec.rb 0000664 0000000 0000000 00000032016 14105170370 0023071 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/active_record'
require File.expand_path('../activerecord_test_connector', __FILE__)
ActiverecordTestConnector.setup
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
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 "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 "overrides empty? count call with a total_entries fixed value" do
lambda {
topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => 999
topics.should_not be_empty
}.should run_queries(0)
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 = with_condition.references(:projects) if with_condition.respond_to?(:references)
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 "should count with select" do
Topic.select('title, content').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
expected = topics(:ar)
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 == expected
}.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 1 query" do
lambda {
result = Topic.paginate :page => 2
result.total_pages.should == 1
result.should be_empty
}.should run_queries(1)
end
describe "associations" do
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.includes(:topics).order('projects.name').paginate(:page => 1)
}
result.to_a.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.order('projects.id').limit(4).to_a
}.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.where('developers_projects.project_id = 1').joins(join_sql).paginate(:page => 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.where('developers_projects.project_id = 1').joins(join_sql).paginate(:page => 1)
result.should == expected
result.total_entries.should == 2
}.should run_queries(1)
end
it "should paginate with group" do
result = nil
lambda {
result = Developer.select('salary').order('salary').group('salary').
paginate(:page => 1, :per_page => 10).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
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 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
end
will_paginate-3.3.1/spec/finders/activerecord_test_connector.rb 0000664 0000000 0000000 00000005451 14105170370 0025034 0 ustar 00root root 0000000 0000000 require 'active_record'
require 'active_record/fixtures'
require 'stringio'
require 'erb'
$query_count = 0
$query_sql = []
ignore_sql = /
^(
PRAGMA | SHOW\ (max_identifier_length|search_path) |
SELECT\ (currval|CAST|@@IDENTITY|@@ROWCOUNT) |
SHOW\ ((FULL\ )?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 :connected
FIXTURES_PATH = File.expand_path('../../fixtures', __FILE__)
# Set our defaults
self.connected = false
def setup
unless self.connected
setup_connection
load_schema
add_load_path FIXTURES_PATH
self.connected = true
end
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']
erb = ERB.new(File.read(File.expand_path('../../database.yml', __FILE__)))
configurations = YAML.load(erb.result)
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.to_sym)
ActiveRecord::Base.default_timezone = :utc
end
def load_schema
begin
$stdout = StringIO.new
ActiveRecord::Migration.verbose = false
load File.join(FIXTURES_PATH, 'schema.rb')
ensure
$stdout = STDOUT
end
end
module FixtureSetup
def fixtures(*tables)
table_names = tables.map { |t| t.to_s }
fixtures = ActiveRecord::FixtureSet.create_fixtures(ActiverecordTestConnector::FIXTURES_PATH, table_names)
@@loaded_fixtures = {}
@@fixture_cache = {}
unless fixtures.nil?
fixtures.each { |f| @@loaded_fixtures[f.table_name] = f }
end
table_names.each do |table_name|
define_method(table_name) do |*names|
@@fixture_cache[table_name] ||= {}
instances = names.map do |name|
if @@loaded_fixtures[table_name][name.to_s]
@@fixture_cache[table_name][name] ||= @@loaded_fixtures[table_name][name.to_s].find
else
raise StandardError, "No fixture with name '#{name}' found for table '#{table_name}'"
end
end
instances.size == 1 ? instances.first : instances
end
end
end
end
end
will_paginate-3.3.1/spec/fixtures/ 0000775 0000000 0000000 00000000000 14105170370 0017136 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec/fixtures/admin.rb 0000664 0000000 0000000 00000000055 14105170370 0020553 0 ustar 00root root 0000000 0000000 class Admin < User
has_many :companies
end
will_paginate-3.3.1/spec/fixtures/developer.rb 0000664 0000000 0000000 00000000322 14105170370 0021445 0 ustar 00root root 0000000 0000000 class Developer < User
has_and_belongs_to_many :projects, :join_table => 'developers_projects'
scope :poor, lambda {
where(['salary <= ?', 80000]).order('salary')
}
def self.per_page() 10 end
end
will_paginate-3.3.1/spec/fixtures/developers_projects.yml 0000664 0000000 0000000 00000000332 14105170370 0023740 0 ustar 00root root 0000000 0000000 david_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: 1 will_paginate-3.3.1/spec/fixtures/project.rb 0000664 0000000 0000000 00000000705 14105170370 0021133 0 ustar 00root root 0000000 0000000 class Project < ActiveRecord::Base
has_and_belongs_to_many :developers, :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 = {})
where(['replies.created_at > ?', 15.minutes.ago])
end
end
end
will_paginate-3.3.1/spec/fixtures/projects.yml 0000664 0000000 0000000 00000000142 14105170370 0021507 0 ustar 00root root 0000000 0000000 active_record:
id: 1
name: Active Record
action_controller:
id: 2
name: Action Controller
will_paginate-3.3.1/spec/fixtures/replies.yml 0000664 0000000 0000000 00000001060 14105170370 0021321 0 ustar 00root root 0000000 0000000 witty_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.3.1/spec/fixtures/reply.rb 0000664 0000000 0000000 00000000303 14105170370 0020612 0 ustar 00root root 0000000 0000000 class Reply < ActiveRecord::Base
scope :recent, lambda {
where(['replies.created_at > ?', 15.minutes.ago]).
order('replies.created_at DESC')
}
validates_presence_of :content
end
will_paginate-3.3.1/spec/fixtures/schema.rb 0000664 0000000 0000000 00000002126 14105170370 0020724 0 ustar 00root root 0000000 0000000 ActiveRecord::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.3.1/spec/fixtures/topic.rb 0000664 0000000 0000000 00000000312 14105170370 0020575 0 ustar 00root root 0000000 0000000 class Topic < ActiveRecord::Base
has_many :replies, :dependent => :destroy
belongs_to :project
scope :mentions_activerecord, lambda {
where(['topics.title LIKE ?', '%ActiveRecord%'])
}
end
will_paginate-3.3.1/spec/fixtures/topics.yml 0000664 0000000 0000000 00000001354 14105170370 0021165 0 ustar 00root root 0000000 0000000 futurama:
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.3.1/spec/fixtures/user.rb 0000664 0000000 0000000 00000000044 14105170370 0020437 0 ustar 00root root 0000000 0000000 class User < ActiveRecord::Base
end
will_paginate-3.3.1/spec/fixtures/users.yml 0000664 0000000 0000000 00000000650 14105170370 0021023 0 ustar 00root root 0000000 0000000 david:
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.3.1/spec/matchers/ 0000775 0000000 0000000 00000000000 14105170370 0017073 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec/matchers/deprecation_matcher.rb 0000664 0000000 0000000 00000000763 14105170370 0023426 0 ustar 00root root 0000000 0000000 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.3.1/spec/matchers/phrase_matcher.rb 0000664 0000000 0000000 00000000636 14105170370 0022412 0 ustar 00root root 0000000 0000000 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
will_paginate-3.3.1/spec/matchers/query_count_matcher.rb 0000664 0000000 0000000 00000001214 14105170370 0023476 0 ustar 00root root 0000000 0000000 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.3.1/spec/page_number_spec.rb 0000664 0000000 0000000 00000004531 14105170370 0021113 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/page_number'
require 'json'
describe WillPaginate::PageNumber do
describe "valid" do
def num
WillPaginate::PageNumber.new('12', 'page')
end
it "== 12" do
num.should eq(12)
end
it "inspects to 'page 12'" do
num.inspect.should eq('page 12')
end
it "is a PageNumber" do
(num.instance_of? WillPaginate::PageNumber).should be
end
it "is a kind of Numeric" do
(num.is_a? Numeric).should be
end
it "is a kind of Integer" do
(num.is_a? Integer).should be
end
it "isn't directly a Integer" do
(num.instance_of? Integer).should_not be
end
it "passes the PageNumber=== type check" do |variable|
(WillPaginate::PageNumber === num).should be
end
it "passes the Numeric=== type check" do |variable|
(Numeric === num).should be
end
it "fails the Numeric=== type check" do |variable|
(Integer === num).should_not be
end
it "serializes as JSON number" do
JSON.dump(page: num).should eq('{"page":12}')
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.3.1/spec/per_page_spec.rb 0000664 0000000 0000000 00000001420 14105170370 0020403 0 ustar 00root root 0000000 0000000 require '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.3.1/spec/spec_helper.rb 0000664 0000000 0000000 00000001547 14105170370 0020112 0 ustar 00root root 0000000 0000000 require 'rspec'
require 'view_helpers/view_example_group'
Dir[File.expand_path('../matchers/*_matcher.rb', __FILE__)].each { |matcher| require matcher }
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
def run_queries(num)
QueryCountMatcher.new(num)
end
def ignore_deprecation
ActiveSupport::Deprecation.silence { yield }
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
}
config.mock_with :mocha
config.backtrace_exclusion_patterns << /view_example_group/
end
will_paginate-3.3.1/spec/view_helpers/ 0000775 0000000 0000000 00000000000 14105170370 0017761 5 ustar 00root root 0000000 0000000 will_paginate-3.3.1/spec/view_helpers/action_view_spec.rb 0000664 0000000 0000000 00000032556 14105170370 0023642 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'spec_helper'
require 'action_controller'
require 'action_view'
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 'foo/bar' => 'foo#bar'
get 'baz/list' => 'baz#list'
end
describe WillPaginate::ActionView do
before(:all) do
I18n.load_path.concat WillPaginate::I18n.load_path
I18n.enforce_available_locales = false
ActionController::Parameters.permit_all_parameters = false
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)
lookup_context = []
lookup_context = ActionView::LookupContext.new(lookup_context)
klass = ActionView::Base
klass = klass.with_empty_template_cache if klass.respond_to?(:with_empty_template_cache)
@view = klass.new(lookup_context, @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
text(elements[2]).should == 'Next →'
end
assert_select 'span', 1 do |spans|
spans[0]['class'].should == 'previous_page disabled'
text(spans[0]).should == '← Previous'
end
assert_select 'em.current', '1'
text(pagination[0]).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:
text(elements[0]).should == 'Prev'
elements[0]['rel'].should == 'prev'
text(elements[1]).should == '1'
elements[1]['rel'].should == 'prev'
text(elements[3]).should == 'Next'
elements[3]['rel'].should == 'next'
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 = parse_html_document(expected)
if expected_dom.respond_to?(:canonicalize)
html_document.canonicalize.should == expected_dom.canonicalize
else
html_document.root.should == expected_dom.root
end
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]
parts = query.gsub('&', '&').split('&').sort
parts.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 "doesn't allow tampering with script_name" do
request.params :script_name => 'p0wned', :original_script_name => 'p0wned'
paginate
assert_links_match %r{^/foo/bar}
assert_no_links_match /p0wned/
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 => 'index'
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 => 'index'
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 = Class.new {
attr_reader :controller
include ActionView::Helpers::UrlHelper
include Routes.url_helpers
include WillPaginate::ActionView
}.new
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 = Class.new {
include ActionDispatch::Routing::UrlFor
include Routes.url_helpers
include WillPaginate::ActionView
}.new
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
# TODO: re-enable once Rails 6.1.4 ships
xit "page_entries_info" do
@template = "<%= page_entries_info collection, options %>"
output = render(
collection: WillPaginate::Collection.new(1, 1, 3),
options: {html: false},
)
output.should == "Displaying entries 1 - 0 of 3 in total"
end
private
def translation(data)
I18n.available_locales # triggers loading existing translations
I18n.backend.store_translations(:en, data)
end
# Normalizes differences between HTML::Document and Nokogiri::HTML
def text(node)
node.inner_text.gsub('→', '→').gsub('←', '←')
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(self)
end
def params
@request.params
end
def env
{}
end
def _prefixes
[]
end
end
class IbocorpController < DummyController
end
class DummyRequest
attr_accessor :symbolized_path_parameters
alias :path_parameters :symbolized_path_parameters
def initialize(controller)
@controller = controller
@get = true
@params = {}.with_indifferent_access
@symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
end
def routes
@controller._routes
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
ActionController::Parameters.new(@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.3.1/spec/view_helpers/base_spec.rb 0000664 0000000 0000000 00000011133 14105170370 0022231 0 ustar 00root root 0000000 0000000 require '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
I18n.enforce_available_locales = false
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.3.1/spec/view_helpers/link_renderer_base_spec.rb 0000664 0000000 0000000 00000005234 14105170370 0025141 0 ustar 00root root 0000000 0000000 require '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.3.1/spec/view_helpers/view_example_group.rb 0000664 0000000 0000000 00000004657 14105170370 0024223 0 ustar 00root root 0000000 0000000 require 'active_support'
require 'stringio'
require 'minitest/assertions'
require 'rails/dom/testing/assertions'
require 'will_paginate/array'
module ViewExampleGroup
include Rails::Dom::Testing::Assertions::SelectorAssertions
include Minitest::Assertions
def assert(value, message)
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 parse_html_document(html)
Nokogiri::HTML::Document.parse(html)
end
def html_document
@html_document ||= parse_html_document(@render_output)
end
def document_root_element
html_document.root
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
will_paginate-3.3.1/will_paginate.gemspec 0000664 0000000 0000000 00000003271 14105170370 0020522 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'rbconfig'
require File.expand_path('../lib/will_paginate/version', __FILE__)
Gem::Specification.new do |s|
s.name = 'will_paginate'
s.version = WillPaginate::VERSION::STRING
s.required_ruby_version = '>= 2.0'
s.summary = "Pagination plugin for web frameworks and other apps"
s.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, Hanami, and Merb web apps."
s.authors = ['Mislav Marohnić']
s.email = 'mislav.marohnic@gmail.com'
s.homepage = 'https://github.com/mislav/will_paginate'
s.license = 'MIT'
s.metadata = {
'bug_tracker_uri' => 'https://github.com/mislav/will_paginate/issues',
'changelog_uri' => "https://github.com/mislav/will_paginate/releases/tag/v#{s.version}",
'documentation_uri' => "https://www.rubydoc.info/gems/will_paginate/#{s.version}",
'source_code_uri' => "https://github.com/mislav/will_paginate/tree/v#{s.version}",
'wiki_uri' => 'https://github.com/mislav/will_paginate/wiki'
}
s.rdoc_options = ['--main', 'README.md', '--charset=UTF-8']
s.extra_rdoc_files = ['README.md', 'LICENSE']
s.files = Dir['Rakefile', '{bin,lib,test,spec}/**/*', 'README*', 'LICENSE*']
# include only files in version control
git_dir = File.expand_path('../.git', __FILE__)
void = defined?(File::NULL) ? File::NULL :
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw/ ? 'NUL' : '/dev/null'
if File.directory?(git_dir) and system "git --version >>#{void} 2>&1"
s.files &= `git --git-dir='#{git_dir}' ls-files -z`.split("\0")
end
end