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.
- checksums.yaml +4 -4
- data/.rubocop.yml +511 -89
- data/LICENSE +1 -1
- data/README.markdown +48 -27
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/base.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll/cache.rb +186 -0
- data/lib/jekyll/cleaner.rb +8 -7
- data/lib/jekyll/collection.rb +84 -11
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +8 -28
- data/lib/jekyll/commands/clean.rb +3 -2
- data/lib/jekyll/commands/doctor.rb +46 -35
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +44 -50
- data/lib/jekyll/commands/new_theme.rb +27 -28
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
- data/lib/jekyll/commands/serve/servlet.rb +21 -22
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/commands/serve.rb +75 -97
- data/lib/jekyll/configuration.rb +66 -158
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +36 -34
- data/lib/jekyll/deprecator.rb +2 -4
- data/lib/jekyll/document.rb +107 -72
- data/lib/jekyll/drops/collection_drop.rb +3 -4
- data/lib/jekyll/drops/document_drop.rb +9 -3
- data/lib/jekyll/drops/drop.rb +115 -33
- data/lib/jekyll/drops/excerpt_drop.rb +8 -0
- data/lib/jekyll/drops/site_drop.rb +9 -8
- data/lib/jekyll/drops/static_file_drop.rb +4 -4
- data/lib/jekyll/drops/theme_drop.rb +39 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
- data/lib/jekyll/drops/url_drop.rb +55 -3
- data/lib/jekyll/entry_filter.rb +42 -51
- data/lib/jekyll/excerpt.rb +48 -38
- data/lib/jekyll/external.rb +20 -19
- data/lib/jekyll/filters/date_filters.rb +6 -3
- data/lib/jekyll/filters/grouping_filters.rb +1 -2
- data/lib/jekyll/filters/url_filters.rb +50 -15
- data/lib/jekyll/filters.rb +211 -50
- data/lib/jekyll/frontmatter_defaults.rb +45 -36
- data/lib/jekyll/hooks.rb +26 -26
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/layout.rb +12 -19
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +26 -77
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/page.rb +51 -23
- data/lib/jekyll/page_excerpt.rb +25 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +74 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +15 -5
- data/lib/jekyll/profiler.rb +51 -0
- data/lib/jekyll/reader.rb +65 -10
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +48 -10
- data/lib/jekyll/readers/layout_reader.rb +3 -12
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +32 -19
- data/lib/jekyll/readers/static_file_reader.rb +4 -4
- data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
- data/lib/jekyll/regenerator.rb +4 -12
- data/lib/jekyll/related_posts.rb +1 -1
- data/lib/jekyll/renderer.rb +34 -49
- data/lib/jekyll/site.rb +151 -58
- data/lib/jekyll/static_file.rb +64 -28
- data/lib/jekyll/stevenson.rb +4 -8
- data/lib/jekyll/tags/highlight.rb +44 -57
- data/lib/jekyll/tags/include.rb +114 -80
- data/lib/jekyll/tags/link.rb +12 -7
- data/lib/jekyll/tags/post_url.rb +33 -30
- data/lib/jekyll/theme.rb +20 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +18 -10
- data/lib/jekyll/utils/ansi.rb +2 -2
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +37 -52
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils.rb +29 -28
- data/lib/jekyll/version.rb +1 -1
- data/lib/jekyll.rb +9 -14
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +2 -1
- data/lib/site_template/_config.yml +17 -5
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
- data/lib/theme_template/README.md.erb +1 -3
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -4
- data/rubocop/jekyll/assert_equal_literal_actual.rb +150 -0
- data/rubocop/jekyll/no_p_allowed.rb +5 -6
- data/rubocop/jekyll/no_puts_allowed.rb +5 -6
- metadata +149 -37
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
- data/lib/jekyll/utils/rouge.rb +0 -22
- /data/lib/site_template/{about.md → about.markdown} +0 -0
- /data/lib/site_template/{index.md → index.markdown} +0 -0
data/lib/jekyll/document.rb
CHANGED
|
@@ -5,14 +5,31 @@ module Jekyll
|
|
|
5
5
|
include Comparable
|
|
6
6
|
extend Forwardable
|
|
7
7
|
|
|
8
|
-
attr_reader :path, :site, :extname, :collection
|
|
8
|
+
attr_reader :path, :site, :extname, :collection, :type
|
|
9
9
|
attr_accessor :content, :output
|
|
10
10
|
|
|
11
11
|
def_delegator :self, :read_post_data, :post_read
|
|
12
12
|
|
|
13
|
-
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
|
|
14
|
-
DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)
|
|
15
|
-
DATE_FILENAME_MATCHER = %r!^(
|
|
13
|
+
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m.freeze
|
|
14
|
+
DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
|
|
15
|
+
DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze
|
|
16
|
+
|
|
17
|
+
SASS_FILE_EXTS = %w(.sass .scss).freeze
|
|
18
|
+
YAML_FILE_EXTS = %w(.yaml .yml).freeze
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
|
|
22
|
+
# Class-wide cache to stash and retrieve regexp to detect "super-directories"
|
|
23
|
+
# of a particular Jekyll::Document object.
|
|
24
|
+
#
|
|
25
|
+
# dirname - The *special directory* for the Document.
|
|
26
|
+
# e.g. "_posts" or "_drafts" for Documents from the `site.posts` collection.
|
|
27
|
+
def self.superdirs_regex(dirname)
|
|
28
|
+
@superdirs_regex ||= {}
|
|
29
|
+
@superdirs_regex[dirname] ||= %r!#{dirname}.*!
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#
|
|
16
33
|
|
|
17
34
|
# Create a new Document.
|
|
18
35
|
#
|
|
@@ -27,6 +44,8 @@ module Jekyll
|
|
|
27
44
|
@path = path
|
|
28
45
|
@extname = File.extname(path)
|
|
29
46
|
@collection = relations[:collection]
|
|
47
|
+
@type = @collection.label.to_sym
|
|
48
|
+
|
|
30
49
|
@has_yaml_header = nil
|
|
31
50
|
|
|
32
51
|
if draft?
|
|
@@ -36,7 +55,7 @@ module Jekyll
|
|
|
36
55
|
end
|
|
37
56
|
|
|
38
57
|
data.default_proc = proc do |_, key|
|
|
39
|
-
site.frontmatter_defaults.find(relative_path,
|
|
58
|
+
site.frontmatter_defaults.find(relative_path, type, key)
|
|
40
59
|
end
|
|
41
60
|
|
|
42
61
|
trigger_hooks(:post_init)
|
|
@@ -60,12 +79,19 @@ module Jekyll
|
|
|
60
79
|
data
|
|
61
80
|
end
|
|
62
81
|
|
|
82
|
+
# Returns the document date. If metadata is not present then calculates it
|
|
83
|
+
# based on Jekyll::Site#time or the document file modification time.
|
|
84
|
+
#
|
|
85
|
+
# Return document date string.
|
|
63
86
|
def date
|
|
64
87
|
data["date"] ||= (draft? ? source_file_mtime : site.time)
|
|
65
88
|
end
|
|
66
89
|
|
|
90
|
+
# Return document file modification time in the form of a Time object.
|
|
91
|
+
#
|
|
92
|
+
# Return document file modification Time object.
|
|
67
93
|
def source_file_mtime
|
|
68
|
-
|
|
94
|
+
File.mtime(path)
|
|
69
95
|
end
|
|
70
96
|
|
|
71
97
|
# Returns whether the document is a draft. This is only the case if
|
|
@@ -90,7 +116,7 @@ module Jekyll
|
|
|
90
116
|
#
|
|
91
117
|
# Returns the output extension
|
|
92
118
|
def output_ext
|
|
93
|
-
|
|
119
|
+
renderer.output_ext
|
|
94
120
|
end
|
|
95
121
|
|
|
96
122
|
# The base filename of the document, without the file extname.
|
|
@@ -107,27 +133,35 @@ module Jekyll
|
|
|
107
133
|
@basename ||= File.basename(path)
|
|
108
134
|
end
|
|
109
135
|
|
|
136
|
+
def renderer
|
|
137
|
+
@renderer ||= Jekyll::Renderer.new(site, self)
|
|
138
|
+
end
|
|
139
|
+
|
|
110
140
|
# Produces a "cleaned" relative path.
|
|
111
141
|
# The "cleaned" relative path is the relative path without the extname
|
|
112
142
|
# and with the collection's directory removed as well.
|
|
113
143
|
# This method is useful when building the URL of the document.
|
|
114
144
|
#
|
|
145
|
+
# NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`)
|
|
146
|
+
#
|
|
115
147
|
# Examples:
|
|
116
|
-
# When relative_path is "_methods/site/generate
|
|
148
|
+
# When relative_path is "_methods/site/generate...md":
|
|
117
149
|
# cleaned_relative_path
|
|
118
150
|
# # => "/site/generate"
|
|
119
151
|
#
|
|
120
152
|
# Returns the cleaned relative path of the document.
|
|
121
153
|
def cleaned_relative_path
|
|
122
154
|
@cleaned_relative_path ||=
|
|
123
|
-
relative_path[0..-extname.length - 1]
|
|
155
|
+
relative_path[0..-extname.length - 1]
|
|
156
|
+
.sub(collection.relative_directory, "")
|
|
157
|
+
.gsub(%r!\.*\z!, "")
|
|
124
158
|
end
|
|
125
159
|
|
|
126
160
|
# Determine whether the document is a YAML file.
|
|
127
161
|
#
|
|
128
162
|
# Returns true if the extname is either .yml or .yaml, false otherwise.
|
|
129
163
|
def yaml_file?
|
|
130
|
-
|
|
164
|
+
YAML_FILE_EXTS.include?(extname)
|
|
131
165
|
end
|
|
132
166
|
|
|
133
167
|
# Determine whether the document is an asset file.
|
|
@@ -143,7 +177,7 @@ module Jekyll
|
|
|
143
177
|
#
|
|
144
178
|
# Returns true if extname == .sass or .scss, false otherwise.
|
|
145
179
|
def sass_file?
|
|
146
|
-
|
|
180
|
+
SASS_FILE_EXTS.include?(extname)
|
|
147
181
|
end
|
|
148
182
|
|
|
149
183
|
# Determine whether the document is a CoffeeScript file.
|
|
@@ -159,6 +193,8 @@ module Jekyll
|
|
|
159
193
|
# or if the document doesn't contain any Liquid Tags or Variables,
|
|
160
194
|
# true otherwise.
|
|
161
195
|
def render_with_liquid?
|
|
196
|
+
return false if data["render_with_liquid"] == false
|
|
197
|
+
|
|
162
198
|
!(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
|
|
163
199
|
end
|
|
164
200
|
|
|
@@ -204,11 +240,11 @@ module Jekyll
|
|
|
204
240
|
#
|
|
205
241
|
# Returns the computed URL for the document.
|
|
206
242
|
def url
|
|
207
|
-
@url ||= URL.new(
|
|
243
|
+
@url ||= URL.new(
|
|
208
244
|
:template => url_template,
|
|
209
245
|
:placeholders => url_placeholders,
|
|
210
|
-
:permalink => permalink
|
|
211
|
-
|
|
246
|
+
:permalink => permalink
|
|
247
|
+
).to_s
|
|
212
248
|
end
|
|
213
249
|
|
|
214
250
|
def [](key)
|
|
@@ -221,14 +257,16 @@ module Jekyll
|
|
|
221
257
|
#
|
|
222
258
|
# Returns the full path to the output file of this document.
|
|
223
259
|
def destination(base_directory)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
260
|
+
@destination ||= {}
|
|
261
|
+
@destination[base_directory] ||= begin
|
|
262
|
+
path = site.in_dest_dir(base_directory, URL.unescape_path(url))
|
|
263
|
+
if url.end_with? "/"
|
|
264
|
+
path = File.join(path, "index.html")
|
|
265
|
+
else
|
|
266
|
+
path << output_ext unless path.end_with? output_ext
|
|
267
|
+
end
|
|
268
|
+
path
|
|
230
269
|
end
|
|
231
|
-
path
|
|
232
270
|
end
|
|
233
271
|
|
|
234
272
|
# Write the generated Document file to the destination directory.
|
|
@@ -286,7 +324,7 @@ module Jekyll
|
|
|
286
324
|
#
|
|
287
325
|
# Returns the inspect string for this document.
|
|
288
326
|
def inspect
|
|
289
|
-
"
|
|
327
|
+
"#<#{self.class} #{relative_path} collection=#{collection.label}>"
|
|
290
328
|
end
|
|
291
329
|
|
|
292
330
|
# The string representation for this document.
|
|
@@ -303,6 +341,7 @@ module Jekyll
|
|
|
303
341
|
# equal or greater than the other doc's path. See String#<=> for more details.
|
|
304
342
|
def <=>(other)
|
|
305
343
|
return nil unless other.respond_to?(:data)
|
|
344
|
+
|
|
306
345
|
cmp = data["date"] <=> other.data["date"]
|
|
307
346
|
cmp = path <=> other.path if cmp.nil? || cmp.zero?
|
|
308
347
|
cmp
|
|
@@ -314,16 +353,21 @@ module Jekyll
|
|
|
314
353
|
# True if the document has a collection and if that collection's #write?
|
|
315
354
|
# method returns true, and if the site's Publisher will publish the document.
|
|
316
355
|
# False otherwise.
|
|
356
|
+
#
|
|
357
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
317
358
|
def write?
|
|
318
|
-
|
|
359
|
+
return @write_p if defined?(@write_p)
|
|
360
|
+
|
|
361
|
+
@write_p = collection&.write? && site.publisher.publish?(self)
|
|
319
362
|
end
|
|
363
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
320
364
|
|
|
321
365
|
# The Document excerpt_separator, from the YAML Front-Matter or site
|
|
322
366
|
# default excerpt_separator value
|
|
323
367
|
#
|
|
324
368
|
# Returns the document excerpt_separator
|
|
325
369
|
def excerpt_separator
|
|
326
|
-
(data["excerpt_separator"] || site.config["excerpt_separator"]).to_s
|
|
370
|
+
@excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s
|
|
327
371
|
end
|
|
328
372
|
|
|
329
373
|
# Whether to generate an excerpt
|
|
@@ -335,16 +379,12 @@ module Jekyll
|
|
|
335
379
|
|
|
336
380
|
def next_doc
|
|
337
381
|
pos = collection.docs.index { |post| post.equal?(self) }
|
|
338
|
-
if pos && pos < collection.docs.length - 1
|
|
339
|
-
collection.docs[pos + 1]
|
|
340
|
-
end
|
|
382
|
+
collection.docs[pos + 1] if pos && pos < collection.docs.length - 1
|
|
341
383
|
end
|
|
342
384
|
|
|
343
385
|
def previous_doc
|
|
344
386
|
pos = collection.docs.index { |post| post.equal?(self) }
|
|
345
|
-
if pos && pos
|
|
346
|
-
collection.docs[pos - 1]
|
|
347
|
-
end
|
|
387
|
+
collection.docs[pos - 1] if pos && pos.positive?
|
|
348
388
|
end
|
|
349
389
|
|
|
350
390
|
def trigger_hooks(hook_name, *args)
|
|
@@ -363,18 +403,11 @@ module Jekyll
|
|
|
363
403
|
@related_posts ||= Jekyll::RelatedPosts.new(self).build
|
|
364
404
|
end
|
|
365
405
|
|
|
366
|
-
# Override of normal respond_to? to match method_missing's logic for
|
|
367
|
-
# looking in @data.
|
|
368
|
-
def respond_to?(method, include_private = false)
|
|
369
|
-
data.key?(method.to_s) || super
|
|
370
|
-
end
|
|
371
|
-
|
|
372
406
|
# Override of method_missing to check in @data for the key.
|
|
373
407
|
def method_missing(method, *args, &blck)
|
|
374
408
|
if data.key?(method.to_s)
|
|
375
|
-
Jekyll::Deprecator.deprecation_message "Document##{method} is now a key "
|
|
376
|
-
|
|
377
|
-
Jekyll::Deprecator.deprecation_message "Called by #{caller(0..0)}."
|
|
409
|
+
Jekyll::Deprecator.deprecation_message "Document##{method} is now a key in the #data hash."
|
|
410
|
+
Jekyll.logger.warn "", "Called by #{caller(1..1)[0]}."
|
|
378
411
|
data[method.to_s]
|
|
379
412
|
else
|
|
380
413
|
super
|
|
@@ -391,41 +424,47 @@ module Jekyll
|
|
|
391
424
|
#
|
|
392
425
|
# Returns nothing.
|
|
393
426
|
def categories_from_path(special_dir)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
427
|
+
if relative_path.start_with?(special_dir)
|
|
428
|
+
superdirs = []
|
|
429
|
+
else
|
|
430
|
+
superdirs = relative_path.sub(Document.superdirs_regex(special_dir), "")
|
|
431
|
+
superdirs = superdirs.split(File::SEPARATOR)
|
|
432
|
+
superdirs.reject! { |c| c.empty? || c == special_dir || c == basename }
|
|
398
433
|
end
|
|
434
|
+
|
|
399
435
|
merge_data!({ "categories" => superdirs }, :source => "file path")
|
|
400
436
|
end
|
|
401
437
|
|
|
402
438
|
def populate_categories
|
|
403
|
-
|
|
404
|
-
"categories"
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
439
|
+
categories = Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
|
440
|
+
data, "category", "categories"
|
|
441
|
+
)
|
|
442
|
+
categories.map!(&:to_s)
|
|
443
|
+
categories.flatten!
|
|
444
|
+
categories.uniq!
|
|
445
|
+
|
|
446
|
+
merge_data!({ "categories" => categories })
|
|
410
447
|
end
|
|
411
448
|
|
|
412
449
|
def populate_tags
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
450
|
+
tags = Utils.pluralized_array_from_hash(data, "tag", "tags")
|
|
451
|
+
tags.flatten!
|
|
452
|
+
|
|
453
|
+
merge_data!({ "tags" => tags })
|
|
416
454
|
end
|
|
417
455
|
|
|
418
456
|
private
|
|
457
|
+
|
|
419
458
|
def merge_categories!(other)
|
|
420
459
|
if other.key?("categories") && !other["categories"].nil?
|
|
421
|
-
if other["categories"].is_a?(String)
|
|
422
|
-
|
|
460
|
+
other["categories"] = other["categories"].split if other["categories"].is_a?(String)
|
|
461
|
+
|
|
462
|
+
if data["categories"].is_a?(Array)
|
|
463
|
+
other["categories"] = data["categories"] | other["categories"]
|
|
423
464
|
end
|
|
424
|
-
other["categories"] = (data["categories"] || []) | other["categories"]
|
|
425
465
|
end
|
|
426
466
|
end
|
|
427
467
|
|
|
428
|
-
private
|
|
429
468
|
def merge_date!(source)
|
|
430
469
|
if data.key?("date")
|
|
431
470
|
data["date"] = Utils.parse_date(
|
|
@@ -435,26 +474,20 @@ module Jekyll
|
|
|
435
474
|
end
|
|
436
475
|
end
|
|
437
476
|
|
|
438
|
-
private
|
|
439
477
|
def merge_defaults
|
|
440
|
-
defaults = @site.frontmatter_defaults.all(
|
|
441
|
-
relative_path,
|
|
442
|
-
collection.label.to_sym
|
|
443
|
-
)
|
|
478
|
+
defaults = @site.frontmatter_defaults.all(relative_path, type)
|
|
444
479
|
merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
|
|
445
480
|
end
|
|
446
481
|
|
|
447
|
-
private
|
|
448
482
|
def read_content(**opts)
|
|
449
483
|
self.content = File.read(path, **Utils.merged_file_read_opts(site, opts))
|
|
450
484
|
if content =~ YAML_FRONT_MATTER_REGEXP
|
|
451
|
-
self.content =
|
|
485
|
+
self.content = Regexp.last_match.post_match
|
|
452
486
|
data_file = SafeYAML.load(Regexp.last_match(1))
|
|
453
487
|
merge_data!(data_file, :source => "YAML front matter") if data_file
|
|
454
488
|
end
|
|
455
489
|
end
|
|
456
490
|
|
|
457
|
-
private
|
|
458
491
|
def read_post_data
|
|
459
492
|
populate_title
|
|
460
493
|
populate_categories
|
|
@@ -462,7 +495,6 @@ module Jekyll
|
|
|
462
495
|
generate_excerpt
|
|
463
496
|
end
|
|
464
497
|
|
|
465
|
-
private
|
|
466
498
|
def handle_read_error(error)
|
|
467
499
|
if error.is_a? Psych::SyntaxError
|
|
468
500
|
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}"
|
|
@@ -475,7 +507,6 @@ module Jekyll
|
|
|
475
507
|
end
|
|
476
508
|
end
|
|
477
509
|
|
|
478
|
-
private
|
|
479
510
|
def populate_title
|
|
480
511
|
if relative_path =~ DATE_FILENAME_MATCHER
|
|
481
512
|
date, slug, ext = Regexp.last_match.captures
|
|
@@ -483,6 +514,14 @@ module Jekyll
|
|
|
483
514
|
elsif relative_path =~ DATELESS_FILENAME_MATCHER
|
|
484
515
|
slug, ext = Regexp.last_match.captures
|
|
485
516
|
end
|
|
517
|
+
# `slug` will be nil for documents without an extension since the regex patterns
|
|
518
|
+
# above tests for an extension as well.
|
|
519
|
+
# In such cases, assign `basename_without_ext` as the slug.
|
|
520
|
+
slug ||= basename_without_ext
|
|
521
|
+
|
|
522
|
+
# slugs shouldn't end with a period
|
|
523
|
+
# `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
|
|
524
|
+
slug.gsub!(%r!\.*\z!, "")
|
|
486
525
|
|
|
487
526
|
# Try to ensure the user gets a title.
|
|
488
527
|
data["title"] ||= Utils.titleize_slug(slug)
|
|
@@ -491,18 +530,14 @@ module Jekyll
|
|
|
491
530
|
data["ext"] ||= ext
|
|
492
531
|
end
|
|
493
532
|
|
|
494
|
-
private
|
|
495
533
|
def modify_date(date)
|
|
496
534
|
if !data["date"] || data["date"].to_i == site.time.to_i
|
|
497
535
|
merge_data!({ "date" => date }, :source => "filename")
|
|
498
536
|
end
|
|
499
537
|
end
|
|
500
538
|
|
|
501
|
-
private
|
|
502
539
|
def generate_excerpt
|
|
503
|
-
if generate_excerpt?
|
|
504
|
-
data["excerpt"] ||= Jekyll::Excerpt.new(self)
|
|
505
|
-
end
|
|
540
|
+
data["excerpt"] ||= Jekyll::Excerpt.new(self) if generate_excerpt?
|
|
506
541
|
end
|
|
507
542
|
end
|
|
508
543
|
end
|
|
@@ -7,11 +7,10 @@ module Jekyll
|
|
|
7
7
|
|
|
8
8
|
mutable false
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
:relative_directory
|
|
10
|
+
delegate_method_as :write?, :output
|
|
11
|
+
delegate_methods :label, :docs, :files, :directory, :relative_directory
|
|
13
12
|
|
|
14
|
-
private
|
|
13
|
+
private delegate_method_as :metadata, :fallback_data
|
|
15
14
|
|
|
16
15
|
def to_s
|
|
17
16
|
docs.to_s
|
|
@@ -11,10 +11,11 @@ module Jekyll
|
|
|
11
11
|
|
|
12
12
|
mutable false
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
delegate_method_as :relative_path, :path
|
|
15
|
+
private delegate_method_as :data, :fallback_data
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date
|
|
18
|
+
data_delegators "title", "categories", "tags"
|
|
18
19
|
|
|
19
20
|
def collection
|
|
20
21
|
@obj.collection.label
|
|
@@ -24,8 +25,13 @@ module Jekyll
|
|
|
24
25
|
fallback_data["excerpt"].to_s
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
def name
|
|
29
|
+
fallback_data["name"] || @obj.basename
|
|
30
|
+
end
|
|
31
|
+
|
|
27
32
|
def <=>(other)
|
|
28
33
|
return nil unless other.is_a? DocumentDrop
|
|
34
|
+
|
|
29
35
|
cmp = self["date"] <=> other["date"]
|
|
30
36
|
cmp = self["path"] <=> other["path"] if cmp.nil? || cmp.zero?
|
|
31
37
|
cmp
|
data/lib/jekyll/drops/drop.rb
CHANGED
|
@@ -6,24 +6,101 @@ module Jekyll
|
|
|
6
6
|
include Enumerable
|
|
7
7
|
|
|
8
8
|
NON_CONTENT_METHODS = [:fallback_data, :collapse_document].freeze
|
|
9
|
+
NON_CONTENT_METHOD_NAMES = NON_CONTENT_METHODS.map(&:to_s).freeze
|
|
10
|
+
private_constant :NON_CONTENT_METHOD_NAMES
|
|
9
11
|
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
# A private stash to avoid repeatedly generating the setter method name string for
|
|
13
|
+
# a call to `Drops::Drop#[]=`.
|
|
14
|
+
# The keys of the stash below have a very high probability of being called upon during
|
|
15
|
+
# the course of various `Jekyll::Renderer#run` calls.
|
|
16
|
+
SETTER_KEYS_STASH = {
|
|
17
|
+
"content" => "content=",
|
|
18
|
+
"layout" => "layout=",
|
|
19
|
+
"page" => "page=",
|
|
20
|
+
"paginator" => "paginator=",
|
|
21
|
+
"highlighter_prefix" => "highlighter_prefix=",
|
|
22
|
+
"highlighter_suffix" => "highlighter_suffix=",
|
|
23
|
+
}.freeze
|
|
24
|
+
private_constant :SETTER_KEYS_STASH
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
# Get or set whether the drop class is mutable.
|
|
28
|
+
# Mutability determines whether or not pre-defined fields may be
|
|
29
|
+
# overwritten.
|
|
30
|
+
#
|
|
31
|
+
# is_mutable - Boolean set mutability of the class (default: nil)
|
|
32
|
+
#
|
|
33
|
+
# Returns the mutability of the class
|
|
34
|
+
def mutable(is_mutable = nil)
|
|
35
|
+
@is_mutable = is_mutable || false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def mutable?
|
|
39
|
+
@is_mutable
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# public delegation helper methods that calls onto Drop's instance
|
|
43
|
+
# variable `@obj`.
|
|
24
44
|
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
# Generate private Drop instance_methods for each symbol in the given list.
|
|
46
|
+
#
|
|
47
|
+
# Returns nothing.
|
|
48
|
+
def private_delegate_methods(*symbols)
|
|
49
|
+
symbols.each { |symbol| private delegate_method(symbol) }
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Generate public Drop instance_methods for each symbol in the given list.
|
|
54
|
+
#
|
|
55
|
+
# Returns nothing.
|
|
56
|
+
def delegate_methods(*symbols)
|
|
57
|
+
symbols.each { |symbol| delegate_method(symbol) }
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Generate public Drop instance_method for given symbol that calls `@obj.<sym>`.
|
|
62
|
+
#
|
|
63
|
+
# Returns delegated method symbol.
|
|
64
|
+
def delegate_method(symbol)
|
|
65
|
+
define_method(symbol) { @obj.send(symbol) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Generate public Drop instance_method named `delegate` that calls `@obj.<original>`.
|
|
69
|
+
#
|
|
70
|
+
# Returns delegated method symbol.
|
|
71
|
+
def delegate_method_as(original, delegate)
|
|
72
|
+
define_method(delegate) { @obj.send(original) }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Generate public Drop instance_methods for each string entry in the given list.
|
|
76
|
+
# The generated method(s) access(es) `@obj`'s data hash.
|
|
77
|
+
#
|
|
78
|
+
# Returns nothing.
|
|
79
|
+
def data_delegators(*strings)
|
|
80
|
+
strings.each do |key|
|
|
81
|
+
data_delegator(key) if key.is_a?(String)
|
|
82
|
+
end
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Generate public Drop instance_methods for given string `key`.
|
|
87
|
+
# The generated method access(es) `@obj`'s data hash.
|
|
88
|
+
#
|
|
89
|
+
# Returns method symbol.
|
|
90
|
+
def data_delegator(key)
|
|
91
|
+
define_method(key.to_sym) { @obj.data[key] }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Array of stringified instance methods that do not end with the assignment operator.
|
|
95
|
+
#
|
|
96
|
+
# (<klass>.instance_methods always generates a new Array object so it can be mutated)
|
|
97
|
+
#
|
|
98
|
+
# Returns array of strings.
|
|
99
|
+
def getter_method_names
|
|
100
|
+
@getter_method_names ||= instance_methods.map!(&:to_s).tap do |list|
|
|
101
|
+
list.reject! { |item| item.end_with?("=") }
|
|
102
|
+
end
|
|
103
|
+
end
|
|
27
104
|
end
|
|
28
105
|
|
|
29
106
|
# Create a new Drop
|
|
@@ -34,7 +111,6 @@ module Jekyll
|
|
|
34
111
|
# Returns nothing
|
|
35
112
|
def initialize(obj)
|
|
36
113
|
@obj = obj
|
|
37
|
-
@mutations = {} # only if mutable: true
|
|
38
114
|
end
|
|
39
115
|
|
|
40
116
|
# Access a method in the Drop or a field in the underlying hash data.
|
|
@@ -46,8 +122,8 @@ module Jekyll
|
|
|
46
122
|
#
|
|
47
123
|
# Returns the value for the given key, or nil if none exists
|
|
48
124
|
def [](key)
|
|
49
|
-
if self.class.mutable? &&
|
|
50
|
-
|
|
125
|
+
if self.class.mutable? && mutations.key?(key)
|
|
126
|
+
mutations[key]
|
|
51
127
|
elsif self.class.invokable? key
|
|
52
128
|
public_send key
|
|
53
129
|
else
|
|
@@ -70,11 +146,12 @@ module Jekyll
|
|
|
70
146
|
# and the key matches a method in which case it raises a
|
|
71
147
|
# DropMutationException.
|
|
72
148
|
def []=(key, val)
|
|
73
|
-
|
|
74
|
-
|
|
149
|
+
setter = SETTER_KEYS_STASH[key] || "#{key}="
|
|
150
|
+
if respond_to?(setter)
|
|
151
|
+
public_send(setter, val)
|
|
75
152
|
elsif respond_to?(key.to_s)
|
|
76
153
|
if self.class.mutable?
|
|
77
|
-
|
|
154
|
+
mutations[key] = val
|
|
78
155
|
else
|
|
79
156
|
raise Errors::DropMutationException, "Key #{key} cannot be set in the drop."
|
|
80
157
|
end
|
|
@@ -88,13 +165,10 @@ module Jekyll
|
|
|
88
165
|
#
|
|
89
166
|
# Returns an Array of strings which represent method-specific keys.
|
|
90
167
|
def content_methods
|
|
91
|
-
@content_methods ||=
|
|
92
|
-
self.class.
|
|
93
|
-
- Jekyll::Drops::Drop.
|
|
94
|
-
-
|
|
95
|
-
).map(&:to_s).reject do |method|
|
|
96
|
-
method.end_with?("=")
|
|
97
|
-
end
|
|
168
|
+
@content_methods ||= \
|
|
169
|
+
self.class.getter_method_names \
|
|
170
|
+
- Jekyll::Drops::Drop.getter_method_names \
|
|
171
|
+
- NON_CONTENT_METHOD_NAMES
|
|
98
172
|
end
|
|
99
173
|
|
|
100
174
|
# Check if key exists in Drop
|
|
@@ -104,7 +178,8 @@ module Jekyll
|
|
|
104
178
|
# Returns true if the given key is present
|
|
105
179
|
def key?(key)
|
|
106
180
|
return false if key.nil?
|
|
107
|
-
return true if self.class.mutable? &&
|
|
181
|
+
return true if self.class.mutable? && mutations.key?(key)
|
|
182
|
+
|
|
108
183
|
respond_to?(key) || fallback_data.key?(key)
|
|
109
184
|
end
|
|
110
185
|
|
|
@@ -116,7 +191,7 @@ module Jekyll
|
|
|
116
191
|
# Returns an Array of unique keys for content for the Drop.
|
|
117
192
|
def keys
|
|
118
193
|
(content_methods |
|
|
119
|
-
|
|
194
|
+
mutations.keys |
|
|
120
195
|
fallback_data.keys).flatten
|
|
121
196
|
end
|
|
122
197
|
|
|
@@ -173,7 +248,7 @@ module Jekyll
|
|
|
173
248
|
end
|
|
174
249
|
|
|
175
250
|
def merge(other, &block)
|
|
176
|
-
|
|
251
|
+
dup.tap do |me|
|
|
177
252
|
if block.nil?
|
|
178
253
|
me.merge!(other)
|
|
179
254
|
else
|
|
@@ -205,7 +280,14 @@ module Jekyll
|
|
|
205
280
|
return self[key] if key?(key)
|
|
206
281
|
raise KeyError, %(key not found: "#{key}") if default.nil? && block.nil?
|
|
207
282
|
return yield(key) unless block.nil?
|
|
208
|
-
|
|
283
|
+
|
|
284
|
+
default unless default.nil?
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
private
|
|
288
|
+
|
|
289
|
+
def mutations
|
|
290
|
+
@mutations ||= {}
|
|
209
291
|
end
|
|
210
292
|
end
|
|
211
293
|
end
|