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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +474 -350
  3. data/LICENSE +21 -21
  4. data/README.markdown +83 -86
  5. data/exe/jekyll +57 -57
  6. data/lib/blank_template/_config.yml +3 -3
  7. data/lib/blank_template/_layouts/default.html +12 -12
  8. data/lib/blank_template/_sass/main.scss +9 -9
  9. data/lib/blank_template/assets/css/main.scss +4 -4
  10. data/lib/blank_template/index.md +8 -8
  11. data/lib/jekyll/cache.rb +186 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +310 -309
  14. data/lib/jekyll/command.rb +105 -105
  15. data/lib/jekyll/commands/build.rb +82 -93
  16. data/lib/jekyll/commands/clean.rb +44 -45
  17. data/lib/jekyll/commands/doctor.rb +177 -177
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +168 -169
  20. data/lib/jekyll/commands/new_theme.rb +39 -40
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +119 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/mime_types_charset.json +71 -0
  24. data/lib/jekyll/commands/serve/servlet.rb +206 -202
  25. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  26. data/lib/jekyll/commands/serve.rb +367 -362
  27. data/lib/jekyll/configuration.rb +313 -313
  28. data/lib/jekyll/converter.rb +54 -54
  29. data/lib/jekyll/converters/identity.rb +41 -41
  30. data/lib/jekyll/converters/markdown/kramdown_parser.rb +197 -199
  31. data/lib/jekyll/converters/markdown.rb +113 -113
  32. data/lib/jekyll/converters/smartypants.rb +70 -70
  33. data/lib/jekyll/convertible.rb +257 -257
  34. data/lib/jekyll/data_entry.rb +83 -0
  35. data/lib/jekyll/data_hash.rb +61 -0
  36. data/lib/jekyll/deprecator.rb +50 -50
  37. data/lib/jekyll/document.rb +543 -544
  38. data/lib/jekyll/drops/collection_drop.rb +20 -20
  39. data/lib/jekyll/drops/document_drop.rb +71 -70
  40. data/lib/jekyll/drops/drop.rb +293 -293
  41. data/lib/jekyll/drops/excerpt_drop.rb +23 -19
  42. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  43. data/lib/jekyll/drops/site_drop.rb +71 -66
  44. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  45. data/lib/jekyll/drops/theme_drop.rb +36 -0
  46. data/lib/jekyll/drops/unified_payload_drop.rb +30 -26
  47. data/lib/jekyll/drops/url_drop.rb +140 -140
  48. data/lib/jekyll/entry_filter.rb +117 -121
  49. data/lib/jekyll/errors.rb +20 -20
  50. data/lib/jekyll/excerpt.rb +200 -201
  51. data/lib/jekyll/external.rb +75 -79
  52. data/lib/jekyll/filters/date_filters.rb +110 -110
  53. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  54. data/lib/jekyll/filters/url_filters.rb +98 -98
  55. data/lib/jekyll/filters.rb +532 -535
  56. data/lib/jekyll/frontmatter_defaults.rb +238 -240
  57. data/lib/jekyll/generator.rb +5 -5
  58. data/lib/jekyll/hooks.rb +107 -107
  59. data/lib/jekyll/inclusion.rb +32 -32
  60. data/lib/jekyll/layout.rb +55 -67
  61. data/lib/jekyll/liquid_extensions.rb +22 -22
  62. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  63. data/lib/jekyll/liquid_renderer/table.rb +55 -55
  64. data/lib/jekyll/liquid_renderer.rb +80 -80
  65. data/lib/jekyll/log_adapter.rb +151 -151
  66. data/lib/jekyll/mime.types +939 -866
  67. data/lib/jekyll/page.rb +215 -217
  68. data/lib/jekyll/page_excerpt.rb +25 -25
  69. data/lib/jekyll/page_without_a_file.rb +14 -14
  70. data/lib/jekyll/path_manager.rb +74 -74
  71. data/lib/jekyll/plugin.rb +92 -92
  72. data/lib/jekyll/plugin_manager.rb +123 -115
  73. data/lib/jekyll/profiler.rb +55 -58
  74. data/lib/jekyll/publisher.rb +23 -23
  75. data/lib/jekyll/reader.rb +209 -192
  76. data/lib/jekyll/readers/collection_reader.rb +23 -23
  77. data/lib/jekyll/readers/data_reader.rb +116 -79
  78. data/lib/jekyll/readers/layout_reader.rb +62 -62
  79. data/lib/jekyll/readers/page_reader.rb +25 -25
  80. data/lib/jekyll/readers/post_reader.rb +85 -85
  81. data/lib/jekyll/readers/static_file_reader.rb +25 -25
  82. data/lib/jekyll/readers/theme_assets_reader.rb +52 -52
  83. data/lib/jekyll/regenerator.rb +195 -195
  84. data/lib/jekyll/related_posts.rb +52 -52
  85. data/lib/jekyll/renderer.rb +263 -265
  86. data/lib/jekyll/site.rb +582 -551
  87. data/lib/jekyll/static_file.rb +205 -208
  88. data/lib/jekyll/stevenson.rb +60 -60
  89. data/lib/jekyll/tags/highlight.rb +114 -110
  90. data/lib/jekyll/tags/include.rb +275 -275
  91. data/lib/jekyll/tags/link.rb +42 -42
  92. data/lib/jekyll/tags/post_url.rb +106 -106
  93. data/lib/jekyll/theme.rb +90 -86
  94. data/lib/jekyll/theme_builder.rb +121 -121
  95. data/lib/jekyll/url.rb +167 -167
  96. data/lib/jekyll/utils/ansi.rb +57 -57
  97. data/lib/jekyll/utils/exec.rb +26 -26
  98. data/lib/jekyll/utils/internet.rb +37 -37
  99. data/lib/jekyll/utils/platforms.rb +67 -67
  100. data/lib/jekyll/utils/thread_event.rb +31 -31
  101. data/lib/jekyll/utils/win_tz.rb +46 -75
  102. data/lib/jekyll/utils.rb +378 -367
  103. data/lib/jekyll/version.rb +5 -5
  104. data/lib/jekyll.rb +197 -195
  105. data/lib/site_template/.gitignore +5 -5
  106. data/lib/site_template/404.html +25 -25
  107. data/lib/site_template/_config.yml +55 -55
  108. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  109. data/lib/site_template/about.markdown +18 -18
  110. data/lib/site_template/index.markdown +6 -6
  111. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  112. data/lib/theme_template/Gemfile +4 -4
  113. data/lib/theme_template/LICENSE.txt.erb +21 -21
  114. data/lib/theme_template/README.md.erb +50 -52
  115. data/lib/theme_template/_layouts/default.html +1 -1
  116. data/lib/theme_template/_layouts/page.html +5 -5
  117. data/lib/theme_template/_layouts/post.html +5 -5
  118. data/lib/theme_template/example/_config.yml.erb +1 -1
  119. data/lib/theme_template/example/_post.md +12 -12
  120. data/lib/theme_template/example/index.html +14 -14
  121. data/lib/theme_template/example/style.scss +7 -7
  122. data/lib/theme_template/gitignore.erb +6 -6
  123. data/lib/theme_template/theme.gemspec.erb +16 -16
  124. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  125. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  126. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  127. data/rubocop/jekyll.rb +5 -5
  128. metadata +62 -14
@@ -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