pax_global_header 0000666 0000000 0000000 00000000064 14631541146 0014517 g ustar 00root root 0000000 0000000 52 comment=50017c3eb0712e7b3a53268a81e81a184b7a49f6
mislav-will_paginate-50017c3/ 0000775 0000000 0000000 00000000000 14631541146 0016073 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/.envrc 0000664 0000000 0000000 00000000416 14631541146 0017212 0 ustar 00root root 0000000 0000000 PATH_add ./bin
# 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
mislav-will_paginate-50017c3/.github/ 0000775 0000000 0000000 00000000000 14631541146 0017433 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/.github/dependabot.yml 0000664 0000000 0000000 00000000166 14631541146 0022266 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
mislav-will_paginate-50017c3/.github/workflows/ 0000775 0000000 0000000 00000000000 14631541146 0021470 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/.github/workflows/test.yml 0000664 0000000 0000000 00000010121 14631541146 0023165 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'
- '3.1'
- '3.2'
- '3.3'
gemfile:
- Gemfile
- environments/Gemfile.rails5.0.rb
- environments/Gemfile.rails5.1.rb
- environments/Gemfile.rails5.2.rb
- environments/Gemfile.rails6.0.rb
- environments/Gemfile.rails6.1.rb
- environments/Gemfile.rails-edge.rb
exclude:
- ruby: '2.4'
gemfile: Gemfile
- ruby: '2.5'
gemfile: Gemfile
- ruby: '2.6'
gemfile: Gemfile
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.0.rb
- ruby: '3.1'
gemfile: environments/Gemfile.rails5.0.rb
- ruby: '3.2'
gemfile: environments/Gemfile.rails5.0.rb
- ruby: '3.3'
gemfile: environments/Gemfile.rails5.0.rb
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.1.rb
- ruby: '3.1'
gemfile: environments/Gemfile.rails5.1.rb
- ruby: '3.2'
gemfile: environments/Gemfile.rails5.1.rb
- ruby: '3.3'
gemfile: environments/Gemfile.rails5.1.rb
- ruby: '3.0'
gemfile: environments/Gemfile.rails5.2.rb
- ruby: '3.1'
gemfile: environments/Gemfile.rails5.2.rb
- ruby: '3.2'
gemfile: environments/Gemfile.rails5.2.rb
- ruby: '3.3'
gemfile: environments/Gemfile.rails5.2.rb
- ruby: '2.4'
gemfile: environments/Gemfile.rails6.0.rb
- ruby: '2.4'
gemfile: environments/Gemfile.rails6.1.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
- ruby: '2.7'
gemfile: environments/Gemfile.rails-edge.rb
- ruby: '3.0'
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@v4
- 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'
- '3.1'
- '3.2'
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@v4
- 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
mislav-will_paginate-50017c3/.gitignore 0000664 0000000 0000000 00000000142 14631541146 0020060 0 ustar 00root root 0000000 0000000 Gemfile*.lock
Brewfile.lock.json
.bundle
doc
*.gem
coverage
/bin
vendor/bundle
tags
.ruby-version
mislav-will_paginate-50017c3/.rspec 0000664 0000000 0000000 00000000010 14631541146 0017177 0 ustar 00root root 0000000 0000000 --color
mislav-will_paginate-50017c3/Brewfile 0000664 0000000 0000000 00000000224 14631541146 0017553 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
mislav-will_paginate-50017c3/CONTRIBUTING.md 0000664 0000000 0000000 00000000565 14631541146 0020332 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.
mislav-will_paginate-50017c3/Gemfile 0000664 0000000 0000000 00000000526 14631541146 0017371 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# We test against other Rails versions, too. See `environments/`
rails_version = '~> 7.1.3'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.5.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
mislav-will_paginate-50017c3/LICENSE 0000664 0000000 0000000 00000002057 14631541146 0017104 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.
mislav-will_paginate-50017c3/README.md 0000664 0000000 0000000 00000003032 14631541146 0017350 0 ustar 00root root 0000000 0000000 # will_paginate
will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Hanami::View, and Sequel.
``` ruby
gem 'will_paginate', '~> 4.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/
mislav-will_paginate-50017c3/docker-compose.yml 0000664 0000000 0000000 00000000576 14631541146 0021540 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
mislav-will_paginate-50017c3/environments/ 0000775 0000000 0000000 00000000000 14631541146 0020622 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/environments/Gemfile.non-rails.rb 0000664 0000000 0000000 00000000232 14631541146 0024415 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gem 'rspec', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.4.0'
gem 'sequel', '~> 5.29'
gem 'mongoid', '~> 7.2.0'
mislav-will_paginate-50017c3/environments/Gemfile.rails-edge.rb 0000664 0000000 0000000 00000000545 14631541146 0024536 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', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
mislav-will_paginate-50017c3/environments/Gemfile.rails5.0.rb 0000664 0000000 0000000 00000000551 14631541146 0024054 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', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
# ruby 2.4 compat re: nokogiri
gem 'loofah', '< 2.21.0'
mislav-will_paginate-50017c3/environments/Gemfile.rails5.1.rb 0000664 0000000 0000000 00000000521 14631541146 0024052 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', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
# ruby 2.4 compat re: nokogiri
gem 'loofah', '< 2.21.0'
mislav-will_paginate-50017c3/environments/Gemfile.rails5.2.rb 0000664 0000000 0000000 00000000520 14631541146 0024052 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', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.3.6'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2.3', :group => :pg
# ruby 2.4 compat re: nokogiri
gem 'loofah', '< 2.21.0'
mislav-will_paginate-50017c3/environments/Gemfile.rails6.0.rb 0000664 0000000 0000000 00000000426 14631541146 0024056 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', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
mislav-will_paginate-50017c3/environments/Gemfile.rails6.1.rb 0000664 0000000 0000000 00000000426 14631541146 0024057 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
rails_version = '~> 6.1.0'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.4.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
mislav-will_paginate-50017c3/environments/Gemfile.rails7.0.rb 0000664 0000000 0000000 00000000526 14631541146 0024060 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# We test against other Rails versions, too. See `environments/`
rails_version = '~> 7.0.2'
gem 'activerecord', rails_version
gem 'actionpack', rails_version
gem 'rspec', '~> 3.12'
gem 'mocha', '~> 2.0'
gem 'sqlite3', '~> 1.5.0'
gem 'mysql2', '~> 0.5.2', :group => :mysql
gem 'pg', '~> 1.2', :group => :pg
mislav-will_paginate-50017c3/init.rb 0000664 0000000 0000000 00000000727 14631541146 0017371 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
mislav-will_paginate-50017c3/lib/ 0000775 0000000 0000000 00000000000 14631541146 0016641 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/lib/will_paginate.rb 0000664 0000000 0000000 00000000504 14631541146 0022004 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?(Sinatra) and Sinatra.respond_to? :register
require 'will_paginate/view_helpers/sinatra'
end
mislav-will_paginate-50017c3/lib/will_paginate/ 0000775 0000000 0000000 00000000000 14631541146 0021460 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/lib/will_paginate/active_record.rb 0000664 0000000 0000000 00000016746 14631541146 0024634 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
mislav-will_paginate-50017c3/lib/will_paginate/array.rb 0000664 0000000 0000000 00000002422 14631541146 0023123 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
mislav-will_paginate-50017c3/lib/will_paginate/collection.rb 0000664 0000000 0000000 00000012054 14631541146 0024142 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
mislav-will_paginate-50017c3/lib/will_paginate/core_ext.rb 0000664 0000000 0000000 00000001341 14631541146 0023614 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
mislav-will_paginate-50017c3/lib/will_paginate/deprecation.rb 0000664 0000000 0000000 00000002332 14631541146 0024302 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
mislav-will_paginate-50017c3/lib/will_paginate/i18n.rb 0000664 0000000 0000000 00000001066 14631541146 0022567 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
mislav-will_paginate-50017c3/lib/will_paginate/locale/ 0000775 0000000 0000000 00000000000 14631541146 0022717 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/lib/will_paginate/locale/en.yml 0000664 0000000 0000000 00000002273 14631541146 0024050 0 ustar 00root root 0000000 0000000 en:
will_paginate:
previous_label: "← Previous"
previous_aria_label: "Previous page"
next_label: "Next →"
next_aria_label: "Next page"
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"
mislav-will_paginate-50017c3/lib/will_paginate/mongoid.rb 0000664 0000000 0000000 00000002207 14631541146 0023442 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
mislav-will_paginate-50017c3/lib/will_paginate/page_number.rb 0000664 0000000 0000000 00000002300 14631541146 0024264 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
mislav-will_paginate-50017c3/lib/will_paginate/per_page.rb 0000664 0000000 0000000 00000000751 14631541146 0023572 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
mislav-will_paginate-50017c3/lib/will_paginate/railtie.rb 0000664 0000000 0000000 00000004342 14631541146 0023441 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
mislav-will_paginate-50017c3/lib/will_paginate/sequel.rb 0000664 0000000 0000000 00000001416 14631541146 0023305 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
mislav-will_paginate-50017c3/lib/will_paginate/version.rb 0000664 0000000 0000000 00000000230 14631541146 0023465 0 ustar 00root root 0000000 0000000 module WillPaginate #:nodoc:
module VERSION #:nodoc:
MAJOR = 4
MINOR = 0
TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
end
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers.rb 0000664 0000000 0000000 00000015264 14631541146 0024511 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
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/ 0000775 0000000 0000000 00000000000 14631541146 0024154 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/action_view.rb 0000664 0000000 0000000 00000011136 14631541146 0027012 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
if @template.request.get?
symbolized_update(url_params, @template.params, GET_PARAMS_BLACKLIST)
elsif @template.request.respond_to?(:query_parameters)
symbolized_update(url_params, @template.request.query_parameters, GET_PARAMS_BLACKLIST)
end
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
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/hanami.rb 0000664 0000000 0000000 00000002005 14631541146 0025733 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
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/link_renderer.rb 0000664 0000000 0000000 00000011252 14631541146 0027325 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
aria_label = @template.will_paginate_translate(:previous_aria_label) { "Previous page" }
previous_or_next_page(num, @options[:previous_label], 'previous_page', aria_label)
end
def next_page
num = @collection.current_page < total_pages && @collection.current_page + 1
aria_label = @template.will_paginate_translate(:next_aria_label) { "Next page" }
previous_or_next_page(num, @options[:next_label], 'next_page', aria_label)
end
def previous_or_next_page(page, text, classname, aria_label = nil)
if page
link(text, page, :class => classname, :'aria-label' => aria_label)
else
tag(:span, text, :class => classname + ' disabled', :'aria-label' => aria_label)
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.map do |pair|
unless pair.last.nil?
%( #{pair.first}="#{CGI::escapeHTML(pair.last.to_s)}")
end
end
"<#{name}#{string_attributes.compact.join("")}>#{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
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/link_renderer_base.rb 0000664 0000000 0000000 00000004455 14631541146 0030326 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
mislav-will_paginate-50017c3/lib/will_paginate/view_helpers/sinatra.rb 0000664 0000000 0000000 00000001725 14631541146 0026147 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
mislav-will_paginate-50017c3/script/ 0000775 0000000 0000000 00000000000 14631541146 0017377 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/script/bootstrap 0000775 0000000 0000000 00000000636 14631541146 0021347 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vi:ft=sh:
set -e
brew install libpq
brew install --skip-post-install mysql@5.7
bundle config --local build.mysql2 -- "$(ruby -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]' | xargs -n1 | grep with-openssl-dir)"
bundle config --local build.pg -- --with-pg-config=$(brew --prefix libpq)/bin/pg_config
bundle config --local path "$PWD/vendor/bundle"
bundle install
bundle binstubs rspec-core
mislav-will_paginate-50017c3/script/ci-matrix 0000775 0000000 0000000 00000002430 14631541146 0021221 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',
'environments/Gemfile.rails6.1.rb' => '>= 2.5',
'Gemfile' => '>= 2.7',
'environments/Gemfile.rails-edge.rb' => '>= 3.1',
}
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])
mislav-will_paginate-50017c3/script/release 0000775 0000000 0000000 00000000555 14631541146 0020752 0 ustar 00root root 0000000 0000000 #!/bin/sh
set -euo pipefail
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"
gh release create "v${version}" --title "${name} ${version}" --generate-notes
mislav-will_paginate-50017c3/script/test_all 0000775 0000000 0000000 00000000710 14631541146 0021132 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
mislav-will_paginate-50017c3/spec-non-rails/ 0000775 0000000 0000000 00000000000 14631541146 0020725 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec-non-rails/mongoid_spec.rb 0000664 0000000 0000000 00000011033 14631541146 0023716 0 ustar 00root root 0000000 0000000 require_relative './spec_helper'
require 'will_paginate/mongoid'
RSpec.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")
expect(criteria.page(2)).to eq("itself")
end
it "should not override per_page if set earlier in the chain" do
expect(criteria.paginate(:per_page => 10).page(1).per_page).to eq(10)
expect(criteria.paginate(:per_page => 20).page(1).per_page).to eq(20)
end
end
describe "#per_page" do
it "should set the limit if given an argument" do
expect(criteria.per_page(10).options[:limit]).to eq(10)
end
it "should return the current limit if no argument is given" do
expect(criteria.per_page).to eq(nil)
expect(criteria.per_page(10).per_page).to eq(10)
end
it "should be interchangable with limit" do
expect(criteria.limit(15).per_page).to eq(15)
end
it "should be nil'able" do
expect(criteria.per_page(nil).per_page).to be_nil
end
end
describe "#paginate" do
it "should use criteria" do
expect(criteria.paginate).to be_instance_of(::Mongoid::Criteria)
end
it "should not override page number if set earlier in the chain" do
expect(criteria.page(3).paginate.current_page).to eq(3)
end
it "should limit according to per_page parameter" do
expect(criteria.paginate(:per_page => 10).options).to include(:limit => 10)
end
it "should skip according to page and per_page parameters" do
expect(criteria.paginate(:page => 2, :per_page => 5).options).to include(:skip => 5)
end
specify "first fallback value for per_page option is the current limit" do
expect(criteria.limit(12).paginate.options).to include(:limit => 12)
end
specify "second fallback value for per_page option is WillPaginate.per_page" do
expect(criteria.paginate.options).to include(:limit => WillPaginate.per_page)
end
specify "page should default to 1" do
expect(criteria.paginate.options).to include(:skip => 0)
end
it "should convert strings to integers" do
expect(criteria.paginate(:page => "2", :per_page => "3").options).to include(:limit => 3)
end
describe "collection compatibility" do
describe "#total_count" do
it "should be calculated correctly" do
expect(criteria.paginate(:per_page => 1).total_entries).to eq(4)
expect(criteria.paginate(:per_page => 3).total_entries).to eq(4)
end
it "should be cached" do
criteria.expects(:count).once.returns(123)
criteria.paginate
2.times { expect(criteria.total_entries).to eq(123) }
end
end
it "should calculate total_pages" do
expect(criteria.paginate(:per_page => 1).total_pages).to eq(4)
expect(criteria.paginate(:per_page => 3).total_pages).to eq(2)
expect(criteria.paginate(:per_page => 10).total_pages).to eq(1)
end
it "should return per_page" do
expect(criteria.paginate(:per_page => 1).per_page).to eq(1)
expect(criteria.paginate(:per_page => 5).per_page).to eq(5)
end
describe "#current_page" do
it "should return current_page" do
expect(criteria.paginate(:page => 1).current_page).to eq(1)
expect(criteria.paginate(:page => 3).current_page).to eq(3)
end
it "should be casted to PageNumber" do
page = criteria.paginate(:page => 1).current_page
expect(page.instance_of? WillPaginate::PageNumber).to be
end
end
it "should return offset" do
expect(criteria.paginate(:page => 1).offset).to eq(0)
expect(criteria.paginate(:page => 2, :per_page => 5).offset).to eq(5)
expect(criteria.paginate(:page => 3, :per_page => 10).offset).to eq(20)
end
it "should not pollute plain mongoid criterias" do
%w(total_entries total_pages current_page).each do |method|
expect(criteria).not_to respond_to(method)
end
end
end
end
end
mislav-will_paginate-50017c3/spec-non-rails/sequel_spec.rb 0000664 0000000 0000000 00000003613 14631541146 0023565 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
RSpec.describe Sequel::Dataset::Pagination, 'extension' do
class Car < Sequel::Model
self.dataset = dataset.extension(:pagination)
end
it "should have the #paginate method" do
expect(Car.dataset).to respond_to(:paginate)
end
it "should NOT have the #paginate_by_sql method" do
expect(Car.dataset).not_to 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)
expect(result).not_to be_empty
expect(result.size).to eq(2)
expect(result.length).to eq(2)
expect(result.total_entries).to eq(3)
expect(result.total_pages).to eq(2)
expect(result.per_page).to eq(2)
expect(result.current_page).to eq(1)
end
it "should perform" do
expect(Car.dataset.paginate(1, 2).all).to eq([Car[1], Car[2]])
end
it "should be empty" do
result = Car.dataset.paginate(3, 2)
expect(result).to 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
expect(result.size).to eq(2)
expect(result.first.values[:foo]).to eq("Aston Martin")
end
it "should perform with #filter" do
results = Car.filter(:name => 'Shelby').paginate(1, 2).all
expect(results.size).to eq(1)
expect(results.first).to eq(Car.find(:name => 'Shelby'))
end
end
end
mislav-will_paginate-50017c3/spec-non-rails/spec_helper.rb 0000664 0000000 0000000 00000000525 14631541146 0023545 0 ustar 00root root 0000000 0000000 require 'rspec'
RSpec.configure do |config|
config.mock_with :mocha
config.expose_dsl_globally = false
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
config.disable_monkey_patching!
end
mislav-will_paginate-50017c3/spec/ 0000775 0000000 0000000 00000000000 14631541146 0017025 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec/collection_spec.rb 0000664 0000000 0000000 00000010223 14631541146 0022515 0 ustar 00root root 0000000 0000000 require 'will_paginate/array'
require 'spec_helper'
RSpec.describe WillPaginate::Collection do
before :all do
@simple = ('a'..'e').to_a
end
it "should be a subset of original collection" do
expect(@simple.paginate(:page => 1, :per_page => 3)).to eq(%w( a b c ))
end
it "can be shorter than per_page if on last page" do
expect(@simple.paginate(:page => 2, :per_page => 3)).to eq(%w( d e ))
end
it "should include whole collection if per_page permits" do
expect(@simple.paginate(:page => 1, :per_page => 5)).to eq(@simple)
end
it "should be empty if out of bounds" do
expect(@simple.paginate(:page => 2, :per_page => 5)).to be_empty
end
it "should default to 1 as current page and 30 per-page" do
result = (1..50).to_a.paginate
expect(result.current_page).to eq(1)
expect(result.size).to eq(30)
end
it "should give total_entries precedence over actual size" do
expect(%w(a b c).paginate(:total_entries => 5).total_entries).to eq(5)
end
it "should be an augmented Array" do
entries = %w(a b c)
collection = create(2, 3, 10) do |pager|
expect(pager.replace(entries)).to eq(entries)
end
expect(collection).to eq(entries)
for method in %w(total_pages each offset size current_page per_page total_entries)
expect(collection).to respond_to(method)
end
expect(collection).to be_kind_of(Array)
expect(collection.entries).to be_instance_of(Array)
# TODO: move to another expectation:
expect(collection.offset).to eq(3)
expect(collection.total_pages).to eq(4)
expect(collection).not_to 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)
expect(collection.previous_page).to be_nil
expect(collection.next_page).to eq(2)
end
it "should have both prev/next pages" do
collection = create(2, 1, 3)
expect(collection.previous_page).to eq(1)
expect(collection.next_page).to eq(3)
end
it "should have next_page nil when on last page" do
collection = create(3, 1, 3)
expect(collection.previous_page).to eq(2)
expect(collection.next_page).to be_nil
end
end
describe "out of bounds" do
it "is out of bounds when page number is too high" do
expect(create(2, 3, 2)).to be_out_of_bounds
end
it "isn't out of bounds when inside collection" do
expect(create(1, 3, 2)).not_to be_out_of_bounds
end
it "isn't out of bounds when the collection is empty" do
collection = create(1, 3, 0)
expect(collection).not_to be_out_of_bounds
expect(collection.total_pages).to eq(1)
end
end
describe "guessing total count" do
it "can guess when collection is shorter than limit" do
collection = create { |p| p.replace array }
expect(collection.total_entries).to eq(8)
end
it "should allow explicit total count to override guessed" do
collection = create(2, 5, 10) { |p| p.replace array }
expect(collection.total_entries).to eq(10)
end
it "should not be able to guess when collection is same as limit" do
collection = create { |p| p.replace array(5) }
expect(collection.total_entries).to be_nil
end
it "should not be able to guess when collection is empty" do
collection = create { |p| p.replace array(0) }
expect(collection.total_entries).to 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) }
expect(collection.total_entries).to eq(0)
end
end
it "should not respond to page_count anymore" do
expect { create.page_count }.to raise_error(NoMethodError)
end
it "inherits per_page from global value" do
collection = described_class.new(1)
expect(collection.per_page).to eq(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
mislav-will_paginate-50017c3/spec/console 0000775 0000000 0000000 00000000470 14631541146 0020416 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? '-seq'
opts << '-rwill_paginate/sequel' << '-rfinders/sequel_test_connector'
else
opts << '-rconsole_fixtures'
end
exec 'bundle', 'exec', irb, '-Ilib:spec', *opts
mislav-will_paginate-50017c3/spec/console_fixtures.rb 0000664 0000000 0000000 00000001434 14631541146 0022747 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
mislav-will_paginate-50017c3/spec/database.yml 0000664 0000000 0000000 00000001321 14631541146 0021311 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"] %>
mislav-will_paginate-50017c3/spec/finders/ 0000775 0000000 0000000 00000000000 14631541146 0020457 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec/finders/active_record_spec.rb 0000664 0000000 0000000 00000032617 14631541146 0024640 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/active_record'
require File.expand_path('../activerecord_test_connector', __FILE__)
ActiverecordTestConnector.setup
RSpec.describe WillPaginate::ActiveRecord do
extend ActiverecordTestConnector::FixtureSetup
fixtures :topics, :replies, :users, :projects, :developers_projects
it "should integrate with ActiveRecord::Base" do
expect(ActiveRecord::Base).to respond_to(:paginate)
end
it "should paginate" do
expect {
users = User.paginate(:page => 1, :per_page => 5).to_a
expect(users.length).to eq(5)
}.to execute(2).queries
end
it "should fail when encountering unknown params" do
expect {
User.paginate :foo => 'bar', :page => 1, :per_page => 4
}.to raise_error(ArgumentError)
end
describe "relation" do
it "should return a relation" do
rel = nil
expect {
rel = Developer.paginate(:page => 1)
expect(rel.per_page).to eq(10)
expect(rel.current_page).to eq(1)
}.to execute(0).queries
expect {
expect(rel.total_pages).to eq(2)
}.to execute(1).queries
end
it "should keep per-class per_page number" do
rel = Developer.order('id').paginate(:page => 1)
expect(rel.per_page).to eq(10)
end
it "should be able to change per_page number" do
rel = Developer.order('id').paginate(:page => 1).limit(5)
expect(rel.per_page).to eq(5)
end
it "remembers pagination in sub-relations" do
rel = Topic.paginate(:page => 2, :per_page => 3)
expect {
expect(rel.total_entries).to eq(4)
}.to execute(1).queries
rel = rel.mentions_activerecord
expect(rel.current_page).to eq(2)
expect(rel.per_page).to eq(3)
expect {
expect(rel.total_entries).to eq(1)
}.to execute(1).queries
end
it "supports the page() method" do
rel = Developer.page('1').order('id')
expect(rel.current_page).to eq(1)
expect(rel.per_page).to eq(10)
expect(rel.offset).to eq(0)
rel = rel.limit(5).page(2)
expect(rel.per_page).to eq(5)
expect(rel.offset).to eq(5)
end
it "raises on invalid page number" do
expect {
Developer.page('foo')
}.to raise_error(ArgumentError)
end
it "supports first limit() then page()" do
rel = Developer.limit(3).page(3)
expect(rel.offset).to eq(6)
end
it "supports first page() then limit()" do
rel = Developer.page(3).limit(3)
expect(rel.offset).to eq(6)
end
it "supports #first" do
rel = Developer.order('id').page(2).per_page(4)
expect(rel.first).to eq(users(:dev_5))
expect(rel.first(2)).to eq(users(:dev_5, :dev_6))
end
it "supports #last" do
rel = Developer.order('id').page(2).per_page(4)
expect(rel.last).to eq(users(:dev_8))
expect(rel.last(2)).to eq(users(:dev_7, :dev_8))
expect(rel.page(3).last).to eq(users(:poor_jamis))
end
end
describe "counting" do
it "should guess the total count" do
expect {
topics = Topic.paginate :page => 2, :per_page => 3
expect(topics.total_entries).to eq(4)
}.to execute(1).queries
end
it "should guess that there are no records" do
expect {
topics = Topic.where(:project_id => 999).paginate :page => 1, :per_page => 3
expect(topics.total_entries).to eq(0)
}.to execute(1).queries
end
it "forgets count in sub-relations" do
expect {
topics = Topic.paginate :page => 1, :per_page => 3
expect(topics.total_entries).to eq(4)
expect(topics.where('1 = 1').total_entries).to eq(4)
}.to execute(2).queries
end
it "supports empty? method" do
topics = Topic.paginate :page => 1, :per_page => 3
expect {
expect(topics).not_to be_empty
}.to execute(1).queries
end
it "support empty? for grouped queries" do
topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3
expect {
expect(topics).not_to be_empty
}.to execute(1).queries
end
it "supports `size` for grouped queries" do
topics = Topic.group(:project_id).paginate :page => 1, :per_page => 3
expect {
expect(topics.size).to eq({nil=>2, 1=>2})
}.to execute(1).queries
end
it "overrides total_entries count with a fixed value" do
expect {
topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => 999
expect(topics.total_entries).to eq(999)
# value is kept even in sub-relations
expect(topics.where('1 = 1').total_entries).to eq(999)
}.to execute(0).queries
end
it "supports a non-int for total_entries" do
topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => "999"
expect(topics.total_entries).to eq(999)
end
it "overrides empty? count call with a total_entries fixed value" do
expect {
topics = Topic.paginate :page => 1, :per_page => 3, :total_entries => 999
expect(topics).not_to be_empty
}.to execute(0).queries
end
it "removes :include for count" do
expect {
developers = Developer.paginate(:page => 1, :per_page => 1).includes(:projects)
expect(developers.total_entries).to eq(11)
expect($query_sql.last).not_to match(/\bJOIN\b/)
}.to execute(1).queries
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)
expect(with_condition.total_entries).to eq(1)
expect($query_sql.last).to match(/\bJOIN\b/)
end
it "should count with group" do
expect(Developer.group(:salary).page(1).total_entries).to eq(4)
end
it "should count with select" do
expect(Topic.select('title, content').page(1).total_entries).to eq(4)
end
it "removes :reorder for count with group" do
Project.group(:id).reorder(:id).page(1).total_entries
expect($query_sql.last).not_to match(/\ORDER\b/)
end
it "should not have zero total_pages when the result set is empty" do
expect(Developer.where("1 = 2").page(1).total_pages).to eq(1)
end
end
it "should not ignore :select parameter when it says DISTINCT" do
users = User.select('DISTINCT salary').paginate :page => 2
expect(users.total_entries).to eq(5)
end
describe "paginate_by_sql" do
it "should respond" do
expect(User).to respond_to(:paginate_by_sql)
end
it "should paginate" do
expect {
sql = "select content from topics where content like '%futurama%'"
topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1
expect(topics.total_entries).to eq(1)
expect(topics.first.attributes.has_key?('title')).to be(false)
}.to execute(2).queries
end
it "should respect total_entries setting" do
expect {
sql = "select content from topics"
topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 1, :total_entries => 999
expect(topics.total_entries).to eq(999)
}.to execute(1).queries
end
it "defaults to page 1" do
sql = "select content from topics"
topics = Topic.paginate_by_sql sql, :page => nil, :per_page => 1
expect(topics.current_page).to eq(1)
expect(topics.size).to eq(1)
end
it "should strip the order when counting" do
expected = topics(:ar)
expect {
sql = "select id, title, content from topics order by topics.title"
topics = Topic.paginate_by_sql sql, :page => 1, :per_page => 2
expect(topics.first).to eq(expected)
}.to execute(2).queries
expect($query_sql.last).to include('COUNT')
expect($query_sql.last).not_to 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)
expect(query).to eq(original_query)
end
end
it "doesn't mangle options" do
options = { :page => 1 }
options.expects(:delete).never
options_before = options.dup
Topic.paginate(options)
expect(options).to eq(options_before)
end
it "should get first page of Topics with a single query" do
expect {
result = Topic.paginate :page => nil
result.to_a # trigger loading of records
expect(result.current_page).to eq(1)
expect(result.total_pages).to eq(1)
expect(result.size).to eq(4)
}.to execute(1).queries
end
it "should get second (inexistent) page of Topics, requiring 1 query" do
expect {
result = Topic.paginate :page => 2
expect(result.total_pages).to eq(1)
expect(result).to be_empty
}.to execute(1).queries
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)
expect {
# with association-specified order
result = ignore_deprecation {
dhh.projects.includes(:topics).order('projects.name').paginate(:page => 1)
}
expect(result.to_a).to eq(expected_name_ordered)
expect(result.total_entries).to eq(2)
}.to execute(2).queries
# with explicit order
result = dhh.projects.paginate(:page => 1).reorder('projects.id')
expect(result).to eq(expected_id_ordered)
expect(result.total_entries).to eq(2)
expect {
dhh.projects.order('projects.id').limit(4).to_a
}.not_to raise_error
result = dhh.projects.paginate(:page => 1, :per_page => 4).reorder('projects.id')
expect(result).to eq(expected_id_ordered)
# has_many with implicit order
topic = Topic.find(1)
expected = replies(:spam, :witty_retort)
# FIXME: wow, this is ugly
expect(topic.replies.paginate(:page => 1).map(&:id).sort).to eq(expected.map(&:id).sort)
expect(topic.replies.paginate(:page => 1).reorder('replies.id ASC')).to eq(expected.reverse)
end
it "should paginate through association extension" do
project = Project.order('id').first
expected = [replies(:brave)]
expect {
result = project.replies.only_recent.paginate(:page => 1)
expect(result).to eq(expected)
}.to execute(1).queries
end
end
it "should paginate with joins" do
result = nil
join_sql = 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id'
expect {
result = Developer.where('developers_projects.project_id = 1').joins(join_sql).paginate(:page => 1)
result.to_a # trigger loading of records
expect(result.size).to eq(2)
developer_names = result.map(&:name)
expect(developer_names).to include('David')
expect(developer_names).to include('Jamis')
}.to execute(1).queries
expect {
expected = result.to_a
result = Developer.where('developers_projects.project_id = 1').joins(join_sql).paginate(:page => 1)
expect(result).to eq(expected)
expect(result.total_entries).to eq(2)
}.to execute(1).queries
end
it "should paginate with group" do
result = nil
expect {
result = Developer.select('salary').order('salary').group('salary').
paginate(:page => 1, :per_page => 10).to_a
}.to execute(1).queries
expected = users(:david, :jamis, :dev_10, :poor_jamis).map(&:salary).sort
expect(result.map(&:salary)).to eq(expected)
end
it "should not paginate with dynamic finder" do
expect {
Developer.paginate_by_salary(100000, :page => 1, :per_page => 5)
}.to raise_error(NoMethodError)
end
describe "scopes" do
it "should paginate" do
result = Developer.poor.paginate :page => 1, :per_page => 1
expect(result.size).to eq(1)
expect(result.total_entries).to eq(2)
end
it "should paginate on habtm association" do
project = projects(:active_record)
expect {
result = ignore_deprecation { project.developers.poor.paginate :page => 1, :per_page => 1 }
expect(result.size).to eq(1)
expect(result.total_entries).to eq(1)
}.to execute(2).queries
end
it "should paginate on hmt association" do
project = projects(:active_record)
expected = [replies(:brave)]
expect {
result = project.replies.recent.paginate :page => 1, :per_page => 1
expect(result).to eq(expected)
expect(result.total_entries).to eq(1)
}.to execute(2).queries
end
it "should paginate on has_many association" do
project = projects(:active_record)
expected = [topics(:ar)]
expect {
result = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1
expect(result).to eq(expected)
expect(result.total_entries).to eq(1)
}.to execute(2).queries
end
end
it "should not paginate an array of IDs" do
expect {
Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id')
}.to raise_error(ArgumentError)
end
it "errors out for invalid values" do |variable|
expect {
# page that results in an offset larger than BIGINT
Project.page(307445734561825862)
}.to raise_error(WillPaginate::InvalidPage, "invalid offset: 9223372036854775830")
end
end
mislav-will_paginate-50017c3/spec/finders/activerecord_test_connector.rb 0000664 0000000 0000000 00000007452 14631541146 0026577 0 ustar 00root root 0000000 0000000 require 'active_record'
require 'active_record/fixtures'
require 'stringio'
require 'erb'
require 'time'
require 'date'
require 'yaml'
# forward compatibility with Rails 7 (needed for time expressions within fixtures)
class Time
alias_method :to_fs, :to_s
end unless Time.new.respond_to?(:to_fs)
# monkeypatch needed for Ruby 3.1 & Rails 6.0
YAML.module_eval do
class << self
alias_method :_load_orig, :load
def load(yaml_str)
_load_orig(yaml_str, permitted_classes: [Symbol, Date, Time])
end
end
end if YAML.method(:load).parameters.include?([:key, :permitted_classes])
$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
module Autoloader
def const_missing(name)
super
rescue NameError
file = File.join(FIXTURES_PATH, name.to_s.underscore)
if File.exist?("#{file}.rb")
require file
const_get(name)
else
raise $!
end
end
end
def add_load_path(path)
if ActiveSupport::Dependencies.respond_to?(:autoloader=)
Object.singleton_class.include Autoloader
else
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
dep.autoload_paths.unshift path
end
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)
if ActiveRecord.respond_to?(:default_timezone=)
ActiveRecord.default_timezone = :utc
else
ActiveRecord::Base.default_timezone = :utc
end
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
mislav-will_paginate-50017c3/spec/fixtures/ 0000775 0000000 0000000 00000000000 14631541146 0020676 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec/fixtures/admin.rb 0000664 0000000 0000000 00000000055 14631541146 0022313 0 ustar 00root root 0000000 0000000 class Admin < User
has_many :companies
end
mislav-will_paginate-50017c3/spec/fixtures/developer.rb 0000664 0000000 0000000 00000000322 14631541146 0023205 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
mislav-will_paginate-50017c3/spec/fixtures/developers_projects.yml 0000664 0000000 0000000 00000000332 14631541146 0025500 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 mislav-will_paginate-50017c3/spec/fixtures/project.rb 0000664 0000000 0000000 00000000705 14631541146 0022673 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
mislav-will_paginate-50017c3/spec/fixtures/projects.yml 0000664 0000000 0000000 00000000142 14631541146 0023247 0 ustar 00root root 0000000 0000000 active_record:
id: 1
name: Active Record
action_controller:
id: 2
name: Action Controller
mislav-will_paginate-50017c3/spec/fixtures/replies.yml 0000664 0000000 0000000 00000001065 14631541146 0023066 0 ustar 00root root 0000000 0000000 witty_retort:
id: 1
topic_id: 1
content: Birdman is better!
created_at: <%= 6.hours.ago.utc.to_fs(:db) %>
another:
id: 2
topic_id: 2
content: Nuh uh!
created_at: <%= 1.hour.ago.utc.to_fs(:db) %>
spam:
id: 3
topic_id: 1
content: Nice site!
created_at: <%= 1.hour.ago.utc.to_fs(:db) %>
decisive:
id: 4
topic_id: 4
content: "I'm getting to the bottom of this"
created_at: <%= 30.minutes.ago.utc.to_fs(:db) %>
brave:
id: 5
topic_id: 4
content: "AR doesn't scare me a bit"
created_at: <%= 10.minutes.ago.utc.to_fs(:db) %>
mislav-will_paginate-50017c3/spec/fixtures/reply.rb 0000664 0000000 0000000 00000000303 14631541146 0022352 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
mislav-will_paginate-50017c3/spec/fixtures/schema.rb 0000664 0000000 0000000 00000002126 14631541146 0022464 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
mislav-will_paginate-50017c3/spec/fixtures/topic.rb 0000664 0000000 0000000 00000000312 14631541146 0022335 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
mislav-will_paginate-50017c3/spec/fixtures/topics.yml 0000664 0000000 0000000 00000001360 14631541146 0022722 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_fs(: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_fs(: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_fs(: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_fs(:db) %>
mislav-will_paginate-50017c3/spec/fixtures/user.rb 0000664 0000000 0000000 00000000044 14631541146 0022177 0 ustar 00root root 0000000 0000000 class User < ActiveRecord::Base
end
mislav-will_paginate-50017c3/spec/fixtures/users.yml 0000664 0000000 0000000 00000000650 14631541146 0022563 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
mislav-will_paginate-50017c3/spec/matchers/ 0000775 0000000 0000000 00000000000 14631541146 0020633 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec/matchers/query_count_matcher.rb 0000664 0000000 0000000 00000001163 14631541146 0025241 0 ustar 00root root 0000000 0000000 RSpec::Matchers.define :execute do |expected_count|
match do |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
chain(:queries) {}
supports_block_expectations
failure_message do
"expected #{expected_count} queries, got #{@count}\n#{@queries.join("\n")}"
end
failure_message_when_negated do
"expected query count not to be #{expected_count}"
end
end
mislav-will_paginate-50017c3/spec/page_number_spec.rb 0000664 0000000 0000000 00000004551 14631541146 0022655 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/page_number'
require 'json'
RSpec.describe WillPaginate::PageNumber do
describe "valid" do
def num
WillPaginate::PageNumber.new('12', 'page')
end
it "== 12" do
expect(num).to eq(12)
end
it "inspects to 'page 12'" do
expect(num.inspect).to eq('page 12')
end
it "is a PageNumber" do
expect(num.instance_of? WillPaginate::PageNumber).to be
end
it "is a kind of Numeric" do
expect(num.is_a? Numeric).to be
end
it "is a kind of Integer" do
expect(num.is_a? Integer).to be
end
it "isn't directly a Integer" do
expect(num.instance_of? Integer).not_to be
end
it "passes the PageNumber=== type check" do |variable|
expect(WillPaginate::PageNumber === num).to be
end
it "passes the Numeric=== type check" do |variable|
expect(Numeric === num).to be
end
it "fails the Numeric=== type check" do |variable|
expect(Integer === num).not_to be
end
it "serializes as JSON number" do
expect(JSON.dump(page: num)).to 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
expect { create(nil) }.to raise_error(WillPaginate::InvalidPage)
expect { create('') }.to raise_error(WillPaginate::InvalidPage)
expect { create('Schnitzel') }.to raise_error(WillPaginate::InvalidPage)
end
it "errors out on zero or less" do
expect { create(0) }.to raise_error(WillPaginate::InvalidPage)
expect { create(-1) }.to raise_error(WillPaginate::InvalidPage)
end
it "doesn't error out on zero for 'offset'" do
expect { create(0, 'offset') }.not_to raise_error
expect { create(-1, 'offset') }.to raise_error(WillPaginate::InvalidPage)
end
end
describe "coercion method" do
it "defaults to 'page' name" do
num = WillPaginate::PageNumber(12)
expect(num.inspect).to eq('page 12')
end
it "accepts a custom name" do
num = WillPaginate::PageNumber(12, 'monkeys')
expect(num.inspect).to eq('monkeys 12')
end
it "doesn't affect PageNumber instances" do
num = WillPaginate::PageNumber(12)
num2 = WillPaginate::PageNumber(num)
expect(num2.object_id).to eq(num.object_id)
end
end
end
mislav-will_paginate-50017c3/spec/per_page_spec.rb 0000664 0000000 0000000 00000001457 14631541146 0022155 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/per_page'
RSpec.describe WillPaginate::PerPage do
class MyModel
extend WillPaginate::PerPage
end
it "has the default value" do
expect(MyModel.per_page).to eq(30)
WillPaginate.per_page = 10
begin
expect(MyModel.per_page).to eq(10)
ensure
WillPaginate.per_page = 30
end
end
it "casts values to int" do
WillPaginate.per_page = '10'
begin
expect(MyModel.per_page).to eq(10)
ensure
WillPaginate.per_page = 30
end
end
it "has an explicit value" do
MyModel.per_page = 12
begin
expect(MyModel.per_page).to eq(12)
subclass = Class.new(MyModel)
expect(subclass.per_page).to eq(12)
ensure
MyModel.send(:remove_instance_variable, '@per_page')
end
end
end
mislav-will_paginate-50017c3/spec/spec_helper.rb 0000664 0000000 0000000 00000001652 14631541146 0021647 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::Matchers.alias_matcher :include_phrase, :include
RSpec.configure do |config|
config.include Module.new {
protected
def have_deprecation(msg)
output(/^DEPRECATION WARNING: #{Regexp.escape(msg)}/).to_stderr
end
def ignore_deprecation
if ActiveSupport::Deprecation.respond_to?(:silence)
ActiveSupport::Deprecation.silence { yield }
else
yield
end
end
}
config.mock_with :mocha
config.backtrace_exclusion_patterns << /view_example_group/
config.expose_dsl_globally = false
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
config.disable_monkey_patching!
end
mislav-will_paginate-50017c3/spec/view_helpers/ 0000775 0000000 0000000 00000000000 14631541146 0021521 5 ustar 00root root 0000000 0000000 mislav-will_paginate-50017c3/spec/view_helpers/action_view_spec.rb 0000664 0000000 0000000 00000033416 14631541146 0025376 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
RSpec.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
expect(text(elements[2])).to eq('Next →')
end
assert_select 'span', 1 do |spans|
expect(spans[0]['class']).to eq('previous_page disabled')
expect(text(spans[0])).to eq('← Previous')
end
assert_select 'em.current', '1'
expect(text(pagination[0])).to eq('← 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
expect(paginate(:per_page => 30)).to 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:
expect(text(elements[0])).to eq('Prev')
expect(elements[0]['rel']).to eq('prev')
expect(text(elements[1])).to eq('1')
expect(elements[1]['rel']).to eq('prev')
expect(text(elements[3])).to eq('Next')
expect(elements[3]['rel']).to eq('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.strip.gsub(/\s{2,}/, ' ')
HTML
expected_dom = parse_html_document(expected)
if expected_dom.respond_to?(:canonicalize)
expect(html_document.canonicalize).to eq(expected_dom.canonicalize)
else
expect(html_document.root).to eq(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
expect(parts).to eq(%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 only preserve query parameters on POST" do
request.post
request.params :foo => 'bar'
request.query_parameters = { :hello => 'world' }
paginate
assert_no_links_match /foo=bar/
assert_links_match /hello=world/
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'
expect {
paginate(nil)
}.to 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
expect(urls).to eq(['/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
expect(urls).to eq(['/dummy/page/1', '/dummy/page/3'])
end
end
# TODO: re-enable once Rails 6.1.4 ships
it "page_entries_info" do
@template = "<%= page_entries_info collection, options %>"
output = render(
collection: WillPaginate::Collection.new(1, 1, 3),
options: {html: false},
)
expect(output).to eq("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 query_parameters
if get?
params
else
ActionController::Parameters.new(@query_parameters)
end
end
def query_parameters=(more)
@query_parameters = more.with_indifferent_access
end
def host_with_port
'example.com'
end
alias host host_with_port
def optional_port
''
end
def protocol
'http:'
end
end
mislav-will_paginate-50017c3/spec/view_helpers/base_spec.rb 0000664 0000000 0000000 00000011247 14631541146 0023777 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'
RSpec.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('')
expect(will_paginate(collection, :renderer => renderer)).to eq('')
end
it "should return nil for single-page collections" do
collection = mock 'Collection', :total_pages => 1
expect(will_paginate(collection)).to 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)
expect(will_paginate(collection, :renderer => renderer)).to eql(html)
end
end
describe "pagination_options" do
let(:pagination_options) { WillPaginate::ViewHelpers.pagination_options }
it "deprecates setting :renderer" do
begin
expect {
pagination_options[:renderer] = 'test'
}.to 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
expect(info(:page => 2, :per_page => 5)).to eq("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}'}
}
expect(info(:page => 2, :per_page => 5)).to eq("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}'} }
}
expect(info(:page => 2, :per_page => 5)).to eq("Strings 6 to 10")
end
it "should output HTML by default" do
expect(info({ :page => 2, :per_page => 5 }, :html => true)).to eq(
"Displaying strings 6 - 10 of 26 in total"
)
end
it "should display shortened end results" do
expect(info(:page => 7, :per_page => 4)).to 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)
expect(info(collection)).to include_phrase('project types')
end
it "should adjust output for single-page collections" do
expect(info(('a'..'d').to_a.paginate(:page => 1, :per_page => 5))).to eq("Displaying all 4 strings")
expect(info(['a'].paginate(:page => 1, :per_page => 5))).to eq("Displaying 1 string")
end
it "should display 'no entries found' for empty collections" do
expect(info([].paginate(:page => 1, :per_page => 5))).to eq("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)
expect(info(collection, :model => model)).to eq("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)
expect(info(collection, :model => model)).to eq("Displaying 1 tulip")
end
private
def translation(data)
I18n.backend.store_translations(:en, data)
end
end
end
mislav-will_paginate-50017c3/spec/view_helpers/link_renderer_base_spec.rb 0000664 0000000 0000000 00000005313 14631541146 0026677 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'will_paginate/view_helpers/link_renderer_base'
require 'will_paginate/collection'
RSpec.describe WillPaginate::ViewHelpers::LinkRendererBase do
before do
@renderer = described_class.new
end
it "should raise error when unprepared" do
expect {
@renderer.pagination
}.to raise_error(NoMethodError)
end
it "should prepare with collection and options" do
prepare({})
expect(@renderer.send(:current_page)).to eq(1)
end
it "should have total_pages accessor" do
prepare :total_pages => 42
expect(@renderer.send(:total_pages)).to eq(42)
end
it "should clear old cached values when prepared" do
prepare(:total_pages => 1)
expect(@renderer.send(:total_pages)).to eq(1)
# prepare with different object:
prepare(:total_pages => 2)
expect(@renderer.send(:total_pages)).to eq(2)
end
it "should have pagination definition" do
prepare({ :total_pages => 1 }, :page_links => true)
expect(@renderer.pagination).to eq([: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
expect(@renderer.send(:windowed_page_numbers)).to eq(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
mislav-will_paginate-50017c3/spec/view_helpers/view_example_group.rb 0000664 0000000 0000000 00000004655 14631541146 0025761 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)}=([^&]*)/
expect(links.map { |el|
unescape_href(el) =~ param_pattern
$1 ? $1.to_i : $1
}).to eq(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)
expect(href).to match(pattern)
if numbers
href =~ pattern
pages << ($1.nil?? nil : $1.to_i)
end
end
expect(pages).to eq(numbers) if numbers
end
def assert_no_links_match(pattern)
assert_select 'div.pagination a[href]' do |elements|
elements.each do |el|
expect(unescape_href(el)).not_to match(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, :file_path => %r{spec/view_helpers/}
end
mislav-will_paginate-50017c3/will_paginate.gemspec 0000664 0000000 0000000 00000003213 14631541146 0022256 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 and Sequel, and includes helpers for rendering pagination links in Rails, Sinatra, and Hanami 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['lib/**/*', '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