smart_paginate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .ruby-version
11
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
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
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.9
5
+ - 2.2.5
6
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in smart_paginate.gemspec
4
+ gemspec
5
+
6
+ gem 'rubocop', '~> 0.40.0', group: :test
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,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new(:rubocop)
7
+
8
+ task default: [:spec, :rubocop]
@@ -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,3 @@
1
+ module SmartPaginate
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,10 @@
1
+ require "smart_paginate/active_record"
2
+ require "smart_paginate/paginating_array"
3
+ require "smart_paginate/version"
4
+ require "active_support/concern"
5
+
6
+ module SmartPaginate
7
+ extend ActiveSupport::Concern
8
+
9
+ include SmartPaginate::ActiveRecord
10
+ 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: []