pagy 5.0.0 → 5.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c5f4f4ffd2a294e465f0a026d9795c9ae8e5efe58b968a97df08fa9163bab28
4
- data.tar.gz: 8dc70a9adb26aa4da11f42f1903478d62b3aaff7a17e0bd57163c4b340ffd91e
3
+ metadata.gz: 4af6c795ba446552a412f0f45e76a267cf767d8f4dec3564a90096525bb298ea
4
+ data.tar.gz: 57a3f62877f0ed653ebe68f59963fb865e252e68c55e5c3a91794b9aa3b9584a
5
5
  SHA512:
6
- metadata.gz: c3b6c77ae8ec22c135f6acc127884a4fe334e811b310ffa464bacae46d842a57a1d3c98faac019935c14900fe78aff2aeb0ebf72fef82822bea8dee9fc1943eb
7
- data.tar.gz: 43b8b9aa866735df4ac4cca43b22f04aaa5c08ef9140c3d6b04b4ed0e132681e40f0ef224111dc788c0e558d3b8ac3d5e283d5a42ad24abc4c152a452b5ed5c5
6
+ metadata.gz: 0520f9933ea293895b8d26b0a78ea0af1a61054b5b89fce3a06c1f8f292d82357f6e105f76ab7bd4665f6ee9765bc69ce284428b8fe61b8f0a6b4768136c8e4a
7
+ data.tar.gz: '0903950d58220f510b5c2700b42f23f19c5cd267bc73eb5404d918863717b816836609256ef3a340534a9bc74e50260915b8b023b502c9dbe503bb443fab968f'
data/lib/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (5.0.0)
3
+ # Pagy initializer file (5.1.2)
4
4
  # Customize only what you really need and notice that Pagy works also without any of the following lines.
5
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
6
 
@@ -153,6 +153,11 @@
153
153
  # set to false only if you want to make :trim_extra an opt-in variable
154
154
  # Pagy::DEFAULT[:trim_extra] = false # default true
155
155
 
156
+ # Standalone extra: Use pagy in non Rack environment/gem
157
+ # See https://ddnexus.github.io/pagy/extras/standalone
158
+ # require 'pagy/extras/standalone'
159
+ # Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default
160
+
156
161
 
157
162
  # Rails
158
163
 
@@ -3,7 +3,7 @@
3
3
  // Container of the whole pagy stuff
4
4
  function Pagy(){}
5
5
 
6
- Pagy.version = '5.0.0'
6
+ Pagy.version = '5.1.2'
7
7
 
8
8
  // Used by the waitForMe function
9
9
  Pagy.delay = 100
data/lib/pagy/backend.rb CHANGED
@@ -15,16 +15,17 @@ class Pagy
15
15
  end
16
16
 
17
17
  # Sub-method called only by #pagy: here for easy customization of variables by overriding
18
+ # You may need to override the count call for non AR collections
18
19
  def pagy_get_vars(collection, vars)
19
20
  pagy_set_items_from_params(vars) if defined?(ItemsExtra)
20
- vars[:count] ||= (c = collection.count(:all)).is_a?(Hash) ? c.size : c
21
+ vars[:count] ||= (count = collection.count(:all)).is_a?(Hash) ? count.size : count
21
22
  vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
22
23
  vars
23
24
  end
24
25
 
25
26
  # Sub-method called only by #pagy: here for easy customization of record-extraction by overriding
27
+ # You may need to override this method for collections without offset|limit
26
28
  def pagy_get_items(collection, pagy)
27
- # This should work with ActiveRecord, Sequel, Mongoid...
28
29
  collection.offset(pagy.offset).limit(pagy.items)
29
30
  end
30
31
  end
data/lib/pagy/console.rb CHANGED
@@ -5,8 +5,9 @@ require 'pagy' # so you can require just the extra in the console
5
5
  require 'pagy/extras/standalone'
6
6
 
7
7
  class Pagy
8
- # Provide ready to use pagy environment when included in irb/rails console
8
+ # Provide a ready to use pagy environment when included in irb/rails console
9
9
  module Console
10
+ # Include Backend, Frontend and set the default URL
10
11
  def self.included(main)
11
12
  main.include(Backend)
12
13
  main.include(Frontend)
@@ -14,18 +14,23 @@ class Pagy
14
14
  @offset = (@items * (@page - 1)) + @outset
15
15
  end
16
16
 
17
- # Finalize the instance variables based on the fetched items
18
- def finalize(fetched)
19
- raise OverflowError.new(self), "page #{@page} got no items" \
20
- if fetched.zero? && @page > 1
17
+ # Finalize the instance variables based on the fetched size
18
+ def finalize(fetched_size)
19
+ raise OverflowError.new(self, :page, "to be < #{@page}") if fetched_size.zero? && @page > 1
21
20
 
22
- @pages = @last = (fetched > @items ? @page + 1 : @page)
23
- @in = [fetched, @items].min
21
+ @pages = @last = (fetched_size > @items ? @page + 1 : @page)
22
+ @in = [fetched_size, @items].min
24
23
  @from = @in.zero? ? 0 : @offset - @outset + 1
25
24
  @to = @offset - @outset + @in
26
25
  @prev = (@page - 1 unless @page == 1)
27
26
  @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
28
27
  self
29
28
  end
29
+
30
+ # Override the original series.
31
+ # Return nil if :countless_minimal is enabled
32
+ def series(_size = @vars[:size])
33
+ super unless @vars[:countless_minimal]
34
+ end
30
35
  end
31
36
  end
@@ -3,23 +3,25 @@
3
3
  class Pagy
4
4
  # Generic variable error
5
5
  class VariableError < ArgumentError
6
- attr_reader :pagy
6
+ attr_reader :pagy, :variable, :value
7
7
 
8
- def initialize(pagy)
9
- super
10
- @pagy = pagy
11
- end
12
-
13
- def variable
14
- message =~ /expected :(\w+)/
15
- Regexp.last_match(1)&.to_sym
16
- end
17
-
18
- def value
19
- pagy.vars[variable]
8
+ # Set the variables and prepare the message
9
+ def initialize(pagy, variable, description, value = nil)
10
+ @pagy = pagy
11
+ @variable = variable
12
+ @value = value
13
+ message = +"expected :#{@variable} #{description}"
14
+ message << "; got #{@value.inspect}" if value
15
+ super message
20
16
  end
21
17
  end
22
18
 
23
19
  # Specific overflow error
24
20
  class OverflowError < VariableError; end
21
+
22
+ # I18n configuration error
23
+ class I18nError < StandardError; end
24
+
25
+ # Generic internal error
26
+ class InternalError < StandardError; end
25
27
  end
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module BootstrapExtra
8
10
  # Pagination for bootstrap: it returns the html with the series of links to the pages
9
11
  def pagy_bootstrap_nav(pagy, pagy_id: nil, link_extra: '')
@@ -20,6 +22,7 @@ class Pagy
20
22
  %(<li class="page-item active">#{link.call item}</li>)
21
23
  when :gap
22
24
  %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.gap'}</a></li>)
25
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
23
26
  end
24
27
  end
25
28
  html << pagy_bootstrap_next_html(pagy, link)
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module BulmaExtra
8
10
  # Pagination for Bulma: it returns the html with the series of links to the pages
9
11
  def pagy_bulma_nav(pagy, pagy_id: nil, link_extra: '')
@@ -22,6 +24,7 @@ class Pagy
22
24
  %(class="pagination-link is-current" aria-label="page #{item}" aria-current="page")}</li>)
23
25
  when :gap
24
26
  %(<li><span class="pagination-ellipsis">#{pagy_t 'pagy.nav.gap'}</span></li>)
27
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
25
28
  end
26
29
  end
27
30
  html << %(</ul></nav>)
@@ -23,16 +23,13 @@ class Pagy
23
23
  end
24
24
 
25
25
  # Sub-method called only by #pagy_countless: here for easy customization of record-extraction by overriding
26
+ # You may need to override this method for collections without offset|limit
26
27
  def pagy_countless_get_items(collection, pagy)
27
- # This should work with ActiveRecord, Sequel, Mongoid...
28
28
  return collection.offset(pagy.offset).limit(pagy.items) if pagy.vars[:countless_minimal]
29
29
 
30
- items = collection.offset(pagy.offset).limit(pagy.items + 1).to_a
31
- items_size = items.size
32
- items.pop if items_size == pagy.items + 1
33
- # finalize may adjust pagy.items, so must be used after checking the size
34
- pagy.finalize(items_size)
35
- items
30
+ fetched = collection.offset(pagy.offset).limit(pagy.items + 1).to_a # eager load items + 1
31
+ pagy.finalize(fetched.size) # finalize the pagy object
32
+ fetched[0, pagy.items] # ignore eventual extra item
36
33
  end
37
34
  end
38
35
  Backend.prepend CountlessExtra
@@ -19,8 +19,8 @@ class Pagy
19
19
 
20
20
  module ElasticsearchRails
21
21
  # Return an array used to delay the call of #search
22
- # after the pagination variables are merged to the options
23
- # it also pushes to the same array an eventually called method
22
+ # after the pagination variables are merged to the options.
23
+ # It also pushes to the same array an optional method call.
24
24
  def pagy_elasticsearch_rails(query_or_payload, **options)
25
25
  [self, query_or_payload, options].tap do |args|
26
26
  args.define_singleton_method(:method_missing) { |*a| args += a }
@@ -57,7 +57,7 @@ class Pagy
57
57
  pagy = ::Pagy.new(vars)
58
58
  # with :last_page overflow we need to re-run the method in order to get the hits
59
59
  return pagy_elasticsearch_rails(pagy_search_args, vars.merge(page: pagy.page)) \
60
- if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
60
+ if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
61
61
 
62
62
  [pagy, called.empty? ? response : response.send(*called)]
63
63
  end
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module FoundationExtra
8
10
  # Pagination for Foundation: it returns the html with the series of links to the pages
9
11
  def pagy_foundation_nav(pagy, pagy_id: nil, link_extra: '')
@@ -17,6 +19,7 @@ class Pagy
17
19
  when Integer then %(<li>#{link.call item}</li>) # page link
18
20
  when String then %(<li class="current">#{item}</li>) # active page
19
21
  when :gap then %(<li class="ellipsis gap" aria-hidden="true"></li>) # page gap
22
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
20
23
  end
21
24
  end
22
25
  html << pagy_foundation_next_html(pagy, link)
@@ -13,7 +13,7 @@ class Pagy
13
13
  return super if !@vars[:gearbox_extra] || @vars[:items_extra]
14
14
 
15
15
  gearbox_items = @vars[:gearbox_items]
16
- raise VariableError.new(self), "expected :gearbox_items to be an Array of positives; got #{gearbox_items.inspect}" \
16
+ raise VariableError.new(self, :gearbox_items, 'to be an Array of positives', gearbox_items) \
17
17
  unless gearbox_items.is_a?(Array) && gearbox_items.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier
18
18
 
19
19
  @items = gearbox_items[@page - 1] || gearbox_items.last
@@ -14,9 +14,9 @@ class Pagy # Default variables for this extra
14
14
 
15
15
  # Set the items variable considering the params and other pagy variables
16
16
  def pagy_set_items_from_params(vars)
17
- return if vars[:items]
18
- return unless vars.key?(:items_extra) ? vars[:items_extra] : DEFAULT[:items_extra]
19
- return unless (items = params[vars[:items_param] || DEFAULT[:items_param]])
17
+ return if vars[:items] # :items explicitly set
18
+ return unless vars.key?(:items_extra) ? vars[:items_extra] : DEFAULT[:items_extra] # :items_extra is false
19
+ return unless (items = params[vars[:items_param] || DEFAULT[:items_param]]) # no items from request params
20
20
 
21
21
  vars[:items] = [items.to_i, vars.key?(:max_items) ? vars[:max_items] : DEFAULT[:max_items]].compact.min
22
22
  end
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module MaterializeExtra
8
10
  # Pagination for materialize: it returns the html with the series of links to the pages
9
11
  def pagy_materialize_nav(pagy, pagy_id: nil, link_extra: '')
@@ -17,6 +19,7 @@ class Pagy
17
19
  when Integer then %(<li class="waves-effect">#{link.call item}</li>) # page link
18
20
  when String then %(<li class="active">#{link.call item}</li>) # active page
19
21
  when :gap then %(<li class="gap disabled"><a href="#">#{pagy_t 'pagy.nav.gap'}</a></li>) # page gap
22
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
20
23
  end
21
24
  end
22
25
  html << pagy_materialize_next_html(pagy, link)
@@ -39,13 +39,13 @@ class Pagy
39
39
  pagy = ::Pagy.new(vars)
40
40
  # with :last_page overflow we need to re-run the method in order to get the hits
41
41
  return pagy_meilisearch(pagy_search_args, vars.merge(page: pagy.page)) \
42
- if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
42
+ if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
43
43
 
44
44
  [pagy, results]
45
45
  end
46
46
 
47
- # Sub-method called only by #pagy_meilisearch: here for easy customization of variables by overriding
48
- # the _collection argument is not available when the method is called
47
+ # Sub-method called only by #pagy_meilisearch: here for easy customization of variables by overriding.
48
+ # The _collection argument is not available when the method is called.
49
49
  def pagy_meilisearch_get_vars(_collection, vars)
50
50
  pagy_set_items_from_params(vars) if defined?(ItemsExtra)
51
51
  vars[:items] ||= DEFAULT[:items]
@@ -4,44 +4,20 @@
4
4
  require 'pagy/url_helpers'
5
5
 
6
6
  class Pagy
7
+ DEFAULT[:metadata] = %i[ scaffold_url first_url prev_url page_url next_url last_url
8
+ count page items vars pages last in from to prev next series ]
9
+
7
10
  # Add a specialized backend method for pagination metadata
8
11
  module MetadataExtra
9
12
  private
10
13
 
11
- # Store the array of all the internal variable names usable as METADATA
12
- METADATA = %i[ scaffold_url
13
- first_url
14
- prev_url
15
- page_url
16
- next_url
17
- last_url
18
- count page
19
- items
20
- vars
21
- pages
22
- last
23
- in
24
- from
25
- to
26
- prev
27
- next
28
- series ].tap { |m| m << :sequels if DEFAULT.key?(:steps) }.freeze
29
-
30
- # Set the default metadata variable
31
- Pagy::DEFAULT[:metadata] = METADATA.dup
32
-
33
14
  include UrlHelpers
34
15
 
35
16
  # Return the metadata hash
36
17
  def pagy_metadata(pagy, absolute: nil)
37
- names = pagy.vars[:metadata]
38
- unknown = names - METADATA
39
- raise VariableError.new(pagy), "expected :metadata to be in #{DEFAULT[:metadata].inspect}, got #{unknown.inspect} unknown" \
40
- unless unknown.empty?
41
-
42
18
  scaffold_url = pagy_url_for(pagy, PAGE_PLACEHOLDER, absolute: absolute)
43
19
  {}.tap do |metadata|
44
- names.each do |key|
20
+ pagy.vars[:metadata].each do |key|
45
21
  metadata[key] = case key
46
22
  when :scaffold_url then scaffold_url
47
23
  when :first_url then scaffold_url.sub(PAGE_PLACEHOLDER, 1.to_s)
@@ -51,6 +27,8 @@ class Pagy
51
27
  when :last_url then scaffold_url.sub(PAGE_PLACEHOLDER, pagy.last.to_s)
52
28
  else pagy.send(key)
53
29
  end
30
+ rescue NoMethodError
31
+ raise VariableError.new(pagy, :metadata, 'to contain known keys', key)
54
32
  end
55
33
  end
56
34
  end
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module NavsExtra
8
10
  # Javascript pagination: it returns a nav and a JSON tag used by the Pagy.nav javascript
9
11
  def pagy_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
@@ -31,11 +31,11 @@ class Pagy
31
31
  @prev = @last # prev relative to the actual page
32
32
  extend Series # special series for :empty_page
33
33
  else
34
- raise VariableError.new(self), \
35
- "expected :overflow to be in [:last_page, :empty_page, :exception]; got #{@vars[:overflow].inspect}"
34
+ raise VariableError.new(self, :overflow, 'to be in [:last_page, :empty_page, :exception]', @vars[:overflow])
36
35
  end
37
36
  end
38
37
 
38
+ # Special series for empty page
39
39
  module Series
40
40
  def series(size = @vars[:size])
41
41
  @page = @last # series for last page
@@ -63,8 +63,7 @@ class Pagy
63
63
  @vars[:size] = [] # no page in the series
64
64
  self
65
65
  else
66
- raise VariableError.new(self), \
67
- "expected :overflow to be in [:empty_page, :exception]; got #{@vars[:overflow].inspect}"
66
+ raise VariableError.new(self, :overflow, 'to be in [:empty_page, :exception]', @vars[:overflow])
68
67
  end
69
68
  end
70
69
  end
@@ -7,8 +7,8 @@ class Pagy
7
7
  module SearchkickExtra
8
8
  module Searchkick
9
9
  # Return an array used to delay the call of #search
10
- # after the pagination variables are merged to the options
11
- # it also pushes to the same array an eventually called method
10
+ # after the pagination variables are merged to the options.
11
+ # It also pushes to the same array an optional method call.
12
12
  def pagy_searchkick(term = '*', **options, &block)
13
13
  [self, term, options, block].tap do |args|
14
14
  args.define_singleton_method(:method_missing) { |*a| args += a }
@@ -44,7 +44,7 @@ class Pagy
44
44
  pagy = ::Pagy.new(vars)
45
45
  # with :last_page overflow we need to re-run the method in order to get the hits
46
46
  return pagy_searchkick(pagy_search_args, vars.merge(page: pagy.page)) \
47
- if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
47
+ if defined?(::Pagy::OverflowExtra) && pagy.overflow? && pagy.vars[:overflow] == :last_page
48
48
 
49
49
  [pagy, called.empty? ? results : results.send(*called)]
50
50
  end
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module SemanticExtra
8
10
  # Pagination for semantic: it returns the html with the series of links to the pages
9
11
  def pagy_semantic_nav(pagy, pagy_id: nil, link_extra: '')
@@ -17,6 +19,7 @@ class Pagy
17
19
  when Integer then link.call item # page link
18
20
  when String then %(<a class="item active">#{item}</a>) # current page
19
21
  when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>) # page gap
22
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
20
23
  end
21
24
  end
22
25
  html << pagy_semantic_next_html(pagy, link)
@@ -19,8 +19,7 @@ class Pagy
19
19
  # Notice: if :steps is false it will use the single {0 => @vars[:size]} size
20
20
  def sequels(steps = nil)
21
21
  steps ||= @vars[:steps] || { 0 => @vars[:size] }
22
- raise VariableError.new(self), "expected :steps to define the 0 width; got #{steps.inspect}" \
23
- unless steps.key?(0)
22
+ raise VariableError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
24
23
 
25
24
  {}.tap do |sequels|
26
25
  steps.each { |width, size| sequels[width.to_s] = series(size) }
@@ -31,14 +30,14 @@ class Pagy
31
30
  # Additions for the Frontend
32
31
  module Frontend
33
32
  if defined?(Oj)
34
- # it returns a script tag with the JSON-serialized args generated with the faster oj gem
33
+ # Return a script tag with the JSON-serialized args generated with the faster oj gem
35
34
  def pagy_json_attr(pagy, *args)
36
35
  args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
37
36
  %(data-pagy-json="#{Oj.dump(args, mode: :strict).gsub('"', '&quot;')}")
38
37
  end
39
38
  else
40
39
  require 'json'
41
- # it returns a script tag with the JSON-serialized args generated with the slower to_json
40
+ # Return a script tag with the JSON-serialized args generated with the slower to_json
42
41
  def pagy_json_attr(pagy, *args)
43
42
  args << pagy.vars[:page_param] if pagy.vars[:trim_extra]
44
43
  %(data-pagy-json="#{args.to_json.gsub('"', '&quot;')}")
@@ -3,6 +3,8 @@
3
3
 
4
4
  require 'uri'
5
5
  class Pagy
6
+ # Use pagy without any request object, nor Rack environment/gem, nor any defined params method,
7
+ # even in the irb/rails console without any app or config.
6
8
  module StandaloneExtra
7
9
  # Extracted from Rack::Utils and reformatted for rubocop
8
10
  module QueryUtils
@@ -30,21 +32,22 @@ class Pagy
30
32
  end
31
33
  end
32
34
 
33
- # Without any :url var it works exactly as the regular #pagy_url_for;
34
- # with a defined :url variable it does not use rack/request
35
+ # Return the URL for the page. If there is no pagy.vars[:url]
36
+ # it works exactly as the regular #pagy_url_for, relying on the params method and Rack.
37
+ # If there is a defined pagy.vars[:url] variable it does not need the params method nor Rack.
35
38
  def pagy_url_for(pagy, page, absolute: nil)
36
- p_vars = pagy.vars
37
- return super unless (url = p_vars[:url])
38
-
39
- params = p_vars[:params]
40
- params[p_vars[:page_param].to_s] = page
41
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(ItemsExtra)
42
- # no Rack required in standalone mode
43
- query_string = "?#{QueryUtils.build_nested_query(pagy_massage_params(params))}" unless params.empty?
44
- "#{url}#{query_string}#{p_vars[:fragment]}"
39
+ vars = pagy.vars
40
+ return super unless (url = vars[:url])
41
+
42
+ params = vars[:params].clone # safe when it gets reused
43
+ params[vars[:page_param]] = page
44
+ params[vars[:items_param]] = vars[:items] if vars[:items_extra]
45
+
46
+ query_string = "?#{QueryUtils.build_nested_query(pagy_massage_params(params))}"
47
+ "#{url}#{query_string}#{vars[:fragment]}"
45
48
  end
46
49
  end
47
- # In ruby 3+ we could just use `UrlHelpers.prepend StandaloneExtra` instead of using the next 2 lines
50
+ # In ruby 3+ `UrlHelpers.prepend StandaloneExtra` would be enough instead of using the next 2 lines
48
51
  Frontend.prepend StandaloneExtra
49
52
  Backend.prepend StandaloneExtra
50
53
 
@@ -3,14 +3,17 @@
3
3
 
4
4
  class Pagy
5
5
  module SupportExtra
6
+ # Return the previous page URL string or nil
6
7
  def pagy_prev_url(pagy)
7
8
  pagy_url_for(pagy, pagy.prev) if pagy.prev
8
9
  end
9
10
 
11
+ # Return the next page URL string or nil
10
12
  def pagy_next_url(pagy)
11
13
  pagy_url_for(pagy, pagy.next) if pagy.next
12
14
  end
13
15
 
16
+ # Return the HTML string for the previous page link
14
17
  def pagy_prev_link(pagy, text: pagy_t('pagy.nav.prev'), link_extra: '')
15
18
  if pagy.prev
16
19
  %(<span class="page prev"><a href="#{
@@ -23,6 +26,7 @@ class Pagy
23
26
  end
24
27
  end
25
28
 
29
+ # Return the HTML string for the next page link
26
30
  def pagy_next_link(pagy, text: pagy_t('pagy.nav.next'), link_extra: '')
27
31
  if pagy.next
28
32
  %(<span class="page next"><a href="#{
@@ -35,10 +39,12 @@ class Pagy
35
39
  end
36
40
  end
37
41
 
42
+ # Return the HTML link tag for the previous page or nil
38
43
  def pagy_prev_link_tag(pagy)
39
44
  %(<link href="#{pagy_url_for(pagy, pagy.prev)}" rel="prev"/>) if pagy.prev
40
45
  end
41
46
 
47
+ # Return the HTML link tag for the next page or nil
42
48
  def pagy_next_link_tag(pagy)
43
49
  %(<link href="#{pagy_url_for(pagy, pagy.next)}" rel="next"/>) if pagy.next
44
50
  end
@@ -5,7 +5,8 @@ class Pagy
5
5
  DEFAULT[:trim_extra] = true # extra enabled by default
6
6
 
7
7
  module TrimExtra
8
- # Override the original using the pagy_trim method
8
+ # Override the original pagy_link_proc.
9
+ # Call the pagy_trim method if the trim_extra is enabled.
9
10
  def pagy_link_proc(pagy, link_extra: '')
10
11
  link_proc = super(pagy, link_extra: link_extra)
11
12
  return link_proc unless pagy.vars[:trim_extra]
@@ -4,6 +4,8 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
7
9
  module UikitExtra
8
10
  # Pagination for uikit: it returns the html with the series of links to the pages
9
11
  def pagy_uikit_nav(pagy, pagy_id: nil, link_extra: '')
@@ -16,6 +18,7 @@ class Pagy
16
18
  when Integer then %(<li>#{link.call item}</li>)
17
19
  when String then %(<li class="uk-active"><span>#{item}</span></li>)
18
20
  when :gap then %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>)
21
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
19
22
  end
20
23
  end
21
24
  html << pagy_uikit_next_html(pagy, link)
data/lib/pagy/frontend.rb CHANGED
@@ -8,8 +8,8 @@ class Pagy
8
8
  # Used for search and replace, hardcoded also in the pagy.js file
9
9
  PAGE_PLACEHOLDER = '__pagy_page__'
10
10
 
11
- # All the code here has been optimized for performance: it may not look very pretty
12
- # (as most code dealing with many long strings), but its performance makes it very sexy! ;)
11
+ # Frontend modules are specially optimized for performance.
12
+ # The resulting code may not look very elegant, but produces the best benchmarks
13
13
  module Frontend
14
14
  include UrlHelpers
15
15
 
@@ -31,6 +31,7 @@ class Pagy
31
31
  when Integer then %(<span class="page">#{link.call item}</span> ) # page link
32
32
  when String then %(<span class="page active">#{item}</span> ) # current page
33
33
  when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> ) # page gap
34
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
34
35
  end
35
36
  end
36
37
  html << if p_next
data/lib/pagy/i18n.rb CHANGED
@@ -10,7 +10,7 @@ class Pagy
10
10
 
11
11
  # Pluralization rules
12
12
  module P11n
13
- # utility variables
13
+ # Utility variables
14
14
  from0to1 = [0, 1].freeze
15
15
  from2to4 = [2, 3, 4].freeze
16
16
  from5to9 = [5, 6, 7, 8, 9].freeze
@@ -130,7 +130,7 @@ class Pagy
130
130
  locale[:filepath] ||= Pagy.root.join('locales', "#{locale[:locale]}.yml")
131
131
  locale[:pluralize] ||= P11n::LOCALE[locale[:locale]]
132
132
  dictionary = YAML.safe_load(File.read(locale[:filepath], encoding: 'UTF-8'))
133
- raise VariableError, %(expected :locale "#{locale[:locale]}" not found in :filepath "#{locale[:filepath].inspect}") \
133
+ raise I18nError, %(expected :locale "#{locale[:locale]}" not found in :filepath "#{locale[:filepath].inspect}") \
134
134
  unless dictionary.key?(locale[:locale])
135
135
 
136
136
  DATA[locale[:locale]] = [flatten(dictionary[locale[:locale]]), locale[:pluralize]]
@@ -3,15 +3,17 @@
3
3
  class Pagy
4
4
  # Provide the helpers to handle the url in frontend and backend
5
5
  module UrlHelpers
6
- # This works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...)
6
+ # Return the URL for the page, relying on the params method and Rack by default.
7
+ # It supports all Rack-based frameworks (Sinatra, Padrino, Rails, ...).
8
+ # For non-rack environments you can use the standalone extra
7
9
  def pagy_url_for(pagy, page, absolute: nil)
8
- p_vars = pagy.vars
9
- params = request.GET.merge(p_vars[:params])
10
- params[p_vars[:page_param].to_s] = page
11
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(ItemsExtra)
12
- # we rely on Rack by default: use the standalone extra in non rack environments
13
- query_string = "?#{Rack::Utils.build_nested_query(pagy_massage_params(params))}" unless params.empty?
14
- "#{request.base_url if absolute}#{request.path}#{query_string}#{p_vars[:fragment]}"
10
+ vars = pagy.vars
11
+ params = request.params.merge(vars[:params].transform_keys(&:to_s))
12
+ params[vars[:page_param].to_s] = page
13
+ params[vars[:items_param].to_s] = vars[:items] if vars[:items_extra]
14
+
15
+ query_string = "?#{Rack::Utils.build_nested_query(pagy_massage_params(params))}"
16
+ "#{request.base_url if absolute}#{request.path}#{query_string}#{vars[:fragment]}"
15
17
  end
16
18
 
17
19
  # Sub-method called only by #pagy_url_for: here for easy customization of params by overriding
data/lib/pagy.rb CHANGED
@@ -5,7 +5,7 @@ require 'pathname'
5
5
 
6
6
  # Core class
7
7
  class Pagy
8
- VERSION = '5.0.0'
8
+ VERSION = '5.1.2'
9
9
 
10
10
  # Root pathname to get the path of Pagy files like templates or dictionaries
11
11
  def self.root
@@ -32,8 +32,7 @@ class Pagy
32
32
  setup_vars(count: 0, page: 1, outset: 0)
33
33
  setup_items_var
34
34
  setup_pages_var
35
- raise OverflowError.new(self), "expected :page in 1..#{@last}; got #{@page.inspect}" \
36
- if @page > @last
35
+ raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
37
36
 
38
37
  @offset = (@items * (@page - 1)) + @outset
39
38
  @from = [@offset - @outset + 1, @count].min
@@ -46,7 +45,7 @@ class Pagy
46
45
  # Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
47
46
  def series(size = @vars[:size])
48
47
  return [] if size.empty?
49
- raise VariableError.new(self), "expected 4 items >= 0 in :size; got #{size.inspect}" \
48
+ raise VariableError.new(self, :size, 'to contain 4 items >= 0', size) \
50
49
  unless size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
51
50
 
52
51
  # This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
@@ -81,7 +80,7 @@ class Pagy
81
80
  # Setup and validates the passed vars: var must be present and value.to_i must be >= to min
82
81
  def setup_vars(name_min)
83
82
  name_min.each do |name, min|
84
- raise VariableError.new(self), "expected :#{name} >= #{min}; got #{@vars[name].inspect}" \
83
+ raise VariableError.new(self, name, ">= #{min}", @vars[name]) \
85
84
  unless @vars[name] && instance_variable_set(:"@#{name}", @vars[name].to_i) >= min
86
85
  end
87
86
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-16 00:00:00.000000000 Z
11
+ date: 2021-10-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Agnostic pagination in plain ruby. It does it all. Better.
14
14
  email: