coffeebrew_jekyll_paginate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3ea621dece76bb070ca7414e7ae18bba2b01729d3e4be3a58f16dfd040e091bf
4
+ data.tar.gz: ba842e477f22c13151198164443cafdca41be95ad8ced809d41655f124bcb9ee
5
+ SHA512:
6
+ metadata.gz: d4c427ece85c3bc8c60737ebc47d7c130a7de6907bda74abb164184fe735b3d16f5244e448191b17488798ff4573191b9a2c256739201ca50a21ebcdacc36e0f
7
+ data.tar.gz: 007e60e476b29d01456e5cf6675f1cd48c4c49d4ebb68f59317c4867e4fbf6e5524f10549107352940ebfdedbf880eef0844ec6e6df2d468ac76fadb08bfef9e
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## Version 0.1.0
4
+
5
+ [View version doc](https://github.com/coffeebrewapps/coffeebrew_jekyll_paginate/blob/v0.1.0/README.md)
6
+
7
+ - Initial release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Coffee Brew Apps
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,704 @@
1
+ # Jekyll Paginate Plugin
2
+
3
+ A Jekyll plugin to generate site pagination for collections.
4
+
5
+ [![Continuous Integration](https://github.com/coffeebrewapps/coffeebrew_jekyll_paginate/actions/workflows/ruby.yml/badge.svg)](https://github.com/coffeebrewapps/coffeebrew_jekyll_paginate/actions/workflows/ruby.yml) [![Gem Version](https://badge.fury.io/rb/coffeebrew_jekyll_paginate.svg)](https://badge.fury.io/rb/coffeebrew_jekyll_paginate)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your site's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'coffeebrew_jekyll_paginate'
13
+ ```
14
+
15
+ And then add this line to your site's `_config.yml`:
16
+
17
+ ```yml
18
+ plugins:
19
+ - coffeebrew_jekyll_paginate
20
+ ```
21
+
22
+ By default, the plugin doesn't generate any pagination. You need to specify which collections to be paginated. For
23
+ example,
24
+
25
+ ```yml
26
+ ---
27
+ coffeebrew_jekyll_paginate:
28
+ collections:
29
+ books:
30
+ ```
31
+
32
+ Assuming layouts have been setup (see more in [Layouts](#layouts)), then, the plugin will generate paginated
33
+ collections using the default config below:
34
+
35
+ ```yml
36
+ individual_page_pagination: false
37
+ frontmatter_defaults_key: "paginated_%{collection_type}"
38
+ first_page_as_root:
39
+ enabled: false
40
+ permalink: /:collection_type/:page_num_one_index
41
+ index_page: "index"
42
+ per_page: 5
43
+ sort_field: "date"
44
+ sort_reverse: true
45
+ page_num_label: "%{page_num_one_index}"
46
+ ```
47
+
48
+ An example of the generated directory structure is as such:
49
+
50
+ ```bash
51
+ _site/
52
+ ├── books
53
+ │   ├── 1
54
+ │   │   ├── index.html
55
+ │   └── 2
56
+ │   └── index.html
57
+ └── index.html
58
+ ```
59
+
60
+ ## Configuration
61
+
62
+ You can configure for as many collections as needed, and configure a site-wide pagination config, or configure for each
63
+ collection to use its own configuration. If there is no configuration for the site default, or the collection, the
64
+ plugin will use the default values as previously mentioned.
65
+
66
+ ### Site-wide defaults
67
+
68
+ For example, you can configure site-wide defaults that override the plugin's defaults, which will be used for all the
69
+ collections enabled.
70
+
71
+ ```yml
72
+ coffeebrew_jekyll_paginate:
73
+ defaults:
74
+ individual_page_pagination: true
75
+ first_page_as_root:
76
+ enabled: true
77
+ permalink: /
78
+ index_page: /:collection_type
79
+ per_page: 3
80
+ page_num_label: "Page %{page_num_one_index}"
81
+ collections:
82
+ books:
83
+ posts:
84
+ ```
85
+
86
+ If you do override the configuration, the plugin will perform a simple validation on your overrides according to these rules:
87
+
88
+ ### Frontmatter defaults key config
89
+
90
+ This tells the plugin what is the key used for setting defaults. For example, the plugin will use `paginated_posts` for
91
+ `posts` type by default, and this will allow Jekyll to lookup defaults for `type: "paginated_posts"` in `_config.yml`.
92
+
93
+ ```yml
94
+ defaults:
95
+ - scope:
96
+ path: ""
97
+ type: "paginated_posts"
98
+ values:
99
+ layout: "posts_index"
100
+ ```
101
+
102
+ ### Individual page pagination config
103
+
104
+ If set to `true`, this tells the plugin to generate previous/next pagination for individual collection pages. This is
105
+ useful if you want to have individual page-level pagination to navigate to the previous or next page. For example:
106
+
107
+ ```yml
108
+ ---
109
+ layout: default
110
+ ---
111
+ <h1>Posts</h1>
112
+ {% raw %}
113
+ {{ content }}
114
+
115
+ <div class="pagination">
116
+ <ul class="pager">
117
+ <li class="previous">
118
+ <a href="{{ page.paginator.previous_page_path }}">< {{ page.paginator.previous_page.title }}</a>
119
+ </li>
120
+ <li class="next">
121
+ <a href="{{ page.paginator.next_page_path }}">{{ page.paginator.next_page.title }} ></a>
122
+ </li>
123
+ </ul>
124
+ </div>
125
+ {% endraw %}
126
+ ```
127
+
128
+ ### First page as root config
129
+
130
+ This tells the plugin to generate the first page outside of the collection directory in the paginated set. For example,
131
+ if there are 4 pages in the paginated books collection, then the first page will be rendered in `/books.html`, and the
132
+ other pages will be rendered as `/books/2/index.html`, `/books/3/index.html` and `/books/4/index.html`.
133
+
134
+ This will be useful if you want to have the first page as part of your root pages and include it in the navigation.
135
+
136
+ | Key | Allowed Value(s) | Default | Remark |
137
+ | --- | --- | --- | --- |
138
+ | enabled | Boolean | false | If set to `true`, then the plugin will render the first page in a separate path as defined by the `permalink` and `index_page` below. |
139
+ | permalink | String | nil | The directory in which to generate the first page. Normally this will be `/` if you want it to be a root-level page. |
140
+ | index_page | String | nil | The filename of the first page. Normally this will be the name corresponding to the collection. |
141
+
142
+ If `enabled` is `false`, both `permalink` and `index_page` will be ignored, and the plugin will generate the first page
143
+ the same way as the remaining pages.
144
+
145
+ ### Pagination config
146
+
147
+ This tells the plugin how to generate the pagination pages.
148
+
149
+ | Key | Allowed Value(s) | Default | Remark |
150
+ | --- | --- | --- | --- |
151
+ | permalink | String | /:collection_type/:page_num_one_index | The directory in which to generate the page. |
152
+ | index_page | String | index | The filename of the page. |
153
+ | per_page | Integer | 5 | The number of collection items in each page. |
154
+ | sort_field | String | date | The field to be used to sort the collection for deterministic pagination. |
155
+ | sort_reverse | Boolean | true | The collection will be sorted in reverse if set to `true`. |
156
+ | page_num_label | String | %{page_num_one_index} | The format string for the page number label. |
157
+
158
+ A few placeholders are available to be used in the `permalink`, `index_page` and `page_num_label`:
159
+
160
+ | Field | Description |
161
+ | --- | --- |
162
+ | collection_type | This is the collection type current page, eg. `posts`. |
163
+ | page_num_zero_index | This will be the 0-index page number of the current page. |
164
+ | page_num_one_index | This will be the 1-index page number of the current page. |
165
+
166
+ ### Validation
167
+
168
+ If the config overrides have invalid structure, keys or values, the plugin will raise a
169
+ `Jekyll::Errors::InvalidConfigurationError` during build.
170
+
171
+ ## Layouts
172
+
173
+ The plugin does not provide a default layout. You will need to create your own layout in `_layouts` and configure the
174
+ defaults in `_config.yml`, for example, if you want to paginate the `books` collection, then you need to configure
175
+ the layout for the collection:
176
+
177
+ ```yml
178
+ ---
179
+ defaults:
180
+ - scope:
181
+ type: "paginated_books"
182
+ values:
183
+ layout: "books_pagination"
184
+ - scope:
185
+ type: "books"
186
+ values:
187
+ layout: "book"
188
+ permalink: /books/:name:output_ext
189
+ ```
190
+
191
+ As mentioned earlier, you need to set the `scope.type` here to match the `frontmatters_defaults_key` config of the
192
+ plugin. Note that there are 2 layouts configured here, `books_pagination` is used for the paginated collection page,
193
+ and `book` is used for the individual book page.
194
+
195
+ In addition to Jekyll's default page data, you can also use the additional page data and page's paginator data generated
196
+ by the plugin in the layout:
197
+
198
+ ### Paginated collection page
199
+
200
+ Use `page` to access the fields below.
201
+
202
+ | Field | Description |
203
+ | --- | --- |
204
+ | title | Current page's title. |
205
+ | collection | Current page's collection. |
206
+ | collection_type | Current page's collection type. |
207
+ | page_num_zero_index | Current page's 0-index page number. |
208
+ | page_num_one_index | Current page's 1-index page number. |
209
+ | page_num_label | Current page's page number label. |
210
+ | full_url | Current page full url. Can be used to match the current window url for highlighting purpose. |
211
+
212
+ ### Paginated collection paginator
213
+
214
+ Use `page.paginator` to acceess the fields below.
215
+
216
+ | Field | Description |
217
+ | --- | --- |
218
+ | total_pages | Total number of pages of the paginated collection. |
219
+ | pages | All the pages in the collection. |
220
+ | page_num_zero_index | Current page's 0-index page number. |
221
+ | page_num_one_index | Current page's 1-index page number. |
222
+ | page_num_label | Current page's page number label. |
223
+ | collection | Current page's collection. |
224
+ | collection_type | Current page's collection type. |
225
+ | current_page | Current page. |
226
+ | current_page_path | Current page full url. Can be used to match the current window url for highlighting purpose. |
227
+ | previous_page | Previous page. |
228
+ | previous_page_path | Previous page full url. Can be used to generate navigation link. |
229
+ | next_page | Next page. |
230
+ | next_page_path | Next page full url. Can be used to generate navigation link. |
231
+
232
+ An example of the paginated collection page layout `books_pagination`:
233
+
234
+ ```html
235
+ ---
236
+ layout: default
237
+ ---
238
+ <h1>Books</h1>
239
+ <div class="collection">
240
+ {% raw %}
241
+ {% for book in page.paginator.collection %}
242
+ <div class="item">
243
+ <div class="title">
244
+ <span>{{ book.title }}</span>
245
+ </div>
246
+ <p>{{ book.excerpt }}</p>
247
+ </div>
248
+ {% endfor %}
249
+ </div>
250
+
251
+ {% if page.paginator.total_pages > 1 %}
252
+ <div class="pagination">
253
+ <ul class="pager">
254
+ {% if page.paginator.previous_page %}
255
+ <li class="previous">
256
+ <a href="{{ page.paginator.previous_page_path }}"><i class="fa-solid fa-arrow-left"></i> Newer {{ page.paginator.collection_type | capitalize }}</a>
257
+ </li>
258
+ {% endif %}
259
+ {% if page.paginator.next_page %}
260
+ <li class="next">
261
+ <a href="{{ page.paginator.next_page_path }}">Older {{ page.paginator.collection_type | capitalize }} <i class="fa-solid fa-arrow-right"></i></a>
262
+ </li>
263
+ {% endif %}
264
+ </ul>
265
+ </div>
266
+ {% endif %}
267
+ {% endraw %}
268
+ ```
269
+
270
+ The resulting index pages using the example configuration and layout are as such:
271
+
272
+ ### Root page
273
+
274
+ Generated at: `_site/books.html`.
275
+
276
+ ```html
277
+ <!DOCTYPE html>
278
+ <html>
279
+ <head>
280
+ <meta charset="utf-8">
281
+ <title>Books</title>
282
+ </head>
283
+ <body>
284
+ <div class="container">
285
+ <h1>Books</h1>
286
+ <div class="collection">
287
+ <div class="item">
288
+ <div class="title">
289
+ <span>Harry Potter 7</span>
290
+ </div>
291
+ <p>This is the final book in the Harry Potter series.</p>
292
+ </div>
293
+
294
+ <div class="item">
295
+ <div class="title">
296
+ <span>Harry Potter 6</span>
297
+ </div>
298
+ <p>This is the sixth book in the Harry Potter series.</p>
299
+ </div>
300
+
301
+ <div class="item">
302
+ <div class="title">
303
+ <span>Harry Potter 5</span>
304
+ </div>
305
+ <p>This is the fifth book in the Harry Potter series.</p>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="pagination">
310
+ <ul class="pager">
311
+ <li class="next">
312
+ <a href="/books/2/index.html">Older Books <i class="fa-solid fa-arrow-right"></i></a>
313
+ </li>
314
+ </ul>
315
+ </div>
316
+ </div>
317
+ </body>
318
+ </html>
319
+ ```
320
+
321
+ ### Next page
322
+
323
+ Generated at: `_site/books/2/index.html`.
324
+
325
+ Note: Header elements omitted for clarity.
326
+
327
+ ```html
328
+ <div class="container">
329
+ <h1>Books</h1>
330
+ <div class="collection">
331
+ <div class="item">
332
+ <div class="title">
333
+ <span>Harry Potter 4</span>
334
+ </div>
335
+ <p>This is the fourth book in the Harry Potter series.</p>
336
+ </div>
337
+
338
+ <div class="item">
339
+ <div class="title">
340
+ <span>Harry Potter 3</span>
341
+ </div>
342
+ <p>This is the third book in the Harry Potter series.</p>
343
+ </div>
344
+
345
+ <div class="item">
346
+ <div class="title">
347
+ <span>Harry Potter 2</span>
348
+ </div>
349
+ <p>This is the second book in the Harry Potter series.</p>
350
+ </div>
351
+ </div>
352
+
353
+ <div class="pagination">
354
+ <ul class="pager">
355
+ <li class="previous">
356
+ <a href="/books.html"><i class="fa-solid fa-arrow-left"></i> Newer Books</a>
357
+ </li>
358
+ <li class="next">
359
+ <a href="/books/3/index.html">Older Books <i class="fa-solid fa-arrow-right"></i></a>
360
+ </li>
361
+ </ul>
362
+ </div>
363
+ </div>
364
+ ```
365
+
366
+ ### Last page
367
+
368
+ Generated at: `_site/books/3/index.html`.
369
+
370
+ Note: Header elements omitted for clarity.
371
+
372
+ ```html
373
+ <div class="container">
374
+ <h1>Books</h1>
375
+ <div class="collection">
376
+ <div class="item">
377
+ <div class="title">
378
+ <span>Harry Potter 1</span>
379
+ </div>
380
+ <p>This is the first book in the Harry Potter series.</p>
381
+ </div>
382
+ </div>
383
+
384
+ <div class="pagination">
385
+ <ul class="pager">
386
+ <li class="previous">
387
+ <a href="/books/2/index.html"><i class="fa-solid fa-arrow-left"></i> Newer Books</a>
388
+ </li>
389
+ </ul>
390
+ </div>
391
+ </div>
392
+ ```
393
+
394
+ ### Individual page paginator
395
+
396
+ Use `page.paginator` to access the fields below.
397
+
398
+ | Field | Description |
399
+ | --- | --- |
400
+ | collection_type | Current page's collection type. |
401
+ | current_page | Current page. |
402
+ | current_page_path | Current page full url. Can be used to match the current window url for highlighting purpose. |
403
+ | previous_page | Previous page. |
404
+ | previous_page_path | Previous page full url. Can be used to generate navigation link. |
405
+ | next_page | Next page. |
406
+ | next_page_path | Next page full url. Can be used to generate navigation link. |
407
+
408
+ An example of the individual page layout `book`:
409
+
410
+ ```html
411
+ ---
412
+ layout: default
413
+ ---
414
+ <h1>{{ page.title }}</h1>
415
+ {% raw %}
416
+ <div class="title">
417
+ <span>{{ page.title }}</span>
418
+ </div>
419
+ <p>{{ content }}</p>
420
+
421
+ {% if page.paginator %}
422
+ <div class="pagination">
423
+ <ul class="pager">
424
+ {% if page.paginator.previous_page %}
425
+ <li class="previous">
426
+ <a href="{{ page.paginator.previous_page_path }}"><i class="fa-solid fa-arrow-left"></i> Previous Book</a>
427
+ </li>
428
+ {% endif %}
429
+ {% if page.paginator.next_page %}
430
+ <li class="next">
431
+ <a href="{{ page.paginator.next_page_path }}">Next Book <i class="fa-solid fa-arrow-right"></i></a>
432
+ </li>
433
+ {% endif %}
434
+ </ul>
435
+ </div>
436
+ {% endif %}
437
+ {% endraw %}
438
+ ```
439
+
440
+ The resulting page using the example configuration and layout are as such:
441
+
442
+ ### Individual page
443
+
444
+ Generated at: `_site/books/book-1.html`
445
+
446
+ ```html
447
+ <!DOCTYPE html>
448
+ <html>
449
+ <head>
450
+ <meta charset="utf-8">
451
+ <title>Books</title>
452
+ </head>
453
+ <body>
454
+ <div class="container">
455
+ <h1>Book 1</h1>
456
+ <div class="title">
457
+ <span>Book 1</span>
458
+ </div>
459
+ <p>This is book 1.</p>
460
+
461
+ <div class="pagination">
462
+ <ul class="pager">
463
+ <li class="next">
464
+ <a href="/books/book-2.html">Next Book <i class="fa-solid fa-arrow-right"></i></a>
465
+ </li>
466
+ </ul>
467
+ </div>
468
+ </div>
469
+ </body>
470
+ </html>
471
+ ```
472
+
473
+ ## Contributing
474
+
475
+ Contribution to the gem is very much welcome!
476
+
477
+ 1. Fork it (https://github.com/coffeebrewapps/coffeebrew_jekyll_paginate/fork).
478
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
479
+ 3. Make sure you have setup the repo correctly so that you can run RSpec and Rubocop on your changes. Read more under the [Development](#development) section.
480
+ 4. Commit your changes (`git commit -am 'Add some feature'`).
481
+ 5. If you have added something that is worth mentioning in the README, please also update the README.md accordingly and commit the changes.
482
+ 6. Push to the branch (`git push origin my-new-feature`).
483
+ 7. Create a new Pull Request.
484
+
485
+ The repo owner will try to respond to a new PR as soon as possible.
486
+
487
+ ## Development
488
+
489
+ We want to provide a robust gem as much as possible for the users, so writing test cases will be required for any new
490
+ feature.
491
+
492
+ If you are contributing to the gem, please make sure you have setup your development environment correctly so that
493
+ RSpec and Rubocop can run properly.
494
+
495
+ 1. After forking the repo, go into the repo directory (`cd coffeebrew_jekyll_paginate/`).
496
+ 2. Make sure you have the correct Ruby version installed. This gem requires Ruby >= 2.7.0.
497
+ 3. Once you have the correct Ruby version, install the development dependencies (`bundle install`).
498
+ 4. To test that you have everything installed correctly, run the test cases (`bundle exec rspec`).
499
+ 5. You should see all test cases pass successfully.
500
+
501
+ ### Source directory structure
502
+
503
+ All the gem logic lives in the `/lib` directory:
504
+
505
+ ```bash
506
+ lib
507
+ ├── coffeebrew_jekyll_paginate
508
+ │   ├── config.yml
509
+ │   ├── generator.rb
510
+ │   ├── individual_paginator.rb
511
+ │   ├── page.rb
512
+ │   ├── page_drop.rb
513
+ │   ├── paginator.rb
514
+ │   ├── validator.rb
515
+ │   └── version.rb
516
+ └── coffeebrew_jekyll_paginate.rb
517
+ ```
518
+
519
+ The files that are currently in the repo:
520
+
521
+ | File | Description |
522
+ | --- | --- |
523
+ | `lib/coffeebrew_jekyll_paginate/config.yml` | This contains the default configuration for the plugin to generate pagination. |
524
+ | `lib/coffeebrew_jekyll_paginate/generator.rb` | This is the generator that reads the configuration and generate pagination. |
525
+ | `lib/coffeebrew_jekyll_paginate/individual_paginator.rb` | This is the abstract model containing the pagination methods for individual pages. |
526
+ | `lib/coffeebrew_jekyll_paginate/page.rb` | This is the abstract model of the paginated collection pages. |
527
+ | `lib/coffeebrew_jekyll_paginate/page_drop.rb` | This is the page drop used by the paginator class so its methods can be used in Liquid template. |
528
+ | `lib/coffeebrew_jekyll_paginate/paginator.rb` | This is the abstract model containing the pagination methods for paginated collection pages. |
529
+ | `lib/coffeebrew_jekyll_paginate/validator.rb` | This validates the configuration. |
530
+ | `lib/coffeebrew_jekyll_paginate/version.rb` | This contains the version number of the gem. |
531
+ | `lib/coffeebrew_jekyll_paginate.rb` | This is the entry point of the gem, and it loads the dependencies. |
532
+
533
+ ### Test cases directory structure
534
+
535
+ All the test cases and fixtures live in the `/spec` directory:
536
+
537
+ Note: Some files have been omitted for clarity.
538
+
539
+ ```bash
540
+ spec
541
+ ├── coffeebrew_jekyll_paginate_spec.rb
542
+ ├── dest
543
+ ├── fixtures
544
+ │   ├── _books
545
+ │   │   ├── 1997-06-26-harry-potter-1.md
546
+ │   │   ├── 1998-07-02-harry-potter-2.md
547
+ │   │   ├── 1999-07-08-harry-potter-3.md
548
+ │   │   ├── 2000-07-08-harry-potter-4.md
549
+ │   │   ├── 2003-06-21-harry-potter-5.md
550
+ │   │   ├── 2005-07-16-harry-potter-6.md
551
+ │   │   └── 2007-07-21-harry-potter-7.md
552
+ │   ├── _layouts
553
+ │   │   ├── book.html
554
+ │   │   ├── default.html
555
+ │   │   ├── paginated_books.html
556
+ │   │   ├── paginated_posts.html
557
+ │   │   └── post.html
558
+ │   ├── _posts
559
+ │   │   ├── 2021-03-12-test-post-1.md
560
+ │   │   ├── 2021-03-28-test-post-2.md
561
+ │   │   ├── 2021-05-03-test-post-3.md
562
+ │   │   ├── 2021-05-03-test-post-4.md
563
+ │   │   ├── 2022-01-27-test-post-5.md
564
+ │   │   ├── 2022-03-12-test-post-6.md
565
+ │   │   ├── 2022-11-23-test-post-7.md
566
+ │   │   └── 2023-02-21-test-post-8.md
567
+ │   └── _config.yml
568
+ ├── scenarios
569
+ │   ├── default
570
+ │   │   ├── _site
571
+ │   │   │   ├── books
572
+ │   │   │   │   ├── 1
573
+ │   │   │   │   │   └── index.html
574
+ │   │   │   │   ├── 2
575
+ │   │   │   │   │   └── index.html
576
+ │   │   │   │   ├── 1997-06-26-harry-potter-1.html
577
+ │   │   │   │   ├── 1998-07-02-harry-potter-2.html
578
+ │   │   │   │   ├── 1999-07-08-harry-potter-3.html
579
+ │   │   │   │   ├── 2000-07-08-harry-potter-4.html
580
+ │   │   │   │   ├── 2003-06-21-harry-potter-5.html
581
+ │   │   │   │   ├── 2005-07-16-harry-potter-6.html
582
+ │   │   │   │   └── 2007-07-21-harry-potter-7.html
583
+ │   │   │   └── posts
584
+ │   │   │      ├── 1
585
+ │   │   │      │   └── index.html
586
+ │   │   │      ├── 2
587
+ │   │   │      │   └── index.html
588
+ │   │   │      ├── 2021-03-12-test-post-1.html
589
+ │   │   │      ├── 2021-03-28-test-post-2.html
590
+ │   │   │      ├── 2021-05-03-test-post-3.html
591
+ │   │   │      ├── 2021-05-03-test-post-4.html
592
+ │   │   │      ├── 2022-01-27-test-post-5.html
593
+ │   │   │      ├── 2022-03-12-test-post-6.html
594
+ │   │   │      ├── 2022-11-23-test-post-7.html
595
+ │   │   │      └── 2023-02-21-test-post-8.html
596
+ │   │   └── context.rb
597
+ │   └── invalid_config_keys
598
+ │   └── context.rb
599
+ └── spec_helper.rb
600
+ ```
601
+
602
+ The files that are currently in the repo:
603
+
604
+ | File | Description |
605
+ | --- | --- |
606
+ | `spec/coffeebrew_jekyll_paginate_spec.rb` | This is the main RSpec file to be executed. It contains all the contexts of various scenarios. |
607
+ | `spec/dest/` | This directory is where generated files are located. It will be deleted immediately after each context is executed. |
608
+ | `spec/fixtures/` | This directory follows the Jekyll site source structure and contains the minimal files required to generate the paginated pages. |
609
+ | `spec/fixtures/_books` | This directory contains the test books, you can add more to it to test your new feature. |
610
+ | `spec/fixtures/_posts` | This directory contains the test posts, you can add more to it to test your new feature. |
611
+ | `spec/scenarios/` | This directory contains the expected files of various test scenarios. |
612
+ | `spec/scenarios/<scenario>/` | This is the scenario name. |
613
+ | `spec/scenarios/<scenario>/_site/` | This directory contains the expected paginated pages. |
614
+ | `spec/scenarios/<scenario>/context.rb` | This is the file that sets up the context for the test case. |
615
+ | `spec/spec_helper.rb` | This contains RSpec configuration and certain convenience methods for the main RSpec file. |
616
+
617
+ ### Writing test cases
618
+
619
+ There is a certain convention to follow when writing new test scenarios. The recommendation is to use the rake tasks
620
+ provided in the gem to generate the scenario files.
621
+
622
+ For success scenarios, run:
623
+
624
+ ```bash
625
+ bundle exec rake coffeebrew:jekyll:paginate:test:create_success[test_scenario]
626
+ ```
627
+
628
+ This will generate a placeholder file and directory:
629
+
630
+ ```bash
631
+ spec
632
+ ├── coffeebrew_jekyll_paginate_spec.rb
633
+ ├── scenarios
634
+ │   └── test_scenario
635
+ │      ├── _site
636
+ │       └── context.rb
637
+ └── spec_helper.rb
638
+ ```
639
+
640
+ Where the `context.rb` file will be pre-populated:
641
+
642
+ ```ruby
643
+ # frozen_string_literal: true
644
+
645
+ CONTEXT_TEST_SCENARIO = "when using test_scenario config"
646
+
647
+ RSpec.shared_context CONTEXT_TEST_SCENARIO do
648
+ let(:scenario) { "test_scenario" }
649
+ let(:overrides) {} # TODO: remove if unused
650
+ let(:generated_files) {} # TODO: remove if unused
651
+ let(:expected_files) do
652
+ [
653
+ ]
654
+ end
655
+ end
656
+ ```
657
+
658
+ For failure scenarios, run:
659
+
660
+ ```bash
661
+ bundle exec rake coffeebrew:jekyll:paginate:test:create_failure[test_scenario]
662
+ ```
663
+
664
+ This will generate a placeholder file and directory:
665
+
666
+ ```bash
667
+ spec
668
+ ├── coffeebrew_jekyll_paginate_spec.rb
669
+ ├── scenarios
670
+ │   └── test_scenario
671
+ │       └── context.rb
672
+ └── spec_helper.rb
673
+ ```
674
+
675
+ Where the `context.rb` file will be pre-populated:
676
+
677
+ ```ruby
678
+ # frozen_string_literal: true
679
+
680
+ CONTEXT_TEST_SCENARIO = "when using test_scenario config"
681
+
682
+ RSpec.shared_context CONTEXT_TEST_SCENARIO do
683
+ let(:scenario) { "test_scenario" }
684
+ let(:generated_files) { [] }
685
+ let(:expected_files) { [] }
686
+ let(:overrides) do
687
+ {
688
+ }
689
+ end
690
+
691
+ let(:expected_errors) do
692
+ [
693
+ ]
694
+ end
695
+ end
696
+ ```
697
+
698
+ If you do write other test cases that are not asserting the generated files like above, you can initiate your
699
+ convention. The repo owner will evaluate the PR and accept the convention if it fits the repo existing convention, or
700
+ will recommend an alternative if it doesn't.
701
+
702
+ ## License
703
+
704
+ See the [LICENSE](LICENSE) file.
@@ -0,0 +1,13 @@
1
+ coffeebrew_jekyll_paginate:
2
+ defaults:
3
+ individual_page_pagination: false
4
+ frontmatter_defaults_key: "paginated_%{collection_type}"
5
+ first_page_as_root:
6
+ enabled: false
7
+ permalink: /:collection_type/:page_num_one_index
8
+ index_page: "index"
9
+ per_page: 5
10
+ sort_field: "date"
11
+ sort_reverse: true
12
+ page_num_label: "%{page_num_one_index}"
13
+ collections: []
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./page"
4
+ require_relative "./individual_paginator"
5
+ require_relative "./paginator"
6
+ require_relative "./validator"
7
+
8
+ module Coffeebrew
9
+ module Jekyll
10
+ module Paginate
11
+ class Generator < ::Jekyll::Generator
12
+ safe true
13
+ priority :lowest
14
+
15
+ def generate(site)
16
+ @site = site
17
+
18
+ validate!
19
+
20
+ user_collections_config.each do |collection_type, options|
21
+ collection_options = add_collections_defaults(options)
22
+ process_collection(collection_type.to_sym, collection_options)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def validate!
29
+ validator = Coffeebrew::Jekyll::Paginate::Validator.new(@site, user_config)
30
+ validator.validate!
31
+ end
32
+
33
+ def process_collection(collection_type, options)
34
+ sort_field = options["sort_field"].to_sym
35
+ sort_reverse = options["sort_reverse"]
36
+ records = @site.collections[collection_type.to_s].docs
37
+ records.sort_by!(&sort_field)
38
+ records.reverse! if sort_reverse
39
+
40
+ individual_pagination = options["individual_page_pagination"]
41
+ generate_individual_page_paginator(collection_type, records) if individual_pagination
42
+
43
+ pages = generate_pages(collection_type, records, options)
44
+ return if pages.empty?
45
+
46
+ generate_paginators(collection_type, pages)
47
+ end
48
+
49
+ def generate_individual_page_paginator(collection_type, records)
50
+ records.each_with_index do |record, index|
51
+ prev_record = index.positive? ? records[index - 1] : nil
52
+ next_record = index < records.length ? records[index + 1] : nil
53
+ paginator = Paginate::IndividualPaginator.new(collection_type, prev_record, record, next_record)
54
+ record.data["paginator"] = paginator
55
+ end
56
+ end
57
+
58
+ def generate_pages(collection_type, records, options)
59
+ per_page = options["per_page"].to_i
60
+ first_page_as_root = options["first_page_as_root"]
61
+
62
+ records.each_slice(per_page).with_index.map do |page_records, page_num|
63
+ page_options = options.clone
64
+ if first_page_as_root["enabled"] && page_num.zero?
65
+ page_options["permalink"] = first_page_as_root["permalink"]
66
+ page_options["index_page"] = first_page_as_root["index_page"]
67
+ end
68
+ Paginate::Page.new(@site, page_options, collection_type, page_records, page_num)
69
+ end
70
+ end
71
+
72
+ def generate_paginators(collection_type, pages)
73
+ pages.each do |page|
74
+ paginator = Paginate::Paginator.new(pages, collection_type, page.page_num_zero_index)
75
+ page.paginator = paginator
76
+ @site.pages << page
77
+ end
78
+ end
79
+
80
+ def add_collections_defaults(user_options)
81
+ ::Jekyll::Utils.deep_merge_hashes(
82
+ default_defaults_config,
83
+ ::Jekyll::Utils.deep_merge_hashes(user_defaults_config, user_options)
84
+ )
85
+ end
86
+
87
+ def user_collections_config
88
+ @user_collections_config ||= user_config["collections"].to_h.transform_values(&:to_h)
89
+ end
90
+
91
+ def user_defaults_config
92
+ @user_defaults_config ||= user_config["defaults"].to_h
93
+ end
94
+
95
+ def user_config
96
+ @user_config ||= @site.config["coffeebrew_jekyll_paginate"].to_h
97
+ end
98
+
99
+ def default_defaults_config
100
+ @default_defaults_config ||= default_config.dig("coffeebrew_jekyll_paginate", "defaults").to_h
101
+ end
102
+
103
+ def default_config
104
+ @default_config ||= YAML.safe_load(File.read(default_config_path))
105
+ end
106
+
107
+ def default_config_path
108
+ @default_config_path ||= File.expand_path("config.yml", __dir__)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./page_drop"
4
+
5
+ module Coffeebrew
6
+ module Jekyll
7
+ module Paginate
8
+ class IndividualPaginator
9
+ attr_reader :collection_type,
10
+ :current_page, :current_page_path,
11
+ :previous_page, :previous_page_path,
12
+ :next_page, :next_page_path
13
+
14
+ def initialize(collection_type, previous_page, current_page, next_page)
15
+ @collection_type = collection_type
16
+ @current_page = current_page
17
+ @current_page_path = full_url(@current_page)
18
+ @previous_page = previous_page
19
+ @previous_page_path = full_url(@previous_page)
20
+ @next_page = next_page
21
+ @next_page_path = full_url(@next_page)
22
+ end
23
+
24
+ def data
25
+ @data ||= {
26
+ "collection_type" => collection_type,
27
+ "current_page" => current_page,
28
+ "current_page_path" => current_page_path,
29
+ "previous_page" => previous_page,
30
+ "previous_page_path" => previous_page_path,
31
+ "next_page" => next_page,
32
+ "next_page_path" => next_page_path
33
+ }
34
+ end
35
+
36
+ def to_liquid
37
+ @to_liquid ||= Paginate::PageDrop.new(self)
38
+ end
39
+
40
+ private
41
+
42
+ def full_url(page)
43
+ return "" if page.nil?
44
+
45
+ page.url
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coffeebrew
4
+ module Jekyll
5
+ module Paginate
6
+ class Page < ::Jekyll::Page
7
+ attr_reader :paginator, :collection_type, :collection,
8
+ :page_num_zero_index, :page_num_one_index
9
+
10
+ def initialize(site, config, collection_type, collection, page_num_zero_index) # rubocop:disable Lint/MissingSuper
11
+ @site = site
12
+ @config = config
13
+ @collection_type = collection_type
14
+ @collection = collection
15
+ @page_num_zero_index = page_num_zero_index
16
+ @page_num_one_index = page_num_zero_index.to_i + 1
17
+
18
+ @base = site.source
19
+ @ext = ".html"
20
+
21
+ build_data
22
+ end
23
+
24
+ def paginator=(paginator)
25
+ @paginator = paginator
26
+ @data["paginator"] = paginator
27
+
28
+ data.default_proc = proc do |_, key|
29
+ site.frontmatter_defaults.find(relative_path, frontmatter_defaults_key, key)
30
+ end
31
+ end
32
+
33
+ def frontmatter_defaults_key
34
+ @frontmatter_defaults_key ||= format(@config["frontmatter_defaults_key"], collection_type: collection_type)
35
+ end
36
+
37
+ def basename
38
+ @basename ||= ::Jekyll::URL.new(template: nil,
39
+ placeholders: basename_placeholders,
40
+ permalink: @config["index_page"])
41
+ .to_s
42
+ end
43
+
44
+ def name
45
+ @name ||= "#{basename}#{ext}"
46
+ end
47
+
48
+ def dir
49
+ @dir ||= ::Jekyll::URL.new(template: nil,
50
+ placeholders: page_dir_placeholders,
51
+ permalink: @config["permalink"])
52
+ .to_s
53
+ end
54
+
55
+ def page_dir_placeholders
56
+ @page_dir_placeholders ||= {
57
+ collection_type: collection_type.to_s,
58
+ page_num_zero_index: page_num_zero_index.to_s,
59
+ page_num_one_index: page_num_one_index.to_s,
60
+ basename: basename,
61
+ output_ext: output_ext
62
+ }
63
+ end
64
+
65
+ def basename_placeholders
66
+ @basename_placeholders ||= {
67
+ collection_type: collection_type.to_s,
68
+ page_num_zero_index: page_num_zero_index.to_s,
69
+ page_num_one_index: page_num_one_index.to_s
70
+ }
71
+ end
72
+
73
+ def url_placeholders
74
+ {
75
+ path: dir,
76
+ basename: basename,
77
+ output_ext: output_ext
78
+ }
79
+ end
80
+
81
+ def page_num_label
82
+ @page_num_label ||= format(@config["page_num_label"],
83
+ page_num_zero_index: page_num_zero_index, page_num_one_index: page_num_one_index)
84
+ end
85
+
86
+ def title
87
+ @title ||= collection_type.capitalize
88
+ end
89
+
90
+ def full_url
91
+ @full_url ||= [dir, name].join("/").squeeze("/")
92
+ end
93
+
94
+ private
95
+
96
+ def build_data
97
+ @data = {
98
+ "title" => title,
99
+ "collection" => collection,
100
+ "collection_type" => collection_type,
101
+ "page_num_zero_index" => page_num_zero_index,
102
+ "page_num_one_index" => page_num_one_index,
103
+ "page_num_label" => page_num_label,
104
+ "full_url" => full_url
105
+ }
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coffeebrew
4
+ module Jekyll
5
+ module Paginate
6
+ class PageDrop < ::Jekyll::Drops::Drop
7
+ extend Forwardable
8
+
9
+ mutable false
10
+
11
+ def_delegators :@obj, :posts, :type, :title, :date, :name, :path, :url, :permalink
12
+ def_delegator :@obj, :data, :fallback_data
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./page_drop"
4
+
5
+ module Coffeebrew
6
+ module Jekyll
7
+ module Paginate
8
+ class Paginator
9
+ attr_reader :total_pages, :pages,
10
+ :page_num_zero_index, :page_num_one_index, :page_num_label,
11
+ :collection, :collection_type,
12
+ :current_page, :current_page_path,
13
+ :previous_page, :previous_page_path,
14
+ :next_page, :next_page_path
15
+
16
+ def initialize(pages, collection_type, page_num_zero_index = 0)
17
+ @total_pages = pages.size
18
+ @pages = pages
19
+ @page_num_zero_index = page_num_zero_index
20
+ @collection_type = collection_type
21
+
22
+ set_current_page
23
+ set_prev_page
24
+ set_next_page
25
+ end
26
+
27
+ def data # rubocop:disable Metrics/MethodLength
28
+ @data ||= {
29
+ "total_pages" => total_pages,
30
+ "pages" => pages,
31
+ "page_num_zero_index" => page_num_zero_index,
32
+ "page_num_one_index" => page_num_one_index,
33
+ "page_num_label" => page_num_label,
34
+ "collection" => collection,
35
+ "collection_type" => collection_type,
36
+ "current_page" => current_page,
37
+ "current_page_path" => current_page_path,
38
+ "previous_page" => previous_page,
39
+ "previous_page_path" => previous_page_path,
40
+ "next_page" => next_page,
41
+ "next_page_path" => next_page_path
42
+ }
43
+ end
44
+
45
+ def to_liquid
46
+ @to_liquid ||= Paginate::PageDrop.new(self)
47
+ end
48
+
49
+ private
50
+
51
+ def set_current_page
52
+ @current_page = pages[page_num_zero_index]
53
+ @current_page_path = full_url(@current_page)
54
+
55
+ @collection = current_page&.collection || []
56
+ @page_num_one_index = @current_page&.page_num_one_index
57
+ @page_num_label = @current_page&.page_num_label
58
+ end
59
+
60
+ def set_prev_page
61
+ return if page_num_zero_index.zero?
62
+
63
+ @previous_page = pages[page_num_zero_index - 1]
64
+ @previous_page_path = full_url(@previous_page)
65
+ end
66
+
67
+ def set_next_page
68
+ return unless page_num_zero_index < total_pages - 1
69
+
70
+ @next_page = pages[page_num_zero_index + 1]
71
+ @next_page_path = full_url(@next_page)
72
+ end
73
+
74
+ def full_url(page)
75
+ return "" if page.nil?
76
+
77
+ page.full_url
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coffeebrew
4
+ module Jekyll
5
+ module Paginate
6
+ class Validator
7
+ ROOT_KEY = "coffeebrew_jekyll_paginate"
8
+ COLLECTIONS_KEY = "collections"
9
+ DEFAULTS_KEY = "defaults"
10
+
11
+ ALLOWED_ROOT_KEYS = [
12
+ COLLECTIONS_KEY,
13
+ DEFAULTS_KEY
14
+ ].freeze
15
+
16
+ ALLOWED_CONFIG_KEYS = {
17
+ "frontmatter_defaults_key" => [],
18
+ "individual_page_pagination" => [true, false],
19
+ "first_page_as_root" => {
20
+ "enabled" => [true, false],
21
+ "permalink" => [],
22
+ "index_page" => []
23
+ },
24
+ "permalink" => [],
25
+ "index_page" => [],
26
+ "per_page" => [],
27
+ "sort_field" => [],
28
+ "sort_reverse" => [true, false],
29
+ "page_num_label" => []
30
+ }.freeze
31
+
32
+ def initialize(site, config)
33
+ @site = site
34
+ @config = config
35
+ @errors = []
36
+ end
37
+
38
+ def validate!
39
+ parse_root
40
+ parse_defaults
41
+ parse_collection_keys
42
+ parse_collections_config
43
+
44
+ return if @errors.empty?
45
+
46
+ ::Jekyll.logger.error "'coffeebrew_jekyll_paginate' config is set incorrectly."
47
+ ::Jekyll.logger.error "Errors:", @errors
48
+
49
+ raise ::Jekyll::Errors::InvalidConfigurationError, "'coffeebrew_jekyll_paginate' config is set incorrectly."
50
+ end
51
+
52
+ private
53
+
54
+ def parse_root
55
+ not_allowed_keys = @config.keys.reject do |key|
56
+ ALLOWED_ROOT_KEYS.include?(key)
57
+ end
58
+ return if not_allowed_keys.empty?
59
+
60
+ @errors << { key: ROOT_KEY, expected: ALLOWED_ROOT_KEYS, got: not_allowed_keys }
61
+ end
62
+
63
+ def defaults_config
64
+ @defaults_config ||= @config[DEFAULTS_KEY].to_h
65
+ end
66
+
67
+ def parse_defaults
68
+ parse(defaults_config, ALLOWED_CONFIG_KEYS, ["#{ROOT_KEY}.#{DEFAULTS_KEY}"])
69
+ end
70
+
71
+ def configured_collections
72
+ @configured_collections ||= collections_config.keys.sort
73
+ end
74
+
75
+ def allowed_collections
76
+ @allowed_collections ||= @site.collections.keys
77
+ end
78
+
79
+ def parse_collection_keys
80
+ not_allowed_collections = configured_collections.reject do |configured_collection|
81
+ allowed_collections.include?(configured_collection)
82
+ end
83
+ return if not_allowed_collections.empty?
84
+
85
+ @errors << {
86
+ key: "#{ROOT_KEY}.collections",
87
+ expected: allowed_collections,
88
+ got: not_allowed_collections
89
+ }
90
+ end
91
+
92
+ def collections_config
93
+ @collections_config ||= @config[COLLECTIONS_KEY].to_h.transform_values(&:to_h)
94
+ end
95
+
96
+ def parse_collections_config
97
+ collections_config.each do |collection_type, options|
98
+ parse(options, ALLOWED_CONFIG_KEYS, ["#{ROOT_KEY}.#{COLLECTIONS_KEY}.#{collection_type}"])
99
+ end
100
+ end
101
+
102
+ def parse(hash, allowed_keys, parent_key)
103
+ hash.each do |key, configured_value|
104
+ allowed_values = allowed_keys[key]
105
+ new_parent_key = parent_key + [key]
106
+
107
+ next if configured_in_allowed_values?(allowed_values, configured_value)
108
+
109
+ if same_hash_type?(allowed_values, configured_value)
110
+ next parse(configured_value, allowed_values, new_parent_key)
111
+ end
112
+
113
+ add_error(new_parent_key, allowed_values, configured_value)
114
+ end
115
+ end
116
+
117
+ def same_hash_type?(allowed_values, configured_value)
118
+ allowed_values.is_a?(Hash) && configured_value.is_a?(Hash)
119
+ end
120
+
121
+ def primitive?(value)
122
+ value.nil? || value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
123
+ end
124
+
125
+ def configured_in_allowed_values?(allowed_values, configured_value)
126
+ allowed_values.is_a?(Array) && primitive?(configured_value) &&
127
+ (allowed_values.empty? || allowed_values.include?(configured_value))
128
+ end
129
+
130
+ def add_error(parent_key, allowed_values, configured_value)
131
+ @errors << { key: parent_key.join("."), expected: allowed_values, got: configured_value }
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coffeebrew
4
+ module Jekyll
5
+ module Paginate
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll"
4
+ require "coffeebrew_jekyll_paginate/generator"
5
+
6
+ module Coffeebrew
7
+ module Jekyll
8
+ module Paginate
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coffeebrew_jekyll_paginate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Coffee Brew Apps
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ description: A Jekyll plugin to generate pagination for site collections
34
+ email:
35
+ - coffeebrewapps@gmail.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files:
39
+ - README.md
40
+ - CHANGELOG.md
41
+ - LICENSE
42
+ files:
43
+ - CHANGELOG.md
44
+ - LICENSE
45
+ - README.md
46
+ - lib/coffeebrew_jekyll_paginate.rb
47
+ - lib/coffeebrew_jekyll_paginate/config.yml
48
+ - lib/coffeebrew_jekyll_paginate/generator.rb
49
+ - lib/coffeebrew_jekyll_paginate/individual_paginator.rb
50
+ - lib/coffeebrew_jekyll_paginate/page.rb
51
+ - lib/coffeebrew_jekyll_paginate/page_drop.rb
52
+ - lib/coffeebrew_jekyll_paginate/paginator.rb
53
+ - lib/coffeebrew_jekyll_paginate/validator.rb
54
+ - lib/coffeebrew_jekyll_paginate/version.rb
55
+ homepage: https://coffeebrewapps.com/coffeebrew_jekyll_paginate
56
+ licenses:
57
+ - MIT
58
+ metadata:
59
+ allowed_push_host: https://rubygems.org
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib/coffeebrew_jekyll_paginate
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.7.0
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.4.10
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: A Jekyll plugin to generate pagination for site collections
80
+ test_files: []