hobo_will_paginate 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE +18 -0
- data/README.md +61 -0
- data/Rakefile +25 -0
- data/lib/will_paginate.rb +25 -0
- data/lib/will_paginate/active_record.rb +216 -0
- data/lib/will_paginate/array.rb +57 -0
- data/lib/will_paginate/collection.rb +149 -0
- data/lib/will_paginate/core_ext.rb +30 -0
- data/lib/will_paginate/data_mapper.rb +95 -0
- data/lib/will_paginate/deprecation.rb +55 -0
- data/lib/will_paginate/i18n.rb +22 -0
- data/lib/will_paginate/locale/en.yml +33 -0
- data/lib/will_paginate/page_number.rb +57 -0
- data/lib/will_paginate/per_page.rb +27 -0
- data/lib/will_paginate/railtie.rb +68 -0
- data/lib/will_paginate/sequel.rb +39 -0
- data/lib/will_paginate/version.rb +9 -0
- data/lib/will_paginate/view_helpers.rb +161 -0
- data/lib/will_paginate/view_helpers/action_view.rb +148 -0
- data/lib/will_paginate/view_helpers/link_renderer.rb +132 -0
- data/lib/will_paginate/view_helpers/link_renderer_base.rb +77 -0
- data/lib/will_paginate/view_helpers/merb.rb +26 -0
- data/lib/will_paginate/view_helpers/sinatra.rb +41 -0
- data/spec/ci.rb +29 -0
- data/spec/collection_spec.rb +139 -0
- data/spec/console +12 -0
- data/spec/console_fixtures.rb +28 -0
- data/spec/database.yml +22 -0
- data/spec/finders/active_record_spec.rb +543 -0
- data/spec/finders/activerecord_test_connector.rb +113 -0
- data/spec/finders/data_mapper_spec.rb +103 -0
- data/spec/finders/data_mapper_test_connector.rb +54 -0
- data/spec/finders/sequel_spec.rb +67 -0
- data/spec/finders/sequel_test_connector.rb +9 -0
- data/spec/fixtures/admin.rb +3 -0
- data/spec/fixtures/developer.rb +13 -0
- data/spec/fixtures/developers_projects.yml +13 -0
- data/spec/fixtures/project.rb +15 -0
- data/spec/fixtures/projects.yml +6 -0
- data/spec/fixtures/replies.yml +29 -0
- data/spec/fixtures/reply.rb +9 -0
- data/spec/fixtures/schema.rb +38 -0
- data/spec/fixtures/topic.rb +7 -0
- data/spec/fixtures/topics.yml +30 -0
- data/spec/fixtures/user.rb +2 -0
- data/spec/fixtures/users.yml +35 -0
- data/spec/page_number_spec.rb +65 -0
- data/spec/per_page_spec.rb +41 -0
- data/spec/spec_helper.rb +71 -0
- data/spec/view_helpers/action_view_spec.rb +423 -0
- data/spec/view_helpers/base_spec.rb +130 -0
- data/spec/view_helpers/link_renderer_base_spec.rb +87 -0
- data/spec/view_helpers/view_example_group.rb +114 -0
- metadata +104 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
# copied from ActiveSupport so we don't depend on it
|
4
|
+
|
5
|
+
unless Hash.method_defined? :except
|
6
|
+
Hash.class_eval do
|
7
|
+
# Returns a new hash without the given keys.
|
8
|
+
def except(*keys)
|
9
|
+
rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
|
10
|
+
reject { |key,| rejected.include?(key) }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Replaces the hash without only the given keys.
|
14
|
+
def except!(*keys)
|
15
|
+
replace(except(*keys))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless String.method_defined? :underscore
|
21
|
+
String.class_eval do
|
22
|
+
def underscore
|
23
|
+
self.to_s.gsub(/::/, '/').
|
24
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
25
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
26
|
+
tr("-", "_").
|
27
|
+
downcase
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'dm-aggregates'
|
3
|
+
require 'will_paginate/per_page'
|
4
|
+
require 'will_paginate/page_number'
|
5
|
+
require 'will_paginate/collection'
|
6
|
+
|
7
|
+
module WillPaginate
|
8
|
+
module DataMapper
|
9
|
+
module Pagination
|
10
|
+
def page(num)
|
11
|
+
pagenum = ::WillPaginate::PageNumber(num.nil? ? 1 : num)
|
12
|
+
per_page = query.limit || self.per_page
|
13
|
+
options = {:offset => pagenum.to_offset(per_page).to_i}
|
14
|
+
options[:limit] = per_page unless query.limit
|
15
|
+
col = new_collection(query.merge(options))
|
16
|
+
col.current_page = pagenum
|
17
|
+
col
|
18
|
+
end
|
19
|
+
|
20
|
+
def paginate(options)
|
21
|
+
options = options.dup
|
22
|
+
pagenum = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
|
23
|
+
per_page = options.delete(:per_page) || self.per_page
|
24
|
+
|
25
|
+
options.delete(:page)
|
26
|
+
options[:limit] = per_page.to_i
|
27
|
+
|
28
|
+
all(options).page(pagenum)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module CollectionMethods
|
33
|
+
include WillPaginate::CollectionMethods
|
34
|
+
|
35
|
+
attr_accessor :current_page
|
36
|
+
|
37
|
+
def paginated?
|
38
|
+
!current_page.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def per_page
|
42
|
+
query.limit || model.per_page
|
43
|
+
end
|
44
|
+
|
45
|
+
def offset
|
46
|
+
query.offset
|
47
|
+
end
|
48
|
+
|
49
|
+
def total_entries
|
50
|
+
@total_entries ||= begin
|
51
|
+
if loaded? and @array.size < per_page and (current_page == 1 or @array.size > 0)
|
52
|
+
offset + @array.size
|
53
|
+
else
|
54
|
+
# :reload prevents Collection.filter from being run, which
|
55
|
+
# would cause a stack overflow
|
56
|
+
clean_query = query.merge(:reload => true)
|
57
|
+
# seems like the only way
|
58
|
+
clean_query.instance_variable_set('@limit', nil)
|
59
|
+
clean_query.instance_variable_set('@offset', 0)
|
60
|
+
new_collection(clean_query).count
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_a
|
66
|
+
if paginated?
|
67
|
+
::WillPaginate::Collection.create(current_page, per_page) do |col|
|
68
|
+
col.replace super
|
69
|
+
col.total_entries ||= total_entries
|
70
|
+
end
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def new_collection(query, resources = nil)
|
79
|
+
col = super
|
80
|
+
col.current_page = self.current_page
|
81
|
+
col
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize_copy(original)
|
85
|
+
super
|
86
|
+
@total_entries = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
::DataMapper::Model.append_extensions PerPage
|
91
|
+
::DataMapper::Model.append_extensions Pagination
|
92
|
+
::DataMapper::Collection.send(:include, Pagination)
|
93
|
+
::DataMapper::Collection.send(:include, CollectionMethods)
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module WillPaginate::Deprecation
|
2
|
+
class << self
|
3
|
+
def warn(message, stack = caller)
|
4
|
+
offending_line = origin_of_call(stack)
|
5
|
+
full_message = "DEPRECATION WARNING: #{message} (called from #{offending_line})"
|
6
|
+
logger = rails_logger || Kernel
|
7
|
+
logger.warn full_message
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def rails_logger
|
13
|
+
defined?(Rails) && Rails.logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def origin_of_call(stack)
|
17
|
+
lib_root = File.expand_path('../../..', __FILE__)
|
18
|
+
stack.find { |line| line.index(lib_root) != 0 } || stack.first
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Hash < ::Hash
|
23
|
+
def initialize(values = {})
|
24
|
+
super()
|
25
|
+
update values
|
26
|
+
@deprecated = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def []=(key, value)
|
30
|
+
check_deprecated(key, value)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def deprecate_key(*keys)
|
35
|
+
message = block_given? ? Proc.new : keys.pop
|
36
|
+
Array(keys).each { |key| @deprecated[key] = message }
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge(another)
|
40
|
+
to_hash.update(another)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_hash
|
44
|
+
::Hash.new.update(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def check_deprecated(key, value)
|
50
|
+
if msg = @deprecated[key] and (!msg.respond_to?(:call) or (msg = msg.call(key, value)))
|
51
|
+
WillPaginate::Deprecation.warn(msg)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module WillPaginate
|
2
|
+
module I18n
|
3
|
+
def self.locale_dir
|
4
|
+
File.expand_path('../locale', __FILE__)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.load_path
|
8
|
+
Dir["#{locale_dir}/*.{rb,yml}"]
|
9
|
+
end
|
10
|
+
|
11
|
+
def will_paginate_translate(keys, options = {})
|
12
|
+
if defined? ::I18n
|
13
|
+
defaults = Array(keys).dup
|
14
|
+
defaults << Proc.new if block_given?
|
15
|
+
::I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => :will_paginate))
|
16
|
+
else
|
17
|
+
key = Array === keys ? keys.first : keys
|
18
|
+
yield key, options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
en:
|
2
|
+
will_paginate:
|
3
|
+
previous_label: "← Previous"
|
4
|
+
next_label: "Next →"
|
5
|
+
page_gap: "…"
|
6
|
+
|
7
|
+
page_entries_info:
|
8
|
+
single_page:
|
9
|
+
zero: "No %{model} found"
|
10
|
+
one: "Displaying 1 %{model}"
|
11
|
+
other: "Displaying all %{count} %{model}"
|
12
|
+
single_page_html:
|
13
|
+
zero: "No %{model} found"
|
14
|
+
one: "Displaying <b>1</b> %{model}"
|
15
|
+
other: "Displaying <b>all %{count}</b> %{model}"
|
16
|
+
|
17
|
+
multi_page: "Displaying %{model} %{from} - %{to} of %{count} in total"
|
18
|
+
multi_page_html: "Displaying %{model} <b>%{from} - %{to}</b> of <b>%{count}</b> in total"
|
19
|
+
|
20
|
+
# models:
|
21
|
+
# entry:
|
22
|
+
# zero: entries
|
23
|
+
# one: entry
|
24
|
+
# few: entries
|
25
|
+
# other: entries
|
26
|
+
|
27
|
+
# line_item:
|
28
|
+
# page_entries_info:
|
29
|
+
# single_page:
|
30
|
+
# zero: "Your shopping cart is empty"
|
31
|
+
# one: "Displaying one item in your cart"
|
32
|
+
# other: "Displaying all %{count} items"
|
33
|
+
# multi_page: "Displaying items %{from} - %{to} of %{count} in total"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module WillPaginate
|
5
|
+
# a module that page number exceptions are tagged with
|
6
|
+
module InvalidPage; end
|
7
|
+
|
8
|
+
# integer representing a page number
|
9
|
+
class PageNumber < DelegateClass(Integer)
|
10
|
+
# a value larger than this is not supported in SQL queries
|
11
|
+
BIGINT = 9223372036854775807
|
12
|
+
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
def initialize(value, name)
|
16
|
+
value = Integer(value)
|
17
|
+
if 'offset' == name ? (value < 0 or value > BIGINT) : value < 1
|
18
|
+
raise RangeError, "invalid #{name}: #{value.inspect}"
|
19
|
+
end
|
20
|
+
@name = name
|
21
|
+
super(value)
|
22
|
+
rescue ArgumentError, TypeError, RangeError => error
|
23
|
+
error.extend InvalidPage
|
24
|
+
raise error
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :to_i, :__getobj__
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
"#{@name} #{to_i}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_offset(per_page)
|
34
|
+
PageNumber.new((to_i - 1) * per_page.to_i, 'offset')
|
35
|
+
end
|
36
|
+
|
37
|
+
def kind_of?(klass)
|
38
|
+
super || to_i.kind_of?(klass)
|
39
|
+
end
|
40
|
+
alias is_a? kind_of?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Ultrahax: makes `Fixnum === current_page` checks pass
|
44
|
+
Numeric.extend Module.new {
|
45
|
+
def ===(obj)
|
46
|
+
obj.instance_of? PageNumber or super
|
47
|
+
end
|
48
|
+
}
|
49
|
+
|
50
|
+
# An idemptotent coercion method
|
51
|
+
def self.PageNumber(value, name = 'page')
|
52
|
+
case value
|
53
|
+
when PageNumber then value
|
54
|
+
else PageNumber.new(value, name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module WillPaginate
|
2
|
+
module PerPage
|
3
|
+
def per_page
|
4
|
+
defined?(@per_page) ? @per_page : WillPaginate.per_page
|
5
|
+
end
|
6
|
+
|
7
|
+
def per_page=(limit)
|
8
|
+
@per_page = limit.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.extended(base)
|
12
|
+
base.extend Inheritance if base.is_a? Class
|
13
|
+
end
|
14
|
+
|
15
|
+
module Inheritance
|
16
|
+
def inherited(subclass)
|
17
|
+
super
|
18
|
+
subclass.per_page = self.per_page
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
extend PerPage
|
24
|
+
|
25
|
+
# default number of items per page
|
26
|
+
self.per_page = 30
|
27
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'will_paginate'
|
2
|
+
require 'will_paginate/page_number'
|
3
|
+
require 'will_paginate/collection'
|
4
|
+
require 'will_paginate/i18n'
|
5
|
+
|
6
|
+
module WillPaginate
|
7
|
+
class Railtie < Rails::Railtie
|
8
|
+
initializer "will_paginate" do |app|
|
9
|
+
ActiveSupport.on_load :active_record do
|
10
|
+
require 'will_paginate/active_record'
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load :action_controller do
|
14
|
+
WillPaginate::Railtie.setup_actioncontroller
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveSupport.on_load :action_view do
|
18
|
+
require 'will_paginate/view_helpers/action_view'
|
19
|
+
end
|
20
|
+
|
21
|
+
self.class.add_locale_path config
|
22
|
+
|
23
|
+
# early access to ViewHelpers.pagination_options
|
24
|
+
require 'will_paginate/view_helpers'
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.setup_actioncontroller
|
28
|
+
( defined?(ActionDispatch::ExceptionWrapper) ?
|
29
|
+
ActionDispatch::ExceptionWrapper : ActionDispatch::ShowExceptions
|
30
|
+
).send :include, ShowExceptionsPatch
|
31
|
+
ActionController::Base.extend ControllerRescuePatch
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_locale_path(config)
|
35
|
+
config.i18n.railties_load_path.unshift(*WillPaginate::I18n.load_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Extending the exception handler middleware so it properly detects
|
39
|
+
# WillPaginate::InvalidPage regardless of it being a tag module.
|
40
|
+
module ShowExceptionsPatch
|
41
|
+
extend ActiveSupport::Concern
|
42
|
+
included { alias_method_chain :status_code, :paginate }
|
43
|
+
def status_code_with_paginate(exception = @exception)
|
44
|
+
if exception.is_a?(WillPaginate::InvalidPage) or
|
45
|
+
(exception.respond_to?(:original_exception) &&
|
46
|
+
exception.original_exception.is_a?(WillPaginate::InvalidPage))
|
47
|
+
Rack::Utils.status_code(:not_found)
|
48
|
+
else
|
49
|
+
original_method = method(:status_code_without_paginate)
|
50
|
+
if original_method.arity != 0
|
51
|
+
original_method.call(exception)
|
52
|
+
else
|
53
|
+
original_method.call()
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module ControllerRescuePatch
|
60
|
+
def rescue_from(*args, &block)
|
61
|
+
if idx = args.index(WillPaginate::InvalidPage)
|
62
|
+
args[idx] = args[idx].name
|
63
|
+
end
|
64
|
+
super(*args, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'sequel/extensions/pagination'
|
3
|
+
require 'will_paginate/collection'
|
4
|
+
|
5
|
+
module WillPaginate
|
6
|
+
# Sequel already supports pagination; we only need to make the
|
7
|
+
# resulting dataset look a bit more like WillPaginate::Collection
|
8
|
+
module SequelMethods
|
9
|
+
include WillPaginate::CollectionMethods
|
10
|
+
|
11
|
+
def total_pages
|
12
|
+
page_count
|
13
|
+
end
|
14
|
+
|
15
|
+
def per_page
|
16
|
+
page_size
|
17
|
+
end
|
18
|
+
|
19
|
+
def size
|
20
|
+
current_page_record_count
|
21
|
+
end
|
22
|
+
alias length size
|
23
|
+
|
24
|
+
def total_entries
|
25
|
+
pagination_record_count
|
26
|
+
end
|
27
|
+
|
28
|
+
def out_of_bounds?
|
29
|
+
current_page > total_pages
|
30
|
+
end
|
31
|
+
|
32
|
+
# Current offset of the paginated collection
|
33
|
+
def offset
|
34
|
+
(current_page - 1) * per_page
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Sequel::Dataset::Pagination.send(:include, SequelMethods)
|
39
|
+
end
|