Skip to content

Commit

Permalink
Simplification of input variables and defaults: params and request_pa…
Browse files Browse the repository at this point in the history
…th are not instance variables
  • Loading branch information
ddnexus committed Apr 10, 2024
1 parent c5280f5 commit 0e09545
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 91 deletions.
75 changes: 36 additions & 39 deletions docs/api/pagy.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ categories:

The scope of the `Pagy` class is keeping track of the all integers and variables involved in the pagination. It basically takes a
few integers (such as the count of the collection, the page number, the items per page, ...), does some simple arithmetic and
creates a very small object that allocates less than 3k of
memory.
creates a very small object that allocates less than 3k of memory.

## Synopsis

Expand Down Expand Up @@ -128,50 +127,48 @@ For example: `pagy(some_scope, items: params[:items])` will work without any add

The only mandatory instance variable to be passed is the `:count` of the collection to paginate: all the other variables are
optional and have sensible defaults. Of course you will also have to pass the `page` or you will always get the default page
number 1.

| Variable | Description | Default |
|:-----------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
| `:anchor_string` | The extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [Customize the link attributes](/docs/how-to.md#customize-the-link-attributes))_ | `nil` |
| `:count` | The total count of the collection to paginate (mandatory argument) | `nil` |
| `:count_args` | The arguments passed to the `collection.count`. You may want to set it to `[]` in ORMs different than ActiveRecord | [:all] |
| `:cycle` | Enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` |
| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `nil` |
| `:items` | The requested number of items for the page | `20` |
| `:jsonapi` | Enable `jsonapi` compliance of the pagy query params | `false` |
| `:max_pages` | Paginate only `:max_pages`. _(see also [Paginate only max_pages](/docs/how-to.md#paginate-only-max_pages-regardless-the-count))_ | `nil` |
| `:outset` | The initial offset of the collection to paginate: pass it only if the collection had an offset | `0` |
| `:page` | The requested page number: extracted from the `request.params`, or forced by passeing a variable | `1` |
| `:page_param` | The name of the page param name used in the url. _(see [Customize the page param](/docs/how-to.md#customize-the-page-param))_ | `:page` |
| `:params` | It can be a `Hash` of params to add to the URL, or a `Proc` that can edit/add/delete the request params _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `{}` |
| `:request_path` | Allows overriding the request path for pagination links. Pass the path only (not the absolute url). _(see [Customize the request path](/docs/how-to.md#customize-the-request-path))_ | `nil` |
| `:size` | The size of the page links to show: can be an array of 4 items or the integer of the total page size. _(see also [Control the page links](/docs/how-to.md#control-the-page-links))_ | `7` |
number `1`. For performance reasons, only the instance variables get validated.

| Variable | Description | Default |
|:-----------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
| `:anchor_string` | The extra attributes string (formatted as a valid HTML `attr="value"`) added to the page links _(see [Customize the link attributes](/docs/how-to.md#customize-the-link-attributes))_ | `nil` |
| `:count` | The total count of the collection to paginate (mandatory argument) | `nil` |
| `:count_args` | The arguments passed to the `collection.count`. You may want to set it to `[]` in ORMs different than ActiveRecord | [:all] |
| `:cycle` | Enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` |
| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `nil` |
| `:items` | The requested number of items for the page | `20` |
| `:jsonapi` | Enable `jsonapi` compliance of the pagy query params | `false` |
| `:max_pages` | Paginate only `:max_pages`. _(see [Paginate only max_pages](/docs/how-to.md#paginate-only-max_pages-regardless-the-count))_ | `nil` |
| `:outset` | The initial offset of the collection to paginate: pass it only if the collection had an offset | `0` |
| `:page` | The requested page number: extracted from the `request.params`, or forced by passeing a variable | `1` |
| `:page_param` | The name of the page param name used in the url. _(see [Customize the page param](/docs/how-to.md#customize-the-page-param))_ | `:page` |
| `:params` | It can be a `Hash` of params to add to the URL, or a `Proc` that can edit/add/delete the request params _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `nil` |
| `:request_path` | Allows overriding the `request.path` for pagination links. Pass the path only (not the absolute url). _(see [Pass the request path](/docs/how-to.md#pass-the-request-path))_ | `nil` |
| `:size` | The size of the page links to show: can be an array of 4 items or the integer of the total page size. _(see also [Control the page links](/docs/how-to.md#control-the-page-links))_ | `7` |

!!!
Extras may add and document their own variables
!!!

### Attribute Readers

Pagy exposes all the instance variables needed for the pagination through a few attribute readers. They all return integers (
or `nil`), except the `vars` hash:

| Reader | Description |
|:---------------|:-------------------------------------------------------------------------------------------------------------------|
| `count` | The collection `:count` |
| `from` | The collection-position of the first item in the page (`:outset` excluded) |
| `in` | The number of the items in the page |
| `items` | The requested number of items for the page |
| `last` | The number of the last page in the collection (ordinal meaning) |
| `next` | The next page number or `nil` if there is no next page |
| `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) |
| `page` | The current page number |
| `pages` | Alias for `last` (cardinal meaning) |
| `params` | The `:params` variable (`Hash` or `Proc`) |
| `prev` | The previous page number or `nil` if there is no previous page |
| `request_path` | The request path used for pagination helpers. If nil, helpers will use `request.path` |
| `to` | The collection-position of the last item in the page (`:outset` excluded) |
| `vars` | The variables hash |
Pagy exposes all its internal instance variables through a few readers. They all return integers (or `nil`), except the
`vars` hash (which contains all the input variables):

| Reader | Description |
|:---------|:-------------------------------------------------------------------------------------------------------------------|
| `count` | The collection `:count` |
| `from` | The collection-position of the first item in the page (`:outset` excluded) |
| `in` | The number of the items in the page |
| `items` | The requested number of items for the page |
| `last` | The number of the last page in the collection (ordinal meaning) |
| `next` | The next page number or `nil` if there is no next page |
| `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) |
| `page` | The current page number |
| `pages` | Alias for `last` (cardinal meaning) |
| `prev` | The previous page number or `nil` if there is no previous page |
| `to` | The collection-position of the last item in the page (`:outset` excluded) |
| `vars` | The variables hash |

### Lowest limit analysis

Expand Down
28 changes: 7 additions & 21 deletions gem/config/pagy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,15 @@
# Should you just cherry pick part of this file, please maintain the require-order of the extras


# Pagy DEFAULT Variables
# Pagy Variables
# See https://ddnexus.github.io/pagy/docs/api/pagy#variables
# All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance by just passing them to
# You can set any pagy variable as a Pagy::DEFAULT. They can also be overridden per instance by just passing them to
# Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods

# Instance variables
# See https://ddnexus.github.io/pagy/docs/api/pagy#instance-variables
# Pagy::DEFAULT[:page] = 1 # default
# Pagy::DEFAULT[:items] = 20 # default
# Pagy::DEFAULT[:outset] = 0 # default

# Other Variables
# See https://ddnexus.github.io/pagy/docs/api/pagy#other-variables
# Pagy::DEFAULT[:size] = [1,4,4,1] # default in pagy < 7.0
# Pagy::DEFAULT[:page_param] = :page # default
# Pagy::DEFAULT[:fragment] = '#fragment' # example
# Pagy::DEFAULT[:anchor_string] = 'data-remote="true"' # example
# Pagy::DEFAULT[:cycle] = true # example
# Pagy::DEFAULT[:request_path] = '/foo' # example
# Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs
# Pagy::DEFAULT[:params] = {} # default
# NOTICE: The :params can be also set as a lambda e.g:
# ->(params){ params.exclude('useless').merge!('custom' => 'useful') }
# Here are the few that make more sense as DEFAULTs:
# Pagy::DEFAULT[:items] = 20 # default
# Pagy::DEFAULT[:size] = [1,4,4,1] # default in pagy < 7.0
# Pagy::DEFAULT[:page_param] = :page # default
# Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs


# Extras
Expand Down
24 changes: 2 additions & 22 deletions gem/lib/pagy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ def self.root
size: 7,
cycle: false,
count_args: [:all], # AR friendly
params: {},
page_param: :page }

attr_reader :count, :page, :items, :vars, :last, :offset, :in, :from, :to, :prev, :next, :params, :request_path
attr_reader :count, :page, :items, :vars, :last, :offset, :in, :from, :to, :prev, :next
alias pages last

# Merge and validate the options, do some simple arithmetic and set the instance variables
Expand All @@ -34,9 +33,6 @@ def initialize(vars)
raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last

setup_offset_var
setup_params_var
setup_request_path_var

@from = [@offset - @outset + 1, @count].min
@to = [@offset - @outset + @items, @count].min
@in = [@to - @from + 1, @count].min
Expand Down Expand Up @@ -116,7 +112,7 @@ def setup_items_var
setup_vars(items: 1)
end

# Setup @last and @last (overridden by the gearbox extra)
# Setup @last (overridden by the gearbox extra)
def setup_last_var
@last = [(@count.to_f / @items).ceil, 1].max
@last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages]
Expand All @@ -127,22 +123,6 @@ def setup_last_var
def setup_offset_var
@offset = (@items * (@page - 1)) + @outset # may be already set from gear_box
end

# Setup and validate @params
def setup_params_var
raise VariableError.new(self, :params, 'must be a Hash or a Proc', @params) \
unless (@params = @vars[:params]).is_a?(Hash) || @params.is_a?(Proc)
end

def setup_request_path_var
request_path = @vars[:request_path]
return if request_path.to_s.empty?

raise VariableError.new(self, :request_path, 'must be a bare path like "/foo"', request_path) \
if !request_path.start_with?('/') || request_path.include?('?')

@request_path = request_path
end
end

require_relative 'pagy/backend'
Expand Down
1 change: 0 additions & 1 deletion gem/lib/pagy/calendar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def initialize(vars) # rubocop:disable Lint/MissingSuper
normalize_vars(vars) # general default
setup_vars(page: 1)
setup_unit_vars
setup_params_var
raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last

@prev = (@page - 1 unless @page == 1)
Expand Down
1 change: 0 additions & 1 deletion gem/lib/pagy/countless.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def initialize(vars = {}) # rubocop:disable Lint/MissingSuper
setup_vars(page: 1, outset: 0)
setup_items_var
setup_offset_var
setup_params_var
end

# Finalize the instance variables based on the fetched size
Expand Down
1 change: 0 additions & 1 deletion test/pagy/extras/metadata_test.rb.rematch
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ pagy/extras/metadata::#pagy_metadata for Pagy#test_0002_returns the full pagy me
:cycle: false
:count_args:
- :all
:params: {}
:page_param: :page
:countless_minimal: false
:steps: false
Expand Down
7 changes: 1 addition & 6 deletions test/pagy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ def series_for(page, *expected)
_ { Pagy.new(count: 100, page: 2, size: [1, 2, 3, '4']).series }.must_raise Pagy::VariableError
_ { Pagy.new(count: 100, page: '11') }.must_raise Pagy::OverflowError
_ { Pagy.new(count: 100, page: 12) }.must_raise Pagy::OverflowError
_ { Pagy.new(count: 100, params: 12) }.must_raise Pagy::VariableError
_ { Pagy.new(count: 100, request_path: "http://example.com/foo") }.must_raise Pagy::VariableError
_ { Pagy.new(count: 100, request_path: "/foo?bar=1") }.must_raise Pagy::VariableError
_ { Pagy.new(count: 100, request_path: "foo") }.must_raise Pagy::VariableError
begin
Pagy.new(count: 100, page: 12)
rescue Pagy::OverflowError => e
Expand Down Expand Up @@ -317,7 +313,7 @@ def series_for(page, *expected)
describe 'accessors' do
it 'has accessors' do
[
:count, :page, :items, :vars, :request_path, # input
:count, :page, :items, :vars, # input
:offset, :pages, :last, :from, :to, :in, :prev, :next, :series # output
].each do |meth|
_(pagy).must_respond_to meth
Expand All @@ -332,7 +328,6 @@ def series_for(page, *expected)
_(Pagy::DEFAULT[:outset]).must_equal 0
_(Pagy::DEFAULT[:size]).must_equal 7
_(Pagy::DEFAULT[:page_param]).must_equal :page
_(Pagy::DEFAULT[:params]).must_equal({})
end
end

Expand Down

0 comments on commit 0e09545

Please sign in to comment.