diff --git a/README.md b/README.md index d3f6c9aa1..c8068654d 100644 --- a/README.md +++ b/README.md @@ -33,20 +33,21 @@ _The [IPS/Kb ratio](http://ddnexus.github.io/pagination-comparison/gems.html#eff ### Straightforward Code - Pagy has a very slim core code of just ~100 line of simple ruby, organized in 3 flat modules very easy to understand and use _(see [more...](https://ddnexus.github.io/pagy/api))_ -- Pagy has a quite fat set of optional extras that you can explicitly require for very efficient and modular customization _(see [extras](https://ddnexus.github.io/extras.md))_ -- No dependencies: it produces its own HTML, URLs, pluralization and interpolation with its own specialized and fast code _(see [why...](https://ddnexus.github.io/pagy/index#specialized-code-instead-of-generic-helpers))_ +- It has a quite fat set of optional extras that you can explicitly require for very efficient and modular customization _(see [extras](https://ddnexus.github.io/extras.md))_ +- It has no dependencies: it produces its own HTML, URLs, pluralization and interpolation with its own specialized and fast code _(see [why...](https://ddnexus.github.io/pagy/index#specialized-code-instead-of-generic-helpers))_ - 100% of its methods are public API, accessible and overridable **right where you use them** (no need of monkey-patching) - 100% test coverage for core code and extras ### Totally Agnostic -- It doesn't need to know anything about your models, ORM or storage, so it doesn't add any code to them _(see [why...](https://ddnexus.github.io/pagy/index#stay-away-from-the-models))_ +- The `Pagy` class doesn't need to know anything about your models, ORM or storage, so it doesn't add any code to them _(see [why...](https://ddnexus.github.io/pagy/index#stay-away-from-the-models))_ - It works with all kinds of collections, even pre-paginated, records, Arrays, JSON data... and just whatever you can count _(see [how...](https://ddnexus.github.io/pagy/how-to#paginate-any-collection))_ -- It works with all Rack frameworks (Rails, Sinatra, Padrino, ecc.) out of the box _(see [more...](https://ddnexus.github.io/pagy/how-to#environment-assumptions))_ -- It works with any possible non-Rack environment by just overriding one or two two-lines methods _(see [more...](https://ddnexus.github.io/pagy/how-to#environment-assumptions))_ +- Pagy works with all Rack frameworks (Rails, Sinatra, Padrino, ecc.) out of the box _(see [more...](https://ddnexus.github.io/pagy/how-to#environment-assumptions))_ +- It works also with any possible non-Rack environment by just overriding one or two two-lines methods _(see [more...](https://ddnexus.github.io/pagy/how-to#environment-assumptions))_ ### Unlike the other gems +- Pagy is very modular and does not load nor execute unnecessary code in your app _(see [why...](https://ddnexus.github.io/pagy/how-to#global-configuration))_ - It works with collections/scopes that already used `limit` and `offset` _(see [how...](https://ddnexus.github.io/pagy/how-to#paginate-a-pre-offsetted-and-pre-limited-collection))_ - It works with helpers or templates _(see [more...](https://ddnexus.github.io/pagy/how-to#using-templates))_ - It raises real `Pagy::OutOfRangeError` exceptions that you can rescue from _(see [how...](https://ddnexus.github.io/pagy/how-to#handling-pagyoutofrangeerror-exception))_ or use the [out_of_range extra](http://ddnexus.github.io/pagy/extras/out_of_range) for a few ready to use common behaviors @@ -108,11 +109,7 @@ Besides the classic pagination `nav`, Pagy offers a few ready to use alternative - [compact nav](http://ddnexus.github.io/pagy/extras/navs#compact-navs): An alternative UI that combines the pagination feature with the navigation info in one compact element: ![pagy-compact](docs/assets/images/pagy-compact-w.png) - [responsive nav](http://ddnexus.github.io/pagy/extras/navs#responsive-navs): On resize, the number of page links adapts in real-time to the available window or container width: ![pagy-responsive](docs/assets/images/pagy-responsive-w.png) -## Chat Support and Feedback - -[Chat on Gitter](https://gitter.im/ruby-pagy/Lobby) - -## Useful Links +## Resources ### GoRails Screencast @@ -120,18 +117,23 @@ Besides the classic pagination `nav`, Pagy offers a few ready to use alternative ### Posts and Tutorials +- [Migrating from WillPaginate and Kaminari](https://ddnexus.github.io/pagy/migration-tips) (practical guide) - [Pagination with Pagy](https://www.imaginarycloud.com/blog/paginating-ruby-on-rails-apps-with-pagy) by Tiago Franco - [Stateful Tabs with Pagy](https://www.imaginarycloud.com/blog/how-to-paginate-ruby-on-rails-apps-with-pagy) by Chris Seelus - [Quick guide for Pagy with Sinatra and Sequel](https://medium.com/@vfreefly/how-to-use-pagy-with-sequel-and-sinatra-157dfec1c417) by Victor Afanasev +- [Detailed Gems Comparison](https://ddnexus.github.io/pagination-comparison/gems.html) (charts and analisys) +- [Benchmarks and Memory Profiles Source](http://github.com/ddnexus/pagination-comparison) (Rails app repository) ### Docs - [Quick Start](https://ddnexus.github.io/pagy/how-to#quick-start) - [Documentation](https://ddnexus.github.io/pagy/index) -- [Migrating from WillPaginate and Kaminari](https://ddnexus.github.io/pagy/migration-tips) - [Changelog](https://github.com/ddnexus/pagy/blob/master/CHANGELOG.md) -- [Detailed Gems Comparison](https://ddnexus.github.io/pagination-comparison/gems.html) -- [Benchmarks and Memory Profiles Source](http://github.com/ddnexus/pagination-comparison) + +### Support and Feedback + +[Chat on Gitter](https://gitter.im/ruby-pagy/Lobby) + ## Please Star and Share! @@ -143,8 +145,9 @@ Pagy is a fresh project and your help would be great. If you like it, you have a - Create an issue if anything should be improved/fixed - Submit a pull request to improve Pagy -- Write a Tutorial or a "How To" topic - Submit some cool extra +- Submit your translation if your language is missing from the [dictionary file](https://github.com/ddnexus/pagy/blob/master/lib/locales/pagy.yml) +- Write a Tutorial or a "How To" topic ## Branches and Pull Requests diff --git a/docs/api/backend.md b/docs/api/backend.md index e2d362950..74601227f 100644 --- a/docs/api/backend.md +++ b/docs/api/backend.md @@ -3,13 +3,13 @@ title: Pagy::Backend --- # Pagy::Backend -This module _(see [source](https://github.com/ddnexus/pagy/blob/master/lib/pagy/backend.rb))_ provides a _generic_ pagination method (`pagy`) that should work with most ORM collection (e.g. `ActiveRecord`, `Sequel`, `Mongoid`, ... collections). +This module _(see [source](https://github.com/ddnexus/pagy/blob/master/lib/pagy/backend.rb))_ provides a _generic_ pagination method (`pagy`) that works with `ActiveRecord` out of the box. For any other collection (e.g. `Sequel`, `Mongoid`, `Elasticsearch`, ...) you may need to override some sub-method or [write your own Pagy methods](#writing-your-own-pagy-methods). For overriding convenience, the `pagy` method calls two sub-methods that you may need to override in order to customize it for any type of collection (e.g. different ORM types, Array, elasticsearch results, etc.). -However, keep in mind that the whole module is basically providing a single functionality: getting a Pagy instance and the paginated items. You could re-write the whole module as one single and simpler method specific to your need, eventually gaining a few IPS in the process. If you seek a bit more performance you are encouraged to [write your own Pagy methods](#writing-your-own-pagy-methods)) +**Notice**: Keep in mind that the whole module is basically providing a single functionality: getting a Pagy instance and the paginated items. You could re-write the whole module as one single and simpler method specific to your need, eventually gaining a few IPS in the process. If you seek a bit more performance you are encouraged to [write your own Pagy methods](#writing-your-own-pagy-methods). -**Notice**: This module works for ActiveRecord collections out of the box. For other types of colections you may need to override some sub-method or write your own `pagy_*` methods. For paginating Arrays you may want to use the [array extra](../extras/array.md). +Check also the [array extra](../extras/array.md) and [searchkick extra](../extras/searchkick.md) for specific backend customizations. ## Synopsys @@ -80,7 +80,7 @@ end ## Writing your own Pagy methods -Somethimes you may need to paginate different kinds of collections (that require different overriding) in the same controller, so using one single `pagy` method would not be an option. +Sometimes you may need to paginate different kinds of collections (that require different overriding) in the same controller, so using one single `pagy` method would not be an option. In that case you can define a number of `pagy_*` custom methods specific for each collection. @@ -94,3 +94,5 @@ end ``` You can easily write a `pagy` method for _any possible_ environment: please read how to [Paginate Any Collection](../how-to.md#paginate-any-collection) for details. + +**IMPORTANT**: If you write some useful backend customization, please [let us know](https://gitter.im/ruby-pagy/Lobby) if you can submit a PR for a specific extra or if you need any help to do it. diff --git a/docs/api/frontend.md b/docs/api/frontend.md index 0e7b5d1fd..c75b4baa8 100644 --- a/docs/api/frontend.md +++ b/docs/api/frontend.md @@ -158,21 +158,43 @@ This method is similar to the `I18n.t` and its equivalent rails `t` helper. It i ## I18n -Pagy is I18n ready. That means that all the UI strings that Pagy uses are stored in a [dictionaray YAML file](https://github.com/ddnexus/pagy/blob/master/lib/locales/pagy.yml), ready to be customized and/or translated/pluralized. +**IMPORTANT**: if you are using pagy with some language missing from the dictionary file, please, submit your translation! -The YAML file is available at `Pagy.root.join('locales', 'pagy.yml')`. It contains a few entries used in the the UI by helpers and templates through the [pagy_t method](#pagy_tpath-vars) (eqivalent to the `I18n.t` or rails `t` helper). +Pagy is I18n ready. That means that all its strings are stored in a [dictionary file](https://github.com/ddnexus/pagy/blob/master/lib/locales/pagy.yml), ready to be customized and/or translated/pluralized and used with or without the `I18n` gem. -By default, the `pagy_t` method uses the Pagy implementation of I18n, which does not depend on the `I18n` gem in any way. It's _5x faster_ and uses _3.5x less memory_, but it provides only pluralization/interpolation without dynamic translation, so it's only useful with single language apps (i.e. only `fr` or only `en` or only ...) that don't need to switch between languages. +The Pagy dictionary is a YAML file containing a few entries used in the the UI by helpers and templates through the [pagy_t method](#pagy_tpath-vars) (eqivalent to the `I18n.t` or rails `t` helper). The file follows the same structure of the standard locale files for `i18n`. -If you need full blown I18n, you should require the `i18n` extra, which will override the `pagy_t` method to use directly `::I18n.t`. +### Multi-language apps -### Pagy::Frontend::I18N Constant +For multi-language apps you need the dynamic translation provided by the [i18n extra](../extras/i18n.md), which delegates the handling of the pagy strings to the `I18n` gem. In that case you need only 2 steps: -The `Pagy::Frontend::I18N` constant is the core of the Pagy I18n implementation. It has no effect if you use the `i18n` extra (which uses the `I18n.t` method directly). This constant allows to control the dictionary file, the language to load and the pluralization proc. +1. require the I18n extra in the initializer file +2. add a copy of the locale file(s) to the usual I18n dir(s), and/or add the pagy entries to the existing files + +**Notice**: For simplicity, you could also use the previous 2 steps for single-language apps, but if you want more performance, please follow the specific documentation below. + +### Single-language apps + +Single-language apps (i.e. only `fr` or only `en` or only ...) don't need to switch between languages, so they don't need the `i18n` extra/`I18n` gem (although it you could choose to use it). + +By default, Pagy handles its own dictionary file directly, providing pluralization and interpolation (without dynamic translation) _5x faster_ and using _3.5x less memory_ than the standard `I18n` gem. + +If you need to use your own language and/or customize the Pagy strings in this scenario, you need the following steps: + +1. copy and edit the [dictionary file](https://github.com/ddnexus/pagy/blob/master/lib/locales/pagy.yml) +2. see [Adding the model translations](#adding-the-model-translations) below +3. load the dictionary file in the initializer file (e.g. `Pagy::Frontend::I18N.load(file:..., language:'en')` +4. check if you need to configure some of the following variables in the [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer. + +#### Pagy::Frontend::I18N Constant + +**IMPORTANT**: This variable has no effect if you use the `i18n` extra. + +The `Pagy::Frontend::I18N` constant is the core of the Pagy I18n implementation. This constant allows to control the dictionary file, the language to load and the pluralization proc. #### Pagy::Frontend::I18N.load(file:..., language:'en') -This method has no effect if the `i18n` extra is used. +**IMPORTANT**: This method has no effect if you use the `i18n` extra. It allows to load a built-in language (different than the default 'en') and/or a custom dictionary file, different from `Pagy.root.join('locales', 'pagy.yml')`. It is tipically used in the Pagy initializer file _(see [Configuration](../how-to.md#global-configuration))_. For example: @@ -187,17 +209,19 @@ Pagy::Frontend::I18N.load(file:'path/to/dictionary.yml') Pagy::Frontend::I18N.load(file:'path/to/dictionary.yml', language:'it') ``` -**Notice**: the Pagy implementation of I18n is designed to speedup single language apps and does not provide dynamic translation, so the `language` is statically loaded at startup-time and cannot be changed. Use the `i18n` extra if you need dynamic translation. +**Notice**: the Pagy implementation of I18n is designed to speedup single-language apps and does not provide dynamic translation, so the `language` is statically loaded at startup-time and cannot be changed. Use the `i18n` extra if you need dynamic translation. #### Pagy::Frontend::I18N[:plural] -This variable controls the internal pluralization. If the `i18n` extra is used it has no effect. +**IMPORTANT**: This variable has no effect if you use the `i18n` extra. + +This variable controls the internal pluralization. Pagy tries to set the language plural proc when you use the `Pagy::Frontend::I18N.load` method, by loading the built-in plural for the language. _(see [plurals.rb](https://github.com/ddnexus/pagy/blob/master/lib/locales/plurals.rb))_ If there is no rule defined for the language loaded, the variable is set to the `:zero_one_other` plural rule (default for English language). -If your custom language requires a pluralization different than `"en"`, you should define a custom rule. For example: +If your custom language requires a pluralization different than `:zero_one_other`, you should define a custom rule. For example: ```ruby # this would apply a custom pluralization rule to the current loaded dictionary @@ -206,3 +230,22 @@ Pagy::Frontend::I18N[:plural] = -> (count) {|count| ...} The custom proc should receive the `count` as a single argument and should return the plural type string (e.g. something like `'zero'`, `'one'` or `'other'`, depending on the passed count). You should customize it only for pluralization types not included in the built-in plural rules. In that case, please submit a PR with your dictionary file and plural rule. Thanks. +#### Adding the model translations + +If you use the `pagy_info` helper with the specific model names instead of the generic "items" string, you may need to add entries for the models in the dictionary file. For example: + +```yaml +en: + pagy: + ... + + activerecord: + models: + product: + zero: Products + one: Product + other: Products + ... +``` + +_(See also the [pagy_info method](#pagy_infopagy))_ diff --git a/docs/how-to.md b/docs/how-to.md index 353c62037..20ac1cb41 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -56,7 +56,9 @@ or with a template: ## Global Configuration -Pagy should work out of the box for most Rack based apps (e.g. Rails) even without configuring anything, however you can configure all its features and all the extras loading a `pagy.rb` initializer file. +Unlike the other pagination gems, Pagy is very modular so it doesn't load nor execute unnecessary code in your app. Every feature that is not strictly needed for the basic pagination can be explicitly required in your initializer file. + +Basic pagination should work out of the box for most Rack based apps (e.g. Rails) even without configuring/requiring anything, however you can tweak all its features and all the extras by loading a `pagy.rb` initializer file. You can copy the comprehensive and annotated [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer and uncomment and edit what you may need. The file contains also all the relevant documentation links. @@ -75,10 +77,10 @@ Pagy works out of the box assuming that: ### Any other scenario assumptions -Pagy can work in any other scenario assuming that: +Pagy can also work in any other scenario assuming that: - If your framework doesn't have a `params` method you may need to define the `params` method or override the `pagy_get_vars` (which uses the `params` method) in your controller -- If the collection you are paginating doesn't respond to `offset` and `limit` you may need to override the `pagy_get_items` method in your controller (to get the items out of your specific collection) +- If the collection you are paginating doesn't respond to `offset` and `limit` you may need to override the `pagy_get_items` method in your controller (to get the items out of your specific collection) or use a specific extra if available (e.g. `array`, `searchkick`, ...) - If your framework doesn't have a `request` method you may need to override the `pagy_url_for` (which uses `Rack` and `request`) in your view **Notice**: the total overriding you may need is usually just a handful of lines at worse, and it doesn't need monkey patching or writing any sub-class or module. @@ -258,7 +260,7 @@ You have many ways to paginate an array with Pagy: ## Paginate a pre-offsetted and pre-limited collection -With the other pagination gems you cannot paginate a subset of a collection that you got using offset and limit. With Pagy it is as simple as just adding the `:outset` variable, set to the initial offset. For example: +With the other pagination gems you cannot paginate a subset of a collection that you got using `offset` and `limit`. With Pagy it is as simple as just adding the `:outset` variable, set to the initial offset. For example: ```ruby subset = Product.offset(100).limit(315) @@ -278,7 +280,7 @@ count = collection.count ## Using the pagy_nav* helpers -These helpers take the Pagy object and returns the HTML string with the pagination links, which are wrapped in a `nav` tag and are ready to use in your view. For example: +These helpers take the Pagy object and return the HTML string with the pagination links, which are wrapped in a `nav` tag and are ready to use in your view. For example: ```erb <%== pagy_nav(@pagy) %> @@ -314,9 +316,9 @@ By default Pagy generates all the page links including the `page` param. If you The `pagy_nav*` helpers are optimized for speed, and they are really fast. On the other hand editing a template might be easier when you have to customize the rendering, however every template system adds some inevitable overhead and it will be about 40-80% slower than using the related helper. That will still be dozens of times faster than the other gems, but... you should choose wisely. -Pagy provides the replacement templates for the `pagy_nav`, `pagy_nav_bootstrap` and the `pagy_nav_bulma` helpers (available with the `bootstrap` and `bulma` extras) in 3 flavors: `erb`, `haml` and `slim`. +Pagy provides the replacement templates for the `pagy_nav`, `pagy_nav_bootstrap`, `pagy_nav_bulma` and the `pagy_nav_foundation` helpers (available with the relative extras) in 3 flavors: `erb`, `haml` and `slim`. -They produce exactly the same output of the helpers, but they are slower, so use them only if you need to edit something. In that case customize a copy in your app, then use it as any other template: just remember to pass the `:pagy` local set to the `@pagy` object. Here are the links to the sources to copy: +They produce exactly the same output of the helpers, but since they are slower, using them wouldn't make any sense unless you need to change something. In that case customize a copy in your app, then use it as any other template: just remember to pass the `:pagy` local set to the `@pagy` object. Here are the links to the sources to copy: - `pagy` - [nav.html.erb](https://github.com/ddnexus/pagy/blob/master/lib/templates/nav.html.erb) @@ -378,7 +380,7 @@ That may work very well with static (or almost static) DBs, where there is not m ## Adding HTTP headers -The HTTP pagination headers may be useful for APIs, but they are out of scope for Pagy. However there are a couple of gems that support Pagy and do that for you in a quite automatic way. +The HTTP pagination headers may be useful for APIs, but they are currently out of scope for Pagy. However there are a couple of gems that support Pagy and do that for you in a quite automatic way. Please, take a look at: