jekyll 3.2.1 → 3.3.0.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jekyll might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -4
- data/exe/jekyll +1 -1
- data/lib/jekyll.rb +5 -3
- data/lib/jekyll/commands/build.rb +16 -5
- data/lib/jekyll/commands/new.rb +30 -4
- data/lib/jekyll/commands/new_theme.rb +4 -2
- data/lib/jekyll/commands/serve.rb +35 -10
- data/lib/jekyll/configuration.rb +1 -1
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -1
- data/lib/jekyll/convertible.rb +21 -82
- data/lib/jekyll/document.rb +116 -79
- data/lib/jekyll/excerpt.rb +1 -1
- data/lib/jekyll/filters.rb +3 -0
- data/lib/jekyll/filters/url_filters.rb +40 -0
- data/lib/jekyll/hooks.rb +2 -2
- data/lib/jekyll/page.rb +5 -1
- data/lib/jekyll/reader.rb +1 -0
- data/lib/jekyll/readers/theme_assets_reader.rb +47 -0
- data/lib/jekyll/renderer.rb +26 -6
- data/lib/jekyll/site.rb +10 -1
- data/lib/jekyll/static_file.rb +7 -2
- data/lib/jekyll/tags/highlight.rb +1 -1
- data/lib/jekyll/tags/link.rb +4 -2
- data/lib/jekyll/tags/post_url.rb +3 -2
- data/lib/jekyll/theme.rb +8 -4
- data/lib/jekyll/theme_builder.rb +1 -1
- data/lib/jekyll/utils.rb +13 -1
- data/lib/jekyll/utils/platforms.rb +39 -2
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/_config.yml +7 -2
- data/lib/site_template/index.md +6 -0
- data/lib/theme_template/README.md.erb +1 -1
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -1
- metadata +21 -7
- data/lib/site_template/css/main.scss +0 -39
- data/lib/site_template/feed.xml +0 -30
- data/lib/site_template/index.html +0 -23
data/lib/jekyll/document.rb
CHANGED
@@ -51,19 +51,9 @@ module Jekyll
|
|
51
51
|
#
|
52
52
|
# Returns the merged data.
|
53
53
|
def merge_data!(other, source: "YAML front matter")
|
54
|
-
|
55
|
-
if other["categories"].is_a?(String)
|
56
|
-
other["categories"] = other["categories"].split(" ").map(&:strip)
|
57
|
-
end
|
58
|
-
other["categories"] = (data["categories"] || []) | other["categories"]
|
59
|
-
end
|
54
|
+
merge_categories!(other)
|
60
55
|
Utils.deep_merge_hashes!(data, other)
|
61
|
-
|
62
|
-
data["date"] = Utils.parse_date(
|
63
|
-
data["date"].to_s,
|
64
|
-
"Document '#{relative_path}' does not have a valid date in the #{source}."
|
65
|
-
)
|
66
|
-
end
|
56
|
+
merge_date!(source)
|
67
57
|
data
|
68
58
|
end
|
69
59
|
|
@@ -90,8 +80,7 @@ module Jekyll
|
|
90
80
|
# Returns a String path which represents the relative path
|
91
81
|
# from the site source to this document
|
92
82
|
def relative_path
|
93
|
-
@relative_path ||=
|
94
|
-
.relative_path_from(Pathname.new(site.source)).to_s
|
83
|
+
@relative_path ||= Pathutil.new(path).relative_path_from(site.source).to_s
|
95
84
|
end
|
96
85
|
|
97
86
|
# The output extension of the document.
|
@@ -264,20 +253,9 @@ module Jekyll
|
|
264
253
|
@data = SafeYAML.load_file(path)
|
265
254
|
else
|
266
255
|
begin
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
)
|
271
|
-
merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
|
272
|
-
|
273
|
-
self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
|
274
|
-
if content =~ YAML_FRONT_MATTER_REGEXP
|
275
|
-
self.content = $POSTMATCH
|
276
|
-
data_file = SafeYAML.load(Regexp.last_match(1))
|
277
|
-
merge_data!(data_file, :source => "YAML front matter") if data_file
|
278
|
-
end
|
279
|
-
|
280
|
-
post_read
|
256
|
+
merge_defaults
|
257
|
+
read_content(opts)
|
258
|
+
read_post_data
|
281
259
|
rescue SyntaxError => e
|
282
260
|
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{e.message}"
|
283
261
|
rescue => e
|
@@ -287,56 +265,6 @@ module Jekyll
|
|
287
265
|
end
|
288
266
|
end
|
289
267
|
|
290
|
-
def post_read
|
291
|
-
if relative_path =~ DATE_FILENAME_MATCHER
|
292
|
-
date, slug, ext = Regexp.last_match.captures
|
293
|
-
if !data["date"] || data["date"].to_i == site.time.to_i
|
294
|
-
merge_data!({ "date" => date }, :source => "filename")
|
295
|
-
end
|
296
|
-
elsif relative_path =~ DATELESS_FILENAME_MATCHER
|
297
|
-
slug, ext = Regexp.last_match.captures
|
298
|
-
end
|
299
|
-
|
300
|
-
# Try to ensure the user gets a title.
|
301
|
-
data["title"] ||= Utils.titleize_slug(slug)
|
302
|
-
# Only overwrite slug & ext if they aren't specified.
|
303
|
-
data["slug"] ||= slug
|
304
|
-
data["ext"] ||= ext
|
305
|
-
|
306
|
-
populate_categories
|
307
|
-
populate_tags
|
308
|
-
generate_excerpt
|
309
|
-
end
|
310
|
-
|
311
|
-
# Add superdirectories of the special_dir to categories.
|
312
|
-
# In the case of es/_posts, 'es' is added as a category.
|
313
|
-
# In the case of _posts/es, 'es' is NOT added as a category.
|
314
|
-
#
|
315
|
-
# Returns nothing.
|
316
|
-
def categories_from_path(special_dir)
|
317
|
-
superdirs = relative_path.sub(%r!#{special_dir}(.*)!, "")
|
318
|
-
.split(File::SEPARATOR)
|
319
|
-
.reject do |c|
|
320
|
-
c.empty? || c.eql?(special_dir) || c.eql?(basename)
|
321
|
-
end
|
322
|
-
merge_data!({ "categories" => superdirs }, :source => "file path")
|
323
|
-
end
|
324
|
-
|
325
|
-
def populate_categories
|
326
|
-
merge_data!({
|
327
|
-
"categories" => (
|
328
|
-
Array(data["categories"]) +
|
329
|
-
Utils.pluralized_array_from_hash(data, "category", "categories")
|
330
|
-
).map(&:to_s).flatten.uniq
|
331
|
-
})
|
332
|
-
end
|
333
|
-
|
334
|
-
def populate_tags
|
335
|
-
merge_data!({
|
336
|
-
"tags" => Utils.pluralized_array_from_hash(data, "tag", "tags").flatten
|
337
|
-
})
|
338
|
-
end
|
339
|
-
|
340
268
|
# Create a Liquid-understandable version of this Document.
|
341
269
|
#
|
342
270
|
# Returns a Hash representing this Document's data.
|
@@ -443,7 +371,116 @@ module Jekyll
|
|
443
371
|
end
|
444
372
|
end
|
445
373
|
|
446
|
-
|
374
|
+
def respond_to_missing?(method, *)
|
375
|
+
data.key?(method.to_s) || super
|
376
|
+
end
|
377
|
+
|
378
|
+
private
|
379
|
+
def merge_categories!(other)
|
380
|
+
if other.key?("categories") && !other["categories"].nil?
|
381
|
+
if other["categories"].is_a?(String)
|
382
|
+
other["categories"] = other["categories"].split(%r!\s+!).map(&:strip)
|
383
|
+
end
|
384
|
+
other["categories"] = (data["categories"] || []) | other["categories"]
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
private
|
389
|
+
def merge_date!(source)
|
390
|
+
if data.key?("date") && !data["date"].is_a?(Time)
|
391
|
+
data["date"] = Utils.parse_date(
|
392
|
+
data["date"].to_s,
|
393
|
+
"Document '#{relative_path}' does not have a valid date in the #{source}."
|
394
|
+
)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
private
|
399
|
+
def merge_defaults
|
400
|
+
defaults = @site.frontmatter_defaults.all(
|
401
|
+
relative_path,
|
402
|
+
collection.label.to_sym
|
403
|
+
)
|
404
|
+
merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
|
405
|
+
end
|
406
|
+
|
407
|
+
private
|
408
|
+
def read_content(opts)
|
409
|
+
self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
|
410
|
+
if content =~ YAML_FRONT_MATTER_REGEXP
|
411
|
+
self.content = $POSTMATCH
|
412
|
+
data_file = SafeYAML.load(Regexp.last_match(1))
|
413
|
+
merge_data!(data_file, :source => "YAML front matter") if data_file
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
private
|
418
|
+
def read_post_data
|
419
|
+
populate_title
|
420
|
+
populate_categories
|
421
|
+
populate_tags
|
422
|
+
generate_excerpt
|
423
|
+
end
|
424
|
+
|
425
|
+
private
|
426
|
+
def populate_title
|
427
|
+
if relative_path =~ DATE_FILENAME_MATCHER
|
428
|
+
date, slug, ext = Regexp.last_match.captures
|
429
|
+
modify_date(date)
|
430
|
+
elsif relative_path =~ DATELESS_FILENAME_MATCHER
|
431
|
+
slug, ext = Regexp.last_match.captures
|
432
|
+
end
|
433
|
+
|
434
|
+
# Try to ensure the user gets a title.
|
435
|
+
data["title"] ||= Utils.titleize_slug(slug)
|
436
|
+
# Only overwrite slug & ext if they aren't specified.
|
437
|
+
data["slug"] ||= slug
|
438
|
+
data["ext"] ||= ext
|
439
|
+
end
|
440
|
+
|
441
|
+
private
|
442
|
+
def modify_date(date)
|
443
|
+
if !data["date"] || data["date"].to_i == site.time.to_i
|
444
|
+
merge_data!({ "date" => date }, :source => "filename")
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
# Add superdirectories of the special_dir to categories.
|
449
|
+
# In the case of es/_posts, 'es' is added as a category.
|
450
|
+
# In the case of _posts/es, 'es' is NOT added as a category.
|
451
|
+
#
|
452
|
+
# Returns nothing.
|
453
|
+
private
|
454
|
+
def categories_from_path(special_dir)
|
455
|
+
superdirs = relative_path.sub(%r!#{special_dir}(.*)!, "")
|
456
|
+
.split(File::SEPARATOR)
|
457
|
+
.reject do |c|
|
458
|
+
c.empty? || c == special_dir || c == basename
|
459
|
+
end
|
460
|
+
merge_data!({ "categories" => superdirs }, :source => "file path")
|
461
|
+
end
|
462
|
+
|
463
|
+
private
|
464
|
+
def populate_categories
|
465
|
+
merge_data!({
|
466
|
+
"categories" => (
|
467
|
+
Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
468
|
+
data,
|
469
|
+
"category",
|
470
|
+
"categories"
|
471
|
+
)
|
472
|
+
).map(&:to_s).flatten.uniq
|
473
|
+
})
|
474
|
+
end
|
475
|
+
|
476
|
+
private
|
477
|
+
def populate_tags
|
478
|
+
merge_data!({
|
479
|
+
"tags" => Utils.pluralized_array_from_hash(data, "tag", "tags").flatten
|
480
|
+
})
|
481
|
+
end
|
482
|
+
|
483
|
+
private
|
447
484
|
def generate_excerpt
|
448
485
|
if generate_excerpt?
|
449
486
|
data["excerpt"] ||= Jekyll::Excerpt.new(self)
|
data/lib/jekyll/excerpt.rb
CHANGED
data/lib/jekyll/filters.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "addressable/uri"
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
module URLFilters
|
6
|
+
# Produces an absolute URL based on site.url and site.baseurl.
|
7
|
+
#
|
8
|
+
# input - the URL to make absolute.
|
9
|
+
#
|
10
|
+
# Returns the absolute URL as a String.
|
11
|
+
def absolute_url(input)
|
12
|
+
return if input.nil?
|
13
|
+
site = @context.registers[:site]
|
14
|
+
return relative_url(input).to_s if site.config["url"].nil?
|
15
|
+
Addressable::URI.parse(site.config["url"] + relative_url(input)).normalize.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# Produces a URL relative to the domain root based on site.baseurl.
|
19
|
+
#
|
20
|
+
# input - the URL to make relative to the domain root
|
21
|
+
#
|
22
|
+
# Returns a URL relative to the domain root as a String.
|
23
|
+
def relative_url(input)
|
24
|
+
return if input.nil?
|
25
|
+
site = @context.registers[:site]
|
26
|
+
return ensure_leading_slash(input.to_s) if site.config["baseurl"].nil?
|
27
|
+
Addressable::URI.parse(
|
28
|
+
ensure_leading_slash(site.config["baseurl"]) + ensure_leading_slash(input.to_s)
|
29
|
+
).normalize.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def ensure_leading_slash(input)
|
34
|
+
return input if input.nil? || input.empty? || input.start_with?("/")
|
35
|
+
"/#{input}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/jekyll/hooks.rb
CHANGED
@@ -54,7 +54,7 @@ module Jekyll
|
|
54
54
|
|
55
55
|
# Ensure the priority is a Fixnum
|
56
56
|
def self.priority_value(priority)
|
57
|
-
return priority if priority.is_a?(
|
57
|
+
return priority if priority.is_a?(Integer)
|
58
58
|
PRIORITY_MAP[priority] || DEFAULT_PRIORITY
|
59
59
|
end
|
60
60
|
|
@@ -80,7 +80,7 @@ module Jekyll
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def self.insert_hook(owner, event, priority, &block)
|
83
|
-
@hook_priority[block] =
|
83
|
+
@hook_priority[block] = [-priority, @hook_priority.size]
|
84
84
|
@registry[owner][event] << block
|
85
85
|
end
|
86
86
|
|
data/lib/jekyll/page.rb
CHANGED
@@ -40,7 +40,11 @@ module Jekyll
|
|
40
40
|
@base = base
|
41
41
|
@dir = dir
|
42
42
|
@name = name
|
43
|
-
@path = site.
|
43
|
+
@path = if site.in_theme_dir(base) == base # we're in a theme
|
44
|
+
site.in_theme_dir(base, dir, name)
|
45
|
+
else
|
46
|
+
site.in_source_dir(base, dir, name)
|
47
|
+
end
|
44
48
|
|
45
49
|
process(name)
|
46
50
|
read_yaml(File.join(base, dir), name)
|
data/lib/jekyll/reader.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class ThemeAssetsReader
|
3
|
+
attr_reader :site
|
4
|
+
def initialize(site)
|
5
|
+
@site = site
|
6
|
+
end
|
7
|
+
|
8
|
+
def read
|
9
|
+
return unless site.theme && site.theme.assets_path
|
10
|
+
|
11
|
+
Find.find(site.theme.assets_path) do |path|
|
12
|
+
next if File.directory?(path)
|
13
|
+
if File.symlink?(path)
|
14
|
+
Jekyll.logger.warn "Theme reader:", "Ignored symlinked asset: #{path}"
|
15
|
+
else
|
16
|
+
read_theme_asset(path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def read_theme_asset(path)
|
23
|
+
base = site.theme.root
|
24
|
+
dir = File.dirname(path.sub("#{site.theme.root}/", ""))
|
25
|
+
name = File.basename(path)
|
26
|
+
|
27
|
+
if Utils.has_yaml_header?(path)
|
28
|
+
append_unless_exists site.pages,
|
29
|
+
Jekyll::Page.new(site, base, dir, name)
|
30
|
+
else
|
31
|
+
append_unless_exists site.static_files,
|
32
|
+
Jekyll::StaticFile.new(site, base, dir, name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def append_unless_exists(haystack, new_item)
|
37
|
+
if haystack.any? { |file| file.relative_path == new_item.relative_path }
|
38
|
+
Jekyll.logger.debug "Theme:",
|
39
|
+
"Ignoring #{new_item.relative_path} in theme due to existing file " \
|
40
|
+
"with that path in site."
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
haystack << new_item
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/jekyll/renderer.rb
CHANGED
@@ -2,12 +2,32 @@
|
|
2
2
|
|
3
3
|
module Jekyll
|
4
4
|
class Renderer
|
5
|
-
attr_reader :document, :site
|
5
|
+
attr_reader :document, :site
|
6
|
+
attr_writer :layouts, :payload
|
6
7
|
|
7
8
|
def initialize(site, document, site_payload = nil)
|
8
9
|
@site = site
|
9
10
|
@document = document
|
10
|
-
@payload = site_payload
|
11
|
+
@payload = site_payload
|
12
|
+
end
|
13
|
+
|
14
|
+
# Fetches the payload used in Liquid rendering.
|
15
|
+
# It can be written with #payload=(new_payload)
|
16
|
+
# Falls back to site.site_payload if no payload is set.
|
17
|
+
#
|
18
|
+
# Returns a Jekyll::Drops::UnifiedPayloadDrop
|
19
|
+
def payload
|
20
|
+
@payload ||= site.site_payload
|
21
|
+
end
|
22
|
+
|
23
|
+
# The list of layouts registered for this Renderer.
|
24
|
+
# It can be written with #layouts=(new_layouts)
|
25
|
+
# Falls back to site.layouts if no layouts are registered.
|
26
|
+
#
|
27
|
+
# Returns a Hash of String => Jekyll::Layout identified
|
28
|
+
# as basename without the extension name.
|
29
|
+
def layouts
|
30
|
+
@layouts || site.layouts
|
11
31
|
end
|
12
32
|
|
13
33
|
# Determine which converters to use based on this document's
|
@@ -15,7 +35,7 @@ module Jekyll
|
|
15
35
|
#
|
16
36
|
# Returns an array of Converter instances.
|
17
37
|
def converters
|
18
|
-
@converters ||= site.converters.select { |c| c.matches(document.extname) }
|
38
|
+
@converters ||= site.converters.select { |c| c.matches(document.extname) }.sort
|
19
39
|
end
|
20
40
|
|
21
41
|
# Determine the extname the outputted file should have
|
@@ -126,7 +146,7 @@ module Jekyll
|
|
126
146
|
#
|
127
147
|
# Returns true if the layout is invalid, false if otherwise
|
128
148
|
def invalid_layout?(layout)
|
129
|
-
!document.data["layout"].nil? && layout.nil?
|
149
|
+
!document.data["layout"].nil? && layout.nil? && !(document.is_a? Jekyll::Excerpt)
|
130
150
|
end
|
131
151
|
|
132
152
|
# Render layouts and place given content inside.
|
@@ -137,7 +157,7 @@ module Jekyll
|
|
137
157
|
# Returns the content placed in the Liquid-rendered layouts
|
138
158
|
def place_in_layouts(content, payload, info)
|
139
159
|
output = content.dup
|
140
|
-
layout =
|
160
|
+
layout = layouts[document.data["layout"]]
|
141
161
|
|
142
162
|
Jekyll.logger.warn(
|
143
163
|
"Build Warning:",
|
@@ -167,7 +187,7 @@ module Jekyll
|
|
167
187
|
site.in_source_dir(layout.path)
|
168
188
|
) if document.write?
|
169
189
|
|
170
|
-
if (layout =
|
190
|
+
if (layout = layouts[layout.data["layout"]])
|
171
191
|
break if used.include?(layout)
|
172
192
|
used << layout
|
173
193
|
end
|