jekyll 3.4.5 → 3.5.0
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 +38 -30
- data/exe/jekyll +2 -2
- data/lib/jekyll/collection.rb +2 -2
- data/lib/jekyll/command.rb +5 -0
- data/lib/jekyll/commands/new.rb +1 -1
- data/lib/jekyll/commands/serve.rb +7 -6
- data/lib/jekyll/configuration.rb +64 -42
- data/lib/jekyll/converter.rb +2 -2
- data/lib/jekyll/convertible.rb +5 -3
- data/lib/jekyll/document.rb +61 -44
- data/lib/jekyll/drops/site_drop.rb +4 -0
- data/lib/jekyll/entry_filter.rb +2 -1
- data/lib/jekyll/errors.rb +5 -4
- data/lib/jekyll/external.rb +14 -1
- data/lib/jekyll/filters.rb +23 -21
- data/lib/jekyll/filters/grouping_filters.rb +1 -1
- data/lib/jekyll/filters/url_filters.rb +22 -4
- data/lib/jekyll/hooks.rb +1 -1
- data/lib/jekyll/liquid_renderer/table.rb +2 -2
- data/lib/jekyll/page.rb +1 -1
- data/lib/jekyll/plugin.rb +1 -1
- data/lib/jekyll/plugin_manager.rb +19 -7
- data/lib/jekyll/reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +8 -2
- data/lib/jekyll/readers/theme_assets_reader.rb +1 -1
- data/lib/jekyll/renderer.rb +113 -66
- data/lib/jekyll/site.rb +5 -1
- data/lib/jekyll/tags/post_url.rb +1 -1
- data/lib/jekyll/theme.rb +4 -0
- data/lib/jekyll/url.rb +1 -8
- data/lib/jekyll/utils/win_tz.rb +2 -2
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/404.html +24 -0
- data/lib/site_template/_config.yml +13 -4
- data/lib/site_template/about.md +7 -4
- metadata +5 -4
data/lib/jekyll/document.rb
CHANGED
@@ -3,10 +3,13 @@
|
|
3
3
|
module Jekyll
|
4
4
|
class Document
|
5
5
|
include Comparable
|
6
|
+
extend Forwardable
|
6
7
|
|
7
8
|
attr_reader :path, :site, :extname, :collection
|
8
9
|
attr_accessor :content, :output
|
9
10
|
|
11
|
+
def_delegator :self, :read_post_data, :post_read
|
12
|
+
|
10
13
|
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
|
11
14
|
DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!
|
12
15
|
DATE_FILENAME_MATCHER = %r!^(?:.+/)*(\d{2,4}-\d{1,2}-\d{1,2})-(.*)(\.[^.]+)$!
|
@@ -147,7 +150,7 @@ module Jekyll
|
|
147
150
|
#
|
148
151
|
# Returns true if extname == .coffee, false otherwise.
|
149
152
|
def coffeescript_file?
|
150
|
-
".coffee"
|
153
|
+
extname == ".coffee"
|
151
154
|
end
|
152
155
|
|
153
156
|
# Determine whether the file should be rendered with Liquid.
|
@@ -158,12 +161,19 @@ module Jekyll
|
|
158
161
|
!(coffeescript_file? || yaml_file?)
|
159
162
|
end
|
160
163
|
|
164
|
+
# Determine whether the file should be rendered with a layout.
|
165
|
+
#
|
166
|
+
# Returns true if the Front Matter specifies that `layout` is set to `none`.
|
167
|
+
def no_layout?
|
168
|
+
data["layout"] == "none"
|
169
|
+
end
|
170
|
+
|
161
171
|
# Determine whether the file should be placed into layouts.
|
162
172
|
#
|
163
|
-
# Returns false if the document is
|
164
|
-
# true otherwise.
|
173
|
+
# Returns false if the document is set to `layouts: none`, or is either an
|
174
|
+
# asset file or a yaml file. Returns true otherwise.
|
165
175
|
def place_in_layout?
|
166
|
-
!(asset_file? || yaml_file?)
|
176
|
+
!(asset_file? || yaml_file? || no_layout?)
|
167
177
|
end
|
168
178
|
|
169
179
|
# The URL template where the document would be accessible.
|
@@ -256,11 +266,8 @@ module Jekyll
|
|
256
266
|
merge_defaults
|
257
267
|
read_content(opts)
|
258
268
|
read_post_data
|
259
|
-
rescue SyntaxError => e
|
260
|
-
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{e.message}"
|
261
269
|
rescue => e
|
262
|
-
|
263
|
-
Jekyll.logger.error "Error:", "could not read file #{path}: #{e.message}"
|
270
|
+
handle_read_error(e)
|
264
271
|
end
|
265
272
|
end
|
266
273
|
end
|
@@ -364,7 +371,7 @@ module Jekyll
|
|
364
371
|
if data.key?(method.to_s)
|
365
372
|
Jekyll::Deprecator.deprecation_message "Document##{method} is now a key "\
|
366
373
|
"in the #data hash."
|
367
|
-
Jekyll::Deprecator.deprecation_message "Called by #{caller
|
374
|
+
Jekyll::Deprecator.deprecation_message "Called by #{caller(0..0)}."
|
368
375
|
data[method.to_s]
|
369
376
|
else
|
370
377
|
super
|
@@ -375,6 +382,38 @@ module Jekyll
|
|
375
382
|
data.key?(method.to_s) || super
|
376
383
|
end
|
377
384
|
|
385
|
+
# Add superdirectories of the special_dir to categories.
|
386
|
+
# In the case of es/_posts, 'es' is added as a category.
|
387
|
+
# In the case of _posts/es, 'es' is NOT added as a category.
|
388
|
+
#
|
389
|
+
# Returns nothing.
|
390
|
+
def categories_from_path(special_dir)
|
391
|
+
superdirs = relative_path.sub(%r!#{special_dir}(.*)!, "")
|
392
|
+
.split(File::SEPARATOR)
|
393
|
+
.reject do |c|
|
394
|
+
c.empty? || c == special_dir || c == basename
|
395
|
+
end
|
396
|
+
merge_data!({ "categories" => superdirs }, :source => "file path")
|
397
|
+
end
|
398
|
+
|
399
|
+
def populate_categories
|
400
|
+
merge_data!({
|
401
|
+
"categories" => (
|
402
|
+
Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
403
|
+
data,
|
404
|
+
"category",
|
405
|
+
"categories"
|
406
|
+
)
|
407
|
+
).map(&:to_s).flatten.uniq,
|
408
|
+
})
|
409
|
+
end
|
410
|
+
|
411
|
+
def populate_tags
|
412
|
+
merge_data!({
|
413
|
+
"tags" => Utils.pluralized_array_from_hash(data, "tag", "tags").flatten,
|
414
|
+
})
|
415
|
+
end
|
416
|
+
|
378
417
|
private
|
379
418
|
def merge_categories!(other)
|
380
419
|
if other.key?("categories") && !other["categories"].nil?
|
@@ -422,6 +461,19 @@ module Jekyll
|
|
422
461
|
generate_excerpt
|
423
462
|
end
|
424
463
|
|
464
|
+
private
|
465
|
+
def handle_read_error(error)
|
466
|
+
if error.is_a? SyntaxError
|
467
|
+
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}"
|
468
|
+
else
|
469
|
+
Jekyll.logger.error "Error:", "could not read file #{path}: #{error.message}"
|
470
|
+
end
|
471
|
+
|
472
|
+
if site.config["strict_front_matter"] || error.is_a?(Jekyll::Errors::FatalException)
|
473
|
+
raise error
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
425
477
|
private
|
426
478
|
def populate_title
|
427
479
|
if relative_path =~ DATE_FILENAME_MATCHER
|
@@ -445,41 +497,6 @@ module Jekyll
|
|
445
497
|
end
|
446
498
|
end
|
447
499
|
|
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
500
|
private
|
484
501
|
def generate_excerpt
|
485
502
|
if generate_excerpt?
|
data/lib/jekyll/entry_filter.rb
CHANGED
data/lib/jekyll/errors.rb
CHANGED
@@ -9,9 +9,10 @@ module Jekyll
|
|
9
9
|
InvalidYAMLFrontMatterError = Class.new(FatalException)
|
10
10
|
MissingDependencyException = Class.new(FatalException)
|
11
11
|
|
12
|
-
InvalidDateError
|
13
|
-
InvalidPostNameError
|
14
|
-
PostURLError
|
15
|
-
InvalidURLError
|
12
|
+
InvalidDateError = Class.new(FatalException)
|
13
|
+
InvalidPostNameError = Class.new(FatalException)
|
14
|
+
PostURLError = Class.new(FatalException)
|
15
|
+
InvalidURLError = Class.new(FatalException)
|
16
|
+
InvalidConfigurationError = Class.new(FatalException)
|
16
17
|
end
|
17
18
|
end
|
data/lib/jekyll/external.rb
CHANGED
@@ -23,12 +23,25 @@ module Jekyll
|
|
23
23
|
require name
|
24
24
|
rescue LoadError
|
25
25
|
Jekyll.logger.debug "Couldn't load #{name}. Skipping."
|
26
|
-
yield(name) if block_given?
|
26
|
+
yield(name, version_constraint(name)) if block_given?
|
27
27
|
false
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
#
|
33
|
+
# The version constraint required to activate a given gem.
|
34
|
+
# Usually the gem version requirement is "> 0," because any version
|
35
|
+
# will do. In the case of jekyll-docs, however, we require the exact
|
36
|
+
# same version as Jekyll.
|
37
|
+
#
|
38
|
+
# Returns a String version constraint in a parseable form for
|
39
|
+
# RubyGems.
|
40
|
+
def version_constraint(gem_name)
|
41
|
+
return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs")
|
42
|
+
"> 0"
|
43
|
+
end
|
44
|
+
|
32
45
|
#
|
33
46
|
# Require a gem or gems. If it's not present, show a very nice error
|
34
47
|
# message that explains everything and is much more helpful than the
|
data/lib/jekyll/filters.rb
CHANGED
@@ -80,6 +80,7 @@ module Jekyll
|
|
80
80
|
#
|
81
81
|
# Returns the formatted String.
|
82
82
|
def date_to_long_string(date)
|
83
|
+
return date if date.to_s.empty?
|
83
84
|
time(date).strftime("%d %B %Y")
|
84
85
|
end
|
85
86
|
|
@@ -94,6 +95,7 @@ module Jekyll
|
|
94
95
|
#
|
95
96
|
# Returns the formatted String.
|
96
97
|
def date_to_xmlschema(date)
|
98
|
+
return date if date.to_s.empty?
|
97
99
|
time(date).xmlschema
|
98
100
|
end
|
99
101
|
|
@@ -108,6 +110,7 @@ module Jekyll
|
|
108
110
|
#
|
109
111
|
# Returns the formatted String.
|
110
112
|
def date_to_rfc822(date)
|
113
|
+
return date if date.to_s.empty?
|
111
114
|
time(date).rfc822
|
112
115
|
end
|
113
116
|
|
@@ -280,10 +283,11 @@ module Jekyll
|
|
280
283
|
end
|
281
284
|
end
|
282
285
|
|
283
|
-
def pop(array,
|
286
|
+
def pop(array, num = 1)
|
284
287
|
return array unless array.is_a?(Array)
|
288
|
+
num = Liquid::Utils.to_integer(num)
|
285
289
|
new_ary = array.dup
|
286
|
-
new_ary.pop(
|
290
|
+
new_ary.pop(num)
|
287
291
|
new_ary
|
288
292
|
end
|
289
293
|
|
@@ -294,10 +298,11 @@ module Jekyll
|
|
294
298
|
new_ary
|
295
299
|
end
|
296
300
|
|
297
|
-
def shift(array,
|
301
|
+
def shift(array, num = 1)
|
298
302
|
return array unless array.is_a?(Array)
|
303
|
+
num = Liquid::Utils.to_integer(num)
|
299
304
|
new_ary = array.dup
|
300
|
-
new_ary.shift(
|
305
|
+
new_ary.shift(num)
|
301
306
|
new_ary
|
302
307
|
end
|
303
308
|
|
@@ -310,11 +315,11 @@ module Jekyll
|
|
310
315
|
|
311
316
|
def sample(input, num = 1)
|
312
317
|
return input unless input.respond_to?(:sample)
|
313
|
-
|
314
|
-
if
|
318
|
+
num = Liquid::Utils.to_integer(num) rescue 1
|
319
|
+
if num == 1
|
315
320
|
input.sample
|
316
321
|
else
|
317
|
-
input.sample(
|
322
|
+
input.sample(num)
|
318
323
|
end
|
319
324
|
end
|
320
325
|
|
@@ -345,25 +350,20 @@ module Jekyll
|
|
345
350
|
|
346
351
|
private
|
347
352
|
def time(input)
|
348
|
-
|
349
|
-
|
350
|
-
input.clone
|
351
|
-
when Date
|
352
|
-
input.to_time
|
353
|
-
when String
|
354
|
-
Time.parse(input) rescue Time.at(input.to_i)
|
355
|
-
when Numeric
|
356
|
-
Time.at(input)
|
357
|
-
else
|
353
|
+
date = Liquid::Utils.to_date(input)
|
354
|
+
unless date.respond_to?(:to_time)
|
358
355
|
raise Errors::InvalidDateError,
|
359
356
|
"Invalid Date: '#{input.inspect}' is not a valid datetime."
|
360
|
-
end
|
357
|
+
end
|
358
|
+
date.to_time.dup.localtime
|
361
359
|
end
|
362
360
|
|
363
361
|
private
|
364
362
|
def item_property(item, property)
|
365
363
|
if item.respond_to?(:to_liquid)
|
366
|
-
item.to_liquid
|
364
|
+
property.to_s.split(".").reduce(item.to_liquid) do |subvalue, attribute|
|
365
|
+
subvalue[attribute]
|
366
|
+
end
|
367
367
|
elsif item.respond_to?(:data)
|
368
368
|
item.data[property.to_s]
|
369
369
|
else
|
@@ -402,9 +402,11 @@ module Jekyll
|
|
402
402
|
operator = parser.consume?(:comparison)
|
403
403
|
condition =
|
404
404
|
if operator
|
405
|
-
Liquid::Condition.new(left_expr,
|
405
|
+
Liquid::Condition.new(Liquid::Expression.parse(left_expr),
|
406
|
+
operator,
|
407
|
+
Liquid::Expression.parse(parser.expression))
|
406
408
|
else
|
407
|
-
Liquid::Condition.new(left_expr)
|
409
|
+
Liquid::Condition.new(Liquid::Expression.parse(left_expr))
|
408
410
|
end
|
409
411
|
parser.consume(:end_of_string)
|
410
412
|
|
@@ -10,7 +10,7 @@ module Jekyll
|
|
10
10
|
# Returns the absolute URL as a String.
|
11
11
|
def absolute_url(input)
|
12
12
|
return if input.nil?
|
13
|
-
|
13
|
+
return input if Addressable::URI.parse(input).absolute?
|
14
14
|
return relative_url(input).to_s if site.config["url"].nil?
|
15
15
|
Addressable::URI.parse(site.config["url"] + relative_url(input)).normalize.to_s
|
16
16
|
end
|
@@ -22,14 +22,32 @@ module Jekyll
|
|
22
22
|
# Returns a URL relative to the domain root as a String.
|
23
23
|
def relative_url(input)
|
24
24
|
return if input.nil?
|
25
|
-
|
26
|
-
parts = [site.config["baseurl"], input]
|
25
|
+
return ensure_leading_slash(input.to_s) if sanitized_baseurl.nil?
|
27
26
|
Addressable::URI.parse(
|
28
|
-
|
27
|
+
ensure_leading_slash(sanitized_baseurl) + ensure_leading_slash(input.to_s)
|
29
28
|
).normalize.to_s
|
30
29
|
end
|
31
30
|
|
31
|
+
# Strips trailing `/index.html` from URLs to create pretty permalinks
|
32
|
+
#
|
33
|
+
# input - the URL with a possible `/index.html`
|
34
|
+
#
|
35
|
+
# Returns a URL with the trailing `/index.html` removed
|
36
|
+
def strip_index(input)
|
37
|
+
return if input.nil? || input.to_s.empty?
|
38
|
+
input.sub(%r!/index\.html?$!, "/")
|
39
|
+
end
|
40
|
+
|
32
41
|
private
|
42
|
+
|
43
|
+
def site
|
44
|
+
@context.registers[:site]
|
45
|
+
end
|
46
|
+
|
47
|
+
def sanitized_baseurl
|
48
|
+
site.config["baseurl"].to_s.chomp("/")
|
49
|
+
end
|
50
|
+
|
33
51
|
def ensure_leading_slash(input)
|
34
52
|
return input if input.nil? || input.empty? || input.start_with?("/")
|
35
53
|
"/#{input}"
|
data/lib/jekyll/hooks.rb
CHANGED
@@ -32,7 +32,7 @@ module Jekyll
|
|
32
32
|
|
33
33
|
row_data.each_index do |cell_index|
|
34
34
|
str << "-" * widths[cell_index]
|
35
|
-
str << "-+-" unless cell_index == row_data.length-1
|
35
|
+
str << "-+-" unless cell_index == row_data.length - 1
|
36
36
|
end
|
37
37
|
|
38
38
|
str << "\n"
|
@@ -49,7 +49,7 @@ module Jekyll
|
|
49
49
|
cell_data.rjust(widths[cell_index], " ")
|
50
50
|
end
|
51
51
|
|
52
|
-
str << " | " unless cell_index == row_data.length-1
|
52
|
+
str << " | " unless cell_index == row_data.length - 1
|
53
53
|
end
|
54
54
|
|
55
55
|
str << "\n"
|
data/lib/jekyll/page.rb
CHANGED
@@ -127,7 +127,7 @@ module Jekyll
|
|
127
127
|
# layouts - The Hash of {"name" => "layout"}.
|
128
128
|
# site_payload - The site payload Hash.
|
129
129
|
#
|
130
|
-
# Returns
|
130
|
+
# Returns String rendered page.
|
131
131
|
def render(layouts, site_payload)
|
132
132
|
site_payload["page"] = to_liquid
|
133
133
|
site_payload["paginator"] = pager.to_liquid
|
data/lib/jekyll/plugin.rb
CHANGED
@@ -15,6 +15,7 @@ module Jekyll
|
|
15
15
|
#
|
16
16
|
# Returns nothing
|
17
17
|
def conscientious_require
|
18
|
+
require_theme_deps if site.theme
|
18
19
|
require_plugin_files
|
19
20
|
require_gems
|
20
21
|
deprecation_checks
|
@@ -25,10 +26,21 @@ module Jekyll
|
|
25
26
|
# Returns nothing.
|
26
27
|
def require_gems
|
27
28
|
Jekyll::External.require_with_graceful_fail(
|
28
|
-
site.gems.select { |
|
29
|
+
site.gems.select { |plugin| plugin_allowed?(plugin) }
|
29
30
|
)
|
30
31
|
end
|
31
32
|
|
33
|
+
# Require each of the runtime_dependencies specified by the theme's gemspec.
|
34
|
+
#
|
35
|
+
# Returns false only if no dependencies have been specified, otherwise nothing.
|
36
|
+
def require_theme_deps
|
37
|
+
return false unless site.theme.runtime_dependencies
|
38
|
+
site.theme.runtime_dependencies.each do |dep|
|
39
|
+
next if dep.name == "jekyll"
|
40
|
+
External.require_with_graceful_fail(dep.name) if plugin_allowed?(dep.name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
32
44
|
def self.require_from_bundler
|
33
45
|
if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && File.file?("Gemfile")
|
34
46
|
require "bundler"
|
@@ -47,12 +59,12 @@ module Jekyll
|
|
47
59
|
|
48
60
|
# Check whether a gem plugin is allowed to be used during this build.
|
49
61
|
#
|
50
|
-
#
|
62
|
+
# plugin_name - the name of the plugin
|
51
63
|
#
|
52
|
-
# Returns true if the
|
64
|
+
# Returns true if the plugin name is in the whitelist or if the site is not
|
53
65
|
# in safe mode.
|
54
|
-
def plugin_allowed?(
|
55
|
-
!site.safe || whitelist.include?(
|
66
|
+
def plugin_allowed?(plugin_name)
|
67
|
+
!site.safe || whitelist.include?(plugin_name)
|
56
68
|
end
|
57
69
|
|
58
70
|
# Build an array of allowed plugin gem names.
|
@@ -87,12 +99,12 @@ module Jekyll
|
|
87
99
|
end
|
88
100
|
|
89
101
|
def deprecation_checks
|
90
|
-
pagination_included = (site.config["
|
102
|
+
pagination_included = (site.config["plugins"] || []).include?("jekyll-paginate") ||
|
91
103
|
defined?(Jekyll::Paginate)
|
92
104
|
if site.config["paginate"] && !pagination_included
|
93
105
|
Jekyll::Deprecator.deprecation_message "You appear to have pagination " \
|
94
106
|
"turned on, but you haven't included the `jekyll-paginate` gem. " \
|
95
|
-
"Ensure you have `
|
107
|
+
"Ensure you have `plugins: [jekyll-paginate]` in your configuration file."
|
96
108
|
end
|
97
109
|
end
|
98
110
|
end
|