jekyll 4.1.1 → 4.2.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.
@@ -22,22 +22,25 @@ module Jekyll
22
22
  :post_write => [],
23
23
  },
24
24
  :pages => {
25
- :post_init => [],
26
- :pre_render => [],
27
- :post_render => [],
28
- :post_write => [],
25
+ :post_init => [],
26
+ :pre_render => [],
27
+ :post_convert => [],
28
+ :post_render => [],
29
+ :post_write => [],
29
30
  },
30
31
  :posts => {
31
- :post_init => [],
32
- :pre_render => [],
33
- :post_render => [],
34
- :post_write => [],
32
+ :post_init => [],
33
+ :pre_render => [],
34
+ :post_convert => [],
35
+ :post_render => [],
36
+ :post_write => [],
35
37
  },
36
38
  :documents => {
37
- :post_init => [],
38
- :pre_render => [],
39
- :post_render => [],
40
- :post_write => [],
39
+ :post_init => [],
40
+ :pre_render => [],
41
+ :post_convert => [],
42
+ :post_render => [],
43
+ :post_write => [],
41
44
  },
42
45
  :clean => {
43
46
  :on_obsolete => [],
@@ -67,10 +70,11 @@ module Jekyll
67
70
  # register a single hook to be called later, internal API
68
71
  def self.register_one(owner, event, priority, &block)
69
72
  @registry[owner] ||= {
70
- :post_init => [],
71
- :pre_render => [],
72
- :post_render => [],
73
- :post_write => [],
73
+ :post_init => [],
74
+ :pre_render => [],
75
+ :post_convert => [],
76
+ :post_render => [],
77
+ :post_write => [],
74
78
  }
75
79
 
76
80
  unless @registry[owner][event]
@@ -58,5 +58,10 @@ module Jekyll
58
58
  def process(name)
59
59
  self.ext = File.extname(name)
60
60
  end
61
+
62
+ # Returns the object as a debug String.
63
+ def inspect
64
+ "#<#{self.class} @path=#{@path.inspect}>"
65
+ end
61
66
  end
62
67
  end
@@ -64,12 +64,7 @@ module Jekyll
64
64
  #
65
65
  # Returns the String destination directory.
66
66
  def dir
67
- if url.end_with?("/")
68
- url
69
- else
70
- url_dir = File.dirname(url)
71
- url_dir.end_with?("/") ? url_dir : "#{url_dir}/"
72
- end
67
+ url.end_with?("/") ? url : url_dir
73
68
  end
74
69
 
75
70
  # The full path and filename of the post. Defined in the YAML of the post
@@ -121,6 +116,8 @@ module Jekyll
121
116
  # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`)
122
117
  # Returns nothing.
123
118
  def process(name)
119
+ return unless name
120
+
124
121
  self.ext = File.extname(name)
125
122
  self.basename = name[0..-ext.length - 1].gsub(%r!\.*\z!, "")
126
123
  end
@@ -147,7 +144,7 @@ module Jekyll
147
144
 
148
145
  # The path to the page source file, relative to the site source
149
146
  def relative_path
150
- @relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).sub(%r!\A/!, "")
147
+ @relative_path ||= PathManager.join(@dir, @name).sub(%r!\A/!, "")
151
148
  end
152
149
 
153
150
  # Obtain destination path.
@@ -156,10 +153,13 @@ module Jekyll
156
153
  #
157
154
  # Returns the destination file path String.
158
155
  def destination(dest)
159
- path = site.in_dest_dir(dest, URL.unescape_path(url))
160
- path = File.join(path, "index") if url.end_with?("/")
161
- path << output_ext unless path.end_with? output_ext
162
- path
156
+ @destination ||= {}
157
+ @destination[dest] ||= begin
158
+ path = site.in_dest_dir(dest, URL.unescape_path(url))
159
+ path = File.join(path, "index") if url.end_with?("/")
160
+ path << output_ext unless path.end_with? output_ext
161
+ path
162
+ end
163
163
  end
164
164
 
165
165
  # Returns the object as a debug String.
@@ -192,11 +192,11 @@ module Jekyll
192
192
  def excerpt
193
193
  return @excerpt if defined?(@excerpt)
194
194
 
195
- @excerpt = data["excerpt"]&.to_s
195
+ @excerpt = data["excerpt"] ? data["excerpt"].to_s : nil
196
196
  end
197
197
 
198
198
  def generate_excerpt?
199
- !excerpt_separator.empty? && self.class == Jekyll::Page && html?
199
+ !excerpt_separator.empty? && instance_of?(Jekyll::Page) && html?
200
200
  end
201
201
 
202
202
  private
@@ -206,5 +206,12 @@ module Jekyll
206
206
 
207
207
  data["excerpt"] ||= Jekyll::PageExcerpt.new(self)
208
208
  end
209
+
210
+ def url_dir
211
+ @url_dir ||= begin
212
+ value = File.dirname(url)
213
+ value.end_with?("/") ? value : "#{value}/"
214
+ end
215
+ end
209
216
  end
210
217
  end
@@ -16,16 +16,59 @@ module Jekyll
16
16
  # This class cannot be initialized from outside
17
17
  private_class_method :new
18
18
 
19
- # Wraps `File.join` to cache the frozen result.
20
- # Reassigns `nil`, empty strings and empty arrays to a frozen empty string beforehand.
21
- #
22
- # Returns a frozen string.
23
- def self.join(base, item)
24
- base = "" if base.nil? || base.empty?
25
- item = "" if item.nil? || item.empty?
26
- @join ||= {}
27
- @join[base] ||= {}
28
- @join[base][item] ||= File.join(base, item).freeze
19
+ class << self
20
+ # Wraps `File.join` to cache the frozen result.
21
+ # Reassigns `nil`, empty strings and empty arrays to a frozen empty string beforehand.
22
+ #
23
+ # Returns a frozen string.
24
+ def join(base, item)
25
+ base = "" if base.nil? || base.empty?
26
+ item = "" if item.nil? || item.empty?
27
+ @join ||= {}
28
+ @join[base] ||= {}
29
+ @join[base][item] ||= File.join(base, item).freeze
30
+ end
31
+
32
+ # Ensures the questionable path is prefixed with the base directory
33
+ # and prepends the questionable path with the base directory if false.
34
+ #
35
+ # Returns a frozen string.
36
+ def sanitized_path(base_directory, questionable_path)
37
+ @sanitized_path ||= {}
38
+ @sanitized_path[base_directory] ||= {}
39
+ @sanitized_path[base_directory][questionable_path] ||= begin
40
+ if questionable_path.nil?
41
+ base_directory.freeze
42
+ else
43
+ sanitize_and_join(base_directory, questionable_path).freeze
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def sanitize_and_join(base_directory, questionable_path)
51
+ clean_path = if questionable_path.start_with?("~")
52
+ questionable_path.dup.insert(0, "/")
53
+ else
54
+ questionable_path
55
+ end
56
+ clean_path = File.expand_path(clean_path, "/")
57
+ return clean_path if clean_path.eql?(base_directory)
58
+
59
+ # remove any remaining extra leading slashes not stripped away by calling
60
+ # `File.expand_path` above.
61
+ clean_path.squeeze!("/")
62
+ return clean_path if clean_path.start_with?(slashed_dir_cache(base_directory))
63
+
64
+ clean_path.sub!(%r!\A\w:/!, "/")
65
+ join(base_directory, clean_path)
66
+ end
67
+
68
+ def slashed_dir_cache(base_directory)
69
+ @slashed_dir_cache ||= {}
70
+ @slashed_dir_cache[base_directory] ||= base_directory.sub(%r!\z!, "/")
71
+ end
29
72
  end
30
73
  end
31
74
  end
@@ -164,8 +164,6 @@ module Jekyll
164
164
  entry_filter = EntryFilter.new(site)
165
165
 
166
166
  site.include.each do |entry|
167
- next if entry == ".htaccess"
168
-
169
167
  entry_path = site.in_source_dir(entry)
170
168
  next if File.directory?(entry_path)
171
169
  next if entry_filter.symlink?(entry_path)
@@ -175,13 +173,20 @@ module Jekyll
175
173
  end
176
174
 
177
175
  def read_included_file(entry_path)
178
- dir = File.dirname(entry_path).sub(site.source, "")
179
- file = Array(File.basename(entry_path))
180
176
  if Utils.has_yaml_header?(entry_path)
181
- site.pages.concat(PageReader.new(site, dir).read(file))
177
+ conditionally_generate_entry(entry_path, site.pages, PageReader)
182
178
  else
183
- site.static_files.concat(StaticFileReader.new(site, dir).read(file))
179
+ conditionally_generate_entry(entry_path, site.static_files, StaticFileReader)
184
180
  end
185
181
  end
182
+
183
+ def conditionally_generate_entry(entry_path, container, reader)
184
+ return if container.find { |item| site.in_source_dir(item.relative_path) == entry_path }
185
+
186
+ dir, files = File.split(entry_path)
187
+ dir.sub!(site.source, "")
188
+ files = Array(files)
189
+ container.concat(reader.new(site, dir).read(files))
190
+ end
186
191
  end
187
192
  end
@@ -8,6 +8,7 @@ module Jekyll
8
8
  @site = site
9
9
  @content = {}
10
10
  @entry_filter = EntryFilter.new(site)
11
+ @source_dir = site.in_source_dir("/")
11
12
  end
12
13
 
13
14
  # Read all the files in <dir> and adds them to @content
@@ -53,6 +54,8 @@ module Jekyll
53
54
  #
54
55
  # Returns the contents of the data file.
55
56
  def read_data_file(path)
57
+ Jekyll.logger.debug "Reading:", path.sub(@source_dir, "")
58
+
56
59
  case File.extname(path).downcase
57
60
  when ".csv"
58
61
  CSV.read(path,
@@ -57,7 +57,7 @@ module Jekyll
57
57
  Document.new(path,
58
58
  :site => @site,
59
59
  :collection => @site.posts)
60
- end.reject(&:nil?)
60
+ end.tap(&:compact!)
61
61
  end
62
62
 
63
63
  private
@@ -46,7 +46,7 @@ module Jekyll
46
46
  end
47
47
 
48
48
  def most_recent_posts
49
- @most_recent_posts ||= (site.posts.docs.last(11).reverse - [post]).first(10)
49
+ @most_recent_posts ||= (site.posts.docs.last(11).reverse! - [post]).first(10)
50
50
  end
51
51
  end
52
52
  end
@@ -36,7 +36,7 @@ module Jekyll
36
36
  #
37
37
  # Returns Array of Converter instances.
38
38
  def converters
39
- @converters ||= site.converters.select { |c| c.matches(document.extname) }.sort
39
+ @converters ||= site.converters.select { |c| c.matches(document.extname) }.tap(&:sort!)
40
40
  end
41
41
 
42
42
  # Determine the extname the outputted file should have
@@ -66,7 +66,7 @@ module Jekyll
66
66
  # Render the document.
67
67
  #
68
68
  # Returns String rendered document output
69
- # rubocop: disable Metrics/AbcSize
69
+ # rubocop: disable Metrics/AbcSize, Metrics/MethodLength
70
70
  def render_document
71
71
  info = {
72
72
  :registers => { :site => site, :page => payload["page"] },
@@ -84,6 +84,10 @@ module Jekyll
84
84
  output = convert(output.to_s)
85
85
  document.content = output
86
86
 
87
+ Jekyll.logger.debug "Post-Convert Hooks:", document.relative_path
88
+ document.trigger_hooks(:post_convert)
89
+ output = document.content
90
+
87
91
  if document.place_in_layout?
88
92
  Jekyll.logger.debug "Rendering Layout:", document.relative_path
89
93
  output = place_in_layouts(output, payload, info)
@@ -91,7 +95,7 @@ module Jekyll
91
95
 
92
96
  output
93
97
  end
94
- # rubocop: enable Metrics/AbcSize
98
+ # rubocop: enable Metrics/AbcSize, Metrics/MethodLength
95
99
 
96
100
  # Convert the document using the converters which match this renderer's document.
97
101
  #
@@ -251,7 +255,7 @@ module Jekyll
251
255
  def output_exts
252
256
  @output_exts ||= converters.map do |c|
253
257
  c.output_ext(document.extname)
254
- end.compact
258
+ end.tap(&:compact!)
255
259
  end
256
260
 
257
261
  def liquid_options
@@ -117,6 +117,7 @@ module Jekyll
117
117
 
118
118
  Jekyll::Cache.clear_if_config_changed config
119
119
  Jekyll::Hooks.trigger :site, :after_reset, self
120
+ nil
120
121
  end
121
122
  # rubocop:enable Metrics/MethodLength
122
123
  # rubocop:enable Metrics/AbcSize
@@ -180,6 +181,7 @@ module Jekyll
180
181
  reader.read
181
182
  limit_posts!
182
183
  Jekyll::Hooks.trigger :site, :post_read, self
184
+ nil
183
185
  end
184
186
 
185
187
  # Run each of the Generators.
@@ -192,6 +194,7 @@ module Jekyll
192
194
  Jekyll.logger.debug "Generating:",
193
195
  "#{generator.class} finished in #{Time.now - start} seconds."
194
196
  end
197
+ nil
195
198
  end
196
199
 
197
200
  # Render the site to the destination.
@@ -208,6 +211,7 @@ module Jekyll
208
211
  render_pages(payload)
209
212
 
210
213
  Jekyll::Hooks.trigger :site, :post_render, self, payload
214
+ nil
211
215
  end
212
216
 
213
217
  # Remove orphaned files and empty directories in destination.
@@ -215,17 +219,20 @@ module Jekyll
215
219
  # Returns nothing.
216
220
  def cleanup
217
221
  site_cleaner.cleanup!
222
+ nil
218
223
  end
219
224
 
220
225
  # Write static files, pages, and posts.
221
226
  #
222
227
  # Returns nothing.
223
228
  def write
229
+ Jekyll::Commands::Doctor.conflicting_urls(self)
224
230
  each_site_file do |item|
225
231
  item.write(dest) if regenerator.regenerate?(item)
226
232
  end
227
233
  regenerator.write_metadata
228
234
  Jekyll::Hooks.trigger :site, :post_write, self
235
+ nil
229
236
  end
230
237
 
231
238
  def posts
@@ -309,8 +316,9 @@ module Jekyll
309
316
  # passed in as argument.
310
317
 
311
318
  def instantiate_subclasses(klass)
312
- klass.descendants.select { |c| !safe || c.safe }.sort.map do |c|
313
- c.new(config)
319
+ klass.descendants.select { |c| !safe || c.safe }.tap do |result|
320
+ result.sort!
321
+ result.map! { |c| c.new(config) }
314
322
  end
315
323
  end
316
324
 
@@ -434,6 +442,13 @@ module Jekyll
434
442
  @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str)
435
443
  end
436
444
 
445
+ # Public
446
+ #
447
+ # Returns the object as a debug String.
448
+ def inspect
449
+ "#<#{self.class} @source=#{@source}>"
450
+ end
451
+
437
452
  private
438
453
 
439
454
  def load_theme_configuration(config)
@@ -55,8 +55,8 @@ module Jekyll
55
55
  #
56
56
  # Returns destination file path.
57
57
  def destination(dest)
58
- dest = @site.in_dest_dir(dest)
59
- @site.in_dest_dir(dest, Jekyll::URL.unescape_path(url))
58
+ @destination ||= {}
59
+ @destination[dest] ||= @site.in_dest_dir(dest, Jekyll::URL.unescape_path(url))
60
60
  end
61
61
 
62
62
  def destination_rel_dir
@@ -36,20 +36,16 @@ module Jekyll
36
36
 
37
37
  def parse_params(context)
38
38
  params = {}
39
- markup = @params
40
-
41
- while (match = VALID_SYNTAX.match(markup))
42
- markup = markup[match.end(0)..-1]
43
-
44
- value = if match[2]
45
- match[2].gsub('\\"', '"')
46
- elsif match[3]
47
- match[3].gsub("\\'", "'")
48
- elsif match[4]
49
- context[match[4]]
39
+ @params.scan(VALID_SYNTAX) do |key, d_quoted, s_quoted, variable|
40
+ value = if d_quoted
41
+ d_quoted.include?('\\"') ? d_quoted.gsub('\\"', '"') : d_quoted
42
+ elsif s_quoted
43
+ s_quoted.include?("\\'") ? s_quoted.gsub("\\'", "'") : s_quoted
44
+ elsif variable
45
+ context[variable]
50
46
  end
51
47
 
52
- params[match[1]] = value
48
+ params[key] = value
53
49
  end
54
50
  params
55
51
  end
@@ -205,7 +201,7 @@ module Jekyll
205
201
  @site.inclusions[file] ||= locate_include_file(file)
206
202
  inclusion = @site.inclusions[file]
207
203
 
208
- add_include_to_dependency(inclusion, context) if @site.incremental?
204
+ add_include_to_dependency(inclusion, context) if @site.config["incremental"]
209
205
 
210
206
  context.stack do
211
207
  context["include"] = parse_params(context) if @params
@@ -253,20 +249,18 @@ module Jekyll
253
249
  end
254
250
 
255
251
  def page_path(context)
256
- if context.registers[:page].nil?
257
- context.registers[:site].source
258
- else
259
- site = context.registers[:site]
260
- page_payload = context.registers[:page]
261
- resource_path = \
262
- if page_payload["collection"].nil?
263
- page_payload["path"]
264
- else
265
- File.join(site.config["collections_dir"], page_payload["path"])
266
- end
267
- resource_path.sub!(%r!/#excerpt\z!, "")
268
- site.in_source_dir File.dirname(resource_path)
269
- end
252
+ page, site = context.registers.values_at(:page, :site)
253
+ return site.source unless page
254
+
255
+ site.in_source_dir File.dirname(resource_path(page, site))
256
+ end
257
+
258
+ private
259
+
260
+ def resource_path(page, site)
261
+ path = page["path"]
262
+ path = File.join(site.config["collections_dir"], path) if page["collection"]
263
+ path.sub(%r!/#excerpt\z!, "")
270
264
  end
271
265
  end
272
266
  end