jekyll 4.2.1 → 4.3.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 +474 -350
- data/LICENSE +21 -21
- data/README.markdown +83 -86
- data/exe/jekyll +57 -57
- data/lib/blank_template/_config.yml +3 -3
- data/lib/blank_template/_layouts/default.html +12 -12
- data/lib/blank_template/_sass/main.scss +9 -9
- data/lib/blank_template/assets/css/main.scss +4 -4
- data/lib/blank_template/index.md +8 -8
- data/lib/jekyll/cache.rb +186 -190
- data/lib/jekyll/cleaner.rb +111 -111
- data/lib/jekyll/collection.rb +310 -309
- data/lib/jekyll/command.rb +105 -105
- data/lib/jekyll/commands/build.rb +82 -93
- data/lib/jekyll/commands/clean.rb +44 -45
- data/lib/jekyll/commands/doctor.rb +177 -177
- data/lib/jekyll/commands/help.rb +34 -34
- data/lib/jekyll/commands/new.rb +168 -169
- data/lib/jekyll/commands/new_theme.rb +39 -40
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +119 -122
- data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
- data/lib/jekyll/commands/serve/mime_types_charset.json +71 -0
- data/lib/jekyll/commands/serve/servlet.rb +206 -202
- data/lib/jekyll/commands/serve/websockets.rb +81 -81
- data/lib/jekyll/commands/serve.rb +367 -362
- data/lib/jekyll/configuration.rb +313 -313
- data/lib/jekyll/converter.rb +54 -54
- data/lib/jekyll/converters/identity.rb +41 -41
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +197 -199
- data/lib/jekyll/converters/markdown.rb +113 -113
- data/lib/jekyll/converters/smartypants.rb +70 -70
- data/lib/jekyll/convertible.rb +257 -257
- data/lib/jekyll/data_entry.rb +83 -0
- data/lib/jekyll/data_hash.rb +61 -0
- data/lib/jekyll/deprecator.rb +50 -50
- data/lib/jekyll/document.rb +543 -544
- data/lib/jekyll/drops/collection_drop.rb +20 -20
- data/lib/jekyll/drops/document_drop.rb +71 -70
- data/lib/jekyll/drops/drop.rb +293 -293
- data/lib/jekyll/drops/excerpt_drop.rb +23 -19
- data/lib/jekyll/drops/jekyll_drop.rb +32 -32
- data/lib/jekyll/drops/site_drop.rb +71 -66
- data/lib/jekyll/drops/static_file_drop.rb +14 -14
- data/lib/jekyll/drops/theme_drop.rb +36 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +30 -26
- data/lib/jekyll/drops/url_drop.rb +140 -140
- data/lib/jekyll/entry_filter.rb +117 -121
- data/lib/jekyll/errors.rb +20 -20
- data/lib/jekyll/excerpt.rb +200 -201
- data/lib/jekyll/external.rb +75 -79
- data/lib/jekyll/filters/date_filters.rb +110 -110
- data/lib/jekyll/filters/grouping_filters.rb +64 -64
- data/lib/jekyll/filters/url_filters.rb +98 -98
- data/lib/jekyll/filters.rb +532 -535
- data/lib/jekyll/frontmatter_defaults.rb +238 -240
- data/lib/jekyll/generator.rb +5 -5
- data/lib/jekyll/hooks.rb +107 -107
- data/lib/jekyll/inclusion.rb +32 -32
- data/lib/jekyll/layout.rb +55 -67
- data/lib/jekyll/liquid_extensions.rb +22 -22
- data/lib/jekyll/liquid_renderer/file.rb +77 -77
- data/lib/jekyll/liquid_renderer/table.rb +55 -55
- data/lib/jekyll/liquid_renderer.rb +80 -80
- data/lib/jekyll/log_adapter.rb +151 -151
- data/lib/jekyll/mime.types +939 -866
- data/lib/jekyll/page.rb +215 -217
- data/lib/jekyll/page_excerpt.rb +25 -25
- data/lib/jekyll/page_without_a_file.rb +14 -14
- data/lib/jekyll/path_manager.rb +74 -74
- data/lib/jekyll/plugin.rb +92 -92
- data/lib/jekyll/plugin_manager.rb +123 -115
- data/lib/jekyll/profiler.rb +55 -58
- data/lib/jekyll/publisher.rb +23 -23
- data/lib/jekyll/reader.rb +209 -192
- data/lib/jekyll/readers/collection_reader.rb +23 -23
- data/lib/jekyll/readers/data_reader.rb +116 -79
- data/lib/jekyll/readers/layout_reader.rb +62 -62
- data/lib/jekyll/readers/page_reader.rb +25 -25
- data/lib/jekyll/readers/post_reader.rb +85 -85
- data/lib/jekyll/readers/static_file_reader.rb +25 -25
- data/lib/jekyll/readers/theme_assets_reader.rb +52 -52
- data/lib/jekyll/regenerator.rb +195 -195
- data/lib/jekyll/related_posts.rb +52 -52
- data/lib/jekyll/renderer.rb +263 -265
- data/lib/jekyll/site.rb +582 -551
- data/lib/jekyll/static_file.rb +205 -208
- data/lib/jekyll/stevenson.rb +60 -60
- data/lib/jekyll/tags/highlight.rb +114 -110
- data/lib/jekyll/tags/include.rb +275 -275
- data/lib/jekyll/tags/link.rb +42 -42
- data/lib/jekyll/tags/post_url.rb +106 -106
- data/lib/jekyll/theme.rb +90 -86
- data/lib/jekyll/theme_builder.rb +121 -121
- data/lib/jekyll/url.rb +167 -167
- data/lib/jekyll/utils/ansi.rb +57 -57
- data/lib/jekyll/utils/exec.rb +26 -26
- data/lib/jekyll/utils/internet.rb +37 -37
- data/lib/jekyll/utils/platforms.rb +67 -67
- data/lib/jekyll/utils/thread_event.rb +31 -31
- data/lib/jekyll/utils/win_tz.rb +46 -75
- data/lib/jekyll/utils.rb +378 -367
- data/lib/jekyll/version.rb +5 -5
- data/lib/jekyll.rb +197 -195
- data/lib/site_template/.gitignore +5 -5
- data/lib/site_template/404.html +25 -25
- data/lib/site_template/_config.yml +55 -55
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
- data/lib/site_template/about.markdown +18 -18
- data/lib/site_template/index.markdown +6 -6
- data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
- data/lib/theme_template/Gemfile +4 -4
- data/lib/theme_template/LICENSE.txt.erb +21 -21
- data/lib/theme_template/README.md.erb +50 -52
- data/lib/theme_template/_layouts/default.html +1 -1
- data/lib/theme_template/_layouts/page.html +5 -5
- data/lib/theme_template/_layouts/post.html +5 -5
- data/lib/theme_template/example/_config.yml.erb +1 -1
- data/lib/theme_template/example/_post.md +12 -12
- data/lib/theme_template/example/index.html +14 -14
- data/lib/theme_template/example/style.scss +7 -7
- data/lib/theme_template/gitignore.erb +6 -6
- data/lib/theme_template/theme.gemspec.erb +16 -16
- data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
- data/rubocop/jekyll/no_p_allowed.rb +23 -23
- data/rubocop/jekyll/no_puts_allowed.rb +23 -23
- data/rubocop/jekyll.rb +5 -5
- metadata +62 -14
data/lib/jekyll/convertible.rb
CHANGED
|
@@ -1,257 +1,257 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Convertible provides methods for converting a pagelike item
|
|
4
|
-
# from a certain type of markup into actual content
|
|
5
|
-
#
|
|
6
|
-
# Requires
|
|
7
|
-
# self.site -> Jekyll::Site
|
|
8
|
-
# self.content
|
|
9
|
-
# self.content=
|
|
10
|
-
# self.data=
|
|
11
|
-
# self.ext=
|
|
12
|
-
# self.output=
|
|
13
|
-
# self.name
|
|
14
|
-
# self.path
|
|
15
|
-
# self.type -> :page, :post or :draft
|
|
16
|
-
|
|
17
|
-
module Jekyll
|
|
18
|
-
module Convertible
|
|
19
|
-
# Returns the contents as a String.
|
|
20
|
-
def to_s
|
|
21
|
-
content || ""
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Whether the file is published or not, as indicated in YAML front-matter
|
|
25
|
-
def published?
|
|
26
|
-
!(data.key?("published") && data["published"] == false)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Read the YAML frontmatter.
|
|
30
|
-
#
|
|
31
|
-
# base - The String path to the dir containing the file.
|
|
32
|
-
# name - The String filename of the file.
|
|
33
|
-
# opts - optional parameter to File.read, default at site configs
|
|
34
|
-
#
|
|
35
|
-
# Returns nothing.
|
|
36
|
-
# rubocop:disable Metrics/AbcSize
|
|
37
|
-
def read_yaml(base, name, opts = {})
|
|
38
|
-
filename = @path || site.in_source_dir(base, name)
|
|
39
|
-
Jekyll.logger.debug "Reading:", relative_path
|
|
40
|
-
|
|
41
|
-
begin
|
|
42
|
-
self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts))
|
|
43
|
-
if content =~ Document::YAML_FRONT_MATTER_REGEXP
|
|
44
|
-
self.content = Regexp.last_match.post_match
|
|
45
|
-
self.data = SafeYAML.load(Regexp.last_match(1))
|
|
46
|
-
end
|
|
47
|
-
rescue Psych::SyntaxError => e
|
|
48
|
-
Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}"
|
|
49
|
-
raise e if site.config["strict_front_matter"]
|
|
50
|
-
rescue StandardError => e
|
|
51
|
-
Jekyll.logger.warn "Error reading file #{filename}: #{e.message}"
|
|
52
|
-
raise e if site.config["strict_front_matter"]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
self.data ||= {}
|
|
56
|
-
|
|
57
|
-
validate_data! filename
|
|
58
|
-
validate_permalink! filename
|
|
59
|
-
|
|
60
|
-
self.data
|
|
61
|
-
end
|
|
62
|
-
# rubocop:enable Metrics/AbcSize
|
|
63
|
-
|
|
64
|
-
def validate_data!(filename)
|
|
65
|
-
unless self.data.is_a?(Hash)
|
|
66
|
-
raise Errors::InvalidYAMLFrontMatterError,
|
|
67
|
-
"Invalid YAML front matter in #{filename}"
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def validate_permalink!(filename)
|
|
72
|
-
if self.data["permalink"] == ""
|
|
73
|
-
raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Transform the contents based on the content type.
|
|
78
|
-
#
|
|
79
|
-
# Returns the transformed contents.
|
|
80
|
-
def transform
|
|
81
|
-
renderer.convert(content)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Determine the extension depending on content_type.
|
|
85
|
-
#
|
|
86
|
-
# Returns the String extension for the output file.
|
|
87
|
-
# e.g. ".html" for an HTML output file.
|
|
88
|
-
def output_ext
|
|
89
|
-
renderer.output_ext
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Determine which converter to use based on this convertible's
|
|
93
|
-
# extension.
|
|
94
|
-
#
|
|
95
|
-
# Returns the Converter instance.
|
|
96
|
-
def converters
|
|
97
|
-
renderer.converters
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Render Liquid in the content
|
|
101
|
-
#
|
|
102
|
-
# content - the raw Liquid content to render
|
|
103
|
-
# payload - the payload for Liquid
|
|
104
|
-
# info - the info for Liquid
|
|
105
|
-
#
|
|
106
|
-
# Returns the converted content
|
|
107
|
-
def render_liquid(content, payload, info, path)
|
|
108
|
-
renderer.render_liquid(content, payload, info, path)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
|
112
|
-
#
|
|
113
|
-
# Returns the Hash representation of this Convertible.
|
|
114
|
-
def to_liquid(attrs = nil)
|
|
115
|
-
further_data = \
|
|
116
|
-
(attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh|
|
|
117
|
-
hsh[attribute] = send(attribute)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# The type of a document,
|
|
124
|
-
# i.e., its classname downcase'd and to_sym'd.
|
|
125
|
-
#
|
|
126
|
-
# Returns the type of self.
|
|
127
|
-
def type
|
|
128
|
-
:pages if is_a?(Page)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# returns the owner symbol for hook triggering
|
|
132
|
-
def hook_owner
|
|
133
|
-
:pages if is_a?(Page)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Determine whether the document is an asset file.
|
|
137
|
-
# Asset files include CoffeeScript files and Sass/SCSS files.
|
|
138
|
-
#
|
|
139
|
-
# Returns true if the extname belongs to the set of extensions
|
|
140
|
-
# that asset files use.
|
|
141
|
-
def asset_file?
|
|
142
|
-
sass_file? || coffeescript_file?
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Determine whether the document is a Sass file.
|
|
146
|
-
#
|
|
147
|
-
# Returns true if extname == .sass or .scss, false otherwise.
|
|
148
|
-
def sass_file?
|
|
149
|
-
Jekyll::Document::SASS_FILE_EXTS.include?(ext)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# Determine whether the document is a CoffeeScript file.
|
|
153
|
-
#
|
|
154
|
-
# Returns true if extname == .coffee, false otherwise.
|
|
155
|
-
def coffeescript_file?
|
|
156
|
-
ext == ".coffee"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# Determine whether the file should be rendered with Liquid.
|
|
160
|
-
#
|
|
161
|
-
# Returns true if the file has Liquid Tags or Variables, false otherwise.
|
|
162
|
-
def render_with_liquid?
|
|
163
|
-
return false if data["render_with_liquid"] == false
|
|
164
|
-
|
|
165
|
-
Jekyll::Utils.has_liquid_construct?(content)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Determine whether the file should be placed into layouts.
|
|
169
|
-
#
|
|
170
|
-
# Returns false if the document is an asset file or if the front matter
|
|
171
|
-
# specifies `layout: none`
|
|
172
|
-
def place_in_layout?
|
|
173
|
-
!(asset_file? || no_layout?)
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# Checks if the layout specified in the document actually exists
|
|
177
|
-
#
|
|
178
|
-
# layout - the layout to check
|
|
179
|
-
#
|
|
180
|
-
# Returns true if the layout is invalid, false if otherwise
|
|
181
|
-
def invalid_layout?(layout)
|
|
182
|
-
!data["layout"].nil? && layout.nil? && !(is_a? Jekyll::Excerpt)
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
# Recursively render layouts
|
|
186
|
-
#
|
|
187
|
-
# layouts - a list of the layouts
|
|
188
|
-
# payload - the payload for Liquid
|
|
189
|
-
# info - the info for Liquid
|
|
190
|
-
#
|
|
191
|
-
# Returns nothing
|
|
192
|
-
def render_all_layouts(layouts, payload, info)
|
|
193
|
-
renderer.layouts = layouts
|
|
194
|
-
self.output = renderer.place_in_layouts(output, payload, info)
|
|
195
|
-
ensure
|
|
196
|
-
@renderer = nil # this will allow the modifications above to disappear
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Add any necessary layouts to this convertible document.
|
|
200
|
-
#
|
|
201
|
-
# payload - The site payload Drop or Hash.
|
|
202
|
-
# layouts - A Hash of {"name" => "layout"}.
|
|
203
|
-
#
|
|
204
|
-
# Returns nothing.
|
|
205
|
-
def do_layout(payload, layouts)
|
|
206
|
-
self.output = renderer.tap do |doc_renderer|
|
|
207
|
-
doc_renderer.layouts = layouts
|
|
208
|
-
doc_renderer.payload = payload
|
|
209
|
-
end.run
|
|
210
|
-
|
|
211
|
-
Jekyll.logger.debug "Post-Render Hooks:", relative_path
|
|
212
|
-
Jekyll::Hooks.trigger hook_owner, :post_render, self
|
|
213
|
-
ensure
|
|
214
|
-
@renderer = nil # this will allow the modifications above to disappear
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# Write the generated page file to the destination directory.
|
|
218
|
-
#
|
|
219
|
-
# dest - The String path to the destination dir.
|
|
220
|
-
#
|
|
221
|
-
# Returns nothing.
|
|
222
|
-
def write(dest)
|
|
223
|
-
path = destination(dest)
|
|
224
|
-
FileUtils.mkdir_p(File.dirname(path))
|
|
225
|
-
Jekyll.logger.debug "Writing:", path
|
|
226
|
-
File.write(path, output, :mode => "wb")
|
|
227
|
-
Jekyll::Hooks.trigger hook_owner, :post_write, self
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
# Accessor for data properties by Liquid.
|
|
231
|
-
#
|
|
232
|
-
# property - The String name of the property to retrieve.
|
|
233
|
-
#
|
|
234
|
-
# Returns the String value or nil if the property isn't included.
|
|
235
|
-
def [](property)
|
|
236
|
-
if self.class::ATTRIBUTES_FOR_LIQUID.include?(property)
|
|
237
|
-
send(property)
|
|
238
|
-
else
|
|
239
|
-
data[property]
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def renderer
|
|
244
|
-
@renderer ||= Jekyll::Renderer.new(site, self)
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
private
|
|
248
|
-
|
|
249
|
-
def defaults
|
|
250
|
-
@defaults ||= site.frontmatter_defaults.all(relative_path, type)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def no_layout?
|
|
254
|
-
data["layout"] == "none"
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Convertible provides methods for converting a pagelike item
|
|
4
|
+
# from a certain type of markup into actual content
|
|
5
|
+
#
|
|
6
|
+
# Requires
|
|
7
|
+
# self.site -> Jekyll::Site
|
|
8
|
+
# self.content
|
|
9
|
+
# self.content=
|
|
10
|
+
# self.data=
|
|
11
|
+
# self.ext=
|
|
12
|
+
# self.output=
|
|
13
|
+
# self.name
|
|
14
|
+
# self.path
|
|
15
|
+
# self.type -> :page, :post or :draft
|
|
16
|
+
|
|
17
|
+
module Jekyll
|
|
18
|
+
module Convertible
|
|
19
|
+
# Returns the contents as a String.
|
|
20
|
+
def to_s
|
|
21
|
+
content || ""
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Whether the file is published or not, as indicated in YAML front-matter
|
|
25
|
+
def published?
|
|
26
|
+
!(data.key?("published") && data["published"] == false)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Read the YAML frontmatter.
|
|
30
|
+
#
|
|
31
|
+
# base - The String path to the dir containing the file.
|
|
32
|
+
# name - The String filename of the file.
|
|
33
|
+
# opts - optional parameter to File.read, default at site configs
|
|
34
|
+
#
|
|
35
|
+
# Returns nothing.
|
|
36
|
+
# rubocop:disable Metrics/AbcSize
|
|
37
|
+
def read_yaml(base, name, opts = {})
|
|
38
|
+
filename = @path || site.in_source_dir(base, name)
|
|
39
|
+
Jekyll.logger.debug "Reading:", relative_path
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts))
|
|
43
|
+
if content =~ Document::YAML_FRONT_MATTER_REGEXP
|
|
44
|
+
self.content = Regexp.last_match.post_match
|
|
45
|
+
self.data = SafeYAML.load(Regexp.last_match(1))
|
|
46
|
+
end
|
|
47
|
+
rescue Psych::SyntaxError => e
|
|
48
|
+
Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}"
|
|
49
|
+
raise e if site.config["strict_front_matter"]
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
Jekyll.logger.warn "Error reading file #{filename}: #{e.message}"
|
|
52
|
+
raise e if site.config["strict_front_matter"]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self.data ||= {}
|
|
56
|
+
|
|
57
|
+
validate_data! filename
|
|
58
|
+
validate_permalink! filename
|
|
59
|
+
|
|
60
|
+
self.data
|
|
61
|
+
end
|
|
62
|
+
# rubocop:enable Metrics/AbcSize
|
|
63
|
+
|
|
64
|
+
def validate_data!(filename)
|
|
65
|
+
unless self.data.is_a?(Hash)
|
|
66
|
+
raise Errors::InvalidYAMLFrontMatterError,
|
|
67
|
+
"Invalid YAML front matter in #{filename}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_permalink!(filename)
|
|
72
|
+
if self.data["permalink"] == ""
|
|
73
|
+
raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Transform the contents based on the content type.
|
|
78
|
+
#
|
|
79
|
+
# Returns the transformed contents.
|
|
80
|
+
def transform
|
|
81
|
+
renderer.convert(content)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Determine the extension depending on content_type.
|
|
85
|
+
#
|
|
86
|
+
# Returns the String extension for the output file.
|
|
87
|
+
# e.g. ".html" for an HTML output file.
|
|
88
|
+
def output_ext
|
|
89
|
+
renderer.output_ext
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Determine which converter to use based on this convertible's
|
|
93
|
+
# extension.
|
|
94
|
+
#
|
|
95
|
+
# Returns the Converter instance.
|
|
96
|
+
def converters
|
|
97
|
+
renderer.converters
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Render Liquid in the content
|
|
101
|
+
#
|
|
102
|
+
# content - the raw Liquid content to render
|
|
103
|
+
# payload - the payload for Liquid
|
|
104
|
+
# info - the info for Liquid
|
|
105
|
+
#
|
|
106
|
+
# Returns the converted content
|
|
107
|
+
def render_liquid(content, payload, info, path)
|
|
108
|
+
renderer.render_liquid(content, payload, info, path)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
|
112
|
+
#
|
|
113
|
+
# Returns the Hash representation of this Convertible.
|
|
114
|
+
def to_liquid(attrs = nil)
|
|
115
|
+
further_data = \
|
|
116
|
+
(attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh|
|
|
117
|
+
hsh[attribute] = send(attribute)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The type of a document,
|
|
124
|
+
# i.e., its classname downcase'd and to_sym'd.
|
|
125
|
+
#
|
|
126
|
+
# Returns the type of self.
|
|
127
|
+
def type
|
|
128
|
+
:pages if is_a?(Page)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# returns the owner symbol for hook triggering
|
|
132
|
+
def hook_owner
|
|
133
|
+
:pages if is_a?(Page)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Determine whether the document is an asset file.
|
|
137
|
+
# Asset files include CoffeeScript files and Sass/SCSS files.
|
|
138
|
+
#
|
|
139
|
+
# Returns true if the extname belongs to the set of extensions
|
|
140
|
+
# that asset files use.
|
|
141
|
+
def asset_file?
|
|
142
|
+
sass_file? || coffeescript_file?
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Determine whether the document is a Sass file.
|
|
146
|
+
#
|
|
147
|
+
# Returns true if extname == .sass or .scss, false otherwise.
|
|
148
|
+
def sass_file?
|
|
149
|
+
Jekyll::Document::SASS_FILE_EXTS.include?(ext)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Determine whether the document is a CoffeeScript file.
|
|
153
|
+
#
|
|
154
|
+
# Returns true if extname == .coffee, false otherwise.
|
|
155
|
+
def coffeescript_file?
|
|
156
|
+
ext == ".coffee"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Determine whether the file should be rendered with Liquid.
|
|
160
|
+
#
|
|
161
|
+
# Returns true if the file has Liquid Tags or Variables, false otherwise.
|
|
162
|
+
def render_with_liquid?
|
|
163
|
+
return false if data["render_with_liquid"] == false
|
|
164
|
+
|
|
165
|
+
Jekyll::Utils.has_liquid_construct?(content)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Determine whether the file should be placed into layouts.
|
|
169
|
+
#
|
|
170
|
+
# Returns false if the document is an asset file or if the front matter
|
|
171
|
+
# specifies `layout: none`
|
|
172
|
+
def place_in_layout?
|
|
173
|
+
!(asset_file? || no_layout?)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Checks if the layout specified in the document actually exists
|
|
177
|
+
#
|
|
178
|
+
# layout - the layout to check
|
|
179
|
+
#
|
|
180
|
+
# Returns true if the layout is invalid, false if otherwise
|
|
181
|
+
def invalid_layout?(layout)
|
|
182
|
+
!data["layout"].nil? && layout.nil? && !(is_a? Jekyll::Excerpt)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Recursively render layouts
|
|
186
|
+
#
|
|
187
|
+
# layouts - a list of the layouts
|
|
188
|
+
# payload - the payload for Liquid
|
|
189
|
+
# info - the info for Liquid
|
|
190
|
+
#
|
|
191
|
+
# Returns nothing
|
|
192
|
+
def render_all_layouts(layouts, payload, info)
|
|
193
|
+
renderer.layouts = layouts
|
|
194
|
+
self.output = renderer.place_in_layouts(output, payload, info)
|
|
195
|
+
ensure
|
|
196
|
+
@renderer = nil # this will allow the modifications above to disappear
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Add any necessary layouts to this convertible document.
|
|
200
|
+
#
|
|
201
|
+
# payload - The site payload Drop or Hash.
|
|
202
|
+
# layouts - A Hash of {"name" => "layout"}.
|
|
203
|
+
#
|
|
204
|
+
# Returns nothing.
|
|
205
|
+
def do_layout(payload, layouts)
|
|
206
|
+
self.output = renderer.tap do |doc_renderer|
|
|
207
|
+
doc_renderer.layouts = layouts
|
|
208
|
+
doc_renderer.payload = payload
|
|
209
|
+
end.run
|
|
210
|
+
|
|
211
|
+
Jekyll.logger.debug "Post-Render Hooks:", relative_path
|
|
212
|
+
Jekyll::Hooks.trigger hook_owner, :post_render, self
|
|
213
|
+
ensure
|
|
214
|
+
@renderer = nil # this will allow the modifications above to disappear
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Write the generated page file to the destination directory.
|
|
218
|
+
#
|
|
219
|
+
# dest - The String path to the destination dir.
|
|
220
|
+
#
|
|
221
|
+
# Returns nothing.
|
|
222
|
+
def write(dest)
|
|
223
|
+
path = destination(dest)
|
|
224
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
225
|
+
Jekyll.logger.debug "Writing:", path
|
|
226
|
+
File.write(path, output, :mode => "wb")
|
|
227
|
+
Jekyll::Hooks.trigger hook_owner, :post_write, self
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Accessor for data properties by Liquid.
|
|
231
|
+
#
|
|
232
|
+
# property - The String name of the property to retrieve.
|
|
233
|
+
#
|
|
234
|
+
# Returns the String value or nil if the property isn't included.
|
|
235
|
+
def [](property)
|
|
236
|
+
if self.class::ATTRIBUTES_FOR_LIQUID.include?(property)
|
|
237
|
+
send(property)
|
|
238
|
+
else
|
|
239
|
+
data[property]
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def renderer
|
|
244
|
+
@renderer ||= Jekyll::Renderer.new(site, self)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
private
|
|
248
|
+
|
|
249
|
+
def defaults
|
|
250
|
+
@defaults ||= site.frontmatter_defaults.all(relative_path, type)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def no_layout?
|
|
254
|
+
data["layout"] == "none"
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
class DataEntry
|
|
5
|
+
attr_accessor :context
|
|
6
|
+
attr_reader :data
|
|
7
|
+
|
|
8
|
+
# Create a Jekyll wrapper for given parsed data object.
|
|
9
|
+
#
|
|
10
|
+
# site - The current Jekyll::Site instance.
|
|
11
|
+
# abs_path - Absolute path to the data source file.
|
|
12
|
+
# parsed_data - Parsed representation of data source file contents.
|
|
13
|
+
#
|
|
14
|
+
# Returns nothing.
|
|
15
|
+
def initialize(site, abs_path, parsed_data)
|
|
16
|
+
@site = site
|
|
17
|
+
@path = abs_path
|
|
18
|
+
@data = parsed_data
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Liquid representation of current instance is the parsed data object.
|
|
22
|
+
#
|
|
23
|
+
# Mark as a dependency for regeneration here since every renderable object primarily uses the
|
|
24
|
+
# parsed data object while the parent resource is being rendered by Liquid. Accessing the data
|
|
25
|
+
# object directly via Ruby interface `#[]()` is outside the scope of regeneration.
|
|
26
|
+
#
|
|
27
|
+
# FIXME: Marking as dependency on every call is non-ideal. Optimize at later day.
|
|
28
|
+
#
|
|
29
|
+
# Returns the parsed data object.
|
|
30
|
+
def to_liquid
|
|
31
|
+
add_regenerator_dependencies if incremental_build?
|
|
32
|
+
@data
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# -- Overrides to maintain backwards compatibility --
|
|
36
|
+
|
|
37
|
+
# Any missing method will be forwarded to the underlying data object stored in the instance
|
|
38
|
+
# variable `@data`.
|
|
39
|
+
def method_missing(method, *args, &block)
|
|
40
|
+
@data.respond_to?(method) ? @data.send(method, *args, &block) : super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def respond_to_missing?(method, *)
|
|
44
|
+
@data.respond_to?(method) || super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def <=>(other)
|
|
48
|
+
data <=> (other.is_a?(self.class) ? other.data : other)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def ==(other)
|
|
52
|
+
data == (other.is_a?(self.class) ? other.data : other)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Explicitly defined to bypass re-routing from `method_missing` hook for greater performance.
|
|
56
|
+
#
|
|
57
|
+
# Returns string representation of parsed data object.
|
|
58
|
+
def inspect
|
|
59
|
+
@data.inspect
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def incremental_build?
|
|
65
|
+
@incremental = @site.config["incremental"] if @incremental.nil?
|
|
66
|
+
@incremental
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def add_regenerator_dependencies
|
|
70
|
+
page = context.registers[:page]
|
|
71
|
+
return unless page&.key?("path")
|
|
72
|
+
|
|
73
|
+
absolute_path = \
|
|
74
|
+
if page["collection"]
|
|
75
|
+
@site.in_source_dir(@site.config["collections_dir"], page["path"])
|
|
76
|
+
else
|
|
77
|
+
@site.in_source_dir(page["path"])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
@site.regenerator.add_dependency(absolute_path, @path)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
# A class that behaves very similar to Ruby's `Hash` class yet different in how it is handled by
|
|
5
|
+
# Liquid. This class emulates Hash by delegation instead of inheritance to minimize overridden
|
|
6
|
+
# methods especially since some Hash methods returns another Hash instance instead of the
|
|
7
|
+
# subclass instance.
|
|
8
|
+
class DataHash
|
|
9
|
+
#
|
|
10
|
+
# Delegate given (zero-arity) method(s) to the Hash object stored in instance variable
|
|
11
|
+
# `@registry`.
|
|
12
|
+
# NOTE: Avoiding the use of `Forwardable` module's `def_delegators` for preventing unnecessary
|
|
13
|
+
# creation of interim objects on multiple calls.
|
|
14
|
+
def self.delegate_to_registry(*symbols)
|
|
15
|
+
symbols.each { |sym| define_method(sym) { @registry.send(sym) } }
|
|
16
|
+
end
|
|
17
|
+
private_class_method :delegate_to_registry
|
|
18
|
+
|
|
19
|
+
# -- core instance methods --
|
|
20
|
+
|
|
21
|
+
attr_accessor :context
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
@registry = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def [](key)
|
|
28
|
+
@registry[key].tap do |value|
|
|
29
|
+
value.context = context if value.respond_to?(:context=)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# `Hash#to_liquid` returns the Hash instance itself.
|
|
34
|
+
# Mimic that behavior by returning `self` instead of returning the `@registry` variable value.
|
|
35
|
+
def to_liquid
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# -- supplementary instance methods to emulate Hash --
|
|
40
|
+
|
|
41
|
+
delegate_to_registry :freeze, :inspect
|
|
42
|
+
|
|
43
|
+
def merge(other, &block)
|
|
44
|
+
merged_registry = @registry.merge(other, &block)
|
|
45
|
+
dup.tap { |d| d.instance_variable_set(:@registry, merged_registry) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def merge!(other, &block)
|
|
49
|
+
@registry.merge!(other, &block)
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def method_missing(method, *args, &block)
|
|
54
|
+
@registry.send(method, *args, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def respond_to_missing?(method, *)
|
|
58
|
+
@registry.respond_to?(method)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|