jekyll 4.0.0.pre.beta1 → 4.2.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +204 -18
  3. data/README.markdown +2 -6
  4. data/lib/blank_template/_layouts/default.html +1 -1
  5. data/lib/jekyll.rb +6 -17
  6. data/lib/jekyll/cleaner.rb +3 -3
  7. data/lib/jekyll/collection.rb +2 -2
  8. data/lib/jekyll/command.rb +4 -2
  9. data/lib/jekyll/commands/doctor.rb +19 -15
  10. data/lib/jekyll/commands/new.rb +4 -4
  11. data/lib/jekyll/commands/new_theme.rb +0 -2
  12. data/lib/jekyll/commands/serve.rb +12 -1
  13. data/lib/jekyll/configuration.rb +18 -19
  14. data/lib/jekyll/converters/identity.rb +2 -2
  15. data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -1
  16. data/lib/jekyll/convertible.rb +30 -23
  17. data/lib/jekyll/document.rb +41 -19
  18. data/lib/jekyll/drops/collection_drop.rb +3 -3
  19. data/lib/jekyll/drops/document_drop.rb +4 -3
  20. data/lib/jekyll/drops/drop.rb +98 -20
  21. data/lib/jekyll/drops/site_drop.rb +3 -3
  22. data/lib/jekyll/drops/static_file_drop.rb +4 -4
  23. data/lib/jekyll/drops/url_drop.rb +11 -3
  24. data/lib/jekyll/entry_filter.rb +18 -7
  25. data/lib/jekyll/excerpt.rb +1 -1
  26. data/lib/jekyll/filters.rb +112 -28
  27. data/lib/jekyll/filters/url_filters.rb +45 -15
  28. data/lib/jekyll/frontmatter_defaults.rb +14 -19
  29. data/lib/jekyll/hooks.rb +22 -21
  30. data/lib/jekyll/inclusion.rb +32 -0
  31. data/lib/jekyll/layout.rb +5 -0
  32. data/lib/jekyll/liquid_renderer.rb +18 -15
  33. data/lib/jekyll/liquid_renderer/file.rb +10 -0
  34. data/lib/jekyll/liquid_renderer/table.rb +1 -64
  35. data/lib/jekyll/page.rb +42 -11
  36. data/lib/jekyll/page_excerpt.rb +25 -0
  37. data/lib/jekyll/path_manager.rb +53 -10
  38. data/lib/jekyll/profiler.rb +58 -0
  39. data/lib/jekyll/reader.rb +11 -6
  40. data/lib/jekyll/readers/collection_reader.rb +1 -0
  41. data/lib/jekyll/readers/data_reader.rb +4 -0
  42. data/lib/jekyll/readers/layout_reader.rb +1 -0
  43. data/lib/jekyll/readers/page_reader.rb +1 -0
  44. data/lib/jekyll/readers/post_reader.rb +2 -1
  45. data/lib/jekyll/readers/static_file_reader.rb +1 -0
  46. data/lib/jekyll/readers/theme_assets_reader.rb +1 -0
  47. data/lib/jekyll/related_posts.rb +1 -1
  48. data/lib/jekyll/renderer.rb +15 -17
  49. data/lib/jekyll/site.rb +34 -10
  50. data/lib/jekyll/static_file.rb +17 -12
  51. data/lib/jekyll/tags/include.rb +82 -33
  52. data/lib/jekyll/tags/link.rb +2 -1
  53. data/lib/jekyll/tags/post_url.rb +3 -4
  54. data/lib/jekyll/theme.rb +6 -8
  55. data/lib/jekyll/url.rb +8 -5
  56. data/lib/jekyll/utils.rb +5 -5
  57. data/lib/jekyll/utils/platforms.rb +34 -49
  58. data/lib/jekyll/utils/win_tz.rb +1 -1
  59. data/lib/jekyll/version.rb +1 -1
  60. data/lib/theme_template/theme.gemspec.erb +1 -4
  61. metadata +34 -39
@@ -67,6 +67,8 @@ module Jekyll
67
67
  cmd.option "show_drafts", "-D", "--drafts", "Render posts in the _drafts folder"
68
68
  cmd.option "unpublished", "--unpublished",
69
69
  "Render posts that were marked as unpublished"
70
+ cmd.option "disable_disk_cache", "--disable-disk-cache",
71
+ "Disable caching to disk in non-safe mode"
70
72
  cmd.option "quiet", "-q", "--quiet", "Silence output."
71
73
  cmd.option "verbose", "-V", "--verbose", "Print verbose output."
72
74
  cmd.option "incremental", "-I", "--incremental", "Enable incremental rebuild."
@@ -84,7 +86,7 @@ module Jekyll
84
86
  # klass - an array of Jekyll::Command subclasses associated with the command
85
87
  #
86
88
  # Note that all exceptions are rescued..
87
- # rubocop: disable RescueException
89
+ # rubocop: disable Lint/RescueException
88
90
  def process_with_graceful_fail(cmd, options, *klass)
89
91
  klass.each { |k| k.process(options) if k.respond_to?(:process) }
90
92
  rescue Exception => e
@@ -97,7 +99,7 @@ module Jekyll
97
99
  Jekyll.logger.error "", " for any additional information or backtrace. "
98
100
  Jekyll.logger.abort_with "", dashes
99
101
  end
100
- # rubocop: enable RescueException
102
+ # rubocop: enable Lint/RescueException
101
103
  end
102
104
  end
103
105
  end
@@ -67,15 +67,16 @@ module Jekyll
67
67
 
68
68
  def conflicting_urls(site)
69
69
  conflicting_urls = false
70
- urls = {}
71
- urls = collect_urls(urls, site.pages, site.dest)
72
- urls = collect_urls(urls, site.posts.docs, site.dest)
73
- urls.each do |url, paths|
70
+ destination_map(site).each do |dest, paths|
74
71
  next unless paths.size > 1
75
72
 
76
73
  conflicting_urls = true
77
- Jekyll.logger.warn "Conflict:", "The URL '#{url}' is the destination" \
78
- " for the following pages: #{paths.join(", ")}"
74
+ Jekyll.logger.warn "Conflict:",
75
+ "The following destination is shared by multiple files."
76
+ Jekyll.logger.warn "", "The written file may end up with unexpected contents."
77
+ Jekyll.logger.warn "", dest.to_s.cyan
78
+ paths.each { |path| Jekyll.logger.warn "", " - #{path}" }
79
+ Jekyll.logger.warn ""
79
80
  end
80
81
  conflicting_urls
81
82
  end
@@ -84,7 +85,7 @@ module Jekyll
84
85
  return true unless Utils::Platforms.osx?
85
86
 
86
87
  if Dir.pwd != `pwd`.strip
87
- Jekyll.logger.error " " + <<-STR.strip.gsub(%r!\n\s+!, "\n ")
88
+ Jekyll.logger.error <<~STR
88
89
  We have detected that there might be trouble using fsevent on your
89
90
  operating system, you can read https://github.com/thibaudgg/rb-fsevent/wiki/no-fsevents-fired-(OSX-bug)
90
91
  for possible work arounds or you can work around it immediately
@@ -122,16 +123,19 @@ module Jekyll
122
123
 
123
124
  private
124
125
 
125
- def collect_urls(urls, things, destination)
126
- things.each do |thing|
127
- dest = thing.destination(destination)
128
- if urls[dest]
129
- urls[dest] << thing.path
130
- else
131
- urls[dest] = [thing.path]
126
+ def destination_map(site)
127
+ {}.tap do |result|
128
+ site.each_site_file do |thing|
129
+ next if allow_used_permalink?(thing)
130
+
131
+ dest_path = thing.destination(site.dest)
132
+ (result[dest_path] ||= []) << thing.path
132
133
  end
133
134
  end
134
- urls
135
+ end
136
+
137
+ def allow_used_permalink?(item)
138
+ defined?(JekyllRedirectFrom) && item.is_a?(JekyllRedirectFrom::RedirectPage)
135
139
  end
136
140
 
137
141
  def case_insensitive_urls(things, destination)
@@ -80,24 +80,24 @@ module Jekyll
80
80
  # Happy Jekylling!
81
81
  gem "jekyll", "~> #{Jekyll::VERSION}"
82
82
  # This is the default theme for new Jekyll sites. You may change this to anything you like.
83
- gem "minima", "~> 2.0"
83
+ gem "minima", "~> 2.5"
84
84
  # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
85
85
  # uncomment the line below. To upgrade, run `bundle update github-pages`.
86
86
  # gem "github-pages", group: :jekyll_plugins
87
87
  # If you have any plugins, put them here!
88
88
  group :jekyll_plugins do
89
- gem "jekyll-feed", "~> 0.6"
89
+ gem "jekyll-feed", "~> 0.12"
90
90
  end
91
91
 
92
92
  # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
93
93
  # and associated library.
94
- install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
94
+ platforms :mingw, :x64_mingw, :mswin, :jruby do
95
95
  gem "tzinfo", "~> 1.2"
96
96
  gem "tzinfo-data"
97
97
  end
98
98
 
99
99
  # Performance-booster for watching directories on Windows
100
- gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?
100
+ gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
101
101
 
102
102
  RUBY
103
103
  end
@@ -20,7 +20,6 @@ module Jekyll
20
20
  end
21
21
  end
22
22
 
23
- # rubocop:disable Metrics/AbcSize
24
23
  def process(args, opts)
25
24
  if !args || args.empty?
26
25
  raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
@@ -35,7 +34,6 @@ module Jekyll
35
34
  " is ready for you in #{theme.path.to_s.cyan}!"
36
35
  Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
37
36
  end
38
- # rubocop:enable Metrics/AbcSize
39
37
  end
40
38
  end
41
39
  end
@@ -249,6 +249,9 @@ module Jekyll
249
249
 
250
250
  def default_url(opts)
251
251
  config = configuration_from_options(opts)
252
+ auth = config.values_at("host", "port").join(":")
253
+ return config["url"] if auth == "127.0.0.1:4000"
254
+
252
255
  format_url(
253
256
  config["ssl_cert"] && config["ssl_key"],
254
257
  config["host"] == "127.0.0.1" ? "localhost" : config["host"],
@@ -307,7 +310,15 @@ module Jekyll
307
310
  require "webrick/https"
308
311
 
309
312
  opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
310
- opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
313
+ begin
314
+ opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
315
+ rescue StandardError
316
+ if defined?(OpenSSL::PKey::EC)
317
+ opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key))
318
+ else
319
+ raise
320
+ end
321
+ end
311
322
  opts[:SSLEnable] = true
312
323
  end
313
324
 
@@ -4,7 +4,7 @@ module Jekyll
4
4
  class Configuration < Hash
5
5
  # Default options. Overridden by values in _config.yml.
6
6
  # Strings rather than symbols are used for compatibility with YAML.
7
- DEFAULTS = Configuration[{
7
+ DEFAULTS = {
8
8
  # Where things are
9
9
  "source" => Dir.pwd,
10
10
  "destination" => File.join(Dir.pwd, "_site"),
@@ -66,7 +66,7 @@ module Jekyll
66
66
 
67
67
  "kramdown" => {
68
68
  "auto_ids" => true,
69
- "toc_levels" => "1..6",
69
+ "toc_levels" => (1..6).to_a,
70
70
  "entity_output" => "as_char",
71
71
  "smart_quotes" => "lsquo,rsquo,ldquo,rdquo",
72
72
  "input" => "GFM",
@@ -75,7 +75,7 @@ module Jekyll
75
75
  "footnote_nr" => 1,
76
76
  "show_warnings" => false,
77
77
  },
78
- }.map { |k, v| [k, v.freeze] }].freeze
78
+ }.each_with_object(Configuration.new) { |(k, v), hsh| hsh[k] = v.freeze }.freeze
79
79
 
80
80
  class << self
81
81
  # Static: Produce a Configuration ready for use in a Site.
@@ -94,7 +94,7 @@ module Jekyll
94
94
  #
95
95
  # Return a copy of the hash where all its keys are strings
96
96
  def stringify_keys
97
- reduce({}) { |hsh, (k, v)| hsh.merge(k.to_s => v) }
97
+ each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v }
98
98
  end
99
99
 
100
100
  def get_config_value_with_override(config_key, override)
@@ -235,7 +235,9 @@ module Jekyll
235
235
 
236
236
  # Ensure we have a hash.
237
237
  if config["collections"].is_a?(Array)
238
- config["collections"] = Hash[config["collections"].map { |c| [c, {}] }]
238
+ config["collections"] = config["collections"].each_with_object({}) do |collection, hash|
239
+ hash[collection] = {}
240
+ end
239
241
  end
240
242
 
241
243
  config["collections"] = Utils.deep_merge_hashes(
@@ -267,21 +269,18 @@ module Jekyll
267
269
 
268
270
  private
269
271
 
272
+ STYLE_TO_PERMALINK = {
273
+ :none => "/:categories/:title:output_ext",
274
+ :date => "/:categories/:year/:month/:day/:title:output_ext",
275
+ :ordinal => "/:categories/:year/:y_day/:title:output_ext",
276
+ :pretty => "/:categories/:year/:month/:day/:title/",
277
+ :weekdate => "/:categories/:year/W:week/:short_day/:title:output_ext",
278
+ }.freeze
279
+
280
+ private_constant :STYLE_TO_PERMALINK
281
+
270
282
  def style_to_permalink(permalink_style)
271
- case permalink_style.to_sym
272
- when :pretty
273
- "/:categories/:year/:month/:day/:title/"
274
- when :none
275
- "/:categories/:title:output_ext"
276
- when :date
277
- "/:categories/:year/:month/:day/:title:output_ext"
278
- when :ordinal
279
- "/:categories/:year/:y_day/:title:output_ext"
280
- when :weekdate
281
- "/:categories/:year/W:week/:short_day/:title:output_ext"
282
- else
283
- permalink_style.to_s
284
- end
283
+ STYLE_TO_PERMALINK[permalink_style.to_sym] || permalink_style.to_s
285
284
  end
286
285
 
287
286
  def check_include_exclude(config)
@@ -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,13 +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
106
  end
38
107
 
39
108
  def convert(content)
40
- document = Kramdown::Document.new(content, @config)
109
+ document = Kramdown::JekyllDocument.new(content, @config)
41
110
  html_output = document.to_html
42
111
  if @config["show_warnings"]
43
112
  document.warnings.each do |warning|
@@ -35,13 +35,13 @@ module Jekyll
35
35
  # Returns nothing.
36
36
  # rubocop:disable Metrics/AbcSize
37
37
  def read_yaml(base, name, opts = {})
38
- filename = File.join(base, name)
38
+ filename = @path || site.in_source_dir(base, name)
39
+ Jekyll.logger.debug "Reading:", relative_path
39
40
 
40
41
  begin
41
- self.content = File.read(@path || site.in_source_dir(base, name),
42
- Utils.merged_file_read_opts(site, opts))
42
+ self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts))
43
43
  if content =~ Document::YAML_FRONT_MATTER_REGEXP
44
- self.content = $POSTMATCH
44
+ self.content = Regexp.last_match.post_match
45
45
  self.data = SafeYAML.load(Regexp.last_match(1))
46
46
  end
47
47
  rescue Psych::SyntaxError => e
@@ -69,7 +69,7 @@ module Jekyll
69
69
  end
70
70
 
71
71
  def validate_permalink!(filename)
72
- if self.data["permalink"]&.to_s&.empty?
72
+ if self.data["permalink"] == ""
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
- _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,18 +105,14 @@ 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]
118
-
119
- defaults = site.frontmatter_defaults.all(relative_path, type)
115
+ further_data = attribute_hash(attrs || self.class::ATTRIBUTES_FOR_LIQUID)
120
116
  Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
121
117
  end
122
118
 
@@ -190,10 +186,10 @@ module Jekyll
190
186
  #
191
187
  # Returns nothing
192
188
  def render_all_layouts(layouts, payload, info)
193
- _renderer.layouts = layouts
194
- self.output = _renderer.place_in_layouts(output, payload, info)
189
+ renderer.layouts = layouts
190
+ self.output = renderer.place_in_layouts(output, payload, info)
195
191
  ensure
196
- @_renderer = nil # this will allow the modifications above to disappear
192
+ @renderer = nil # this will allow the modifications above to disappear
197
193
  end
198
194
 
199
195
  # Add any necessary layouts to this convertible document.
@@ -203,15 +199,15 @@ module Jekyll
203
199
  #
204
200
  # Returns nothing.
205
201
  def do_layout(payload, layouts)
206
- self.output = _renderer.tap do |renderer|
207
- renderer.layouts = layouts
208
- renderer.payload = payload
202
+ self.output = renderer.tap do |doc_renderer|
203
+ doc_renderer.layouts = layouts
204
+ doc_renderer.payload = payload
209
205
  end.run
210
206
 
211
207
  Jekyll.logger.debug "Post-Render Hooks:", relative_path
212
208
  Jekyll::Hooks.trigger hook_owner, :post_render, self
213
209
  ensure
214
- @_renderer = nil # this will allow the modifications above to disappear
210
+ @renderer = nil # this will allow the modifications above to disappear
215
211
  end
216
212
 
217
213
  # Write the generated page file to the destination directory.
@@ -240,10 +236,21 @@ module Jekyll
240
236
  end
241
237
  end
242
238
 
239
+ def renderer
240
+ @renderer ||= Jekyll::Renderer.new(site, self)
241
+ end
242
+
243
243
  private
244
244
 
245
- def _renderer
246
- @_renderer ||= Jekyll::Renderer.new(site, self)
245
+ def defaults
246
+ @defaults ||= site.frontmatter_defaults.all(relative_path, type)
247
+ end
248
+
249
+ def attribute_hash(attrs)
250
+ @attribute_hash ||= {}
251
+ @attribute_hash[attrs] ||= attrs.each_with_object({}) do |attribute, hsh|
252
+ hsh[attribute] = send(attribute)
253
+ end
247
254
  end
248
255
 
249
256
  def no_layout?