jekyll 4.0.0.pre.alpha1 → 4.1.1

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +58 -17
  3. data/lib/jekyll.rb +5 -1
  4. data/lib/jekyll/cache.rb +71 -64
  5. data/lib/jekyll/cleaner.rb +5 -5
  6. data/lib/jekyll/collection.rb +6 -4
  7. data/lib/jekyll/command.rb +4 -2
  8. data/lib/jekyll/commands/new.rb +4 -4
  9. data/lib/jekyll/commands/serve.rb +9 -1
  10. data/lib/jekyll/commands/serve/servlet.rb +13 -14
  11. data/lib/jekyll/commands/serve/websockets.rb +1 -1
  12. data/lib/jekyll/configuration.rb +40 -129
  13. data/lib/jekyll/converters/identity.rb +2 -2
  14. data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -9
  15. data/lib/jekyll/convertible.rb +21 -20
  16. data/lib/jekyll/document.rb +56 -31
  17. data/lib/jekyll/drops/document_drop.rb +12 -0
  18. data/lib/jekyll/drops/drop.rb +14 -8
  19. data/lib/jekyll/drops/site_drop.rb +11 -1
  20. data/lib/jekyll/drops/url_drop.rb +52 -1
  21. data/lib/jekyll/entry_filter.rb +38 -44
  22. data/lib/jekyll/excerpt.rb +3 -3
  23. data/lib/jekyll/filters.rb +140 -22
  24. data/lib/jekyll/filters/url_filters.rb +41 -14
  25. data/lib/jekyll/frontmatter_defaults.rb +15 -20
  26. data/lib/jekyll/hooks.rb +2 -5
  27. data/lib/jekyll/inclusion.rb +32 -0
  28. data/lib/jekyll/liquid_renderer.rb +18 -15
  29. data/lib/jekyll/liquid_renderer/file.rb +10 -0
  30. data/lib/jekyll/liquid_renderer/table.rb +18 -61
  31. data/lib/jekyll/mime.types +53 -11
  32. data/lib/jekyll/page.rb +26 -2
  33. data/lib/jekyll/page_excerpt.rb +25 -0
  34. data/lib/jekyll/path_manager.rb +31 -0
  35. data/lib/jekyll/profiler.rb +58 -0
  36. data/lib/jekyll/reader.rb +4 -1
  37. data/lib/jekyll/readers/collection_reader.rb +1 -0
  38. data/lib/jekyll/readers/data_reader.rb +1 -0
  39. data/lib/jekyll/readers/layout_reader.rb +1 -0
  40. data/lib/jekyll/readers/page_reader.rb +5 -5
  41. data/lib/jekyll/readers/post_reader.rb +2 -1
  42. data/lib/jekyll/readers/static_file_reader.rb +3 -3
  43. data/lib/jekyll/readers/theme_assets_reader.rb +1 -0
  44. data/lib/jekyll/renderer.rb +9 -15
  45. data/lib/jekyll/site.rb +21 -12
  46. data/lib/jekyll/static_file.rb +15 -10
  47. data/lib/jekyll/tags/highlight.rb +2 -4
  48. data/lib/jekyll/tags/include.rb +67 -11
  49. data/lib/jekyll/tags/post_url.rb +8 -5
  50. data/lib/jekyll/theme.rb +19 -10
  51. data/lib/jekyll/url.rb +7 -3
  52. data/lib/jekyll/utils.rb +14 -18
  53. data/lib/jekyll/utils/platforms.rb +1 -1
  54. data/lib/jekyll/utils/win_tz.rb +1 -1
  55. data/lib/jekyll/version.rb +1 -1
  56. data/lib/theme_template/theme.gemspec.erb +1 -4
  57. metadata +33 -36
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Jekyll
4
4
  module Converters
5
- # Identify converter. Returns same content as given.
5
+ # Identity converter. Returns same content as given.
6
6
  # For more info on converters see https://jekyllrb.com/docs/plugins/converters/
7
7
  class Identity < Converter
8
8
  safe true
@@ -12,7 +12,7 @@ module Jekyll
12
12
  # Public: Does the given extension match this converter's list of acceptable extensions?
13
13
  # Takes one argument: the file's extension (including the dot).
14
14
  #
15
- # ext - The String extension to check (not relevant here)
15
+ # _ext - The String extension to check (not relevant here)
16
16
  #
17
17
  # Returns true since it always matches.
18
18
  def matches(_ext)
@@ -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
@@ -31,14 +99,14 @@ module Jekyll
31
99
  def setup
32
100
  @config["syntax_highlighter"] ||= highlighter
33
101
  @config["syntax_highlighter_opts"] ||= {}
102
+ @config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext"
34
103
  @config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"]
35
104
  @config["coderay"] ||= {} # XXX: Legacy.
36
105
  modernize_coderay_config
37
- make_accessible
38
106
  end
39
107
 
40
108
  def convert(content)
41
- document = Kramdown::Document.new(content, @config)
109
+ document = Kramdown::JekyllDocument.new(content, @config)
42
110
  html_output = document.to_html
43
111
  if @config["show_warnings"]
44
112
  document.warnings.each do |warning|
@@ -64,13 +132,6 @@ module Jekyll
64
132
  end
65
133
  end
66
134
 
67
- def make_accessible(hash = @config)
68
- hash.keys.each do |key|
69
- hash[key.to_sym] = hash[key]
70
- make_accessible(hash[key]) if hash[key].is_a?(Hash)
71
- end
72
- end
73
-
74
135
  # config[kramdown][syntax_higlighter] >
75
136
  # config[kramdown][enable_coderay] >
76
137
  # config[highlighter]
@@ -39,7 +39,7 @@ module Jekyll
39
39
 
40
40
  begin
41
41
  self.content = File.read(@path || site.in_source_dir(base, name),
42
- Utils.merged_file_read_opts(site, opts))
42
+ **Utils.merged_file_read_opts(site, opts))
43
43
  if content =~ Document::YAML_FRONT_MATTER_REGEXP
44
44
  self.content = $POSTMATCH
45
45
  self.data = SafeYAML.load(Regexp.last_match(1))
@@ -78,7 +78,7 @@ module Jekyll
78
78
  #
79
79
  # Returns the transformed contents.
80
80
  def transform
81
- _renderer.convert(content)
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
- _renderer.output_ext
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
- _renderer.converters
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
- _renderer.render_liquid(content, payload, info, path)
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 = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map do |attribute|
116
- [attribute, send(attribute)]
117
- end]
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)
@@ -146,7 +147,7 @@ module Jekyll
146
147
  #
147
148
  # Returns true if extname == .sass or .scss, false otherwise.
148
149
  def sass_file?
149
- %w(.sass .scss).include?(ext)
150
+ Jekyll::Document::SASS_FILE_EXTS.include?(ext)
150
151
  end
151
152
 
152
153
  # Determine whether the document is a CoffeeScript file.
@@ -190,10 +191,10 @@ module Jekyll
190
191
  #
191
192
  # Returns nothing
192
193
  def render_all_layouts(layouts, payload, info)
193
- _renderer.layouts = layouts
194
- self.output = _renderer.place_in_layouts(output, payload, info)
194
+ renderer.layouts = layouts
195
+ self.output = renderer.place_in_layouts(output, payload, info)
195
196
  ensure
196
- @_renderer = nil # this will allow the modifications above to disappear
197
+ @renderer = nil # this will allow the modifications above to disappear
197
198
  end
198
199
 
199
200
  # Add any necessary layouts to this convertible document.
@@ -203,15 +204,15 @@ module Jekyll
203
204
  #
204
205
  # Returns nothing.
205
206
  def do_layout(payload, layouts)
206
- self.output = _renderer.tap do |renderer|
207
- renderer.layouts = layouts
208
- renderer.payload = payload
207
+ self.output = renderer.tap do |doc_renderer|
208
+ doc_renderer.layouts = layouts
209
+ doc_renderer.payload = payload
209
210
  end.run
210
211
 
211
212
  Jekyll.logger.debug "Post-Render Hooks:", relative_path
212
213
  Jekyll::Hooks.trigger hook_owner, :post_render, self
213
214
  ensure
214
- @_renderer = nil # this will allow the modifications above to disappear
215
+ @renderer = nil # this will allow the modifications above to disappear
215
216
  end
216
217
 
217
218
  # Write the generated page file to the destination directory.
@@ -240,12 +241,12 @@ module Jekyll
240
241
  end
241
242
  end
242
243
 
243
- private
244
-
245
- def _renderer
246
- @_renderer ||= Jekyll::Renderer.new(site, self)
244
+ def renderer
245
+ @renderer ||= Jekyll::Renderer.new(site, self)
247
246
  end
248
247
 
248
+ private
249
+
249
250
  def no_layout?
250
251
  data["layout"] == "none"
251
252
  end
@@ -5,7 +5,7 @@ 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
@@ -14,6 +14,23 @@ module Jekyll
14
14
  DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
15
15
  DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze
16
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
+ #
33
+
17
34
  # Create a new Document.
18
35
  #
19
36
  # path - the path to the file
@@ -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, collection.label, key)
58
+ site.frontmatter_defaults.find(relative_path, type, key)
40
59
  end
41
60
 
42
61
  trigger_hooks(:post_init)
@@ -97,7 +116,7 @@ module Jekyll
97
116
  #
98
117
  # Returns the output extension
99
118
  def output_ext
100
- @output_ext ||= Jekyll::Renderer.new(site, self).output_ext
119
+ renderer.output_ext
101
120
  end
102
121
 
103
122
  # The base filename of the document, without the file extname.
@@ -114,6 +133,10 @@ module Jekyll
114
133
  @basename ||= File.basename(path)
115
134
  end
116
135
 
136
+ def renderer
137
+ @renderer ||= Jekyll::Renderer.new(site, self)
138
+ end
139
+
117
140
  # Produces a "cleaned" relative path.
118
141
  # The "cleaned" relative path is the relative path without the extname
119
142
  # and with the collection's directory removed as well.
@@ -138,7 +161,7 @@ module Jekyll
138
161
  #
139
162
  # Returns true if the extname is either .yml or .yaml, false otherwise.
140
163
  def yaml_file?
141
- %w(.yaml .yml).include?(extname)
164
+ YAML_FILE_EXTS.include?(extname)
142
165
  end
143
166
 
144
167
  # Determine whether the document is an asset file.
@@ -154,7 +177,7 @@ module Jekyll
154
177
  #
155
178
  # Returns true if extname == .sass or .scss, false otherwise.
156
179
  def sass_file?
157
- %w(.sass .scss).include?(extname)
180
+ SASS_FILE_EXTS.include?(extname)
158
181
  end
159
182
 
160
183
  # Determine whether the document is a CoffeeScript file.
@@ -279,7 +302,7 @@ module Jekyll
279
302
  else
280
303
  begin
281
304
  merge_defaults
282
- read_content(opts)
305
+ read_content(**opts)
283
306
  read_post_data
284
307
  rescue StandardError => e
285
308
  handle_read_error(e)
@@ -373,12 +396,6 @@ module Jekyll
373
396
  @related_posts ||= Jekyll::RelatedPosts.new(self).build
374
397
  end
375
398
 
376
- # Override of normal respond_to? to match method_missing's logic for
377
- # looking in @data.
378
- def respond_to?(method, include_private = false)
379
- data.key?(method.to_s) || super
380
- end
381
-
382
399
  # Override of method_missing to check in @data for the key.
383
400
  def method_missing(method, *args, &blck)
384
401
  if data.key?(method.to_s)
@@ -401,28 +418,33 @@ module Jekyll
401
418
  #
402
419
  # Returns nothing.
403
420
  def categories_from_path(special_dir)
404
- superdirs = relative_path.sub(%r!#{special_dir}(.*)!, "")
405
- .split(File::SEPARATOR)
406
- .reject do |c|
407
- c.empty? || c == special_dir || c == basename
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 }
408
427
  end
428
+
409
429
  merge_data!({ "categories" => superdirs }, :source => "file path")
410
430
  end
411
431
 
412
432
  def populate_categories
413
- merge_data!(
414
- "categories" => (
415
- Array(data["categories"]) + Utils.pluralized_array_from_hash(
416
- data, "category", "categories"
417
- )
418
- ).map(&:to_s).flatten.uniq
433
+ categories = Array(data["categories"]) + Utils.pluralized_array_from_hash(
434
+ data, "category", "categories"
419
435
  )
436
+ categories.map!(&:to_s)
437
+ categories.flatten!
438
+ categories.uniq!
439
+
440
+ merge_data!({ "categories" => categories })
420
441
  end
421
442
 
422
443
  def populate_tags
423
- merge_data!(
424
- "tags" => Utils.pluralized_array_from_hash(data, "tag", "tags").flatten
425
- )
444
+ tags = Utils.pluralized_array_from_hash(data, "tag", "tags")
445
+ tags.flatten!
446
+
447
+ merge_data!({ "tags" => tags })
426
448
  end
427
449
 
428
450
  private
@@ -444,15 +466,12 @@ module Jekyll
444
466
  end
445
467
 
446
468
  def merge_defaults
447
- defaults = @site.frontmatter_defaults.all(
448
- relative_path,
449
- collection.label.to_sym
450
- )
469
+ defaults = @site.frontmatter_defaults.all(relative_path, type)
451
470
  merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
452
471
  end
453
472
 
454
- def read_content(opts)
455
- self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
473
+ def read_content(**opts)
474
+ self.content = File.read(path, **Utils.merged_file_read_opts(site, opts))
456
475
  if content =~ YAML_FRONT_MATTER_REGEXP
457
476
  self.content = $POSTMATCH
458
477
  data_file = SafeYAML.load(Regexp.last_match(1))
@@ -479,6 +498,7 @@ module Jekyll
479
498
  end
480
499
  end
481
500
 
501
+ # rubocop:disable Metrics/AbcSize
482
502
  def populate_title
483
503
  if relative_path =~ DATE_FILENAME_MATCHER
484
504
  date, slug, ext = Regexp.last_match.captures
@@ -486,6 +506,10 @@ module Jekyll
486
506
  elsif relative_path =~ DATELESS_FILENAME_MATCHER
487
507
  slug, ext = Regexp.last_match.captures
488
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
489
513
 
490
514
  # slugs shouldn't end with a period
491
515
  # `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
@@ -497,6 +521,7 @@ module Jekyll
497
521
  data["slug"] ||= slug
498
522
  data["ext"] ||= ext
499
523
  end
524
+ # rubocop:enable Metrics/AbcSize
500
525
 
501
526
  def modify_date(date)
502
527
  if !data["date"] || data["date"].to_i == site.time.to_i
@@ -64,6 +64,18 @@ module Jekyll
64
64
  result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
65
65
  end
66
66
  end
67
+
68
+ def title
69
+ @obj.data["title"]
70
+ end
71
+
72
+ def categories
73
+ @obj.data["categories"]
74
+ end
75
+
76
+ def tags
77
+ @obj.data["tags"]
78
+ end
67
79
  end
68
80
  end
69
81
  end