jekyll 3.0.5 → 3.1.0.pre.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of jekyll might be problematic. Click here for more details.

Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +1 -1
  3. data/lib/jekyll.rb +6 -5
  4. data/lib/jekyll/cleaner.rb +1 -1
  5. data/lib/jekyll/collection.rb +8 -11
  6. data/lib/jekyll/commands/clean.rb +2 -2
  7. data/lib/jekyll/commands/doctor.rb +23 -1
  8. data/lib/jekyll/commands/serve.rb +148 -103
  9. data/lib/jekyll/commands/serve/servlet.rb +61 -0
  10. data/lib/jekyll/configuration.rb +26 -46
  11. data/lib/jekyll/converters/markdown.rb +51 -36
  12. data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -17
  13. data/lib/jekyll/convertible.rb +5 -4
  14. data/lib/jekyll/document.rb +19 -63
  15. data/lib/jekyll/drops/collection_drop.rb +24 -0
  16. data/lib/jekyll/drops/document_drop.rb +28 -0
  17. data/lib/jekyll/drops/drop.rb +128 -0
  18. data/lib/jekyll/drops/jekyll_drop.rb +21 -0
  19. data/lib/jekyll/drops/site_drop.rb +39 -0
  20. data/lib/jekyll/drops/unified_payload_drop.rb +26 -0
  21. data/lib/jekyll/drops/url_drop.rb +51 -0
  22. data/lib/jekyll/entry_filter.rb +1 -1
  23. data/lib/jekyll/errors.rb +3 -4
  24. data/lib/jekyll/excerpt.rb +0 -2
  25. data/lib/jekyll/external.rb +1 -0
  26. data/lib/jekyll/filters.rb +10 -0
  27. data/lib/jekyll/frontmatter_defaults.rb +8 -1
  28. data/lib/jekyll/liquid_renderer/file.rb +1 -1
  29. data/lib/jekyll/page.rb +15 -11
  30. data/lib/jekyll/plugin_manager.rb +4 -10
  31. data/lib/jekyll/renderer.rb +12 -19
  32. data/lib/jekyll/site.rb +2 -20
  33. data/lib/jekyll/tags/highlight.rb +5 -5
  34. data/lib/jekyll/tags/include.rb +13 -2
  35. data/lib/jekyll/url.rb +22 -12
  36. data/lib/jekyll/utils.rb +48 -8
  37. data/lib/jekyll/utils/ansi.rb +59 -0
  38. data/lib/jekyll/utils/platforms.rb +2 -1
  39. data/lib/jekyll/version.rb +1 -1
  40. metadata +14 -5
@@ -0,0 +1,61 @@
1
+ require "webrick"
2
+
3
+ module Jekyll
4
+ module Commands
5
+ class Serve
6
+ class Servlet < WEBrick::HTTPServlet::FileHandler
7
+ DEFAULTS = {
8
+ "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
9
+ "no-store, no-cache, must-revalidate"
10
+ }
11
+
12
+ def initialize(server, root, callbacks)
13
+ # So we can access them easily.
14
+ @jekyll_opts = server.config[:JekyllOptions]
15
+ set_defaults
16
+ super
17
+ end
18
+
19
+ # Add the ability to tap file.html the same way that Nginx does on our
20
+ # Docker images (or on Github pages.) The difference is that we might end
21
+ # up with a different preference on which comes first.
22
+
23
+ def search_file(req, res, basename)
24
+ # /file.* > /file/index.html > /file.html
25
+ super || super(req, res, "#{basename}.html")
26
+ end
27
+
28
+ #
29
+
30
+ def do_GET(req, res)
31
+ rtn = super
32
+ validate_and_ensure_charset(req, res)
33
+ res.header.merge!(@headers)
34
+ rtn
35
+ end
36
+
37
+ #
38
+
39
+ private
40
+ def validate_and_ensure_charset(req, res)
41
+ key = res.header.keys.grep(/content-type/i).first
42
+ typ = res.header[key]
43
+
44
+ unless typ =~ /;\s*charset=/
45
+ res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
46
+ end
47
+ end
48
+
49
+ #
50
+
51
+ private
52
+ def set_defaults
53
+ hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
54
+ DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
55
+ hash[key] = val if !hash.key?(key)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -65,39 +65,14 @@ module Jekyll
65
65
 
66
66
  'kramdown' => {
67
67
  'auto_ids' => true,
68
- 'footnote_nr' => 1,
69
- 'entity_output' => 'as_char',
70
68
  'toc_levels' => '1..6',
69
+ 'entity_output' => 'as_char',
71
70
  'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo',
72
- 'enable_coderay' => false,
73
-
74
- 'coderay' => {
75
- 'coderay_wrap' => 'div',
76
- 'coderay_line_numbers' => 'inline',
77
- 'coderay_line_number_start' => 1,
78
- 'coderay_tab_width' => 4,
79
- 'coderay_bold_every' => 10,
80
- 'coderay_css' => 'style'
81
- }
71
+ 'input' => "GFM",
72
+ 'hard_wrap' => false,
73
+ 'footnote_nr' => 1
82
74
  }
83
- }].freeze
84
-
85
- class << self
86
- # Static: Produce a Configuration ready for use in a Site.
87
- # It takes the input, fills in the defaults where values do not
88
- # exist, and patches common issues including migrating options for
89
- # backwards compatiblity. Except where a key or value is being fixed,
90
- # the user configuration will override the defaults.
91
- #
92
- # user_config - a Hash or Configuration of overrides.
93
- #
94
- # Returns a Configuration filled with defaults and fixed for common
95
- # problems and backwards-compatibility.
96
- def from(user_config)
97
- Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys).
98
- fix_common_issues.add_default_collections
99
- end
100
- end
75
+ }]
101
76
 
102
77
  # Public: Turn all keys into string
103
78
  #
@@ -135,7 +110,7 @@ module Jekyll
135
110
  Jekyll::External.require_with_graceful_fail('toml') unless defined?(TOML)
136
111
  TOML.load_file(filename)
137
112
  when /\.ya?ml/i
138
- SafeYAML.load_file(filename)
113
+ SafeYAML.load_file(filename) || {}
139
114
  else
140
115
  raise ArgumentError, "No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
141
116
  end
@@ -170,7 +145,7 @@ module Jekyll
170
145
  # Returns this configuration, overridden by the values in the file
171
146
  def read_config_file(file)
172
147
  next_config = safe_load_file(file)
173
- raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow) unless next_config.is_a?(Hash)
148
+ check_config_is_hash!(next_config, file)
174
149
  Jekyll.logger.info "Configuration file:", file
175
150
  next_config
176
151
  rescue SystemCallError
@@ -194,7 +169,6 @@ module Jekyll
194
169
 
195
170
  begin
196
171
  files.each do |config_file|
197
- next if config_file.nil? or config_file.empty?
198
172
  new_config = read_config_file(config_file)
199
173
  configuration = Utils.deep_merge_hashes(configuration, new_config)
200
174
  end
@@ -254,14 +228,15 @@ module Jekyll
254
228
  end
255
229
 
256
230
  %w[include exclude].each do |option|
257
- if config.fetch(option, []).is_a?(String)
231
+ config[option] ||= []
232
+ if config[option].is_a?(String)
258
233
  Jekyll::Deprecator.deprecation_message "The '#{option}' configuration option" +
259
234
  " must now be specified as an array, but you specified" +
260
235
  " a string. For now, we've treated the string you provided" +
261
236
  " as a list of comma-separated values."
262
237
  config[option] = csv_to_array(config[option])
263
238
  end
264
- config[option].map!(&:to_s) if config[option]
239
+ config[option].map!(&:to_s)
265
240
  end
266
241
 
267
242
  if (config['kramdown'] || {}).key?('use_coderay')
@@ -296,22 +271,14 @@ module Jekyll
296
271
  def add_default_collections
297
272
  config = clone
298
273
 
299
- # It defaults to `{}`, so this is only if someone sets it to null manually.
300
274
  return config if config['collections'].nil?
301
275
 
302
- # Ensure we have a hash.
303
276
  if config['collections'].is_a?(Array)
304
277
  config['collections'] = Hash[config['collections'].map{|c| [c, {}]}]
305
278
  end
306
-
307
- config['collections'] = Utils.deep_merge_hashes(
308
- { 'posts' => {} }, config['collections']
309
- ).tap do |collections|
310
- collections['posts']['output'] = true
311
- if config['permalink']
312
- collections['posts']['permalink'] ||= style_to_permalink(config['permalink'])
313
- end
314
- end
279
+ config['collections']['posts'] ||= {}
280
+ config['collections']['posts']['output'] = true
281
+ config['collections']['posts']['permalink'] = style_to_permalink(config['permalink'])
315
282
 
316
283
  config
317
284
  end
@@ -326,6 +293,7 @@ module Jekyll
326
293
  end
327
294
 
328
295
  private
296
+
329
297
  def style_to_permalink(permalink_style)
330
298
  case permalink_style.to_sym
331
299
  when :pretty
@@ -340,5 +308,17 @@ module Jekyll
340
308
  permalink_style.to_s
341
309
  end
342
310
  end
311
+
312
+ # Private: Checks if a given config is a hash
313
+ #
314
+ # extracted_config - the value to check
315
+ # file - the file from which the config was extracted
316
+ #
317
+ # Raises an ArgumentError if given config is not a hash
318
+ def check_config_is_hash!(extracted_config, file)
319
+ unless extracted_config.is_a?(Hash)
320
+ raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow)
321
+ end
322
+ end
343
323
  end
344
324
  end
@@ -1,54 +1,59 @@
1
1
  module Jekyll
2
2
  module Converters
3
3
  class Markdown < Converter
4
- safe true
5
-
6
4
  highlighter_prefix "\n"
7
5
  highlighter_suffix "\n"
6
+ safe true
8
7
 
9
8
  def setup
10
9
  return if @setup
11
- @parser =
12
- case @config['markdown'].downcase
13
- when 'redcarpet' then RedcarpetParser.new(@config)
14
- when 'kramdown' then KramdownParser.new(@config)
15
- when 'rdiscount' then RDiscountParser.new(@config)
16
- else
17
- # So they can't try some tricky bullshit or go down the ancestor chain, I hope.
18
- if allowed_custom_class?(@config['markdown'])
19
- self.class.const_get(@config['markdown']).new(@config)
20
- else
21
- Jekyll.logger.error "Invalid Markdown Processor:", "#{@config['markdown']}"
22
- Jekyll.logger.error "", "Valid options are [ #{valid_processors.join(" | ")} ]"
23
- raise Errors::FatalException, "Invalid Markdown Processor: #{@config['markdown']}"
24
- end
25
- end
10
+ if (!@parser = get_processor)
11
+ Jekyll.logger.error "Invalid Markdown processor given:", @config["markdown"]
12
+ Jekyll.logger.info "", "Custom processors are not loaded in safe mode" if @config["safe"]
13
+ Jekyll.logger.error "", "Available processors are: #{valid_processors.join(", ")}"
14
+ raise Errors::FatalException, "Bailing out; invalid Markdown processor."
15
+ end
16
+
26
17
  @setup = true
27
18
  end
28
19
 
20
+ def get_processor
21
+ case @config["markdown"].downcase
22
+ when "redcarpet" then return RedcarpetParser.new(@config)
23
+ when "kramdown" then return KramdownParser.new(@config)
24
+ when "rdiscount" then return RDiscountParser.new(@config)
25
+ else
26
+ get_custom_processor
27
+ end
28
+ end
29
+
30
+ # Public: Provides you with a list of processors, the ones we
31
+ # support internally and the ones that you have provided to us (if you
32
+ # are not in safe mode.)
33
+
29
34
  def valid_processors
30
- %w[
31
- rdiscount
32
- kramdown
33
- redcarpet
34
- ] + third_party_processors
35
+ %W(rdiscount kramdown redcarpet) + third_party_processors
35
36
  end
36
37
 
38
+ # Public: A list of processors that you provide via plugins.
39
+ # This is really only available if you are not in safe mode, if you are
40
+ # in safe mode (re: Github) then there will be none.
41
+
37
42
  def third_party_processors
38
- self.class.constants - %w[
39
- KramdownParser
40
- RDiscountParser
41
- RedcarpetParser
42
- PRIORITIES
43
- ].map(&:to_sym)
43
+ self.class.constants - \
44
+ %w[KramdownParser RDiscountParser RedcarpetParser PRIORITIES].map(
45
+ &:to_sym
46
+ )
44
47
  end
45
48
 
46
49
  def extname_list
47
- @extname_list ||= @config['markdown_ext'].split(',').map { |e| ".#{e.downcase}" }
50
+ @extname_list ||= @config['markdown_ext'].split(',').map do |e|
51
+ ".#{e.downcase}"
52
+ end
48
53
  end
49
54
 
50
55
  def matches(ext)
51
- extname_list.include? ext.downcase
56
+ extname_list.include?(ext.downcase)
52
57
  end
53
58
 
54
59
  def output_ext(ext)
@@ -61,16 +66,26 @@ module Jekyll
61
66
  end
62
67
 
63
68
  private
69
+ def get_custom_processor
70
+ converter_name = @config["markdown"]
71
+ if custom_class_allowed?(converter_name)
72
+ self.class.const_get(converter_name).new(@config)
73
+ end
74
+ end
64
75
 
65
- # Private: Determine whether a class name is an allowed custom markdown
66
- # class name
76
+ # Private: Determine whether a class name is an allowed custom
77
+ # markdown class name.
67
78
  #
68
79
  # parser_name - the name of the parser class
69
80
  #
70
- # Returns true if the parser name contains only alphanumeric characters
71
- # and is defined within Jekyll::Converters::Markdown
72
- def allowed_custom_class?(parser_name)
73
- parser_name !~ /[^A-Za-z0-9]/ && self.class.constants.include?(parser_name.to_sym)
81
+ # Returns true if the parser name contains only alphanumeric
82
+ # characters and is defined within Jekyll::Converters::Markdown
83
+
84
+ private
85
+ def custom_class_allowed?(parser_name)
86
+ parser_name !~ /[^A-Za-z0-9_]/ && self.class.constants.include?(
87
+ parser_name.to_sym
88
+ )
74
89
  end
75
90
  end
76
91
  end
@@ -1,33 +1,86 @@
1
+ # Frozen-string-literal: true
2
+ # Encoding: utf-8
3
+
1
4
  module Jekyll
2
5
  module Converters
3
6
  class Markdown
4
7
  class KramdownParser
8
+ CODERAY_DEFAULTS = {
9
+ "css" => "style",
10
+ "bold_every" => 10,
11
+ "line_numbers" => "inline",
12
+ "line_number_start" => 1,
13
+ "tab_width" => 4,
14
+ "wrap" => "div"
15
+ }
16
+
5
17
  def initialize(config)
6
- require 'kramdown'
7
- @config = config
8
- # If kramdown supported highlighter enabled, use that
9
- highlighter = @config['highlighter']
10
- if highlighter == 'rouge' || highlighter == 'coderay'
11
- @config['kramdown']['syntax_highlighter'] ||= highlighter
12
- end
13
- rescue LoadError
14
- STDERR.puts 'You are missing a library required for Markdown. Please run:'
15
- STDERR.puts ' $ [sudo] gem install kramdown'
16
- raise Errors::FatalException.new("Missing dependency: kramdown")
18
+ Jekyll::External.require_with_graceful_fail "kramdown"
19
+ @main_fallback_highlighter = config["highlighter"] || "rogue"
20
+ @config = config["kramdown"] || {}
21
+ setup
22
+ end
23
+
24
+ # Setup and normalize the configuration:
25
+ # * Create Kramdown if it doesn't exist.
26
+ # * Set syntax_highlighter, detecting enable_coderay and merging highlighter if none.
27
+ # * Merge kramdown[coderay] into syntax_highlighter_opts stripping coderay_.
28
+ # * Make sure `syntax_highlighter_opts` exists.
29
+
30
+ def setup
31
+ @config["syntax_highlighter"] ||= highlighter
32
+ @config["syntax_highlighter_opts"] ||= {}
33
+ @config["coderay"] ||= {} # XXX: Legacy.
34
+ modernize_coderay_config
17
35
  end
18
36
 
19
37
  def convert(content)
20
- # Check for use of coderay
21
- if @config['kramdown']['enable_coderay']
22
- %w[wrap line_numbers line_numbers_start tab_width bold_every css default_lang].each do |opt|
23
- key = "coderay_#{opt}"
24
- @config['kramdown'][key] = @config['kramdown']['coderay'][key] unless @config['kramdown'].key?(key)
38
+ Kramdown::Document.new(content, @config).to_html
39
+ end
40
+
41
+ # config[kramdown][syntax_higlighter] > config[kramdown][enable_coderay] > config[highlighter]
42
+ # Where `enable_coderay` is now deprecated because Kramdown
43
+ # supports Rouge now too.
44
+
45
+ private
46
+ def highlighter
47
+ @highlighter ||= begin
48
+ if highlighter = @config["syntax_highlighter"] then highlighter
49
+ elsif @config.key?("enable_coderay") && @config["enable_coderay"]
50
+ Jekyll::Deprecator.deprecation_message "You are using 'enable_coderay', use syntax_highlighter: coderay in your configuration file."
51
+ "coderay"
52
+ else
53
+ @main_fallback_highlighter
25
54
  end
26
55
  end
56
+ end
27
57
 
28
- Kramdown::Document.new(content, Utils.symbolize_hash_keys(@config['kramdown'])).to_html
58
+ private
59
+ def strip_coderay_prefix(hash)
60
+ hash.each_with_object({}) do |(key, val), hsh|
61
+ cleaned_key = key.gsub(/\Acoderay_/, "")
62
+ Jekyll::Deprecator.deprecation_message "You are using '#{key}'. Normalizing to #{cleaned_key}." if key != cleaned_key
63
+ hsh[cleaned_key] = val
64
+ end
29
65
  end
30
66
 
67
+ # If our highlighter is CodeRay we go in to merge the CodeRay defaults
68
+ # with your "coderay" key if it's there, deprecating it in the
69
+ # process of you using it.
70
+
71
+ private
72
+ def modernize_coderay_config
73
+ if highlighter == "coderay"
74
+ Jekyll::Deprecator.deprecation_message "You are using 'kramdown.coderay' in your configuration, please use 'syntax_highlighter_opts' instead."
75
+ @config["syntax_highlighter_opts"] = begin
76
+ strip_coderay_prefix(
77
+ @config["syntax_highlighter_opts"] \
78
+ .merge(CODERAY_DEFAULTS) \
79
+ .merge(@config["coderay"])
80
+ )
81
+ end
82
+ end
83
+ end
31
84
  end
32
85
  end
33
86
  end
@@ -210,7 +210,8 @@ module Jekyll
210
210
 
211
211
  while layout
212
212
  Jekyll.logger.debug "Rendering Layout:", path
213
- payload = Utils.deep_merge_hashes(payload, {"content" => output, "page" => layout.data})
213
+ payload.content = output
214
+ payload.layout = layout.data
214
215
 
215
216
  self.output = render_liquid(layout.content,
216
217
  payload,
@@ -244,11 +245,11 @@ module Jekyll
244
245
 
245
246
  Jekyll.logger.debug "Pre-Render Hooks:", self.relative_path
246
247
  Jekyll::Hooks.trigger hook_owner, :pre_render, self, payload
247
- info = { :filters => [Jekyll::Filters], :registers => { :site => site, :page => payload['page'] } }
248
+ info = { :filters => [Jekyll::Filters], :registers => { :site => site, :page => payload.page } }
248
249
 
249
250
  # render and transform content (this becomes the final content of the object)
250
- payload["highlighter_prefix"] = converters.first.highlighter_prefix
251
- payload["highlighter_suffix"] = converters.first.highlighter_suffix
251
+ payload.highlighter_prefix = converters.first.highlighter_prefix
252
+ payload.highlighter_suffix = converters.first.highlighter_suffix
252
253
 
253
254
  if render_with_liquid?
254
255
  Jekyll.logger.debug "Rendering Liquid:", self.relative_path