foliate 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e632e2cdf928b30535057da735d185e35d5bb80
4
+ data.tar.gz: dcaed853a25f108a2838ad7c686a9e389e55cdb2
5
+ SHA512:
6
+ metadata.gz: b34de5919e49576e9a4c27b84488d179a2a021e618dcbbec69707121023a12fb2ca69eb9a2d0e3058687602bbe2dcde50ffe4b5a058239fe2d2efe006f4ff32a
7
+ data.tar.gz: 3b8719a28e535fd8ba94b0ec5bcf78a43451d01ba34172c87389bf05217100aceb042e21888a57232dffec8732c40aa483620427fb95adcb64656128527c708d
@@ -0,0 +1,20 @@
1
+ Copyright 2017
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,106 @@
1
+ # foliate
2
+
3
+ Pagination for Ruby on Rails.
4
+
5
+ **Why another pagination library?** Because a different approach leads
6
+ to a cleaner and much simpler implementation.
7
+
8
+ **How is it different?** Instead of extending ActiveRecord, or
9
+ dynamically defining methods on objects after instantiating them,
10
+ *foliate* adds a single method to ActionController:
11
+
12
+ ```ruby
13
+ ## app/controllers/posts_controller.rb
14
+ class PostsController < ApplicationController
15
+
16
+ def index
17
+ @posts = paginate(Post) # <-- single method
18
+ end
19
+
20
+ end
21
+ ```
22
+
23
+ Calling `paginate` with something like an ActiveRecord::Relation (or an
24
+ Array) returns an ActiveRecord::Relation (or an Array) scoped to the
25
+ current page of records, as dictated by `params[:page]`.
26
+
27
+ Calling `paginate` also sets a `@pagination` instance variable for use
28
+ in the view. This object can be passed directly to `render`, which will
29
+ then render the "app/views/pagination/_pagination.html.erb" view
30
+ partial:
31
+
32
+ ```html
33
+ <!-- app/views/posts/index.html.erb -->
34
+
35
+ Do something with @posts here...
36
+
37
+ <%= render @pagination %>
38
+ ```
39
+
40
+ **How does that look?** By default, something like this:
41
+
42
+ <img src="screenshots/page_input.png" alt="page input pagination">
43
+
44
+
45
+ ## More Information
46
+
47
+ **How do I customize the appearance of the pagination?** Running the
48
+ *foliate* installation generator creates
49
+ "app/views/pagination/_pagination.html.erb" and
50
+ "app/assets/stylesheets/pagination.css" in your project directory.
51
+ These files can be edited to meet your needs.
52
+
53
+ **How many records are in each page?** By default, *foliate* allots
54
+ `Foliate.config.default_per_page` records per page, which is set in
55
+ "config/initializers/foliate.rb". However, this can be overridden by
56
+ passing `per_page:` to `paginate`:
57
+
58
+ ```ruby
59
+ @posts = paginate(Post, per_page: 50)
60
+ ```
61
+
62
+ **What if I have a very large table, and don't want to incur a count of
63
+ all records for each page?** The `paginate` method accepts a
64
+ `total_records:` argument, which will prevent a SQL count when set:
65
+
66
+ ```ruby
67
+ @posts = paginate(Post, total_records: Post.cached_count)
68
+ ```
69
+
70
+ **What if I want a different param than `:page` to dictate the current
71
+ page?** That can be configured with `Foliate.config.page_param`, which
72
+ is set in "config/initializers/foliate.rb".
73
+
74
+ **For even more information,** see the
75
+ [full documentation](http://www.rubydoc.info/gems/foliate/).
76
+
77
+
78
+ ## Installation
79
+
80
+ Add this line to your application's Gemfile:
81
+
82
+ ```ruby
83
+ gem "foliate"
84
+ ```
85
+
86
+ Then execute:
87
+
88
+ ```bash
89
+ $ bundle
90
+ ```
91
+
92
+ And finally, run the installation generator:
93
+
94
+ ```bash
95
+ $ rails generate foliate:install
96
+ ```
97
+
98
+
99
+ ## Contributing
100
+
101
+ Run `rake test` to run the tests.
102
+
103
+
104
+ ## License
105
+
106
+ [MIT License](https://opensource.org/licenses/MIT)
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'yard'
8
+
9
+ YARD::Rake::YardocTask.new(:doc) do |t|
10
+ end
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ require 'bundler/gem_tasks'
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new(:test) do |t|
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = false
26
+ end
27
+
28
+
29
+ task default: :test
@@ -0,0 +1,3 @@
1
+ require "foliate/version"
2
+ require "foliate/config"
3
+ require "foliate/railtie"
@@ -0,0 +1,31 @@
1
+ module Foliate
2
+
3
+ class Config
4
+ # @return [Integer]
5
+ # default number of records to allot per page (defaults to +10+)
6
+ attr_accessor :default_per_page
7
+
8
+ # @return [Symbol]
9
+ # URL query param name for specifying page numbers (defaults to
10
+ # +:page+)
11
+ attr_accessor :page_param
12
+
13
+ def initialize
14
+ @default_per_page = 10
15
+ @page_param = :page
16
+ end
17
+ end
18
+
19
+ # Foliate global configuration object.
20
+ #
21
+ # @return [Foliate::Config]
22
+ def self.config
23
+ @config ||= Foliate::Config.new
24
+ end
25
+
26
+ # @param c [Foliate::Config]
27
+ def self.config=(c)
28
+ @config = c
29
+ end
30
+
31
+ end
@@ -0,0 +1,61 @@
1
+ require "foliate/config"
2
+ require "foliate/pagination"
3
+
4
+ module Foliate
5
+ module Controller
6
+
7
+ # Paginates +records+, and returns the current page of records
8
+ # according to <code>params[Foliate.config.page_param]</code>
9
+ # (typically, <code>params[:page]</code>). Also sets the
10
+ # +@pagination+ instance variable for use in the view (see
11
+ # {Foliate::Pagination}).
12
+ #
13
+ # Returns an ActiveRecord::Relation if +records+ is an
14
+ # ActiveRecord::Relation. Returns an Array if +records+ is an
15
+ # Array.
16
+ #
17
+ # By default, allots <code>Foliate.config.default_per_page</code>
18
+ # number of records per page. This can be overridden by specifying
19
+ # +per_page:+.
20
+ #
21
+ # By default, if +records+ is an ActiveRecord::Relation, computes
22
+ # the total number of pages by performing a SQL count query. If the
23
+ # underlying table is very large, this query could have a noticeable
24
+ # performance cost. This can be circumvented by specifying
25
+ # +total_records:+, using an estimated or cached record count.
26
+ #
27
+ # @example basic pagination
28
+ # @posts = paginate(Post)
29
+ #
30
+ # @example paginated search
31
+ # @posts = paginate(Post.where(status: params[:show_only]))
32
+ #
33
+ # @example user-specified per_page
34
+ # @posts = paginate(Post, per_page: params[:at_a_time])
35
+ #
36
+ # @example simple cached count
37
+ # count = Rails.cache.fetch("Post/count", expires_in: 5.minutes){ Post.count }
38
+ # @posts = paginate(Post, total_records: count)
39
+ #
40
+ # @param records [ActiveRecord::Relation, Array]
41
+ # @param per_page [Integer, String]
42
+ # @param total_records [Integer]
43
+ # @return [ActiveRecord::Relation, Array]
44
+ def paginate(records, per_page: nil, total_records: nil)
45
+ @pagination = Foliate::Pagination.new.tap do |p|
46
+ p.current_page = [params[Foliate.config.page_param].to_i, 1].max
47
+ p.per_page = per_page.try(&:to_i) || Foliate.config.default_per_page
48
+ p.total_records = total_records || (records.is_a?(Array) ?
49
+ records.length : records.unscope(:limit).unscope(:offset).count)
50
+ p.controller = params[:controller]
51
+ p.action = params[:action]
52
+ p.query_params = request.query_parameters.except(Foliate.config.page_param)
53
+ end
54
+
55
+ records.is_a?(Array) ?
56
+ records[@pagination.offset, @pagination.per_page].to_a :
57
+ records.limit(@pagination.per_page).offset(@pagination.offset)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,111 @@
1
+ require "foliate/config"
2
+
3
+ module Foliate
4
+ class Pagination
5
+
6
+ # @return [Integer]
7
+ # current page number
8
+ attr_accessor :current_page
9
+
10
+ # @return [Integer]
11
+ # number of records per page
12
+ attr_accessor :per_page
13
+
14
+ # @return [Integer]
15
+ # total number of records
16
+ attr_accessor :total_records
17
+
18
+ # @return [Symbol]
19
+ # originating controller
20
+ attr_accessor :controller
21
+
22
+ # @return [Symbol]
23
+ # originating controller action
24
+ attr_accessor :action
25
+
26
+ # @return [Hash]
27
+ # originating request query params
28
+ attr_accessor :query_params
29
+
30
+ # Computes the total number of pages based on +total_records+ and
31
+ # +per_page+.
32
+ #
33
+ # @return [Integer]
34
+ def total_pages
35
+ (total_records / per_page.to_f).ceil
36
+ end
37
+
38
+ # Computes the record set offset based on +current_page+ and
39
+ # +per_page+.
40
+ #
41
+ # @return [Integer]
42
+ def offset
43
+ (current_page - 1) * per_page
44
+ end
45
+
46
+ # Returns linking params for a specified +page_number+. The
47
+ # returned Hash is intended for use with +link_to+, +url_for+, etc.
48
+ #
49
+ # @example usage in view
50
+ # link_to "First", pagination.params_for_page(1)
51
+ # link_to "Last", pagination.params_for_page(pagination.total_pages)
52
+ #
53
+ # @param page_number [Integer]
54
+ # @return [Hash]
55
+ def params_for_page(page_number)
56
+ { controller: controller, action: action, params: query_params.merge(
57
+ Foliate.config.page_param => (page_number if page_number > 1)
58
+ ) }
59
+ end
60
+
61
+ # Indicates if there is an expected page previous to the current
62
+ # page.
63
+ #
64
+ # @return [Boolean]
65
+ def prev?
66
+ current_page > 1
67
+ end
68
+
69
+ # Indicates if there is an expected page beyond the current page.
70
+ #
71
+ # @return [Boolean]
72
+ def next?
73
+ current_page < total_pages
74
+ end
75
+
76
+ # Linking params for the previous page. Returns nil if {#prev?} is
77
+ # false. See also {#params_for_page}.
78
+ #
79
+ # @example usage in view
80
+ # link_to_if pagination.prev?, "Previous", pagination.prev_page_params
81
+ #
82
+ # @return [Hash, nil]
83
+ def prev_page_params
84
+ params_for_page(current_page - 1) if prev?
85
+ end
86
+
87
+ # Linking params for the next page. Returns nil if {#next?} is
88
+ # false. See also {#params_for_page}.
89
+ #
90
+ # @example usage in view
91
+ # link_to_if pagination.next?, "Next", pagination.next_page_params
92
+ #
93
+ # @return [Hash, nil]
94
+ def next_page_params
95
+ params_for_page(current_page + 1) if next?
96
+ end
97
+
98
+ # Path to the view partial. This method exists to allow
99
+ # +Pagination+ objects to be passed directly to +render+ calls in
100
+ # the view.
101
+ #
102
+ # @example rendering view partial from view
103
+ # render @pagination
104
+ #
105
+ # @return [String]
106
+ def to_partial_path
107
+ "pagination/pagination"
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,12 @@
1
+ require "rails/railtie"
2
+ require "foliate/controller"
3
+
4
+ module Foliate
5
+ class Railtie < Rails::Railtie
6
+ initializer :foliate do |app|
7
+ ActiveSupport.on_load :action_controller do
8
+ ActionController::Base.send :include, Foliate::Controller
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Foliate
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,20 @@
1
+ require "foliate/config"
2
+ require "rails/generators/base"
3
+
4
+ module Foliate
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.join(__dir__, "templates")
8
+
9
+ def copy_config
10
+ template "config/initializer.rb.erb", "config/initializers/foliate.rb"
11
+ copy_file "config/locales.yml", "config/locales/foliate.yml"
12
+ end
13
+
14
+ def copy_view
15
+ copy_file "views/page_input.html.erb", "app/views/pagination/_pagination.html.erb"
16
+ copy_file "stylesheets/page_input.css", "app/assets/stylesheets/pagination.css"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ Foliate.config.tap do |config|
2
+ config.default_per_page = <%= Foliate.config.default_per_page.inspect %>
3
+ config.page_param = <%= Foliate.config.page_param.inspect %>
4
+ end
@@ -0,0 +1,5 @@
1
+ en:
2
+ foliate:
3
+ prev: "Previous"
4
+ next: "Next"
5
+ of: "of"
@@ -0,0 +1,26 @@
1
+ .foliate-page-link {
2
+ color: rgba(0, 0, 0, 0.6);
3
+ }
4
+
5
+ .foliate-i-of-n {
6
+ margin: 0 1em;
7
+ }
8
+
9
+ .foliate-form {
10
+ display: inline-block;
11
+ margin: 0;
12
+ }
13
+
14
+ .foliate-page-input {
15
+ font-size: 1em;
16
+ width: 2.5em;
17
+ border: 1px solid rgba(0, 0, 0, 0.5);
18
+ border-radius: 2px;
19
+ line-height: 1.5em;
20
+ text-align: center;
21
+ font-family: monospace;
22
+ }
23
+
24
+ .foliate-of {
25
+ margin: 0 0.25em;
26
+ }
@@ -0,0 +1,25 @@
1
+ <div class="foliate-pagination">
2
+ <span class="foliate-page-link foliate-prev-link">
3
+ <%= link_to_if pagination.prev?, t("foliate.prev"), pagination.prev_page_params %>
4
+ </span>
5
+
6
+ <span class="foliate-i-of-n">
7
+ <form method="get" class="foliate-form">
8
+ <% pagination.query_params.each do |name, value| %>
9
+ <input type="hidden" name="<%= name %>" value="<%= value %>">
10
+ <% end %>
11
+
12
+ <input type="text" pattern="[0-9]*" class="foliate-page-input"
13
+ name="<%= Foliate.config.page_param %>"
14
+ value="<%= pagination.current_page %>">
15
+ </form>
16
+
17
+ <span class="foliate-of"><%= t("foliate.of") %></span>
18
+
19
+ <span class="foliate-total-pages"><%= pagination.total_pages %></span>
20
+ </span>
21
+
22
+ <span class="foliate-page-link foliate-next-link">
23
+ <%= link_to_if pagination.next?, t("foliate.next"), pagination.next_page_params %>
24
+ </span>
25
+ </div>
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foliate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Hefner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ description:
56
+ email:
57
+ - jonathan.hefner@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/foliate.rb
66
+ - lib/foliate/config.rb
67
+ - lib/foliate/controller.rb
68
+ - lib/foliate/pagination.rb
69
+ - lib/foliate/railtie.rb
70
+ - lib/foliate/version.rb
71
+ - lib/generators/foliate/install/install_generator.rb
72
+ - lib/generators/foliate/install/templates/config/initializer.rb.erb
73
+ - lib/generators/foliate/install/templates/config/locales.yml
74
+ - lib/generators/foliate/install/templates/stylesheets/page_input.css
75
+ - lib/generators/foliate/install/templates/views/page_input.html.erb
76
+ homepage: https://github.com/jonathanhefner/foliate
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.6.13
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Rails pagination
100
+ test_files: []