jekyll 3.8.7 → 4.1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +71 -62
- data/LICENSE +1 -1
- data/README.markdown +46 -17
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/main.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll.rb +10 -1
- data/lib/jekyll/cache.rb +190 -0
- data/lib/jekyll/cleaner.rb +5 -4
- data/lib/jekyll/collection.rb +82 -10
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +11 -20
- data/lib/jekyll/commands/clean.rb +2 -0
- data/lib/jekyll/commands/doctor.rb +15 -8
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +37 -35
- data/lib/jekyll/commands/new_theme.rb +30 -28
- data/lib/jekyll/commands/serve.rb +55 -81
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +6 -10
- data/lib/jekyll/commands/serve/servlet.rb +22 -25
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/configuration.rb +61 -149
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +84 -11
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +30 -31
- data/lib/jekyll/deprecator.rb +1 -3
- data/lib/jekyll/document.rb +89 -61
- data/lib/jekyll/drops/collection_drop.rb +2 -3
- data/lib/jekyll/drops/document_drop.rb +14 -1
- data/lib/jekyll/drops/drop.rb +17 -14
- data/lib/jekyll/drops/excerpt_drop.rb +4 -0
- data/lib/jekyll/drops/page_drop.rb +18 -0
- data/lib/jekyll/drops/site_drop.rb +6 -5
- data/lib/jekyll/drops/unified_payload_drop.rb +1 -0
- data/lib/jekyll/drops/url_drop.rb +53 -1
- data/lib/jekyll/entry_filter.rb +42 -45
- data/lib/jekyll/excerpt.rb +45 -34
- data/lib/jekyll/external.rb +10 -5
- data/lib/jekyll/filters.rb +200 -40
- 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 +46 -14
- data/lib/jekyll/frontmatter_defaults.rb +46 -35
- data/lib/jekyll/hooks.rb +4 -8
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +36 -77
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/mime.types +53 -11
- data/lib/jekyll/page.rb +54 -12
- data/lib/jekyll/page_excerpt.rb +26 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +31 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +2 -0
- data/lib/jekyll/profiler.rb +58 -0
- data/lib/jekyll/reader.rb +42 -9
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +8 -9
- 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 +31 -18
- 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/renderer.rb +23 -40
- data/lib/jekyll/site.rb +91 -38
- data/lib/jekyll/static_file.rb +62 -21
- data/lib/jekyll/stevenson.rb +2 -3
- data/lib/jekyll/tags/highlight.rb +19 -51
- data/lib/jekyll/tags/include.rb +82 -42
- data/lib/jekyll/tags/link.rb +11 -7
- data/lib/jekyll/tags/post_url.rb +25 -21
- data/lib/jekyll/theme.rb +16 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +10 -5
- data/lib/jekyll/utils.rb +18 -21
- data/lib/jekyll/utils/ansi.rb +1 -1
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +8 -8
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils/win_tz.rb +2 -2
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +1 -0
- 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/site_template/{about.md → about.markdown} +0 -0
- data/lib/site_template/{index.md → index.markdown} +0 -0
- 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 +149 -0
- metadata +69 -31
- 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
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# Frozen-string-literal: true
|
|
2
2
|
|
|
3
|
+
module Kramdown
|
|
4
|
+
# A Kramdown::Document subclass meant to optimize memory usage from initializing
|
|
5
|
+
# a kramdown document for parsing.
|
|
6
|
+
#
|
|
7
|
+
# The optimization is by using the same options Hash (and its derivatives) for
|
|
8
|
+
# converting all Markdown documents in a Jekyll site.
|
|
9
|
+
class JekyllDocument < Document
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :options, :parser
|
|
12
|
+
|
|
13
|
+
# The implementation is basically the core logic in +Kramdown::Document#initialize+
|
|
14
|
+
#
|
|
15
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
16
|
+
def setup(options)
|
|
17
|
+
@cache ||= {}
|
|
18
|
+
|
|
19
|
+
# reset variables on a subsequent set up with a different options Hash
|
|
20
|
+
unless @cache[:id] == options.hash
|
|
21
|
+
@options = @parser = nil
|
|
22
|
+
@cache[:id] = options.hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@options ||= Options.merge(options).freeze
|
|
26
|
+
@parser ||= begin
|
|
27
|
+
parser_name = (@options[:input] || "kramdown").to_s
|
|
28
|
+
parser_name = parser_name[0..0].upcase + parser_name[1..-1]
|
|
29
|
+
try_require("parser", parser_name)
|
|
30
|
+
|
|
31
|
+
if Parser.const_defined?(parser_name)
|
|
32
|
+
Parser.const_get(parser_name)
|
|
33
|
+
else
|
|
34
|
+
raise Kramdown::Error, "kramdown has no parser to handle the specified " \
|
|
35
|
+
"input format: #{@options[:input]}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def try_require(type, name)
|
|
44
|
+
require "kramdown/#{type}/#{Utils.snake_case(name)}"
|
|
45
|
+
rescue LoadError
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def initialize(source, options = {})
|
|
51
|
+
JekyllDocument.setup(options)
|
|
52
|
+
|
|
53
|
+
@options = JekyllDocument.options
|
|
54
|
+
@root, @warnings = JekyllDocument.parser.parse(source, @options)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Use Kramdown::Converter::Html class to convert this document into HTML.
|
|
58
|
+
#
|
|
59
|
+
# The implementation is basically an optimized version of core logic in
|
|
60
|
+
# +Kramdown::Document#method_missing+ from kramdown-2.1.0.
|
|
61
|
+
def to_html
|
|
62
|
+
output, warnings = Kramdown::Converter::Html.convert(@root, @options)
|
|
63
|
+
@warnings.concat(warnings)
|
|
64
|
+
output
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#
|
|
70
|
+
|
|
3
71
|
module Jekyll
|
|
4
72
|
module Converters
|
|
5
73
|
class Markdown
|
|
@@ -18,6 +86,7 @@ module Jekyll
|
|
|
18
86
|
@config = config["kramdown"] || {}
|
|
19
87
|
@highlighter = nil
|
|
20
88
|
setup
|
|
89
|
+
load_dependencies
|
|
21
90
|
end
|
|
22
91
|
|
|
23
92
|
# Setup and normalize the configuration:
|
|
@@ -30,13 +99,14 @@ module Jekyll
|
|
|
30
99
|
def setup
|
|
31
100
|
@config["syntax_highlighter"] ||= highlighter
|
|
32
101
|
@config["syntax_highlighter_opts"] ||= {}
|
|
102
|
+
@config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext"
|
|
103
|
+
@config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"]
|
|
33
104
|
@config["coderay"] ||= {} # XXX: Legacy.
|
|
34
105
|
modernize_coderay_config
|
|
35
|
-
make_accessible
|
|
36
106
|
end
|
|
37
107
|
|
|
38
108
|
def convert(content)
|
|
39
|
-
document = Kramdown::
|
|
109
|
+
document = Kramdown::JekyllDocument.new(content, @config)
|
|
40
110
|
html_output = document.to_html
|
|
41
111
|
if @config["show_warnings"]
|
|
42
112
|
document.warnings.each do |warning|
|
|
@@ -47,10 +117,18 @@ module Jekyll
|
|
|
47
117
|
end
|
|
48
118
|
|
|
49
119
|
private
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
120
|
+
|
|
121
|
+
def load_dependencies
|
|
122
|
+
require "kramdown-parser-gfm" if @config["input"] == "GFM"
|
|
123
|
+
|
|
124
|
+
if highlighter == "coderay"
|
|
125
|
+
Jekyll::External.require_with_graceful_fail("kramdown-syntax-coderay")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# `mathjax` emgine is bundled within kramdown-2.x and will be handled by
|
|
129
|
+
# kramdown itself.
|
|
130
|
+
if (math_engine = @config["math_engine"]) && math_engine != "mathjax"
|
|
131
|
+
Jekyll::External.require_with_graceful_fail("kramdown-math-#{math_engine}")
|
|
54
132
|
end
|
|
55
133
|
end
|
|
56
134
|
|
|
@@ -59,8 +137,6 @@ module Jekyll
|
|
|
59
137
|
# config[highlighter]
|
|
60
138
|
# Where `enable_coderay` is now deprecated because Kramdown
|
|
61
139
|
# supports Rouge now too.
|
|
62
|
-
|
|
63
|
-
private
|
|
64
140
|
def highlighter
|
|
65
141
|
return @highlighter if @highlighter
|
|
66
142
|
|
|
@@ -84,7 +160,6 @@ module Jekyll
|
|
|
84
160
|
end
|
|
85
161
|
end
|
|
86
162
|
|
|
87
|
-
private
|
|
88
163
|
def strip_coderay_prefix(hash)
|
|
89
164
|
hash.each_with_object({}) do |(key, val), hsh|
|
|
90
165
|
cleaned_key = key.to_s.gsub(%r!\Acoderay_!, "")
|
|
@@ -102,8 +177,6 @@ module Jekyll
|
|
|
102
177
|
# If our highlighter is CodeRay we go in to merge the CodeRay defaults
|
|
103
178
|
# with your "coderay" key if it's there, deprecating it in the
|
|
104
179
|
# process of you using it.
|
|
105
|
-
|
|
106
|
-
private
|
|
107
180
|
def modernize_coderay_config
|
|
108
181
|
unless @config["coderay"].empty?
|
|
109
182
|
Jekyll::Deprecator.deprecation_message(
|
|
@@ -1,40 +1,60 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
module Kramdown
|
|
4
|
+
module Parser
|
|
5
|
+
class SmartyPants < Kramdown::Parser::Kramdown
|
|
6
|
+
def initialize(source, options)
|
|
7
|
+
super
|
|
8
|
+
@block_parsers = [:block_html, :content]
|
|
9
|
+
@span_parsers = [:smart_quotes, :html_entity, :typographic_syms, :span_html]
|
|
10
|
+
end
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
def parse_content
|
|
13
|
+
add_text @src.scan(%r!\A.*\n!)
|
|
14
|
+
end
|
|
15
|
+
define_parser(:content, %r!\A!)
|
|
16
|
+
end
|
|
12
17
|
end
|
|
13
|
-
define_parser(:content, %r!\A!)
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
module Jekyll
|
|
17
21
|
module Converters
|
|
22
|
+
# SmartyPants converter.
|
|
23
|
+
# For more info on converters see https://jekyllrb.com/docs/plugins/converters/
|
|
18
24
|
class SmartyPants < Converter
|
|
19
25
|
safe true
|
|
20
26
|
priority :low
|
|
21
27
|
|
|
22
28
|
def initialize(config)
|
|
23
|
-
unless defined?(Kramdown)
|
|
24
|
-
Jekyll::External.require_with_graceful_fail "kramdown"
|
|
25
|
-
end
|
|
29
|
+
Jekyll::External.require_with_graceful_fail "kramdown" unless defined?(Kramdown)
|
|
26
30
|
@config = config["kramdown"].dup || {}
|
|
27
31
|
@config[:input] = :SmartyPants
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
# Does the given extension match this converter's list of acceptable extensions?
|
|
35
|
+
# Takes one argument: the file's extension (including the dot).
|
|
36
|
+
#
|
|
37
|
+
# ext - The String extension to check.
|
|
38
|
+
#
|
|
39
|
+
# Returns true if it matches, false otherwise.
|
|
40
|
+
def matches(_ext)
|
|
31
41
|
false
|
|
32
42
|
end
|
|
33
43
|
|
|
34
|
-
|
|
44
|
+
# Public: The extension to be given to the output file (including the dot).
|
|
45
|
+
#
|
|
46
|
+
# ext - The String extension or original file.
|
|
47
|
+
#
|
|
48
|
+
# Returns The String output file extension.
|
|
49
|
+
def output_ext(_ext)
|
|
35
50
|
nil
|
|
36
51
|
end
|
|
37
52
|
|
|
53
|
+
# Logic to do the content conversion.
|
|
54
|
+
#
|
|
55
|
+
# content - String content of file (without front matter).
|
|
56
|
+
#
|
|
57
|
+
# Returns a String of the converted content.
|
|
38
58
|
def convert(content)
|
|
39
59
|
document = Kramdown::Document.new(content, @config)
|
|
40
60
|
html_output = document.to_html.chomp
|
data/lib/jekyll/convertible.rb
CHANGED
|
@@ -46,10 +46,10 @@ module Jekyll
|
|
|
46
46
|
end
|
|
47
47
|
rescue Psych::SyntaxError => e
|
|
48
48
|
Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}"
|
|
49
|
-
raise e if
|
|
49
|
+
raise e if site.config["strict_front_matter"]
|
|
50
50
|
rescue StandardError => e
|
|
51
51
|
Jekyll.logger.warn "Error reading file #{filename}: #{e.message}"
|
|
52
|
-
raise e if
|
|
52
|
+
raise e if site.config["strict_front_matter"]
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
self.data ||= {}
|
|
@@ -64,12 +64,12 @@ module Jekyll
|
|
|
64
64
|
def validate_data!(filename)
|
|
65
65
|
unless self.data.is_a?(Hash)
|
|
66
66
|
raise Errors::InvalidYAMLFrontMatterError,
|
|
67
|
-
|
|
67
|
+
"Invalid YAML front matter in #{filename}"
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def validate_permalink!(filename)
|
|
72
|
-
if self.data["permalink"]
|
|
72
|
+
if self.data["permalink"]&.to_s&.empty?
|
|
73
73
|
raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
|
|
74
74
|
end
|
|
75
75
|
end
|
|
@@ -78,7 +78,7 @@ module Jekyll
|
|
|
78
78
|
#
|
|
79
79
|
# Returns the transformed contents.
|
|
80
80
|
def transform
|
|
81
|
-
|
|
81
|
+
renderer.convert(content)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
# Determine the extension depending on content_type.
|
|
@@ -86,7 +86,7 @@ module Jekyll
|
|
|
86
86
|
# Returns the String extension for the output file.
|
|
87
87
|
# e.g. ".html" for an HTML output file.
|
|
88
88
|
def output_ext
|
|
89
|
-
|
|
89
|
+
renderer.output_ext
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# Determine which converter to use based on this convertible's
|
|
@@ -94,7 +94,7 @@ module Jekyll
|
|
|
94
94
|
#
|
|
95
95
|
# Returns the Converter instance.
|
|
96
96
|
def converters
|
|
97
|
-
|
|
97
|
+
renderer.converters
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
# Render Liquid in the content
|
|
@@ -105,16 +105,17 @@ module Jekyll
|
|
|
105
105
|
#
|
|
106
106
|
# Returns the converted content
|
|
107
107
|
def render_liquid(content, payload, info, path)
|
|
108
|
-
|
|
108
|
+
renderer.render_liquid(content, payload, info, path)
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
|
112
112
|
#
|
|
113
113
|
# Returns the Hash representation of this Convertible.
|
|
114
114
|
def to_liquid(attrs = nil)
|
|
115
|
-
further_data =
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
further_data = \
|
|
116
|
+
(attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh|
|
|
117
|
+
hsh[attribute] = send(attribute)
|
|
118
|
+
end
|
|
118
119
|
|
|
119
120
|
defaults = site.frontmatter_defaults.all(relative_path, type)
|
|
120
121
|
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
|
@@ -125,16 +126,12 @@ module Jekyll
|
|
|
125
126
|
#
|
|
126
127
|
# Returns the type of self.
|
|
127
128
|
def type
|
|
128
|
-
if is_a?(Page)
|
|
129
|
-
:pages
|
|
130
|
-
end
|
|
129
|
+
:pages if is_a?(Page)
|
|
131
130
|
end
|
|
132
131
|
|
|
133
132
|
# returns the owner symbol for hook triggering
|
|
134
133
|
def hook_owner
|
|
135
|
-
if is_a?(Page)
|
|
136
|
-
:pages
|
|
137
|
-
end
|
|
134
|
+
:pages if is_a?(Page)
|
|
138
135
|
end
|
|
139
136
|
|
|
140
137
|
# Determine whether the document is an asset file.
|
|
@@ -150,7 +147,7 @@ module Jekyll
|
|
|
150
147
|
#
|
|
151
148
|
# Returns true if extname == .sass or .scss, false otherwise.
|
|
152
149
|
def sass_file?
|
|
153
|
-
|
|
150
|
+
Jekyll::Document::SASS_FILE_EXTS.include?(ext)
|
|
154
151
|
end
|
|
155
152
|
|
|
156
153
|
# Determine whether the document is a CoffeeScript file.
|
|
@@ -164,6 +161,8 @@ module Jekyll
|
|
|
164
161
|
#
|
|
165
162
|
# Returns true if the file has Liquid Tags or Variables, false otherwise.
|
|
166
163
|
def render_with_liquid?
|
|
164
|
+
return false if data["render_with_liquid"] == false
|
|
165
|
+
|
|
167
166
|
Jekyll::Utils.has_liquid_construct?(content)
|
|
168
167
|
end
|
|
169
168
|
|
|
@@ -181,7 +180,7 @@ module Jekyll
|
|
|
181
180
|
#
|
|
182
181
|
# Returns true if the layout is invalid, false if otherwise
|
|
183
182
|
def invalid_layout?(layout)
|
|
184
|
-
!data["layout"].nil? && layout.nil? && !(
|
|
183
|
+
!data["layout"].nil? && layout.nil? && !(is_a? Jekyll::Excerpt)
|
|
185
184
|
end
|
|
186
185
|
|
|
187
186
|
# Recursively render layouts
|
|
@@ -192,10 +191,10 @@ module Jekyll
|
|
|
192
191
|
#
|
|
193
192
|
# Returns nothing
|
|
194
193
|
def render_all_layouts(layouts, payload, info)
|
|
195
|
-
|
|
196
|
-
self.output =
|
|
194
|
+
renderer.layouts = layouts
|
|
195
|
+
self.output = renderer.place_in_layouts(output, payload, info)
|
|
197
196
|
ensure
|
|
198
|
-
@
|
|
197
|
+
@renderer = nil # this will allow the modifications above to disappear
|
|
199
198
|
end
|
|
200
199
|
|
|
201
200
|
# Add any necessary layouts to this convertible document.
|
|
@@ -205,15 +204,15 @@ module Jekyll
|
|
|
205
204
|
#
|
|
206
205
|
# Returns nothing.
|
|
207
206
|
def do_layout(payload, layouts)
|
|
208
|
-
self.output =
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
self.output = renderer.tap do |doc_renderer|
|
|
208
|
+
doc_renderer.layouts = layouts
|
|
209
|
+
doc_renderer.payload = payload
|
|
211
210
|
end.run
|
|
212
211
|
|
|
213
|
-
Jekyll.logger.debug "Post-Render Hooks:",
|
|
212
|
+
Jekyll.logger.debug "Post-Render Hooks:", relative_path
|
|
214
213
|
Jekyll::Hooks.trigger hook_owner, :post_render, self
|
|
215
214
|
ensure
|
|
216
|
-
@
|
|
215
|
+
@renderer = nil # this will allow the modifications above to disappear
|
|
217
216
|
end
|
|
218
217
|
|
|
219
218
|
# Write the generated page file to the destination directory.
|
|
@@ -242,12 +241,12 @@ module Jekyll
|
|
|
242
241
|
end
|
|
243
242
|
end
|
|
244
243
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def _renderer
|
|
248
|
-
@_renderer ||= Jekyll::Renderer.new(site, self)
|
|
244
|
+
def renderer
|
|
245
|
+
@renderer ||= Jekyll::Renderer.new(site, self)
|
|
249
246
|
end
|
|
250
247
|
|
|
248
|
+
private
|
|
249
|
+
|
|
251
250
|
def no_layout?
|
|
252
251
|
data["layout"] == "none"
|
|
253
252
|
end
|
data/lib/jekyll/deprecator.rb
CHANGED
|
@@ -34,9 +34,7 @@ module Jekyll
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def arg_is_present?(args, deprecated_argument, message)
|
|
37
|
-
if args.include?(deprecated_argument)
|
|
38
|
-
deprecation_message(message)
|
|
39
|
-
end
|
|
37
|
+
deprecation_message(message) if args.include?(deprecated_argument)
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
def deprecation_message(message)
|
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)
|
|
@@ -286,7 +322,7 @@ module Jekyll
|
|
|
286
322
|
#
|
|
287
323
|
# Returns the inspect string for this document.
|
|
288
324
|
def inspect
|
|
289
|
-
"
|
|
325
|
+
"#<#{self.class} #{relative_path} collection=#{collection.label}>"
|
|
290
326
|
end
|
|
291
327
|
|
|
292
328
|
# The string representation for this document.
|
|
@@ -303,6 +339,7 @@ module Jekyll
|
|
|
303
339
|
# equal or greater than the other doc's path. See String#<=> for more details.
|
|
304
340
|
def <=>(other)
|
|
305
341
|
return nil unless other.respond_to?(:data)
|
|
342
|
+
|
|
306
343
|
cmp = data["date"] <=> other.data["date"]
|
|
307
344
|
cmp = path <=> other.path if cmp.nil? || cmp.zero?
|
|
308
345
|
cmp
|
|
@@ -315,7 +352,7 @@ module Jekyll
|
|
|
315
352
|
# method returns true, and if the site's Publisher will publish the document.
|
|
316
353
|
# False otherwise.
|
|
317
354
|
def write?
|
|
318
|
-
collection
|
|
355
|
+
collection&.write? && site.publisher.publish?(self)
|
|
319
356
|
end
|
|
320
357
|
|
|
321
358
|
# The Document excerpt_separator, from the YAML Front-Matter or site
|
|
@@ -323,7 +360,7 @@ module Jekyll
|
|
|
323
360
|
#
|
|
324
361
|
# Returns the document excerpt_separator
|
|
325
362
|
def excerpt_separator
|
|
326
|
-
(data["excerpt_separator"] || site.config["excerpt_separator"]).to_s
|
|
363
|
+
@excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s
|
|
327
364
|
end
|
|
328
365
|
|
|
329
366
|
# Whether to generate an excerpt
|
|
@@ -335,16 +372,12 @@ module Jekyll
|
|
|
335
372
|
|
|
336
373
|
def next_doc
|
|
337
374
|
pos = collection.docs.index { |post| post.equal?(self) }
|
|
338
|
-
if pos && pos < collection.docs.length - 1
|
|
339
|
-
collection.docs[pos + 1]
|
|
340
|
-
end
|
|
375
|
+
collection.docs[pos + 1] if pos && pos < collection.docs.length - 1
|
|
341
376
|
end
|
|
342
377
|
|
|
343
378
|
def previous_doc
|
|
344
379
|
pos = collection.docs.index { |post| post.equal?(self) }
|
|
345
|
-
if pos && pos
|
|
346
|
-
collection.docs[pos - 1]
|
|
347
|
-
end
|
|
380
|
+
collection.docs[pos - 1] if pos && pos.positive?
|
|
348
381
|
end
|
|
349
382
|
|
|
350
383
|
def trigger_hooks(hook_name, *args)
|
|
@@ -363,12 +396,6 @@ module Jekyll
|
|
|
363
396
|
@related_posts ||= Jekyll::RelatedPosts.new(self).build
|
|
364
397
|
end
|
|
365
398
|
|
|
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
399
|
# Override of method_missing to check in @data for the key.
|
|
373
400
|
def method_missing(method, *args, &blck)
|
|
374
401
|
if data.key?(method.to_s)
|
|
@@ -391,41 +418,44 @@ module Jekyll
|
|
|
391
418
|
#
|
|
392
419
|
# Returns nothing.
|
|
393
420
|
def categories_from_path(special_dir)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
421
|
+
if relative_path.start_with?(special_dir)
|
|
422
|
+
superdirs = []
|
|
423
|
+
else
|
|
424
|
+
superdirs = relative_path.sub(Document.superdirs_regex(special_dir), "")
|
|
425
|
+
superdirs = superdirs.split(File::SEPARATOR)
|
|
426
|
+
superdirs.reject! { |c| c.empty? || c == special_dir || c == basename }
|
|
398
427
|
end
|
|
428
|
+
|
|
399
429
|
merge_data!({ "categories" => superdirs }, :source => "file path")
|
|
400
430
|
end
|
|
401
431
|
|
|
402
432
|
def populate_categories
|
|
403
|
-
|
|
404
|
-
"categories"
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
433
|
+
categories = Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
|
434
|
+
data, "category", "categories"
|
|
435
|
+
)
|
|
436
|
+
categories.map!(&:to_s)
|
|
437
|
+
categories.flatten!
|
|
438
|
+
categories.uniq!
|
|
439
|
+
|
|
440
|
+
merge_data!({ "categories" => categories })
|
|
410
441
|
end
|
|
411
442
|
|
|
412
443
|
def populate_tags
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
444
|
+
tags = Utils.pluralized_array_from_hash(data, "tag", "tags")
|
|
445
|
+
tags.flatten!
|
|
446
|
+
|
|
447
|
+
merge_data!({ "tags" => tags })
|
|
416
448
|
end
|
|
417
449
|
|
|
418
450
|
private
|
|
451
|
+
|
|
419
452
|
def merge_categories!(other)
|
|
420
453
|
if other.key?("categories") && !other["categories"].nil?
|
|
421
|
-
if other["categories"].is_a?(String)
|
|
422
|
-
other["categories"] = other["categories"].split
|
|
423
|
-
end
|
|
454
|
+
other["categories"] = other["categories"].split if other["categories"].is_a?(String)
|
|
424
455
|
other["categories"] = (data["categories"] || []) | other["categories"]
|
|
425
456
|
end
|
|
426
457
|
end
|
|
427
458
|
|
|
428
|
-
private
|
|
429
459
|
def merge_date!(source)
|
|
430
460
|
if data.key?("date")
|
|
431
461
|
data["date"] = Utils.parse_date(
|
|
@@ -435,16 +465,11 @@ module Jekyll
|
|
|
435
465
|
end
|
|
436
466
|
end
|
|
437
467
|
|
|
438
|
-
private
|
|
439
468
|
def merge_defaults
|
|
440
|
-
defaults = @site.frontmatter_defaults.all(
|
|
441
|
-
relative_path,
|
|
442
|
-
collection.label.to_sym
|
|
443
|
-
)
|
|
469
|
+
defaults = @site.frontmatter_defaults.all(relative_path, type)
|
|
444
470
|
merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
|
|
445
471
|
end
|
|
446
472
|
|
|
447
|
-
private
|
|
448
473
|
def read_content(**opts)
|
|
449
474
|
self.content = File.read(path, **Utils.merged_file_read_opts(site, opts))
|
|
450
475
|
if content =~ YAML_FRONT_MATTER_REGEXP
|
|
@@ -454,7 +479,6 @@ module Jekyll
|
|
|
454
479
|
end
|
|
455
480
|
end
|
|
456
481
|
|
|
457
|
-
private
|
|
458
482
|
def read_post_data
|
|
459
483
|
populate_title
|
|
460
484
|
populate_categories
|
|
@@ -462,7 +486,6 @@ module Jekyll
|
|
|
462
486
|
generate_excerpt
|
|
463
487
|
end
|
|
464
488
|
|
|
465
|
-
private
|
|
466
489
|
def handle_read_error(error)
|
|
467
490
|
if error.is_a? Psych::SyntaxError
|
|
468
491
|
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}"
|
|
@@ -475,7 +498,7 @@ module Jekyll
|
|
|
475
498
|
end
|
|
476
499
|
end
|
|
477
500
|
|
|
478
|
-
|
|
501
|
+
# rubocop:disable Metrics/AbcSize
|
|
479
502
|
def populate_title
|
|
480
503
|
if relative_path =~ DATE_FILENAME_MATCHER
|
|
481
504
|
date, slug, ext = Regexp.last_match.captures
|
|
@@ -483,6 +506,14 @@ module Jekyll
|
|
|
483
506
|
elsif relative_path =~ DATELESS_FILENAME_MATCHER
|
|
484
507
|
slug, ext = Regexp.last_match.captures
|
|
485
508
|
end
|
|
509
|
+
# `slug` will be nil for documents without an extension since the regex patterns
|
|
510
|
+
# above tests for an extension as well.
|
|
511
|
+
# In such cases, assign `basename_without_ext` as the slug.
|
|
512
|
+
slug ||= basename_without_ext
|
|
513
|
+
|
|
514
|
+
# slugs shouldn't end with a period
|
|
515
|
+
# `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
|
|
516
|
+
slug.gsub!(%r!\.*\z!, "")
|
|
486
517
|
|
|
487
518
|
# Try to ensure the user gets a title.
|
|
488
519
|
data["title"] ||= Utils.titleize_slug(slug)
|
|
@@ -490,19 +521,16 @@ module Jekyll
|
|
|
490
521
|
data["slug"] ||= slug
|
|
491
522
|
data["ext"] ||= ext
|
|
492
523
|
end
|
|
524
|
+
# rubocop:enable Metrics/AbcSize
|
|
493
525
|
|
|
494
|
-
private
|
|
495
526
|
def modify_date(date)
|
|
496
527
|
if !data["date"] || data["date"].to_i == site.time.to_i
|
|
497
528
|
merge_data!({ "date" => date }, :source => "filename")
|
|
498
529
|
end
|
|
499
530
|
end
|
|
500
531
|
|
|
501
|
-
private
|
|
502
532
|
def generate_excerpt
|
|
503
|
-
if generate_excerpt?
|
|
504
|
-
data["excerpt"] ||= Jekyll::Excerpt.new(self)
|
|
505
|
-
end
|
|
533
|
+
data["excerpt"] ||= Jekyll::Excerpt.new(self) if generate_excerpt?
|
|
506
534
|
end
|
|
507
535
|
end
|
|
508
536
|
end
|