From 4788c3c51c58b0cad51c15dcc1ec39bb73da90c5 Mon Sep 17 00:00:00 2001
From: Domizio Demichelis
Date: Tue, 3 Apr 2018 14:48:26 +0700
Subject: [PATCH] grouped the variables :initial, :before, :after and :final
into one single :size array; #series can work with different sizes
---
docs/api/pagy.md | 11 +++++------
docs/how-to.md | 18 +++++++-----------
lib/pagy.rb | 31 +++++++++++++++----------------
test/metrics_test.rb | 6 +-----
test/series_test.rb | 15 +++------------
5 files changed, 31 insertions(+), 50 deletions(-)
diff --git a/docs/api/pagy.md b/docs/api/pagy.md
index 571125d3a..4b440c063 100644
--- a/docs/api/pagy.md
+++ b/docs/api/pagy.md
@@ -68,10 +68,7 @@ These are the core-variables (i.e. instance variables that define the pagination
| `:page` | the requested page number | `1` |
| `:items` | the _requested_ number of items for the page | `20` |
| `:outset` | the initial offset of the collection to paginate: pass it only if the collection was pre-offset(ted) | `0` |
-| `:initial` | max pages to show from the first page | `1` |
-| `:before` | max pages before the current page | `4` |
-| `:after` | max pages after the current page | `4` |
-| `:final` | max pages to show from the last page | `1` |
+| `:size` | the size of the page links to show: array of initial pages, before current page, after current page, final pages. _(see also [Control the page links](/pagy/how-to#control-the-page-links))_ | `[1,4,4,1]` |
Pagy validates the core variables passed and raises an `ArgumentError` exception if any value is wrong. It also raises a specific `Pagy::OutOfRangeError` if the `:page` is out of range, so you can rescue from it and do whatever you think fits.
@@ -107,9 +104,11 @@ Pagy exposes all the instance variables needed for the pagination through a few
| `vars` | the non-core variables hash |
-### series
+### series(size=@vars[:size])
-This method is the core of the pagination. It calculates, memoize and returns an array containing the page numbers and the `:gap` items to be rendered with the navigation links (e.g. `[1, :gap, 7, 8, "9", 10, 11, :gap, 36]`). The nav helpers and the templates basically loop through this array and render the correct item by simply checking its type:
+This method is the core of the pagination. It returns an array containing the page numbers and the `:gap` items to be rendered with the navigation links (e.g. `[1, :gap, 7, 8, "9", 10, 11, :gap, 36]`). It accepts an optional `size` argument (mostly useful for extras), defaulted on the `:size` variable.
+
+The nav helpers and the templates basically loop through this array and render the correct item by simply checking its type:
- if the item is an `Integer` then it is a page link
- if the item is a `String` then it is the current page
diff --git a/docs/how-to.md b/docs/how-to.md
index b27f99ee4..5128fa1ce 100644
--- a/docs/how-to.md
+++ b/docs/how-to.md
@@ -108,32 +108,27 @@ __Notice__: If you need to get the page number from another param or in some dif
### Control the page links
-You can control the number and position of page links in the navigation through the following variables.
+You can control the number and position of page links in the navigation through the `:size` variables. It is an array of 4 integers that specify which and how many page link to show.
-| Variable | Description | Default |
-| ---: | :--- | :--- |
-| `:initial` | max pages to show from the first page | `1` |
-| `:before` | max pages before the current page | `4` |
-| `:after` | max pages after the current page | `4` |
-| `:final` | max pages to show from the last page | `1` |
+The default is `[1,4,4,1]`, which means that you will get `1` initial page, `4` pages before the current page, `4` pages after the current page, and `1` final page
As usual you can set them as global defaults by using the `Pagy::VARS` hash or pass them directly to the `pagy` method.
The navigation links will contain the number of pages set in the variables:
-`:initial`...`:before` `:page` `:after`...`:final`
+`size[0]`...`size[1]` current page `size[2]`...`size[3]`
For example:
```ruby
-pagy = Pagy.new count:1000, page: 10, initial: 3, final: 3 # etc
+pagy = Pagy.new count:1000, page: 10, size: [3,4,4,3] # etc
pagy.series
#=> [1, 2, 3, :gap, 6, 7, 8, 9, "10", 11, 12, 13, 14, :gap, 48, 49, 50]
```
-As you can see by the result of the `series` method, you get 3 explicitly requested`:initial` pages, 1 `:gap` (series interupted), the 4 default `:before` pages, the current `:page` (which is a string), the 4 default `:after` pages, another `:gap` and the 3 explicitly requested `:final` pages
+As you can see by the result of the `series` method, you get 3 initial pages, 1 `:gap` (series interupted), 4 pages before the current page, the current `:page` (which is a string), 4 pages after the current page, another `:gap` and 3 final pages.
-You can easily try different options (also asymmetrical) in a console: just check the `series` array to see what it contains when used with different core variables.
+You can easily try different options (also asymmetrical) in a console by changing the `:size`: just check the `series` array to see what it contains when used in combination with different core variables.
### Using the `pagy_nav` and `pagy_nav_bootstrap` helpers
@@ -290,6 +285,7 @@ You can do so by setting the `:item_path` variable to the path to lookup in the
```
__Notice__: The variables passed to a pagy object have the precedence over the variables returned by the `pagy_get_vars`. The fastest way is passing a literal string to the `pagy` method, the most convenient way is using `pagy_get_vars`.
+__Notice__: The variables passed to a pagy object have the precedence over the variables returned by the `pagy_get_vars`. The fastest way is passing a literal string to the `pagy` method, the most convenient way is using `pagy_get_vars`.
### Handling Pagy::OutOfRangeError exception
diff --git a/lib/pagy.rb b/lib/pagy.rb
index 2743e79d8..782a11ab0 100644
--- a/lib/pagy.rb
+++ b/lib/pagy.rb
@@ -13,7 +13,7 @@ class OutOfRangeError < StandardError; end
def self.root; Pathname.new(__FILE__).dirname end
# default core vars
- VARS = { items:20, outset:0, initial:1, before:4, after:4, final:1 }
+ VARS = { items:20, outset:0, size:[1,4,4,1] }
# default I18n vars
I18N = { file: Pagy.root.join('locales', 'pagy.yml').to_s, plurals: -> (c) {c==0 && 'zero' || c==1 && 'one' || 'other'} }
@@ -23,11 +23,11 @@ def self.root; Pathname.new(__FILE__).dirname end
# merge and validate the options, do some simple aritmetic and set the instance variables
def initialize(vars)
- @vars = VARS.merge(vars) # default vars + instance vars
+ @vars = VARS.merge(vars) # default vars + instance vars
@vars[:page] = (@vars[:page]||1).to_i # set page to 1 if nil
- {count:0, items:1, outset:0, initial:0, before:0, page:1, after:0, final:0}.each do |k,min|
+ { count:0, items:1, outset:0, page:1 }.each do |k,min| # validate core variables
@vars[k] >= min rescue nil || raise(ArgumentError, "expected :#{k} >= #{min}; got #{@vars[k].inspect}")
- instance_variable_set(:"@#{k}", @vars.delete(k)) # set all the core variables
+ instance_variable_set(:"@#{k}", @vars.delete(k)) # set instance variables
end
@pages = @last = [(@count.to_f / @items).ceil, 1].max # cardinal and ordinal meanings
(1..@last).cover?(@page) || raise(OutOfRangeError, "expected :page in 1..#{@last}; got #{@page.inspect}")
@@ -40,18 +40,17 @@ def initialize(vars)
end
# return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
- def series
- @series ||= [].tap do |series|
- [*0..@initial, *@page-@before..@page+@after, *@last-@final+1..@last+1].sort!.each_cons(2) do |a, b|
- if a<0 || a==b || a>@last # skip out of range and duplicates
- elsif a+1 == b; series.push(a) # no gap -> no additions
- elsif a+2 == b; series.push(a, a+1) # 1 page gap -> fill with missing page
- else series.push(a, :gap) # n page gap -> add :gap
- end # skip the end boundary (last+1)
- end
- series.shift # remove the start boundary (0)
- series[series.index(@page)] = @page.to_s # convert the current page to String
- end
+ def series(size=@vars[:size])
+ (0..3).each{|i| size[i]>=0 rescue nil || raise(ArgumentError, "expected 4 items in :size >= 0; got #{size.inspect}")}
+ series = []
+ [*0..size[0], *@page-size[1]..@page+size[2], *@last-size[3]+1..@last+1].sort!.each_cons(2) do |a, b|
+ if a<0 || a==b || a>@last # skip out of range and duplicates
+ elsif a+1 == b; series.push(a) # no gap -> no additions
+ elsif a+2 == b; series.push(a, a+1) # 1 page gap -> fill with missing page
+ else series.push(a, :gap) # n page gap -> add :gap
+ end # skip the end boundary (last+1)
+ end # shift the start boundary (0) and
+ series.tap{|s| s.shift; s[s.index(@page)] = @page.to_s} # convert the current page to String
end
end
diff --git a/test/metrics_test.rb b/test/metrics_test.rb
index b0f3181b6..66e587b36 100644
--- a/test/metrics_test.rb
+++ b/test/metrics_test.rb
@@ -3,11 +3,7 @@
class MetricsTest < Minitest::Test
def setup
- @vars = { items: 10,
- initial: 3,
- final: 3,
- before: 2,
- after: 2 }
+ @vars = { items: 10, size: [3,2,2,3] }
@array = (1..103).to_a.extend(Pagy::Array::PageMethod)
end
diff --git a/test/series_test.rb b/test/series_test.rb
index 7729f3bb2..214090bef 100644
--- a/test/series_test.rb
+++ b/test/series_test.rb
@@ -7,24 +7,15 @@ def setup
@vars0 = { count: 103,
items: 10,
- initial: 0,
- final: 0,
- before: 2,
- after: 2 }
+ size: [0,2,2,0] }
@vars1 = { count: 103,
items: 10,
- initial: 3,
- final: 3,
- before: 0,
- after: 0 }
+ size: [3,0,0,3] }
@vars2 = { count: 103,
items: 10,
- initial: 3,
- final: 0,
- before: 2,
- after: 0 }
+ size: [3,2,0,0] }
end