jekyll 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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