pagy 5.0.0 → 5.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: