jekyll-collection-pages 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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/devcontainer.json +27 -0
  3. data/.devcontainer/post-create.sh +17 -0
  4. data/.github/build.sh +4 -0
  5. data/.github/bump.sh +28 -0
  6. data/.github/dependabot.yml +12 -0
  7. data/.github/pr-labeler.yml +7 -0
  8. data/.github/release-drafter.yml +40 -0
  9. data/.github/release.sh +69 -0
  10. data/.github/test.sh +4 -0
  11. data/.github/workflows/ci.yml +92 -0
  12. data/.github/workflows/pr_labeler.yml +16 -0
  13. data/.github/workflows/release.yml +23 -0
  14. data/.github/workflows/release_draft.yml +61 -0
  15. data/.github/workflows/site.yml +91 -0
  16. data/.gitignore +21 -0
  17. data/.rubocop.yml +43 -0
  18. data/.rubocop_todo.yml +33 -0
  19. data/.ruby-version +1 -0
  20. data/.vscode/settings.json +5 -0
  21. data/.vscode/tasks.json +58 -0
  22. data/CODE_OF_CONDUCT.md +128 -0
  23. data/CONTRIBUTING.md +41 -0
  24. data/Gemfile +39 -0
  25. data/LICENSE +21 -0
  26. data/README.md +152 -0
  27. data/Rakefile +8 -0
  28. data/VERSION +1 -0
  29. data/demo/CODE_OF_CONDUCT.md +1 -0
  30. data/demo/_articles/jekyll-collection-pages-comparison.md +90 -0
  31. data/demo/_articles/jekyll-collection-pages-indices.md +173 -0
  32. data/demo/_articles/jekyll-for-documentation.md +399 -0
  33. data/demo/_articles/linking-obsidian-and-jekyll.md +89 -0
  34. data/demo/_config.yml +83 -0
  35. data/demo/_docs/configuration-guide.md +113 -0
  36. data/demo/_docs/examples.md +159 -0
  37. data/demo/_docs/generated-data.md +76 -0
  38. data/demo/_docs/layout-recipes.md +122 -0
  39. data/demo/_docs/quick-start.md +1 -0
  40. data/demo/_docs/troubleshooting.md +68 -0
  41. data/demo/_layouts/collection_layout.html +27 -0
  42. data/demo/_layouts/tags.html +31 -0
  43. data/demo/articles.md +18 -0
  44. data/demo/assets/img/articles.png +0 -0
  45. data/demo/assets/img/docs.png +0 -0
  46. data/demo/assets/img/jekyll-collection-pages-preview.png +0 -0
  47. data/demo/assets/img/jekyll-collection-pages.png +0 -0
  48. data/demo/assets/img/post-img-1.png +0 -0
  49. data/demo/assets/img/post-img-2.png +0 -0
  50. data/demo/assets/img/post-img-3.png +0 -0
  51. data/demo/assets/img/post-img-4.png +0 -0
  52. data/demo/contributing.md +1 -0
  53. data/demo/directory.md +36 -0
  54. data/demo/docs.md +24 -0
  55. data/demo/gallery.md +14 -0
  56. data/demo/index.md +63 -0
  57. data/demo/tags.md +15 -0
  58. data/jekyll-collection-pages.gemspec +28 -0
  59. data/lib/jekyll/collection_pages.rb +383 -0
  60. data/lib/jekyll-collection-pages.rb +4 -0
  61. metadata +126 -0
data/demo/tags.md ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: Tags
3
+ layout: page
4
+ permalink: /tags/
5
+ ---
6
+
7
+ {%- assign tags_info = site.data.collection_pages.articles.tags %}
8
+ {%- assign tag_permalink = site.data.collection_pages.articles.tags.permalink %}
9
+
10
+ {% include post-index.html
11
+ collection=tags_info.pages
12
+ collection_permalink=tag_permalink
13
+ replace_value=":field"
14
+ per_section=3
15
+ %}
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'jekyll-collection-pages'
5
+ spec.version = File.read(File.expand_path('VERSION', __dir__)).strip
6
+ spec.authors = ['allison@allisonthackston.com']
7
+
8
+ spec.summary = 'A Jekyll plugin for generating tag pages for multiple collections'
9
+ spec.description = 'This Jekyll plugin allows you to generate tag pages for multiple collections, with support for pagination.'
10
+ spec.homepage = 'https://github.com/PrimerPages/jekyll-collection-pages'
11
+ spec.license = 'MIT'
12
+ spec.metadata = {
13
+ 'source_code_uri' => spec.homepage,
14
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
15
+ 'documentation_uri' => 'https://primerpages.github.io/jekyll-collection-pages/',
16
+ 'rubygems_mfa_required' => 'true'
17
+ }
18
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
19
+
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = 'exe'
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ['lib']
26
+
27
+ spec.add_dependency 'jekyll', '>= 3.7', '< 5.0'
28
+ end
@@ -0,0 +1,383 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module CollectionPages
5
+ INDEXFILE = 'index.html'
6
+
7
+ class PathTemplate
8
+ def initialize(raw_template:, tag_field:, collection_name:)
9
+ @tag_field = tag_field
10
+ @collection_name = collection_name
11
+ @template = build_effective_template(raw_template)
12
+ end
13
+
14
+ def for_tag(tag_value)
15
+ TagPathResolver.new(@template, tag_value)
16
+ end
17
+
18
+ def permalink
19
+ TagPathResolver.new(@template, ':field', slugify_value: false).url_for(1)
20
+ end
21
+
22
+ def template
23
+ "/#{@template}"
24
+ end
25
+
26
+ private
27
+
28
+ def build_effective_template(raw)
29
+ sanitized = sanitize_path(raw)
30
+ sanitized = default_placeholder if sanitized.empty?
31
+ sanitized = add_field_placeholder(sanitized)
32
+ sanitized = add_num_placeholder(sanitized)
33
+ sanitized = add_index(sanitized)
34
+ Jekyll.logger.debug('CollectionPages:', "Using path template '#{sanitized}' for collection '#{@collection_name}'.")
35
+ validate_template(sanitized)
36
+
37
+ sanitized
38
+ end
39
+
40
+ def sanitize_path(path)
41
+ path.to_s.strip.sub(%r{^/+}, '').sub(%r{/+\z}, '')
42
+ end
43
+
44
+ def default_placeholder
45
+ @collection_name.to_s
46
+ end
47
+
48
+ def add_field_placeholder(path)
49
+ return path if path.include?(':field')
50
+
51
+ raise ArgumentError, "Path template '#{path}' must include a ':field' placeholder." if path.end_with?('.html') || path.end_with?('.htm')
52
+
53
+ "#{path}/:field"
54
+ end
55
+
56
+ def add_num_placeholder(path)
57
+ return path if path.include?(':num')
58
+
59
+ raise ArgumentError, "Path template '#{path}' must include a ':num' placeholder." if path.end_with?('.html') || path.end_with?('.htm')
60
+
61
+ "#{path}/page:num"
62
+ end
63
+
64
+ def add_index(path)
65
+ return path if path.end_with?('.html') || path.end_with?('.htm')
66
+
67
+ "#{path}/#{CollectionPages::INDEXFILE}"
68
+ end
69
+
70
+ def validate_template(path)
71
+ field_count = path.scan(':field').size
72
+ num_count = path.scan(':num').size
73
+
74
+ error_msg = ''
75
+ error_msg += "Path template '#{path}' must include exactly one ':field' placeholder. " if field_count != 1
76
+ error_msg += "Path template '#{path}' must include exactly one ':num' placeholder. " if num_count != 1
77
+
78
+ if num_count.positive? && field_count.positive?
79
+ field_idx = path.index(':field')
80
+ num_idx = path.index(':num')
81
+ error_msg += "In path template '#{path}', ':field' must come before ':num'. " if num_idx < field_idx
82
+ end
83
+
84
+ segments = path.split('/').reject(&:empty?)
85
+ segments.each do |segment|
86
+ if segment.include?(':field') && segment.include?(':num')
87
+ error_msg += "In path template '#{path}', ':field' and ':num' cannot be in the same file segment. "
88
+ end
89
+ end
90
+
91
+ raise ArgumentError, error_msg unless error_msg.empty?
92
+ end
93
+
94
+ class TagPathResolver
95
+ def initialize(template, field_value, slugify_value: true)
96
+ @template = template
97
+ @value = slugify_value ? Utils.slugify(field_value.to_s) : field_value.to_s
98
+ @segments = template.split('/').reject(&:empty?)
99
+ end
100
+
101
+ def dir_for(page_number)
102
+ segments = @segments
103
+ segments = apply_field_value(segments)
104
+ segments = page_number == 1 ? remove_paginated_segments(segments) : apply_page_number(segments, page_number)
105
+ segments = drop_file_segment(segments)
106
+
107
+ File.join(*segments)
108
+ end
109
+
110
+ def filename_for(page_number)
111
+ return CollectionPages::INDEXFILE if page_number == 1
112
+
113
+ segments = @segments.last(1)
114
+ segments = apply_field_value(segments)
115
+ segments = apply_page_number(segments, page_number)
116
+ segments.join
117
+ end
118
+
119
+ def url_for(page_number)
120
+ dir = dir_for(page_number)
121
+ filename = filename_for(page_number)
122
+ return formatted_index_path(dir) if filename == CollectionPages::INDEXFILE
123
+
124
+ dir.empty? ? "/#{filename}" : "/#{dir}/#{filename}"
125
+ end
126
+
127
+ private
128
+
129
+ def apply_field_value(segments)
130
+ segments.map do |segment|
131
+ segment.include?(':field') ? segment.gsub(':field', @value) : segment
132
+ end
133
+ end
134
+
135
+ def apply_page_number(segments, page_number)
136
+ segments.map do |segment|
137
+ segment.include?(':num') ? segment.gsub(':num', page_number.to_s) : segment
138
+ end
139
+ end
140
+
141
+ def drop_file_segment(segments)
142
+ if segments.last.end_with?('.html') || segments.last.end_with?('.htm')
143
+ segments[0...-1]
144
+ else
145
+ segments
146
+ end
147
+ end
148
+
149
+ def remove_paginated_segments(segments)
150
+ number_index = segments.index { |segment| segment.include?(':num') }
151
+ number_index ? segments[0...number_index] : segments
152
+ end
153
+
154
+ def formatted_index_path(dir)
155
+ return '/' if dir.empty?
156
+
157
+ "/#{dir}/"
158
+ end
159
+ end
160
+ end
161
+
162
+ class TagPagination < Generator
163
+ safe true
164
+ priority :lowest
165
+
166
+ def generate(site)
167
+ return unless site.config['collection_pages']
168
+
169
+ config = site.config['collection_pages']
170
+
171
+ if config.is_a?(Hash)
172
+ Jekyll.logger.debug('CollectionPages:', 'Processing single collection config')
173
+ generate_for_config(site, config)
174
+ elsif config.is_a?(Array)
175
+ Jekyll.logger.debug('CollectionPages:', 'Processing multiple collection config')
176
+ config.each do |collection_config|
177
+ generate_for_config(site, collection_config)
178
+ end
179
+ end
180
+ Jekyll.logger.debug('CollectionPages:', "Generation complete. Total pages: #{site.pages.size}")
181
+ end
182
+
183
+ def generate_for_config(site, config)
184
+ collection_name = config['collection']
185
+ tag_field = config['field']
186
+ tag_base_path = config['path']
187
+ tag_layout = config['layout'] || 'collection_layout.html'
188
+ per_page = normalize_paginate_value(config['paginate'], collection_name, tag_field)
189
+ Jekyll.logger.debug('CollectionPages:', "Generating pages for collection: #{collection_name}::#{tag_field}")
190
+
191
+ path_template = PathTemplate.new(raw_template: tag_base_path, tag_field: tag_field, collection_name: collection_name)
192
+
193
+ site.data['collection_pages'] ||= {}
194
+
195
+ documents_map, metadata_map = generate_paginated_tags(site, path_template, tag_layout, collection_name, tag_field, per_page)
196
+
197
+ collection_registry = site.data['collection_pages'][collection_name] ||= {}
198
+ collection_registry[tag_field] = {
199
+ 'template' => path_template.template,
200
+ 'permalink' => path_template.permalink,
201
+ 'labels' => metadata_map,
202
+ 'pages' => documents_map
203
+ }
204
+ end
205
+
206
+ def sorted_tags(site, collection_name, tag_field)
207
+ tags = {}
208
+ collection = site.collections[collection_name]
209
+ return [] unless collection
210
+
211
+ Jekyll.logger.debug('CollectionPages:', "Found collection '#{collection_name}' with #{collection.docs.size} entries.")
212
+ collection.docs.each do |doc|
213
+ doc_tags = doc.data[tag_field]
214
+ next unless doc_tags
215
+
216
+ doc_tags = [doc_tags] if doc_tags.is_a?(String)
217
+ doc_tags.each do |tag|
218
+ tags[tag] ||= []
219
+ tags[tag] << doc
220
+ end
221
+ end
222
+ tags.keys.sort.map { |tag| [tag, tags[tag]] }
223
+ end
224
+
225
+ def generate_paginated_tags(site, path_template, tag_layout, collection_name, tag_field, per_page)
226
+ tags_with_docs = sorted_tags(site, collection_name, tag_field)
227
+
228
+ documents_map = {}
229
+ metadata_map = {}
230
+
231
+ tags_with_docs.each do |tag, posts_with_tag|
232
+ tag_path = path_template.for_tag(tag)
233
+
234
+ page_count = TagPager.calculate_pages(posts_with_tag, per_page)
235
+ tag_pages = []
236
+ (1..page_count).each do |page_num|
237
+ paginator = TagPager.new(page_num, per_page, posts_with_tag, tag_path) if per_page
238
+ posts_for_page = paginator ? paginator.posts : posts_with_tag
239
+ page_dir = tag_path.dir_for(page_num)
240
+ page_filename = tag_path.filename_for(page_num)
241
+ tag_page = build_page(site, page_dir, page_filename, tag, tag_layout, posts_for_page, page_num, paginator)
242
+ site.pages << tag_page
243
+ tag_pages << tag_page
244
+ end
245
+
246
+ documents_map[tag] = posts_with_tag
247
+ metadata_map[tag] = {
248
+ 'pages' => tag_pages,
249
+ 'index' => tag_pages.first
250
+ }
251
+ Jekyll.logger.info('CollectionPages:',
252
+ "Generated #{tag_pages.size} page(s) for tag '#{tag}' in collection '#{collection_name}'.")
253
+ end
254
+
255
+ [documents_map, metadata_map]
256
+ end
257
+
258
+ def build_page(site, dir, page_filename, tag, layout, posts, page_num, paginator = nil)
259
+ TagIndexPage.new(
260
+ site,
261
+ {
262
+ dir: dir,
263
+ name: page_filename,
264
+ tag: tag,
265
+ layout: layout,
266
+ posts: posts,
267
+ page_num: page_num,
268
+ paginator: paginator
269
+ }
270
+ )
271
+ end
272
+
273
+ private
274
+
275
+ def normalize_paginate_value(value, collection_name, tag_field)
276
+ return nil if value.nil?
277
+
278
+ per_page = Integer(value)
279
+ return per_page if per_page.positive?
280
+
281
+ Jekyll.logger.warn('CollectionPages:',
282
+ "Non-positive paginate value #{value.inspect} for collection '#{collection_name}' field '#{tag_field}'. " \
283
+ 'Falling back to single page generation.')
284
+ nil
285
+ rescue ArgumentError, TypeError
286
+ raise ArgumentError,
287
+ "Invalid paginate value #{value.inspect} for collection '#{collection_name}' field '#{tag_field}'. Expected a numeric value."
288
+ end
289
+ end
290
+ end
291
+
292
+ class TagIndexPage < PageWithoutAFile
293
+ def initialize(site, attributes)
294
+ dir = attributes[:dir]
295
+ name = attributes[:name]
296
+ tag = attributes[:tag]
297
+ layout = attributes[:layout]
298
+ posts = attributes[:posts]
299
+ page_num = attributes[:page_num]
300
+ paginator = attributes[:paginator]
301
+
302
+ # This sets up a page that has no source file on disk.
303
+ super(site, site.source, dir, name) # also calls process(name) internally
304
+
305
+ self.content = '' # virtual page body (optional)
306
+
307
+ self.data = {
308
+ 'layout' => File.basename(layout, '.*'), # layout NAME (no path)
309
+ 'tag' => tag,
310
+ 'title' => tag.to_s,
311
+ 'posts' => posts,
312
+ 'page_num' => page_num
313
+ }
314
+ data['paginator'] = paginator if paginator
315
+ end
316
+ end
317
+
318
+ class TagPager
319
+ attr_reader :page, :per_page, :posts, :total_posts, :total_pages,
320
+ :previous_page, :previous_page_path, :next_page, :next_page_path
321
+
322
+ LIQUID_MAP = {
323
+ 'page' => :page, # the current page number
324
+ 'per_page' => :per_page, # the number of posts per page
325
+ 'posts' => :posts, # the paginated posts for this page
326
+ 'total_posts' => :total_posts, # the total number of posts being paginated
327
+ 'total_pages' => :total_pages, # the total number of pages
328
+ 'previous_page' => :previous_page, # the previous page number, or nil
329
+ 'previous_page_path' => :previous_page_path, # the previous page path, or nil
330
+ 'next_page' => :next_page, # the next page number, or nil
331
+ 'next_page_path' => :next_page_path # the next page path, or nil
332
+ }.freeze
333
+
334
+ def self.calculate_pages(all_posts, per_page)
335
+ per_page_value = per_page.to_i
336
+ return 1 if per_page_value <= 0
337
+
338
+ (all_posts.size.to_f / per_page_value).ceil
339
+ end
340
+
341
+ def initialize(page_num, per_page, all_posts, path_resolver)
342
+ @page = page_num
343
+ @per_page = per_page.to_i.positive? ? per_page.to_i : 0
344
+ @total_posts = all_posts.size
345
+ @total_pages = self.class.calculate_pages(all_posts, @per_page)
346
+ @posts = slice_posts(all_posts)
347
+ @path_resolver = path_resolver
348
+ @previous_page = previous_page_number
349
+ @next_page = next_page_number(total_pages)
350
+ @previous_page_path = page_path(@previous_page)
351
+ @next_page_path = page_path(@next_page)
352
+ end
353
+
354
+ def to_liquid
355
+ LIQUID_MAP.transform_values { |reader| public_send(reader) }
356
+ end
357
+
358
+ private
359
+
360
+ attr_reader :path_resolver
361
+
362
+ def slice_posts(all_posts)
363
+ return all_posts if @per_page <= 0
364
+
365
+ start_index = (@page - 1) * @per_page
366
+ all_posts.slice(start_index, @per_page) || []
367
+ end
368
+
369
+ def previous_page_number
370
+ @page > 1 ? @page - 1 : nil
371
+ end
372
+
373
+ def next_page_number(total_pages)
374
+ @page < total_pages ? @page + 1 : nil
375
+ end
376
+
377
+ def page_path(target_page)
378
+ return unless target_page && target_page <= total_pages
379
+
380
+ path_resolver.url_for(target_page)
381
+ end
382
+ end
383
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jekyll'
4
+ require_relative 'jekyll/collection_pages'
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-collection-pages
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - allison@allisonthackston.com
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-11-18 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: '3.7'
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: '3.7'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ description: This Jekyll plugin allows you to generate tag pages for multiple collections,
34
+ with support for pagination.
35
+ email:
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - ".devcontainer/devcontainer.json"
41
+ - ".devcontainer/post-create.sh"
42
+ - ".github/build.sh"
43
+ - ".github/bump.sh"
44
+ - ".github/dependabot.yml"
45
+ - ".github/pr-labeler.yml"
46
+ - ".github/release-drafter.yml"
47
+ - ".github/release.sh"
48
+ - ".github/test.sh"
49
+ - ".github/workflows/ci.yml"
50
+ - ".github/workflows/pr_labeler.yml"
51
+ - ".github/workflows/release.yml"
52
+ - ".github/workflows/release_draft.yml"
53
+ - ".github/workflows/site.yml"
54
+ - ".gitignore"
55
+ - ".rubocop.yml"
56
+ - ".rubocop_todo.yml"
57
+ - ".ruby-version"
58
+ - ".vscode/settings.json"
59
+ - ".vscode/tasks.json"
60
+ - CODE_OF_CONDUCT.md
61
+ - CONTRIBUTING.md
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - VERSION
67
+ - demo/CODE_OF_CONDUCT.md
68
+ - demo/_articles/jekyll-collection-pages-comparison.md
69
+ - demo/_articles/jekyll-collection-pages-indices.md
70
+ - demo/_articles/jekyll-for-documentation.md
71
+ - demo/_articles/linking-obsidian-and-jekyll.md
72
+ - demo/_config.yml
73
+ - demo/_docs/configuration-guide.md
74
+ - demo/_docs/examples.md
75
+ - demo/_docs/generated-data.md
76
+ - demo/_docs/layout-recipes.md
77
+ - demo/_docs/quick-start.md
78
+ - demo/_docs/troubleshooting.md
79
+ - demo/_layouts/collection_layout.html
80
+ - demo/_layouts/tags.html
81
+ - demo/articles.md
82
+ - demo/assets/img/articles.png
83
+ - demo/assets/img/docs.png
84
+ - demo/assets/img/jekyll-collection-pages-preview.png
85
+ - demo/assets/img/jekyll-collection-pages.png
86
+ - demo/assets/img/post-img-1.png
87
+ - demo/assets/img/post-img-2.png
88
+ - demo/assets/img/post-img-3.png
89
+ - demo/assets/img/post-img-4.png
90
+ - demo/contributing.md
91
+ - demo/directory.md
92
+ - demo/docs.md
93
+ - demo/gallery.md
94
+ - demo/index.md
95
+ - demo/tags.md
96
+ - jekyll-collection-pages.gemspec
97
+ - lib/jekyll-collection-pages.rb
98
+ - lib/jekyll/collection_pages.rb
99
+ homepage: https://github.com/PrimerPages/jekyll-collection-pages
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ source_code_uri: https://github.com/PrimerPages/jekyll-collection-pages
104
+ bug_tracker_uri: https://github.com/PrimerPages/jekyll-collection-pages/issues
105
+ documentation_uri: https://primerpages.github.io/jekyll-collection-pages/
106
+ rubygems_mfa_required: 'true'
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: 2.7.0
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.5.11
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A Jekyll plugin for generating tag pages for multiple collections
126
+ test_files: []