From f28f576eef976657aa76bb136f56a2aef56bdc5d Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Thu, 9 Jan 2025 17:19:01 +0700 Subject: [PATCH] WIP: Super refactoring 3 --- .simplecov | 26 +----- gem/apps/calendar.ru | 2 - gem/apps/demo.ru | 10 +- gem/apps/keyset.ru | 4 +- gem/apps/keyset_sequel.ru | 6 +- gem/apps/rails.ru | 10 +- gem/apps/repro.ru | 6 +- gem/lib/pagy.rb | 8 +- gem/lib/pagy/backend.rb | 2 +- gem/lib/pagy/console.rb | 2 +- gem/lib/pagy/extras/i18n.rb | 9 -- gem/lib/pagy/extras/limit.rb | 32 +------ gem/lib/pagy/extras/standalone.rb | 15 --- gem/lib/pagy/frontend.rb | 26 +----- gem/lib/pagy/keyset.rb | 2 + gem/lib/pagy/links_helper.rb | 9 +- gem/lib/pagy/{autoload.rb => loader.rb} | 16 ++-- gem/lib/pagy/mixins/headers.rb | 6 +- gem/lib/pagy/mixins/limit_selector.rb | 35 +++++++ gem/lib/pagy/mixins/pagy.rb | 57 +++++------- gem/lib/pagy/mixins/pagy_helpers.rb | 41 +++++++++ gem/lib/pagy/offset/calendar/unit.rb | 3 +- gem/lib/pagy/offset/countless.rb | 2 + gem/lib/pagy/ui_support.rb | 3 - gem/lib/pagy/url_helpers.rb | 6 +- test/files/db/test.sqlite3-wal | 0 test/pagy/autoload_test.rb | 7 +- test/pagy/extras/standalone_limit_test.rb | 25 ----- test/pagy/extras/standalone_test.rb | 89 ------------------ .../augmented_test.rb} | 6 +- test/pagy/{extras => mixins}/arel_test.rb | 2 +- test/pagy/{extras => mixins}/array_test.rb | 2 +- .../pagy/{extras => mixins}/bootstrap_test.rb | 2 +- .../{extras => mixins}/bootstrap_test.rb.yaml | 10 +- test/pagy/{extras => mixins}/bulma_test.rb | 2 +- .../{extras => mixins}/bulma_test.rb.yaml | 10 +- .../calendar_test.rb} | 2 +- .../calendar_test.rb.yaml} | 34 +++---- .../countless_test.rb} | 2 +- .../elasticsearch_rails_test.rb | 2 +- .../elasticsearch_rails_test.rb.yaml | 16 ++-- test/pagy/{extras => mixins}/headers_test.rb | 2 +- .../{extras => mixins}/headers_test.rb.yaml | 92 +++++++++---------- test/pagy/{extras => mixins}/jsonapi_test.rb | 6 +- .../{extras => mixins}/jsonapi_test.rb.yaml | 33 +++---- .../keyset_augmented_test.rb | 0 test/pagy/{extras => mixins}/keyset_test.rb | 2 +- .../{extras => mixins}/meilisearch_test.rb | 2 +- .../meilisearch_test.rb.yaml | 6 +- test/pagy/{extras => mixins}/metadata_test.rb | 2 +- .../{extras => mixins}/metadata_test.rb.yaml | 12 +-- test/pagy/{extras => mixins}/pagy_test.rb | 2 +- .../pagy/{extras => mixins}/pagy_test.rb.yaml | 58 ++++++------ .../{extras => mixins}/searchkick_test.rb | 2 +- .../searchkick_test.rb.yaml | 8 +- test/pagy/{ => offset}/calendar_dst_test.rb | 2 +- test/pagy/{ => offset}/calendar_test.rb | 2 +- test/pagy/{ => offset}/calendar_test.rb.yaml | 0 test/pagy/{ => offset}/countless_test.rb | 2 +- test/pagy/url_helpers_test.rb | 20 +++- 60 files changed, 335 insertions(+), 467 deletions(-) delete mode 100644 gem/lib/pagy/extras/standalone.rb rename gem/lib/pagy/{autoload.rb => loader.rb} (77%) create mode 100644 gem/lib/pagy/mixins/limit_selector.rb create mode 100644 gem/lib/pagy/mixins/pagy_helpers.rb delete mode 100644 test/files/db/test.sqlite3-wal delete mode 100644 test/pagy/extras/standalone_limit_test.rb delete mode 100644 test/pagy/extras/standalone_test.rb rename test/pagy/{keyset_for_ui_test.rb => keyset/augmented_test.rb} (98%) rename test/pagy/{extras => mixins}/arel_test.rb (98%) rename test/pagy/{extras => mixins}/array_test.rb (97%) rename test/pagy/{extras => mixins}/bootstrap_test.rb (95%) rename test/pagy/{extras => mixins}/bootstrap_test.rb.yaml (98%) rename test/pagy/{extras => mixins}/bulma_test.rb (95%) rename test/pagy/{extras => mixins}/bulma_test.rb.yaml (98%) rename test/pagy/{extras/calendar_extra_test.rb => mixins/calendar_test.rb} (99%) rename test/pagy/{extras/calendar_extra_test.rb.yaml => mixins/calendar_test.rb.yaml} (96%) rename test/pagy/{extras/countless_extra_test.rb => mixins/countless_test.rb} (98%) rename test/pagy/{extras => mixins}/elasticsearch_rails_test.rb (99%) rename test/pagy/{extras => mixins}/elasticsearch_rails_test.rb.yaml (78%) rename test/pagy/{extras => mixins}/headers_test.rb (99%) rename test/pagy/{extras => mixins}/headers_test.rb.yaml (75%) rename test/pagy/{extras => mixins}/jsonapi_test.rb (96%) rename test/pagy/{extras => mixins}/jsonapi_test.rb.yaml (55%) rename test/pagy/{extras => mixins}/keyset_augmented_test.rb (100%) rename test/pagy/{extras => mixins}/keyset_test.rb (98%) rename test/pagy/{extras => mixins}/meilisearch_test.rb (98%) rename test/pagy/{extras => mixins}/meilisearch_test.rb.yaml (72%) rename test/pagy/{extras => mixins}/metadata_test.rb (98%) rename test/pagy/{extras => mixins}/metadata_test.rb.yaml (87%) rename test/pagy/{extras => mixins}/pagy_test.rb (98%) rename test/pagy/{extras => mixins}/pagy_test.rb.yaml (91%) rename test/pagy/{extras => mixins}/searchkick_test.rb (99%) rename test/pagy/{extras => mixins}/searchkick_test.rb.yaml (77%) rename test/pagy/{ => offset}/calendar_dst_test.rb (99%) rename test/pagy/{ => offset}/calendar_test.rb (99%) rename test/pagy/{ => offset}/calendar_test.rb.yaml (100%) rename test/pagy/{ => offset}/countless_test.rb (98%) diff --git a/.simplecov b/.simplecov index a37d7ede5..3243d77b7 100644 --- a/.simplecov +++ b/.simplecov @@ -11,26 +11,8 @@ SimpleCov.start do merge_timeout 120 enable_coverage :branch - add_group 'All Extras', %w[gem/lib/pagy/extras] - add_group 'Core', %w[gem/lib/pagy.rb - gem/lib/pagy/b64.rb - gem/lib/pagy/backend.rb - gem/lib/pagy/console.rb - gem/lib/pagy/countless.rb - gem/lib/pagy/init_vars.rb - gem/lib/pagy/exceptions.rb - gem/lib/pagy/frontend.rb - gem/lib/pagy/i18n.rb - gem/lib/pagy/url_helpers.rb] - add_group 'Countless', %w[gem/lib/pagy/countless.rb - gem/lib/pagy/extras/countless.rb] - add_group 'Calendar', %w[gem/lib/pagy/calendar - gem/lib/pagy/extras/calendar.rb] - add_group 'Keyset', %w[gem/lib/pagy/keyset.rb - gem/lib/pagy/keyset_for_ui.rb - gem/lib/pagy/keyset/active_record.rb - gem/lib/pagy/keyset/sequel.rb - gem/lib/pagy/extras/keyset.rb - gem/lib/pagy/extras/keyset_for_ui.rb] - add_group 'Tests', %w[test] + add_group 'Core', %w[gem/lib/pagy.rb gem/lib/pagy] + add_group 'Extras', 'gem/lib/pagy/extras' + add_group 'Mixins', 'gem/lib/pagy/mixins' + add_group 'Tests', 'test' end diff --git a/gem/apps/calendar.ru b/gem/apps/calendar.ru index 7c6eb1ea5..92297a4c0 100644 --- a/gem/apps/calendar.ru +++ b/gem/apps/calendar.ru @@ -33,8 +33,6 @@ gemfile(ENV['PAGY_INSTALL_BUNDLE'] == 'true') do end # Pagy initializer -require 'pagy/extras/calendar' -require 'pagy/extras/bootstrap' Pagy::DEFAULT.freeze # Sinatra setup diff --git a/gem/apps/demo.ru b/gem/apps/demo.ru index c22bad8ac..e389858b5 100644 --- a/gem/apps/demo.ru +++ b/gem/apps/demo.ru @@ -39,9 +39,9 @@ STYLES = { pagy: { extra: 'pagy', prefix: '', css_anchor: 'pagy-scss' }, bulma: {}, tailwind: { extra: 'pagy', prefix: '', css_anchor: 'pagy-tailwind-css' } }.freeze -STYLES.each_key do |style| - require "pagy/extras/#{STYLES[style][:extra] || style}" -end +# STYLES.each_key do |style| +# require "pagy/extras/#{STYLES[style][:extra] || style}" +# end require 'pagy/extras/limit' # Sinatra setup @@ -57,7 +57,7 @@ class PagyDemo < Sinatra::Base get '/template' do collection = MockCollection.new - @pagy, @records = pagy(collection) + @pagy, @records = pagy_offset(collection) erb :template, locals: { pagy: @pagy, style: 'pagy' } end @@ -83,7 +83,7 @@ class PagyDemo < Sinatra::Base get("/#{style}") do collection = MockCollection.new - @pagy, @records = pagy(collection) + @pagy, @records = pagy_offset(collection) erb :helpers, locals: { style:, prefix: } end diff --git a/gem/apps/keyset.ru b/gem/apps/keyset.ru index 985b535a0..49c2c7231 100644 --- a/gem/apps/keyset.ru +++ b/gem/apps/keyset.ru @@ -32,15 +32,13 @@ end # Pagy initializer require 'pagy/extras/limit' -require 'pagy/extras/keyset' -require 'pagy/extras/pagy' Pagy::DEFAULT[:limit] = 10 Pagy::DEFAULT.freeze # Sinatra setup require 'sinatra/base' # Sinatra application -class PagyKeysetAugmented < Sinatra::Base +class PagyKeyset < Sinatra::Base include Pagy::Backend # Root route/action get '/' do diff --git a/gem/apps/keyset_sequel.ru b/gem/apps/keyset_sequel.ru index 60d8701da..1f06c29aa 100644 --- a/gem/apps/keyset_sequel.ru +++ b/gem/apps/keyset_sequel.ru @@ -32,8 +32,6 @@ end # Pagy initializer require 'pagy/extras/limit' -require 'pagy/extras/keyset' -require 'pagy/extras/pagy' Pagy::DEFAULT[:limit] = 10 Pagy::DEFAULT.freeze @@ -41,7 +39,7 @@ Pagy::DEFAULT.freeze require 'sinatra/base' require 'logger' # Sinatra application -class PagyKeysetAugmented < Sinatra::Base +class PagyKeysetSequel < Sinatra::Base include Pagy::Backend # Root route/action get '/' do @@ -216,4 +214,4 @@ data.each_line(chomp: true) do |pet| dataset.insert(name:, animal:, birthdate:) end -run PagyKeysetAugmented +run PagyKeysetSequel diff --git a/gem/apps/rails.ru b/gem/apps/rails.ru index 61ed4c83b..bfce8c260 100644 --- a/gem/apps/rails.ru +++ b/gem/apps/rails.ru @@ -59,13 +59,9 @@ unless File.writable?(dir) end # Pagy initializer -require 'pagy/extras/pagy' require 'pagy/extras/limit' -require 'pagy/extras/overflow' -require 'pagy/extras/headers' -Pagy::DEFAULT[:limit] = 10 -Pagy::DEFAULT[:overflow] = :empty_page -Pagy::DEFAULT.freeze +Pagy::DEFAULT[:limit] = 10 +Pagy::Offset::DEFAULT[:overflow] = :empty_page # Activerecord initializer ActiveRecord::Base.logger = Logger.new(OUTPUT) @@ -113,7 +109,7 @@ class CommentsController < ActionController::Base # :nodoc: include Pagy::Backend def index - @pagy, @comments = pagy(Comment.all) + @pagy, @comments = pagy_offset(Comment.all) pagy_headers_merge(@pagy) render inline: TEMPLATE end diff --git a/gem/apps/repro.ru b/gem/apps/repro.ru index 201241afd..b37d06546 100644 --- a/gem/apps/repro.ru +++ b/gem/apps/repro.ru @@ -31,10 +31,8 @@ end # Edit this section adding/removing the extras and Pagy::DEFAULT as needed # pagy initializer -require 'pagy/extras/pagy' require 'pagy/extras/limit' -require 'pagy/extras/overflow' -Pagy::DEFAULT[:overflow] = :empty_page +Pagy::Offset::DEFAULT[:overflow] = :empty_page Pagy::DEFAULT.freeze # Sinatra setup @@ -56,7 +54,7 @@ class PagyRepro < Sinatra::Base # Edit this action as needed get '/' do collection = MockCollection.new - @pagy, @records = pagy(collection) + @pagy, @records = pagy_offset(collection) erb :main end diff --git a/gem/lib/pagy.rb b/gem/lib/pagy.rb index 086044ad9..12ddfaa7e 100644 --- a/gem/lib/pagy.rb +++ b/gem/lib/pagy.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true require 'pathname' -require_relative 'pagy/autoload' +require_relative 'pagy/loader' # Top superclass: it should define only what's common to all the subclasses class Pagy @@ -15,6 +15,7 @@ class Pagy autoload :ElasticsearchRails, 'pagy/mixins/elasticsearch_rails' autoload :Meilisearch, 'pagy/mixins/meilisearch' autoload :Searchkick, 'pagy/mixins/searchkick' + autoload :Console, 'pagy/console' VERSION = '9.3.3' PAGE_TOKEN = 'P ' @@ -28,7 +29,10 @@ def self.root @root ||= Pathname.new(__dir__).parent.freeze end - attr_reader :page, :limit, :vars + attr_reader :page, :prev, :next, :in, :limit, :vars, :last + + alias pages last + def self.predict_last? = true # Validates and assign the passed vars: var must be present and value.to_i must be >= to min def assign_and_check(name_min) diff --git a/gem/lib/pagy/backend.rb b/gem/lib/pagy/backend.rb index 00741bbd7..0fb828de9 100644 --- a/gem/lib/pagy/backend.rb +++ b/gem/lib/pagy/backend.rb @@ -8,7 +8,7 @@ class Pagy # or any collection by overriding any of the `pagy_*` methods in your controller. # See also the extras if you need specialized methods to paginate Arrays or other collections module Backend - include Autoload + include Loader private diff --git a/gem/lib/pagy/console.rb b/gem/lib/pagy/console.rb index d4fa05f09..6ff5d378a 100644 --- a/gem/lib/pagy/console.rb +++ b/gem/lib/pagy/console.rb @@ -2,7 +2,6 @@ # frozen_string_literal: true require_relative '../pagy' # so you can require just the extra in the console -require_relative 'extras/standalone' class Pagy # Provide a ready to use pagy environment when included in irb/rails console @@ -11,6 +10,7 @@ module Console def self.included(main) main.include(Backend) main.include(Frontend) + main.define_method(:params) { {} } DEFAULT[:url] = 'http://www.example.com/subdir' end diff --git a/gem/lib/pagy/extras/i18n.rb b/gem/lib/pagy/extras/i18n.rb index 53c84fa95..7ba5a2091 100644 --- a/gem/lib/pagy/extras/i18n.rb +++ b/gem/lib/pagy/extras/i18n.rb @@ -11,16 +11,7 @@ def pagy_t(key, **) end end Frontend.prepend I18nExtra::FrontendOverride - - # Calendar overriding for localization (see also the block in the calendar section of the config/pagy.rb initializer) - module CalendarOverride - def localize(time, opts) - ::I18n.l(time, **opts) - end - end end - Offset::Calendar::Unit.prepend I18nExtra::CalendarOverride if defined?(::Pagy::Offset::Calendar::Unit) - # Add the pagy locales to the I18n.load_path ::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')] end diff --git a/gem/lib/pagy/extras/limit.rb b/gem/lib/pagy/extras/limit.rb index e9dc3e673..bc1e9ccd1 100644 --- a/gem/lib/pagy/extras/limit.rb +++ b/gem/lib/pagy/extras/limit.rb @@ -6,7 +6,8 @@ class Pagy DEFAULT[:limit_max] = 100 DEFAULT[:limit_extra] = true # extra enabled by default - # Allow the client to request a custom limit per page with an optional selector UI + # Allow the client to request a custom limit per page + # with an optional selector UI module LimitExtra # Additions for the Backend module module BackendAddOn @@ -27,34 +28,5 @@ def pagy_get_limit_param(vars) end end Backend.prepend LimitExtra::BackendAddOn - - # Additions for the Frontend module - module FrontendAddOn - # Return the limit selector HTML. For example "Show [20] items per page" - def pagy_limit_selector_js(pagy, id: nil, item_name: nil) - return '' unless pagy.vars[:limit_extra] - - id = %( id="#{id}") if id - vars = pagy.vars - limit = vars[:limit] - vars[:limit] = LIMIT_TOKEN # limit token replaced in the javascript - url_token = pagy_page_url(pagy, PAGE_TOKEN) - vars[:limit] = limit # restore the limit - - limit_input = %(#{ - A_TAG}) - - %() - end - end - Frontend.prepend LimitExtra::FrontendAddOn end end diff --git a/gem/lib/pagy/extras/standalone.rb b/gem/lib/pagy/extras/standalone.rb deleted file mode 100644 index 937d2e212..000000000 --- a/gem/lib/pagy/extras/standalone.rb +++ /dev/null @@ -1,15 +0,0 @@ -# See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/standalone -# frozen_string_literal: true - -require_relative '../url_helpers' - -class Pagy - # Use pagy without any request object, nor Rack environment/gem, nor any defined params method, - # even in the irb/rails console without any app or config. - # Define a dummy params method if it's not already defined in the including module - module Backend - def self.included(controller) - controller.define_method(:params) { {} } unless controller.method_defined?(:params) - end - end -end diff --git a/gem/lib/pagy/frontend.rb b/gem/lib/pagy/frontend.rb index 4fef012a0..21d12bbfe 100644 --- a/gem/lib/pagy/frontend.rb +++ b/gem/lib/pagy/frontend.rb @@ -9,7 +9,7 @@ class Pagy # Frontend modules are specially optimized for performance. # The resulting code may not look very elegant, but produces the best benchmarks module Frontend - include Autoload + include Loader include UrlHelpers # Return a performance optimized lambda to generate the HTML anchor element (a tag) @@ -43,30 +43,6 @@ def pagy_info(pagy, id: nil, item_name: nil) }) end - # Generic pagination: it returns the html with the series of links to the pages - def pagy_nav(pagy, id: nil, aria_label: nil, **vars) - id = %( id="#{id}") if id - a = pagy_anchor(pagy, **vars) - data = %( #{pagy_data(pagy, :n)}) if defined?(::Pagy::Keyset::Augmented) && pagy.is_a?(Keyset::Augmented) - - html = %(#{ - prev_a(pagy, a)}) - pagy.series(**vars).each do |item| - # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] - html << case item - when Integer - a.(item) - when String - %(#{pagy.label_for(item)}) - when :gap - %(#{pagy_t('pagy.gap')}) - else - raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}" - end - end - html << %(#{next_a(pagy, a)}) - end - # Similar to I18n.t: just ~18x faster using ~10x less memory # (@pagy_locale explicitly initialized in order to avoid warning) def pagy_t(key, **) diff --git a/gem/lib/pagy/keyset.rb b/gem/lib/pagy/keyset.rb index bbef6c15f..aff933120 100644 --- a/gem/lib/pagy/keyset.rb +++ b/gem/lib/pagy/keyset.rb @@ -39,6 +39,8 @@ def initialize(set, **vars) # rubocop:disable Lint/MissingSuper assign_filter_args end + def self.predict_last? = false + # Assign the filter_args def assign_filter_args return unless @prev_cutoff diff --git a/gem/lib/pagy/links_helper.rb b/gem/lib/pagy/links_helper.rb index a56ba7bbf..80a071115 100644 --- a/gem/lib/pagy/links_helper.rb +++ b/gem/lib/pagy/links_helper.rb @@ -5,13 +5,10 @@ module LinksHelper def pagy_links(pagy, **) url_str = pagy_page_url(pagy, PAGE_TOKEN, **) { first: url_str.sub(PAGE_TOKEN, '1') }.tap do |links| - links[:next] = url_str.sub(PAGE_TOKEN, pagy.next.to_s) if pagy.next - next if defined?(::Pagy::Keyset) && pagy.is_a?(Keyset) - links[:prev] = url_str.sub(PAGE_TOKEN, pagy.prev.to_s) if pagy.prev - links[:last] = url_str.sub(PAGE_TOKEN, pagy.last.to_s) if pagy.last \ - && !(defined?(::Pagy::Offset::Countless) && pagy.is_a?(Offset::Countless)) - end.slice(:first, :prev, :next, :last) + links[:next] = url_str.sub(PAGE_TOKEN, pagy.next.to_s) if pagy.next + links[:last] = url_str.sub(PAGE_TOKEN, pagy.last.to_s) if pagy.class.predict_last? + end end end end diff --git a/gem/lib/pagy/autoload.rb b/gem/lib/pagy/loader.rb similarity index 77% rename from gem/lib/pagy/autoload.rb rename to gem/lib/pagy/loader.rb index fdcf87e7f..a4790b333 100644 --- a/gem/lib/pagy/autoload.rb +++ b/gem/lib/pagy/loader.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Pagy - module Autoload + module Loader METHOD_MIXINS = { pagy_arel: :arel, pagy_array: :array, pagy_bootstrap_nav: :bootstrap, @@ -18,18 +18,20 @@ module Autoload pagy_headers_merge: :headers, pagy_keyset: :keyset, pagy_keyset_augmented_js: :keyset_augmented, + pagy_limit_selector_js: :limit_selector, new_from_meilisearch: :meilisearch, pagy_meilisearch: :meilisearch, pagy_metadata: :metadata, pagy_offset: :offset, + pagy_nav: :pagy, pagy_nav_js: :pagy, pagy_combo_nav_js: :pagy, - pagy_prev_url: :pagy, - pagy_next_url: :pagy, - pagy_prev_a: :pagy, - pagy_next_a: :pagy, - pagy_prev_link: :pagy, - pagy_next_link: :pagy, + pagy_prev_url: :pagy_helpers, + pagy_next_url: :pagy_helpers, + pagy_prev_a: :pagy_helpers, + pagy_next_a: :pagy_helpers, + pagy_prev_link: :pagy_helpers, + pagy_next_link: :pagy_helpers, new_from_searchkick: :searchkick, pagy_searchkick: :searchkick }.freeze diff --git a/gem/lib/pagy/mixins/headers.rb b/gem/lib/pagy/mixins/headers.rb index 0898ebd68..a1f721d6b 100644 --- a/gem/lib/pagy/mixins/headers.rb +++ b/gem/lib/pagy/mixins/headers.rb @@ -26,7 +26,7 @@ def pagy_headers(pagy, **) # If it's not in the vars, the autoloading kicked-in after the object creation, # which means that no custom DEFAULT has been set, so we use the original headers = pagy.vars[:headers] || DEFAULT[:headers] - pagy_link_header(pagy, **).tap do |hash| + { 'link' => pagy_link_header(pagy, **) }.tap do |hash| hash[headers[:page]] = pagy.page.to_s if pagy.page && headers[:page] hash[headers[:limit]] = pagy.limit.to_s \ if headers[:limit] && !(defined?(::Pagy::Offset::Calendar) && pagy.is_a?(Offset::Calendar::Unit)) @@ -38,8 +38,8 @@ def pagy_headers(pagy, **) end end - def pagy_link_header(pagy, absolute: true, **vars) - pagy_links(pagy, absolute:, **vars).map { |key, link| %(<#{link}>; rel="#{key}") }.join(', ') + def pagy_link_header(pagy, **) + pagy_links(pagy, **, absolute: true).map { |key, link| %(<#{link}>; rel="#{key}") }.join(', ') end end Backend.prepend HeadersMixin diff --git a/gem/lib/pagy/mixins/limit_selector.rb b/gem/lib/pagy/mixins/limit_selector.rb new file mode 100644 index 000000000..8fa3620a5 --- /dev/null +++ b/gem/lib/pagy/mixins/limit_selector.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require_relative '../extras/limit' + +class Pagy + module LimitSelectorMixin + # Additions for the Frontend module + module FrontendAddOn + # Return the limit selector HTML. For example "Show [20] items per page" + def pagy_limit_selector_js(pagy, id: nil, item_name: nil) + return '' unless pagy.vars[:limit_extra] + + id = %( id="#{id}") if id + vars = pagy.vars + limit = vars[:limit] + vars[:limit] = LIMIT_TOKEN # limit token replaced in the javascript + url_token = pagy_page_url(pagy, PAGE_TOKEN) + vars[:limit] = limit # restore the limit + + limit_input = %(#{A_TAG}) + + %() + end + end + Frontend.prepend FrontendAddOn + end +end diff --git a/gem/lib/pagy/mixins/pagy.rb b/gem/lib/pagy/mixins/pagy.rb index 95c3f58bc..9a7f480f3 100644 --- a/gem/lib/pagy/mixins/pagy.rb +++ b/gem/lib/pagy/mixins/pagy.rb @@ -5,7 +5,30 @@ class Pagy # Frontend modules are specially optimized for performance. # The resulting code may not look very elegant, but produces the best benchmarks module PagyMixin - # pagy_nav is defined in the Frontend itself + # Generic pagination: it returns the html with the series of links to the pages + def pagy_nav(pagy, id: nil, aria_label: nil, **vars) + id = %( id="#{id}") if id + a = pagy_anchor(pagy, **vars) + data = %( #{pagy_data(pagy, :n)}) if defined?(::Pagy::Keyset::Augmented) && pagy.is_a?(Keyset::Augmented) + + html = %(#{ + prev_a(pagy, a)}) + pagy.series(**vars).each do |item| + # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] + html << case item + when Integer + a.(item) + when String + %(#{pagy.label_for(item)}) + when :gap + %(#{pagy_t('pagy.gap')}) + else + raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}" + end + end + html << %(#{next_a(pagy, a)}) + end + # Javascript pagination: it returns a nav with a data-pagy attribute used by the pagy.js file def pagy_nav_js(pagy, id: nil, aria_label: nil, **vars) sequels = pagy.sequels(**vars) @@ -41,38 +64,6 @@ def pagy_combo_nav_js(pagy, id: nil, aria_label: nil, **vars) next_a(pagy, a) }) end - - # Return the previous page URL string or nil - def pagy_prev_url(pagy, **vars) - pagy_page_url(pagy, pagy.prev, **vars) if pagy.prev - end - - # Return the next page URL string or nil - def pagy_next_url(pagy, **vars) - pagy_page_url(pagy, pagy.next, **vars) if pagy.next - end - - # Return the enabled/disabled previous page anchor tag - def pagy_prev_a(pagy, text: pagy_t('pagy.prev'), aria_label: pagy_t('pagy.aria_label.prev'), **vars) - a = pagy_anchor(pagy, **vars) - prev_a(pagy, a, text:, aria_label:) - end - - # Return the enabled/disabled next page anchor tag - def pagy_next_a(pagy, text: pagy_t('pagy.next'), aria_label: pagy_t('pagy.aria_label.next'), **vars) - a = pagy_anchor(pagy, **vars) - next_a(pagy, a, text:, aria_label:) - end - - # Conditionally return the previous page link tag - def pagy_prev_link(pagy, **vars) - %() if pagy.prev - end - - # Conditionally return the next page link tag - def pagy_next_link(pagy, **vars) - %() if pagy.next - end end Frontend.prepend PagyMixin end diff --git a/gem/lib/pagy/mixins/pagy_helpers.rb b/gem/lib/pagy/mixins/pagy_helpers.rb new file mode 100644 index 000000000..cfe09d406 --- /dev/null +++ b/gem/lib/pagy/mixins/pagy_helpers.rb @@ -0,0 +1,41 @@ +# See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/pagy +# frozen_string_literal: true + +class Pagy + # Frontend modules are specially optimized for performance. + # The resulting code may not look very elegant, but produces the best benchmarks + module PagyHelpersMixin + # Return the previous page URL string or nil + def pagy_prev_url(pagy, **vars) + pagy_page_url(pagy, pagy.prev, **vars) if pagy.prev + end + + # Return the next page URL string or nil + def pagy_next_url(pagy, **vars) + pagy_page_url(pagy, pagy.next, **vars) if pagy.next + end + + # Return the enabled/disabled previous page anchor tag + def pagy_prev_a(pagy, text: pagy_t('pagy.prev'), aria_label: pagy_t('pagy.aria_label.prev'), **vars) + a = pagy_anchor(pagy, **vars) + prev_a(pagy, a, text:, aria_label:) + end + + # Return the enabled/disabled next page anchor tag + def pagy_next_a(pagy, text: pagy_t('pagy.next'), aria_label: pagy_t('pagy.aria_label.next'), **vars) + a = pagy_anchor(pagy, **vars) + next_a(pagy, a, text:, aria_label:) + end + + # Conditionally return the previous page link tag + def pagy_prev_link(pagy, **vars) + %() if pagy.prev + end + + # Conditionally return the next page link tag + def pagy_next_link(pagy, **vars) + %() if pagy.next + end + end + Frontend.prepend PagyHelpersMixin +end diff --git a/gem/lib/pagy/offset/calendar/unit.rb b/gem/lib/pagy/offset/calendar/unit.rb index b4496eb58..2b726cf1b 100644 --- a/gem/lib/pagy/offset/calendar/unit.rb +++ b/gem/lib/pagy/offset/calendar/unit.rb @@ -85,8 +85,9 @@ def assign_unit_vars end # Apply the strftime format to the time (overridden by the i18n extra when localization is required) + # Calendar overriding for localization (see also the block in the calendar section of the config/pagy.rb initializer) def localize(time, opts) - time.strftime(opts[:format]) + defined?(::Pagy::I18nExtra) ? ::I18n.l(time, **opts) : time.strftime(opts[:format]) end # Number of time units to offset from the @initial time, in order to get the ordered starting time for the page. diff --git a/gem/lib/pagy/offset/countless.rb b/gem/lib/pagy/offset/countless.rb index 1313bb96c..494de1e67 100644 --- a/gem/lib/pagy/offset/countless.rb +++ b/gem/lib/pagy/offset/countless.rb @@ -15,6 +15,8 @@ def initialize(**vars) # rubocop:disable Lint/MissingSuper assign_offset end + def self.predict_last? = false + # Finalize the instance variables based on the fetched size def finalize(fetched_size) raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1 diff --git a/gem/lib/pagy/ui_support.rb b/gem/lib/pagy/ui_support.rb index 91e752731..d88433a66 100644 --- a/gem/lib/pagy/ui_support.rb +++ b/gem/lib/pagy/ui_support.rb @@ -2,9 +2,6 @@ class Pagy module UISupport - attr_reader :in, :last, :prev - alias pages last - # Label for the current page. Allow the customization of the output (overridden by the calendar extra) def label = @page.to_s diff --git a/gem/lib/pagy/url_helpers.rb b/gem/lib/pagy/url_helpers.rb index ff230ad22..884d4a54e 100644 --- a/gem/lib/pagy/url_helpers.rb +++ b/gem/lib/pagy/url_helpers.rb @@ -16,7 +16,11 @@ def build_nested_query(value, prefix = nil, unescaped = []) value.map { |v| build_nested_query(v, "#{prefix}[]", unescaped) }.join('&') when Hash value.map do |k, v| - build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k), unescaped) + new_k = prefix ? "#{prefix}[#{escape(k)}]" : escape(k) + if unescaped.size.positive? && new_k != k.to_s && unescaped.include?(k.to_s) + unescaped[unescaped.find_index(k.to_s)] = new_k + end + build_nested_query(v, new_k, unescaped) end.delete_if(&:empty?).join('&') when nil escape(prefix) diff --git a/test/files/db/test.sqlite3-wal b/test/files/db/test.sqlite3-wal deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/pagy/autoload_test.rb b/test/pagy/autoload_test.rb index 7bda513b4..e785e25e3 100644 --- a/test/pagy/autoload_test.rb +++ b/test/pagy/autoload_test.rb @@ -12,8 +12,7 @@ def app(**) describe 'Autoload thread safety' do threads = [] shared_result = [] - - times = 1000 + times = 1000 times.times do threads << Thread.new do @@ -33,10 +32,12 @@ def app(**) shared_result << e.class end end - threads.each(&:join) it "autoload safely" do _(shared_result).must_equal Array.new(times, :success) end + it "uses super" do + _ { MockApp.new.pagy_unknown_method }.must_raise NoMethodError + end end diff --git a/test/pagy/extras/standalone_limit_test.rb b/test/pagy/extras/standalone_limit_test.rb deleted file mode 100644 index cff2ed108..000000000 --- a/test/pagy/extras/standalone_limit_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../test_helper' -require 'pagy/extras/standalone' -require 'pagy/extras/limit' - -require_relative '../../mock_helpers/app' - -describe 'pagy/extras/standalone_limit' do - let(:app) { MockApp.new } - - describe '#pagy_page_url' do - it 'renders url with params and fragment' do - pagy = Pagy::Offset.new(count: 1000, page: 3, params: { a: 3, b: 4 }) - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "/foo?page=5&a=3&b=4&limit=20#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "http://example.com:3000/foo?page=5&a=3&b=4&limit=20#fragment" - pagy = Pagy::Offset.new(count: 1000, page: 3, params: { a: [1, 2, 3] }, url: 'http://www.pagy-standalone.com/subdir') - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&page=5&limit=20#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&page=5&limit=20#fragment" - pagy = Pagy::Offset.new(count: 1000, page: 3, params: { a: nil }, url: '') - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "?a&page=5&limit=20#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "?a&page=5&limit=20#fragment" - end - end -end diff --git a/test/pagy/extras/standalone_test.rb b/test/pagy/extras/standalone_test.rb deleted file mode 100644 index bf05698ab..000000000 --- a/test/pagy/extras/standalone_test.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../test_helper' -require 'pagy/extras/standalone' - -require_relative '../../mock_helpers/app' - -class EmptyController - include Pagy::Backend -end - -class FilledController - def params - { a: 'a', b: 'b' } - end - include Pagy::Backend -end - -describe 'pagy/extras/standalone' do - let(:app) { MockApp.new } - - describe 'defines #params if missing' do - it 'defines a dummy #params' do - _(EmptyController.new.params).must_equal({}) - end - it 'does not define a dummy #params' do - _(FilledController.new.params).must_equal({ a: 'a', b: 'b' }) - end - end - - describe '#pagy_page_url' do - it 'renders basic url' do - pagy = Pagy::Offset.new count: 1000, page: 3 - _(app.pagy_page_url(pagy, 5)).must_equal '/foo?page=5' - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal 'http://example.com:3000/foo?page=5' - pagy = Pagy::Offset.new count: 1000, page: 3, url: 'http://www.pagy-standalone.com/subdir' - _(app.pagy_page_url(pagy, 5)).must_equal 'http://www.pagy-standalone.com/subdir?page=5' - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal 'http://www.pagy-standalone.com/subdir?page=5' - pagy = Pagy::Offset.new count: 1000, page: 3, url: '' - _(app.pagy_page_url(pagy, 5)).must_equal '?page=5' - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal '?page=5' - end - - it 'renders url with params' do - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: 3, b: 4 } - _(app.pagy_page_url(pagy, 5)).must_equal '/foo?page=5&a=3&b=4' - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal 'http://example.com:3000/foo?page=5&a=3&b=4' - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: 3, b: 4 }, url: 'http://www.pagy-standalone.com/subdir' - _(app.pagy_page_url(pagy, 5)).must_equal "http://www.pagy-standalone.com/subdir?a=3&b=4&page=5" - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal "http://www.pagy-standalone.com/subdir?a=3&b=4&page=5" - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: 3, b: 4 }, url: '' - _(app.pagy_page_url(pagy, 5)).must_equal "?a=3&b=4&page=5" - _(app.pagy_page_url(pagy, 5, absolute: true)).must_equal "?a=3&b=4&page=5" - end - it 'renders url with fragment' do - pagy = Pagy::Offset.new count: 1000, page: 3 - _(app.pagy_page_url(pagy, 6, fragment: '#fragment')).must_equal '/foo?page=6#fragment' - _(app.pagy_page_url(pagy, 6, absolute: true, fragment: '#fragment')).must_equal 'http://example.com:3000/foo?page=6#fragment' - pagy = Pagy::Offset.new count: 1000, page: 3, url: 'http://www.pagy-standalone.com/subdir' - _(app.pagy_page_url(pagy, 6, fragment: '#fragment')).must_equal 'http://www.pagy-standalone.com/subdir?page=6#fragment' - _(app.pagy_page_url(pagy, 6, absolute: true, fragment: '#fragment')).must_equal 'http://www.pagy-standalone.com/subdir?page=6#fragment' - pagy = Pagy::Offset.new count: 1000, page: 3, url: '' - _(app.pagy_page_url(pagy, 6, fragment: '#fragment')).must_equal '?page=6#fragment' - _(app.pagy_page_url(pagy, 6, absolute: true, fragment: '#fragment')).must_equal '?page=6#fragment' - end - it 'renders url with params and fragment' do - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: 3, b: 4 } - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal '/foo?page=5&a=3&b=4#fragment' - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal 'http://example.com:3000/foo?page=5&a=3&b=4#fragment' - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: [1, 2, 3] }, url: 'http://www.pagy-standalone.com/subdir' - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&page=5#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&page=5#fragment" - pagy = Pagy::Offset.new count: 1000, page: 3, params: { a: nil }, url: '' - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "?a&page=5#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "?a&page=5#fragment" - end - it 'renders url with params lambda and fragment' do - pagy = Pagy::Offset.new count: 1000, page: 3, params: ->(p) { p.merge(a: 3, b: 4) } - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal '/foo?page=5&a=3&b=4#fragment' - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal 'http://example.com:3000/foo?page=5&a=3&b=4#fragment' - pagy = Pagy::Offset.new count: 1000, page: 3, params: ->(p) { p.merge(a: [1, 2, 3]) }, url: 'http://www.pagy-standalone.com/subdir' - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?page=5&a%5B%5D=1&a%5B%5D=2&a%5B%5D=3#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "http://www.pagy-standalone.com/subdir?page=5&a%5B%5D=1&a%5B%5D=2&a%5B%5D=3#fragment" - pagy = Pagy::Offset.new count: 1000, page: 3, params: ->(p) { p.merge(a: nil) }, url: '' - _(app.pagy_page_url(pagy, 5, fragment: '#fragment')).must_equal "?page=5&a#fragment" - _(app.pagy_page_url(pagy, 5, absolute: true, fragment: '#fragment')).must_equal "?page=5&a#fragment" - end - end -end diff --git a/test/pagy/keyset_for_ui_test.rb b/test/pagy/keyset/augmented_test.rb similarity index 98% rename from test/pagy/keyset_for_ui_test.rb rename to test/pagy/keyset/augmented_test.rb index d67454812..b530cd7de 100644 --- a/test/pagy/keyset_for_ui_test.rb +++ b/test/pagy/keyset/augmented_test.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative '../test_helper' -require_relative '../files/models' -require_relative '../../gem/lib/pagy/b64' +require_relative '../../test_helper' +require_relative '../../files/models' +require 'pagy/b64' [Pet, PetSequel].each do |model| describe "Pagy Keyset with #{model}" do diff --git a/test/pagy/extras/arel_test.rb b/test/pagy/mixins/arel_test.rb similarity index 98% rename from test/pagy/extras/arel_test.rb rename to test/pagy/mixins/arel_test.rb index 2701c946b..8d99edf80 100644 --- a/test/pagy/extras/arel_test.rb +++ b/test/pagy/mixins/arel_test.rb @@ -6,7 +6,7 @@ require_relative '../../mock_helpers/collection' require_relative '../../mock_helpers/app' -describe 'pagy/extras/arel' do +describe 'pagy/mixins/arel' do let(:app) { MockApp.new } describe '#pagy_arel' do diff --git a/test/pagy/extras/array_test.rb b/test/pagy/mixins/array_test.rb similarity index 97% rename from test/pagy/extras/array_test.rb rename to test/pagy/mixins/array_test.rb index 164738463..43df953f9 100644 --- a/test/pagy/extras/array_test.rb +++ b/test/pagy/mixins/array_test.rb @@ -4,7 +4,7 @@ require_relative '../../mock_helpers/app' -describe 'pagy/extras/array' do +describe 'pagy/mixins/array' do let(:app) { MockApp.new } describe '#pagy_array' do diff --git a/test/pagy/extras/bootstrap_test.rb b/test/pagy/mixins/bootstrap_test.rb similarity index 95% rename from test/pagy/extras/bootstrap_test.rb rename to test/pagy/mixins/bootstrap_test.rb index aabaa6d0d..50810121c 100644 --- a/test/pagy/extras/bootstrap_test.rb +++ b/test/pagy/mixins/bootstrap_test.rb @@ -6,7 +6,7 @@ EXTRA = 'bootstrap' PREFIX = '_bootstrap' -describe "pagy/extras/#{EXTRA}" do +describe "pagy/mixins/#{EXTRA}" do include NavTests describe "#pagy#{PREFIX}_nav" do diff --git a/test/pagy/extras/bootstrap_test.rb.yaml b/test/pagy/mixins/bootstrap_test.rb.yaml similarity index 98% rename from test/pagy/extras/bootstrap_test.rb.yaml rename to test/pagy/mixins/bootstrap_test.rb.yaml index 83bca1267..4720d160f 100644 --- a/test/pagy/extras/bootstrap_test.rb.yaml +++ b/test/pagy/mixins/bootstrap_test.rb.yaml @@ -1,5 +1,5 @@ --- -pagy/extras/bootstrap___pagy_bootstrap_combo_nav_js_test_0001_renders_first,_intermediate_and_last_pages: +pagy/mixins/bootstrap___pagy_bootstrap_combo_nav_js_test_0001_renders_first,_intermediate_and_last_pages: :plain_1: '' -pagy/extras/bootstrap___pagy_bootstrap_nav_test_0001_renders_first,_intermediate_and_last_pages: +pagy/mixins/bootstrap___pagy_bootstrap_nav_test_0001_renders_first,_intermediate_and_last_pages: :plain_1: -pagy/extras/bootstrap___pagy_bootstrap_nav_js_test_0002_renders_first,_intermediate_and_last_pages_with_required_steps: +pagy/mixins/bootstrap___pagy_bootstrap_nav_js_test_0002_renders_first,_intermediate_and_last_pages_with_required_steps: :plain_1: :extras_1: @@ -132,14 +132,14 @@ pagy/extras/bootstrap___pagy_bootstrap_nav_js_test_0002_renders_first,_intermedi :extras_50: :keyset: -pagy/extras/bootstrap___pagy_bootstrap_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Countless: +pagy/mixins/bootstrap___pagy_bootstrap_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Countless: :plain_1_0: :extras_1_0: :plain_2_23: :extras_2_23: -pagy/extras/bootstrap___pagy_bootstrap_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Offset__Countless: +pagy/mixins/bootstrap___pagy_bootstrap_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Offset__Countless: :plain_1_0: :extras_1_0: diff --git a/test/pagy/extras/bulma_test.rb b/test/pagy/mixins/bulma_test.rb similarity index 95% rename from test/pagy/extras/bulma_test.rb rename to test/pagy/mixins/bulma_test.rb index 3faa6b28b..a22f44751 100644 --- a/test/pagy/extras/bulma_test.rb +++ b/test/pagy/mixins/bulma_test.rb @@ -6,7 +6,7 @@ EXTRA = 'bulma' PREFIX = '_bulma' -describe "pagy/extras/#{EXTRA}" do +describe "pagy/mixins/#{EXTRA}" do include NavTests describe "#pagy#{PREFIX}_nav" do diff --git a/test/pagy/extras/bulma_test.rb.yaml b/test/pagy/mixins/bulma_test.rb.yaml similarity index 98% rename from test/pagy/extras/bulma_test.rb.yaml rename to test/pagy/mixins/bulma_test.rb.yaml index 79906586b..8aef5974c 100644 --- a/test/pagy/extras/bulma_test.rb.yaml +++ b/test/pagy/mixins/bulma_test.rb.yaml @@ -1,5 +1,5 @@ --- -pagy/extras/bulma___pagy_bulma_combo_nav_js_test_0001_renders_first,_intermediate_and_last_pages: +pagy/mixins/bulma___pagy_bulma_combo_nav_js_test_0001_renders_first,_intermediate_and_last_pages: :plain_1: '' -pagy/extras/bulma___pagy_bulma_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Countless: +pagy/mixins/bulma___pagy_bulma_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Countless: :plain_1_0: :extras_1_0: :extras_2_23: -pagy/extras/bulma___pagy_bulma_nav_js_test_0002_renders_first,_intermediate_and_last_pages_with_required_steps: +pagy/mixins/bulma___pagy_bulma_nav_js_test_0002_renders_first,_intermediate_and_last_pages_with_required_steps: :plain_1: :extras_1: :keyset: -pagy/extras/bulma___pagy_bulma_nav_test_0001_renders_first,_intermediate_and_last_pages: +pagy/mixins/bulma___pagy_bulma_nav_test_0001_renders_first,_intermediate_and_last_pages: :plain_1: -pagy/extras/bulma___pagy_bulma_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Offset__Countless: +pagy/mixins/bulma___pagy_bulma_nav_js_test_0001_renders_single_and_multiple_pages_when_used_with_Pagy__Offset__Countless: :plain_1_0: :extras_1_0: -pagy/extras/calendar__Counts_feature_test_0003_works_with_anchor_string: +pagy/mixins/calendar__Counts_feature_test_0003_works_with_anchor_string: :year: -pagy/extras/calendar__Counts_feature_test_0002_works_with_MockApp__CalendarCountsSkip: +pagy/mixins/calendar__Counts_feature_test_0002_works_with_MockApp__CalendarCountsSkip: :year: