jekyll 3.9.3 → 4.4.1

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +511 -89
  3. data/LICENSE +1 -1
  4. data/README.markdown +48 -27
  5. data/lib/blank_template/_config.yml +3 -0
  6. data/lib/blank_template/_layouts/default.html +12 -0
  7. data/lib/blank_template/_sass/base.scss +9 -0
  8. data/lib/blank_template/assets/css/main.scss +4 -0
  9. data/lib/blank_template/index.md +8 -0
  10. data/lib/jekyll/cache.rb +186 -0
  11. data/lib/jekyll/cleaner.rb +8 -7
  12. data/lib/jekyll/collection.rb +84 -11
  13. data/lib/jekyll/command.rb +33 -6
  14. data/lib/jekyll/commands/build.rb +8 -28
  15. data/lib/jekyll/commands/clean.rb +3 -2
  16. data/lib/jekyll/commands/doctor.rb +46 -35
  17. data/lib/jekyll/commands/help.rb +1 -1
  18. data/lib/jekyll/commands/new.rb +44 -50
  19. data/lib/jekyll/commands/new_theme.rb +27 -28
  20. data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
  21. data/lib/jekyll/commands/serve/servlet.rb +21 -22
  22. data/lib/jekyll/commands/serve/websockets.rb +1 -1
  23. data/lib/jekyll/commands/serve.rb +75 -97
  24. data/lib/jekyll/configuration.rb +66 -158
  25. data/lib/jekyll/converters/identity.rb +18 -0
  26. data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
  27. data/lib/jekyll/converters/markdown.rb +49 -40
  28. data/lib/jekyll/converters/smartypants.rb +34 -14
  29. data/lib/jekyll/convertible.rb +36 -34
  30. data/lib/jekyll/deprecator.rb +2 -4
  31. data/lib/jekyll/document.rb +107 -72
  32. data/lib/jekyll/drops/collection_drop.rb +3 -4
  33. data/lib/jekyll/drops/document_drop.rb +9 -3
  34. data/lib/jekyll/drops/drop.rb +115 -33
  35. data/lib/jekyll/drops/excerpt_drop.rb +8 -0
  36. data/lib/jekyll/drops/site_drop.rb +9 -8
  37. data/lib/jekyll/drops/static_file_drop.rb +4 -4
  38. data/lib/jekyll/drops/theme_drop.rb +39 -0
  39. data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
  40. data/lib/jekyll/drops/url_drop.rb +55 -3
  41. data/lib/jekyll/entry_filter.rb +42 -51
  42. data/lib/jekyll/excerpt.rb +48 -38
  43. data/lib/jekyll/external.rb +20 -19
  44. data/lib/jekyll/filters/date_filters.rb +6 -3
  45. data/lib/jekyll/filters/grouping_filters.rb +1 -2
  46. data/lib/jekyll/filters/url_filters.rb +50 -15
  47. data/lib/jekyll/filters.rb +211 -50
  48. data/lib/jekyll/frontmatter_defaults.rb +45 -36
  49. data/lib/jekyll/hooks.rb +26 -26
  50. data/lib/jekyll/inclusion.rb +32 -0
  51. data/lib/jekyll/layout.rb +12 -19
  52. data/lib/jekyll/liquid_extensions.rb +0 -2
  53. data/lib/jekyll/liquid_renderer/file.rb +24 -3
  54. data/lib/jekyll/liquid_renderer/table.rb +26 -77
  55. data/lib/jekyll/liquid_renderer.rb +31 -16
  56. data/lib/jekyll/log_adapter.rb +5 -1
  57. data/lib/jekyll/page.rb +51 -23
  58. data/lib/jekyll/page_excerpt.rb +25 -0
  59. data/lib/jekyll/page_without_a_file.rb +0 -4
  60. data/lib/jekyll/path_manager.rb +74 -0
  61. data/lib/jekyll/plugin.rb +5 -11
  62. data/lib/jekyll/plugin_manager.rb +15 -5
  63. data/lib/jekyll/profiler.rb +51 -0
  64. data/lib/jekyll/reader.rb +65 -10
  65. data/lib/jekyll/readers/collection_reader.rb +1 -0
  66. data/lib/jekyll/readers/data_reader.rb +48 -10
  67. data/lib/jekyll/readers/layout_reader.rb +3 -12
  68. data/lib/jekyll/readers/page_reader.rb +5 -5
  69. data/lib/jekyll/readers/post_reader.rb +32 -19
  70. data/lib/jekyll/readers/static_file_reader.rb +4 -4
  71. data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
  72. data/lib/jekyll/regenerator.rb +4 -12
  73. data/lib/jekyll/related_posts.rb +1 -1
  74. data/lib/jekyll/renderer.rb +34 -49
  75. data/lib/jekyll/site.rb +151 -58
  76. data/lib/jekyll/static_file.rb +64 -28
  77. data/lib/jekyll/stevenson.rb +4 -8
  78. data/lib/jekyll/tags/highlight.rb +44 -57
  79. data/lib/jekyll/tags/include.rb +114 -80
  80. data/lib/jekyll/tags/link.rb +12 -7
  81. data/lib/jekyll/tags/post_url.rb +33 -30
  82. data/lib/jekyll/theme.rb +20 -18
  83. data/lib/jekyll/theme_builder.rb +91 -89
  84. data/lib/jekyll/url.rb +18 -10
  85. data/lib/jekyll/utils/ansi.rb +2 -2
  86. data/lib/jekyll/utils/exec.rb +0 -1
  87. data/lib/jekyll/utils/internet.rb +2 -4
  88. data/lib/jekyll/utils/platforms.rb +37 -52
  89. data/lib/jekyll/utils/thread_event.rb +1 -5
  90. data/lib/jekyll/utils.rb +29 -28
  91. data/lib/jekyll/version.rb +1 -1
  92. data/lib/jekyll.rb +9 -14
  93. data/lib/site_template/.gitignore +2 -0
  94. data/lib/site_template/404.html +2 -1
  95. data/lib/site_template/_config.yml +17 -5
  96. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
  97. data/lib/theme_template/README.md.erb +1 -3
  98. data/lib/theme_template/gitignore.erb +1 -0
  99. data/lib/theme_template/theme.gemspec.erb +1 -4
  100. data/rubocop/jekyll/assert_equal_literal_actual.rb +150 -0
  101. data/rubocop/jekyll/no_p_allowed.rb +5 -6
  102. data/rubocop/jekyll/no_puts_allowed.rb +5 -6
  103. metadata +149 -37
  104. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
  105. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
  106. data/lib/jekyll/utils/rouge.rb +0 -22
  107. /data/lib/site_template/{about.md → about.markdown} +0 -0
  108. /data/lib/site_template/{index.md → index.markdown} +0 -0
data/lib/jekyll/site.rb CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  module Jekyll
4
4
  class Site
5
- attr_reader :source, :dest, :config
6
- attr_accessor :layouts, :pages, :static_files, :drafts,
7
- :exclude, :include, :lsi, :highlighter, :permalink_style,
8
- :time, :future, :unpublished, :safe, :plugins, :limit_posts,
9
- :show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
10
- :gems, :plugin_manager, :theme
5
+ attr_accessor :baseurl, :converters, :data, :drafts, :exclude,
6
+ :file_read_opts, :future, :gems, :generators, :highlighter,
7
+ :include, :inclusions, :keep_files, :layouts, :limit_posts,
8
+ :lsi, :pages, :permalink_style, :plugin_manager, :plugins,
9
+ :reader, :safe, :show_drafts, :static_files, :theme, :time,
10
+ :unpublished
11
11
 
12
- attr_accessor :converters, :generators, :reader
13
- attr_reader :regenerator, :liquid_renderer, :includes_load_paths
12
+ attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths,
13
+ :liquid_renderer, :profiler, :regenerator, :source
14
14
 
15
15
  # Public: Initialize a new Site.
16
16
  #
@@ -22,7 +22,11 @@ module Jekyll
22
22
 
23
23
  self.config = config
24
24
 
25
+ @cache_dir = in_source_dir(config["cache_dir"])
26
+ @filter_cache = {}
27
+
25
28
  @reader = Reader.new(self)
29
+ @profiler = Profiler.new(self)
26
30
  @regenerator = Regenerator.new(self)
27
31
  @liquid_renderer = LiquidRenderer.new(self)
28
32
 
@@ -44,13 +48,14 @@ module Jekyll
44
48
  @config = config.clone
45
49
 
46
50
  %w(safe lsi highlighter baseurl exclude include future unpublished
47
- show_drafts limit_posts keep_files).each do |opt|
48
- self.send("#{opt}=", config[opt])
51
+ show_drafts limit_posts keep_files).each do |opt|
52
+ send(:"#{opt}=", config[opt])
49
53
  end
50
54
 
51
55
  # keep using `gems` to avoid breaking change
52
56
  self.gems = config["plugins"]
53
57
 
58
+ configure_cache
54
59
  configure_plugins
55
60
  configure_theme
56
61
  configure_include_paths
@@ -58,6 +63,8 @@ module Jekyll
58
63
 
59
64
  self.permalink_style = config["permalink"].to_sym
60
65
 
66
+ # Read in a _config.yml from the current theme-gem at the very end.
67
+ @config = load_theme_configuration(config) if theme
61
68
  @config
62
69
  end
63
70
 
@@ -65,19 +72,23 @@ module Jekyll
65
72
  #
66
73
  # Returns nothing.
67
74
  def process
75
+ return profiler.profile_process if config["profile"]
76
+
68
77
  reset
69
78
  read
70
79
  generate
71
80
  render
72
81
  cleanup
73
82
  write
74
- print_stats if config["profile"]
75
83
  end
76
84
 
77
85
  def print_stats
78
86
  Jekyll.logger.info @liquid_renderer.stats_table
79
87
  end
80
88
 
89
+ # rubocop:disable Metrics/AbcSize
90
+ # rubocop:disable Metrics/MethodLength
91
+ #
81
92
  # Reset Site details.
82
93
  #
83
94
  # Returns nothing
@@ -88,22 +99,28 @@ module Jekyll
88
99
  Time.now
89
100
  end
90
101
  self.layouts = {}
102
+ self.inclusions = {}
91
103
  self.pages = []
92
104
  self.static_files = []
93
105
  self.data = {}
106
+ @post_attr_hash = {}
94
107
  @site_data = nil
95
108
  @collections = nil
109
+ @documents = nil
96
110
  @docs_to_write = nil
97
111
  @regenerator.clear_cache
98
112
  @liquid_renderer.reset
99
113
  @site_cleaner = nil
114
+ frontmatter_defaults.reset
100
115
 
101
- if limit_posts < 0
102
- raise ArgumentError, "limit_posts must be a non-negative number"
103
- end
116
+ raise ArgumentError, "limit_posts must be a non-negative number" if limit_posts.negative?
104
117
 
118
+ Jekyll::Cache.clear_if_config_changed config
105
119
  Jekyll::Hooks.trigger :site, :after_reset, self
120
+ nil
106
121
  end
122
+ # rubocop:enable Metrics/MethodLength
123
+ # rubocop:enable Metrics/AbcSize
107
124
 
108
125
  # Load necessary libraries, plugins, converters, and generators.
109
126
  #
@@ -124,7 +141,7 @@ module Jekyll
124
141
  Pathname.new(source).ascend do |path|
125
142
  if path == dest_pathname
126
143
  raise Errors::FatalException,
127
- "Destination directory cannot be or contain the Source directory."
144
+ "Destination directory cannot be or contain the Source directory."
128
145
  end
129
146
  end
130
147
  end
@@ -135,9 +152,9 @@ module Jekyll
135
152
  #
136
153
  # Returns a Hash containing collection name-to-instance pairs.
137
154
  def collections
138
- @collections ||= Hash[collection_names.map do |coll|
139
- [coll, Jekyll::Collection.new(self, coll)]
140
- end]
155
+ @collections ||= collection_names.each_with_object({}) do |name, hsh|
156
+ hsh[name] = Jekyll::Collection.new(self, name)
157
+ end
141
158
  end
142
159
 
143
160
  # The list of collection names.
@@ -164,6 +181,7 @@ module Jekyll
164
181
  reader.read
165
182
  limit_posts!
166
183
  Jekyll::Hooks.trigger :site, :post_read, self
184
+ nil
167
185
  end
168
186
 
169
187
  # Run each of the Generators.
@@ -174,8 +192,9 @@ module Jekyll
174
192
  start = Time.now
175
193
  generator.generate(self)
176
194
  Jekyll.logger.debug "Generating:",
177
- "#{generator.class} finished in #{Time.now - start} seconds."
195
+ "#{generator.class} finished in #{Time.now - start} seconds."
178
196
  end
197
+ nil
179
198
  end
180
199
 
181
200
  # Render the site to the destination.
@@ -192,6 +211,7 @@ module Jekyll
192
211
  render_pages(payload)
193
212
 
194
213
  Jekyll::Hooks.trigger :site, :post_render, self, payload
214
+ nil
195
215
  end
196
216
 
197
217
  # Remove orphaned files and empty directories in destination.
@@ -199,17 +219,20 @@ module Jekyll
199
219
  # Returns nothing.
200
220
  def cleanup
201
221
  site_cleaner.cleanup!
222
+ nil
202
223
  end
203
224
 
204
225
  # Write static files, pages, and posts.
205
226
  #
206
227
  # Returns nothing.
207
228
  def write
229
+ Jekyll::Commands::Doctor.conflicting_urls(self)
208
230
  each_site_file do |item|
209
231
  item.write(dest) if regenerator.regenerate?(item)
210
232
  end
211
233
  regenerator.write_metadata
212
234
  Jekyll::Hooks.trigger :site, :post_write, self
235
+ nil
213
236
  end
214
237
 
215
238
  def posts
@@ -232,12 +255,14 @@ module Jekyll
232
255
  def post_attr_hash(post_attr)
233
256
  # Build a hash map based on the specified post attribute ( post attr =>
234
257
  # array of posts ) then sort each array in reverse order.
235
- hash = Hash.new { |h, key| h[key] = [] }
236
- posts.docs.each do |p|
237
- p.data[post_attr].each { |t| hash[t] << p } if p.data[post_attr]
258
+ @post_attr_hash[post_attr] ||= begin
259
+ hash = Hash.new { |h, key| h[key] = [] }
260
+ posts.docs.each do |p|
261
+ p.data[post_attr]&.each { |t| hash[t] << p }
262
+ end
263
+ hash.each_value { |posts| posts.sort!.reverse! }
264
+ hash
238
265
  end
239
- hash.each_value { |posts| posts.sort!.reverse! }
240
- hash
241
266
  end
242
267
 
243
268
  def tags
@@ -279,10 +304,10 @@ module Jekyll
279
304
  # klass - The Class of the Converter to fetch.
280
305
  def find_converter_instance(klass)
281
306
  @find_converter_instance ||= {}
282
- @find_converter_instance[klass] ||= begin
283
- converters.find { |converter| converter.instance_of?(klass) } || \
284
- raise("No Converters found for #{klass}")
285
- end
307
+ @find_converter_instance[klass] ||= converters.find do |converter|
308
+ converter.instance_of?(klass)
309
+ end || \
310
+ raise("No Converters found for #{klass}")
286
311
  end
287
312
 
288
313
  # klass - class or module containing the subclasses.
@@ -291,8 +316,9 @@ module Jekyll
291
316
  # passed in as argument.
292
317
 
293
318
  def instantiate_subclasses(klass)
294
- klass.descendants.select { |c| !safe || c.safe }.sort.map do |c|
295
- c.new(config)
319
+ klass.descendants.select { |c| !safe || c.safe }.tap do |result|
320
+ result.sort!
321
+ result.map! { |c| c.new(config) }
296
322
  end
297
323
  end
298
324
 
@@ -302,11 +328,11 @@ module Jekyll
302
328
  # Returns
303
329
  def relative_permalinks_are_deprecated
304
330
  if config["relative_permalinks"]
305
- Jekyll.logger.abort_with "Since v3.0, permalinks for pages" \
306
- " in subfolders must be relative to the" \
307
- " site source directory, not the parent" \
308
- " directory. Check https://jekyllrb.com/docs/upgrading/"\
309
- " for more info."
331
+ Jekyll.logger.abort_with "Since v3.0, permalinks for pages " \
332
+ "in subfolders must be relative to the " \
333
+ "site source directory, not the parent " \
334
+ "directory. Check https://jekyllrb.com/docs/upgrading/ " \
335
+ "for more info."
310
336
  end
311
337
  end
312
338
 
@@ -317,6 +343,13 @@ module Jekyll
317
343
  documents.select(&:write?)
318
344
  end
319
345
 
346
+ # Get the to be written static files
347
+ #
348
+ # Returns an Array of StaticFiles which should be written
349
+ def static_files_to_write
350
+ static_files.select(&:write?)
351
+ end
352
+
320
353
  # Get all the documents
321
354
  #
322
355
  # Returns an Array of all Documents
@@ -327,11 +360,9 @@ module Jekyll
327
360
  end
328
361
 
329
362
  def each_site_file
330
- %w(pages static_files docs_to_write).each do |type|
331
- send(type).each do |item|
332
- yield item
333
- end
334
- end
363
+ pages.each { |page| yield page }
364
+ static_files.each { |file| yield(file) if file.write? }
365
+ collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } }
335
366
  end
336
367
 
337
368
  # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults
@@ -377,6 +408,7 @@ module Jekyll
377
408
  # Returns a path which is prefixed with the theme root directory.
378
409
  def in_theme_dir(*paths)
379
410
  return nil unless theme
411
+
380
412
  paths.reduce(theme.root) do |base, path|
381
413
  Jekyll.sanitized_path(base, path)
382
414
  end
@@ -394,6 +426,18 @@ module Jekyll
394
426
  end
395
427
  end
396
428
 
429
+ # Public: Prefix a given path with the cache directory.
430
+ #
431
+ # paths - (optional) path elements to a file or directory within the
432
+ # cache directory
433
+ #
434
+ # Returns a path which is prefixed with the cache directory.
435
+ def in_cache_dir(*paths)
436
+ paths.reduce(cache_dir) do |base, path|
437
+ Jekyll.sanitized_path(base, path)
438
+ end
439
+ end
440
+
397
441
  # Public: The full path to the directory that houses all the collections registered
398
442
  # with the current site.
399
443
  #
@@ -403,14 +447,47 @@ module Jekyll
403
447
  @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str)
404
448
  end
405
449
 
450
+ # Public
451
+ #
452
+ # Returns the object as a debug String.
453
+ def inspect
454
+ "#<#{self.class} @source=#{@source}>"
455
+ end
456
+
457
+ private
458
+
459
+ def load_theme_configuration(config)
460
+ return config if config["ignore_theme_config"] == true
461
+
462
+ theme_config_file = in_theme_dir("_config.yml")
463
+ return config unless File.exist?(theme_config_file)
464
+
465
+ # Bail out if the theme_config_file is a symlink file irrespective of safe mode
466
+ return config if File.symlink?(theme_config_file)
467
+
468
+ theme_config = SafeYAML.load_file(theme_config_file)
469
+ return config unless theme_config.is_a?(Hash)
470
+
471
+ Jekyll.logger.info "Theme Config file:", theme_config_file
472
+
473
+ # theme_config should not be overriding Jekyll's defaults
474
+ theme_config.delete_if { |key, _| Configuration::DEFAULTS.key?(key) }
475
+
476
+ # Override theme_config with existing config and return the result.
477
+ # Additionally ensure we return a `Jekyll::Configuration` instance instead of a Hash.
478
+ Utils.deep_merge_hashes(theme_config, config)
479
+ .each_with_object(Jekyll::Configuration.new) do |(key, value), conf|
480
+ conf[key] = value
481
+ end
482
+ end
483
+
406
484
  # Limits the current posts; removes the posts which exceed the limit_posts
407
485
  #
408
486
  # Returns nothing
409
- private
410
487
  def limit_posts!
411
- if limit_posts > 0
412
- limit = posts.docs.length < limit_posts ? posts.docs.length : limit_posts
413
- self.posts.docs = posts.docs[-limit, limit]
488
+ if limit_posts.positive?
489
+ limit = [posts.docs.length, limit_posts].min
490
+ posts.docs = posts.docs[-limit, limit]
414
491
  end
415
492
  end
416
493
 
@@ -418,18 +495,37 @@ module Jekyll
418
495
  # already exist.
419
496
  #
420
497
  # Returns The Cleaner
421
- private
422
498
  def site_cleaner
423
499
  @site_cleaner ||= Cleaner.new(self)
424
500
  end
425
501
 
426
- private
502
+ def hide_cache_dir_from_git
503
+ @cache_gitignore_path ||= in_source_dir(config["cache_dir"], ".gitignore")
504
+ return if File.exist?(@cache_gitignore_path)
505
+
506
+ cache_dir_path = in_source_dir(config["cache_dir"])
507
+ FileUtils.mkdir_p(cache_dir_path) unless File.directory?(cache_dir_path)
508
+
509
+ File.open(@cache_gitignore_path, "wb") do |file|
510
+ file.puts("# ignore everything in this directory\n*")
511
+ end
512
+ end
513
+
514
+ # Disable Marshaling cache to disk in Safe Mode
515
+ def configure_cache
516
+ Jekyll::Cache.cache_dir = in_source_dir(config["cache_dir"], "Jekyll/Cache")
517
+ if safe || config["disable_disk_cache"]
518
+ Jekyll::Cache.disable_disk_cache!
519
+ else
520
+ hide_cache_dir_from_git
521
+ end
522
+ end
523
+
427
524
  def configure_plugins
428
525
  self.plugin_manager = Jekyll::PluginManager.new(self)
429
526
  self.plugins = plugin_manager.plugins_path
430
527
  end
431
528
 
432
- private
433
529
  def configure_theme
434
530
  self.theme = nil
435
531
  return if config["theme"].nil?
@@ -438,26 +534,23 @@ module Jekyll
438
534
  if config["theme"].is_a?(String)
439
535
  Jekyll::Theme.new(config["theme"])
440
536
  else
441
- Jekyll.logger.warn "Theme:", "value of 'theme' in config should be " \
442
- "String to use gem-based themes, but got #{config["theme"].class}"
537
+ Jekyll.logger.warn "Theme:", "value of 'theme' in config should be String to use " \
538
+ "gem-based themes, but got #{config["theme"].class}"
443
539
  nil
444
540
  end
445
541
  end
446
542
 
447
- private
448
543
  def configure_include_paths
449
544
  @includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s))
450
- @includes_load_paths << theme.includes_path if theme && theme.includes_path
545
+ @includes_load_paths << theme.includes_path if theme&.includes_path
451
546
  end
452
547
 
453
- private
454
548
  def configure_file_read_opts
455
549
  self.file_read_opts = {}
456
- self.file_read_opts[:encoding] = config["encoding"] if config["encoding"]
550
+ file_read_opts[:encoding] = config["encoding"] if config["encoding"]
457
551
  self.file_read_opts = Jekyll::Utils.merged_file_read_opts(self, {})
458
552
  end
459
553
 
460
- private
461
554
  def render_docs(payload)
462
555
  collections.each_value do |collection|
463
556
  collection.docs.each do |document|
@@ -466,17 +559,17 @@ module Jekyll
466
559
  end
467
560
  end
468
561
 
469
- private
470
562
  def render_pages(payload)
471
- pages.flatten.each do |page|
563
+ pages.each do |page|
472
564
  render_regenerated(page, payload)
473
565
  end
474
566
  end
475
567
 
476
- private
477
568
  def render_regenerated(document, payload)
478
569
  return unless regenerator.regenerate?(document)
479
- document.output = Jekyll::Renderer.new(self, document, payload).run
570
+
571
+ document.renderer.payload = payload
572
+ document.output = document.renderer.run
480
573
  document.trigger_hooks(:post_render)
481
574
  end
482
575
  end
@@ -4,7 +4,9 @@ module Jekyll
4
4
  class StaticFile
5
5
  extend Forwardable
6
6
 
7
- attr_reader :relative_path, :extname, :name, :data
7
+ attr_reader :relative_path, :extname,
8
+ :type, # Returns the type of the collection if present, nil otherwise.
9
+ :name
8
10
 
9
11
  def_delegator :to_liquid, :to_json, :to_json
10
12
 
@@ -25,7 +27,7 @@ module Jekyll
25
27
  # base - The String path to the <source>.
26
28
  # dir - The String path between <source> and the file.
27
29
  # name - The String filename of the file.
28
- # rubocop: disable ParameterLists
30
+ # rubocop: disable Metrics/ParameterLists
29
31
  def initialize(site, base, dir, name, collection = nil)
30
32
  @site = site
31
33
  @base = base
@@ -34,18 +36,17 @@ module Jekyll
34
36
  @collection = collection
35
37
  @relative_path = File.join(*[@dir, @name].compact)
36
38
  @extname = File.extname(@name)
37
- @data = @site.frontmatter_defaults.all(relative_path, type)
39
+ @type = @collection&.label&.to_sym
38
40
  end
39
- # rubocop: enable ParameterLists
41
+ # rubocop: enable Metrics/ParameterLists
40
42
 
41
43
  # Returns source file path.
42
44
  def path
43
- # Static file is from a collection inside custom collections directory
44
- if !@collection.nil? && !@site.config["collections_dir"].empty?
45
- File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
46
- else
47
- File.join(*[@base, @dir, @name].compact)
48
- end
45
+ @path ||= if !@collection.nil? && !@site.config["collections_dir"].empty?
46
+ File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
47
+ else
48
+ File.join(*[@base, @dir, @name].compact)
49
+ end
49
50
  end
50
51
 
51
52
  # Obtain destination path.
@@ -54,7 +55,8 @@ module Jekyll
54
55
  #
55
56
  # Returns destination file path.
56
57
  def destination(dest)
57
- @site.in_dest_dir(*[dest, destination_rel_dir, @name].compact)
58
+ @destination ||= {}
59
+ @destination[dest] ||= @site.in_dest_dir(dest, Jekyll::URL.unescape_path(url))
58
60
  end
59
61
 
60
62
  def destination_rel_dir
@@ -86,7 +88,10 @@ module Jekyll
86
88
  # Returns true unless the defaults for the destination path from
87
89
  # _config.yml contain `published: false`.
88
90
  def write?
89
- defaults.fetch("published", true)
91
+ publishable = defaults.fetch("published", true)
92
+ return publishable unless @collection
93
+
94
+ publishable && @collection.write?
90
95
  end
91
96
 
92
97
  # Write the static file to the destination directory (if modified).
@@ -96,8 +101,8 @@ module Jekyll
96
101
  # Returns false if the file was not modified since last time (no-op).
97
102
  def write(dest)
98
103
  dest_path = destination(dest)
99
-
100
104
  return false if File.exist?(dest_path) && !modified?
105
+
101
106
  self.class.mtimes[path] = mtime
102
107
 
103
108
  FileUtils.mkdir_p(File.dirname(dest_path))
@@ -107,42 +112,66 @@ module Jekyll
107
112
  true
108
113
  end
109
114
 
115
+ def data
116
+ @data ||= @site.frontmatter_defaults.all(relative_path, type)
117
+ end
118
+
110
119
  def to_liquid
111
120
  @to_liquid ||= Drops::StaticFileDrop.new(self)
112
121
  end
113
122
 
123
+ # Generate "basename without extension" and strip away any trailing periods.
124
+ # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`)
114
125
  def basename
115
- File.basename(name, extname)
126
+ @basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "")
116
127
  end
117
128
 
118
129
  def placeholders
119
130
  {
120
131
  :collection => @collection.label,
121
- :path => relative_path[
122
- @collection.relative_directory.size..relative_path.size],
132
+ :path => cleaned_relative_path,
123
133
  :output_ext => "",
124
- :name => "",
134
+ :name => basename,
125
135
  :title => "",
126
136
  }
127
137
  end
128
138
 
139
+ # Similar to Jekyll::Document#cleaned_relative_path.
140
+ # Generates a relative path with the collection's directory removed when applicable
141
+ # and additionally removes any multiple periods in the string.
142
+ #
143
+ # NOTE: `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
144
+ #
145
+ # Examples:
146
+ # When `relative_path` is "_methods/site/my-cool-avatar...png":
147
+ # cleaned_relative_path
148
+ # # => "/site/my-cool-avatar"
149
+ #
150
+ # Returns the cleaned relative path of the static file.
151
+ def cleaned_relative_path
152
+ @cleaned_relative_path ||= begin
153
+ cleaned = relative_path[0..-extname.length - 1]
154
+ cleaned.gsub!(%r!\.*\z!, "")
155
+ cleaned.sub!(@collection.relative_directory, "") if @collection
156
+ cleaned
157
+ end
158
+ end
159
+
129
160
  # Applies a similar URL-building technique as Jekyll::Document that takes
130
161
  # the collection's URL template into account. The default URL template can
131
- # be overriden in the collection's configuration in _config.yml.
162
+ # be overridden in the collection's configuration in _config.yml.
132
163
  def url
133
- @url ||= if @collection.nil?
134
- relative_path
164
+ @url ||= begin
165
+ base = if @collection.nil?
166
+ cleaned_relative_path
135
167
  else
136
- ::Jekyll::URL.new({
168
+ Jekyll::URL.new(
137
169
  :template => @collection.url_template,
138
- :placeholders => placeholders,
139
- })
170
+ :placeholders => placeholders
171
+ )
140
172
  end.to_s.chomp("/")
141
- end
142
-
143
- # Returns the type of the collection if present, nil otherwise.
144
- def type
145
- @type ||= @collection.nil? ? nil : @collection.label.to_sym
173
+ base << extname
174
+ end
146
175
  end
147
176
 
148
177
  # Returns the front matter defaults defined for the file's URL and/or type
@@ -151,7 +180,14 @@ module Jekyll
151
180
  @defaults ||= @site.frontmatter_defaults.all url, type
152
181
  end
153
182
 
183
+ # Returns a debug string on inspecting the static file.
184
+ # Includes only the relative path of the object.
185
+ def inspect
186
+ "#<#{self.class} @relative_path=#{relative_path.inspect}>"
187
+ end
188
+
154
189
  private
190
+
155
191
  def copy_file(dest_path)
156
192
  if @site.safe || Jekyll.env == "production"
157
193
  FileUtils.cp(path, dest_path)
@@ -3,22 +3,18 @@
3
3
  module Jekyll
4
4
  class Stevenson < ::Logger
5
5
  def initialize
6
- @progname = nil
7
- @level = DEBUG
8
- @default_formatter = Formatter.new
9
- @logdev = $stdout
10
- @formatter = proc do |_, _, _, msg|
6
+ formatter = proc do |_, _, _, msg|
11
7
  msg.to_s
12
8
  end
9
+ super($stdout, :formatter => formatter)
13
10
  end
14
11
 
15
12
  def add(severity, message = nil, progname = nil)
16
13
  severity ||= UNKNOWN
17
14
  @logdev = logdevice(severity)
18
15
 
19
- if @logdev.nil? || severity < @level
20
- return true
21
- end
16
+ return true if @logdev.nil? || severity < @level
17
+
22
18
  progname ||= @progname
23
19
  if message.nil?
24
20
  if block_given?