smart_paginate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +96 -0
- data/Rakefile +8 -0
- data/lib/smart_paginate/active_record.rb +98 -0
- data/lib/smart_paginate/paginate.rb +21 -0
- data/lib/smart_paginate/paginating_array.rb +37 -0
- data/lib/smart_paginate/version.rb +3 -0
- data/lib/smart_paginate.rb +10 -0
- data/smart_paginate.gemspec +28 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 70dd5154721fd339facb7008e3088db09d599160
|
4
|
+
data.tar.gz: 85b59219f3271aacfde2867f049ec9db8ba8f1c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 06cf0656bfaa91e5f2fd57ec9f62477dbea410ed8e813536098f82cf426858a868b132082e127a0f302108af62d0aa26a4fe05710ec08fa60f084e75181df6b6
|
7
|
+
data.tar.gz: c19e2c4186646659811d5c78ca3d0527dc6f1c58ae81dd46f67c9ab2cc438a4172ce64155dfe70a00046f3897dae06c063fd41af3ac59a10d834711cd3877502
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.2
|
3
|
+
DisplayCopNames: true
|
4
|
+
DisplayStyleGuide: true
|
5
|
+
|
6
|
+
Metrics/LineLength:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Style/BlockComments:
|
10
|
+
Exclude:
|
11
|
+
- 'spec/**/*.rb'
|
12
|
+
|
13
|
+
Style/Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/GuardClause:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/IfUnlessModifier:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/MutableConstant:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/RedundantSelf:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/StringLiterals:
|
29
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Peter Postma
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# SmartPaginate
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ppostma/smart_paginate.svg?branch=master)](https://travis-ci.org/ppostma/smart_paginate)
|
4
|
+
|
5
|
+
Simple, smart and clean pagination extension for Active Record and plain Ruby Arrays:
|
6
|
+
|
7
|
+
- **Simple:** Easy to use, with a simple interface. It just does pagination, nothing more.
|
8
|
+
- **Smart:** Can navigate through the pages without having to do an expensive count query. SmartPaginate will actually fetch one record more than needed and use it to determine if there's a next page.
|
9
|
+
- **Clean:** The code is as minimal as possible while still useful. SmartPaginate does not auto include itself or monkey patch any classes.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'smart_paginate'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install smart_paginate
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Active Record
|
30
|
+
|
31
|
+
To enable pagination in an Active Record model, include the `SmartPaginate` concern in your class:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class User
|
35
|
+
include SmartPaginate
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Then you can use the `paginate` scope to paginate results:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
users = User.order(:name).paginate(page: 1, per_page: 20)
|
43
|
+
```
|
44
|
+
|
45
|
+
After using `paginate`, the following methods will be available to query the next page, number of pages, etc:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
users.next_page? # true when a next page exists
|
49
|
+
users.next_page # returns next page number
|
50
|
+
users.previous_page? # true when a previous page exists
|
51
|
+
users.previous_page # returns previous page number
|
52
|
+
users.total_entries # returns total number of entries (!)
|
53
|
+
users.total_pages # returns total number of pages (!)
|
54
|
+
```
|
55
|
+
|
56
|
+
**(!) Please note** that the `total_entries` and `total_pages` methods will do a `SELECT COUNT(*)` query to retrieve the total number of entries. This can be very expensive on a table with many records!
|
57
|
+
|
58
|
+
### Array
|
59
|
+
|
60
|
+
For paginating Arrays, use the class `SmartPaginate::PaginatingArray` to convert a plain Array to a paginatable Array:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
array = (1..100).to_a
|
64
|
+
array = SmartPaginate::PaginatingArray(array)
|
65
|
+
array.paginate(page: 1, per_page: 20)
|
66
|
+
```
|
67
|
+
|
68
|
+
### Helpers
|
69
|
+
|
70
|
+
Because SmartPaginate was designed to be as simple and clean as possible, it does not provide any helpers to create pagination links in your views. It is however very easy to write your own, e.g. for Rails:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
module PaginateHelper
|
74
|
+
def paginate(collection, options = {})
|
75
|
+
content_tag(:div, class: "pagination") do
|
76
|
+
if collection.present?
|
77
|
+
options = options.merge(params)
|
78
|
+
|
79
|
+
concat link_to("Previous", url_for(options.merge(per_page: collection.per_page, page: collection.previous_page)), class: "previous_page") if collection.previous_page?
|
80
|
+
concat link_to("Next", url_for(options.merge(per_page: collection.per_page, page: collection.next_page)), class: "next_page") if collection.next_page?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
|
88
|
+
## Contributing
|
89
|
+
|
90
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ppostma/smart_paginate.
|
91
|
+
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
96
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require "smart_paginate/paginate"
|
2
|
+
require "active_support/concern"
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
module SmartPaginate
|
6
|
+
module ActiveRecord
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def paginate(options = {})
|
11
|
+
page = SmartPaginate::Paginate.new(options.fetch(:page), options[:per_page])
|
12
|
+
|
13
|
+
rel = all.extending(RelationMethods)
|
14
|
+
# add one more to the limit so we can quickly determine if there are more pages present
|
15
|
+
rel = rel.limit(page.per_page + 1).offset(page.offset)
|
16
|
+
rel.current_page = page.current_page
|
17
|
+
rel.per_page = page.per_page
|
18
|
+
rel
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module RelationMethods
|
23
|
+
attr_accessor :current_page, :per_page
|
24
|
+
|
25
|
+
# Override #count: make it return the number of entries that we expect
|
26
|
+
def count(*args)
|
27
|
+
if limit_value && per_page && limit_value > per_page
|
28
|
+
rel = except(:limit).limit(per_page)
|
29
|
+
rel.count
|
30
|
+
else
|
31
|
+
super(*args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Override #empty: check fetched records instead of counting
|
36
|
+
def empty?
|
37
|
+
load # make sure we have determined the number of fetched records
|
38
|
+
|
39
|
+
@number_of_records.zero?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Override #load: fetch/slice records and determine number of records
|
43
|
+
def load
|
44
|
+
super
|
45
|
+
slice_records!(@records)
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def next_page?
|
51
|
+
load # make sure we have determined the number of fetched records
|
52
|
+
|
53
|
+
@number_of_records > per_page # there's a next page when we've fetched more records than per_page
|
54
|
+
end
|
55
|
+
|
56
|
+
def previous_page?
|
57
|
+
current_page > 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def next_page
|
61
|
+
current_page + 1 if next_page?
|
62
|
+
end
|
63
|
+
|
64
|
+
def previous_page
|
65
|
+
current_page - 1 if previous_page?
|
66
|
+
end
|
67
|
+
|
68
|
+
def total_pages
|
69
|
+
(total_entries / per_page.to_f).ceil
|
70
|
+
end
|
71
|
+
|
72
|
+
def total_entries
|
73
|
+
@total_entries ||= begin
|
74
|
+
load # make sure we have determined the number of fetched records
|
75
|
+
|
76
|
+
# if we know that there are no more records, then we can calculate total_entries
|
77
|
+
if @number_of_records <= per_page
|
78
|
+
offset_value + @number_of_records
|
79
|
+
else
|
80
|
+
rel = except(:limit, :offset)
|
81
|
+
rel.count
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# remember total number of fetched records and slice records to per_page
|
89
|
+
def slice_records!(records)
|
90
|
+
@number_of_records ||= records.length
|
91
|
+
|
92
|
+
if @number_of_records > per_page
|
93
|
+
records.slice!(per_page)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SmartPaginate
|
2
|
+
class Paginate
|
3
|
+
attr_reader :current_page, :per_page
|
4
|
+
|
5
|
+
def initialize(current_page, per_page = nil)
|
6
|
+
@current_page = convert(current_page, 1)
|
7
|
+
@per_page = convert(per_page, 20)
|
8
|
+
end
|
9
|
+
|
10
|
+
def offset
|
11
|
+
(current_page - 1) * per_page
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def convert(value, default_value)
|
17
|
+
value = value.to_i
|
18
|
+
value > 0 ? value : default_value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "smart_paginate/paginate"
|
2
|
+
|
3
|
+
module SmartPaginate
|
4
|
+
class PaginatingArray < Array
|
5
|
+
attr_accessor :current_page, :per_page, :total_entries
|
6
|
+
|
7
|
+
def paginate(options = {})
|
8
|
+
page = SmartPaginate::Paginate.new(options.fetch(:page), options[:per_page])
|
9
|
+
|
10
|
+
array = self.slice(page.offset, page.per_page)
|
11
|
+
array.current_page = page.current_page
|
12
|
+
array.per_page = page.per_page
|
13
|
+
array.total_entries = length
|
14
|
+
array
|
15
|
+
end
|
16
|
+
|
17
|
+
def next_page?
|
18
|
+
(current_page * per_page) < total_entries
|
19
|
+
end
|
20
|
+
|
21
|
+
def previous_page?
|
22
|
+
current_page > 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def next_page
|
26
|
+
current_page + 1 if next_page?
|
27
|
+
end
|
28
|
+
|
29
|
+
def previous_page
|
30
|
+
current_page - 1 if previous_page?
|
31
|
+
end
|
32
|
+
|
33
|
+
def total_pages
|
34
|
+
(total_entries / per_page.to_f).ceil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'smart_paginate/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "smart_paginate"
|
8
|
+
spec.version = SmartPaginate::VERSION
|
9
|
+
spec.authors = ["Peter Postma"]
|
10
|
+
spec.email = ["peter.postma@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "Simple, smart and clean pagination extension"
|
13
|
+
spec.description = "Simple, smart and clean pagination extension for Active Record and plain Ruby Arrays."
|
14
|
+
spec.homepage = "https://github.com/ppostma"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.4.0", ">= 3.4.0"
|
25
|
+
spec.add_development_dependency "sqlite3", "~> 1.3", ">= 1.3.11"
|
26
|
+
|
27
|
+
spec.add_dependency "activerecord", ">= 4.0.0", "< 4.3"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smart_paginate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Postma
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.4.0
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 3.4.0
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 3.4.0
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.4.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: sqlite3
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.3'
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.3.11
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.3'
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 1.3.11
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: activerecord
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 4.0.0
|
88
|
+
- - "<"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '4.3'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 4.0.0
|
98
|
+
- - "<"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '4.3'
|
101
|
+
description: Simple, smart and clean pagination extension for Active Record and plain
|
102
|
+
Ruby Arrays.
|
103
|
+
email:
|
104
|
+
- peter.postma@gmail.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- ".gitignore"
|
110
|
+
- ".rspec"
|
111
|
+
- ".rubocop.yml"
|
112
|
+
- ".travis.yml"
|
113
|
+
- Gemfile
|
114
|
+
- LICENSE.txt
|
115
|
+
- README.md
|
116
|
+
- Rakefile
|
117
|
+
- lib/smart_paginate.rb
|
118
|
+
- lib/smart_paginate/active_record.rb
|
119
|
+
- lib/smart_paginate/paginate.rb
|
120
|
+
- lib/smart_paginate/paginating_array.rb
|
121
|
+
- lib/smart_paginate/version.rb
|
122
|
+
- smart_paginate.gemspec
|
123
|
+
homepage: https://github.com/ppostma
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.8
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: Simple, smart and clean pagination extension
|
147
|
+
test_files: []
|