jekyll 2.1.1 → 2.2.0
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.
- checksums.yaml +4 -4
- data/History.markdown +36 -3
- data/Rakefile +20 -1
- data/features/post_data.feature +41 -6
- data/jekyll.gemspec +7 -4
- data/lib/jekyll.rb +53 -50
- data/lib/jekyll/command.rb +1 -1
- data/lib/jekyll/commands/build.rb +1 -1
- data/lib/jekyll/converters/markdown.rb +23 -4
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -1
- data/lib/jekyll/converters/markdown/maruku_parser.rb +1 -1
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +1 -5
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +31 -36
- data/lib/jekyll/converters/textile.rb +2 -2
- data/lib/jekyll/convertible.rb +12 -0
- data/lib/jekyll/deprecator.rb +19 -1
- data/lib/jekyll/errors.rb +6 -1
- data/lib/jekyll/excerpt.rb +0 -1
- data/lib/jekyll/frontmatter_defaults.rb +120 -122
- data/lib/jekyll/post.rb +3 -1
- data/lib/jekyll/renderer.rb +12 -0
- data/lib/jekyll/site.rb +2 -2
- data/lib/jekyll/tags/highlight.rb +24 -3
- data/lib/jekyll/tags/include.rb +0 -4
- data/lib/jekyll/version.rb +1 -1
- data/script/cibuild +4 -1
- data/script/proof +22 -0
- data/script/test +8 -2
- data/site/_config.yml +0 -1
- data/site/_posts/2013-05-06-jekyll-1-0-0-released.markdown +1 -1
- data/site/_posts/2013-05-08-jekyll-1-0-1-released.markdown +1 -1
- data/site/_posts/2013-05-12-jekyll-1-0-2-released.markdown +1 -1
- data/site/_posts/2013-06-07-jekyll-1-0-3-released.markdown +1 -1
- data/site/_posts/2014-03-24-jekyll-1-5-0-released.markdown +1 -1
- data/site/_posts/2014-05-06-jekyll-turns-2-0-0.markdown +2 -2
- data/site/_posts/2014-06-28-jekyll-turns-21-i-mean-2-1-0.markdown +1 -1
- data/site/_posts/2014-07-29-jekyll-2-2-0-released.markdown +19 -0
- data/site/docs/assets.md +17 -3
- data/site/docs/contributing.md +1 -1
- data/site/docs/deployment-methods.md +15 -2
- data/site/docs/extras.md +3 -75
- data/site/docs/github-pages.md +1 -1
- data/site/docs/history.md +260 -3
- data/site/docs/index.md +1 -1
- data/site/docs/installation.md +1 -1
- data/site/docs/plugins.md +6 -2
- data/site/docs/posts.md +3 -3
- data/site/docs/resources.md +3 -6
- data/site/docs/troubleshooting.md +0 -10
- data/site/index.html +1 -1
- data/test/test_command.rb +1 -1
- data/test/test_kramdown.rb +1 -1
- data/test/test_post.rb +17 -2
- data/test/test_site.rb +5 -5
- data/test/test_tags.rb +33 -2
- metadata +20 -19
- data/site/docs/heroku.md +0 -9
@@ -13,7 +13,7 @@ module Jekyll
|
|
13
13
|
rescue LoadError
|
14
14
|
STDERR.puts 'You are missing a library required for Textile. Please run:'
|
15
15
|
STDERR.puts ' $ [sudo] gem install RedCloth'
|
16
|
-
raise FatalException.new("Missing dependency: RedCloth")
|
16
|
+
raise Errors::FatalException.new("Missing dependency: RedCloth")
|
17
17
|
end
|
18
18
|
|
19
19
|
def matches(ext)
|
@@ -32,7 +32,7 @@ module Jekyll
|
|
32
32
|
return RedCloth.new(content).to_html if @config['redcloth'].nil?
|
33
33
|
|
34
34
|
# List of attributes defined on RedCloth
|
35
|
-
# (from
|
35
|
+
# (from https://github.com/jgarber/redcloth/blob/master/lib/redcloth/textile_doc.rb)
|
36
36
|
attrs = ['filter_classes', 'filter_html', 'filter_ids', 'filter_styles',
|
37
37
|
'hard_breaks', 'lite_mode', 'no_span_caps', 'sanitize_html']
|
38
38
|
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -153,6 +153,15 @@ module Jekyll
|
|
153
153
|
!asset_file?
|
154
154
|
end
|
155
155
|
|
156
|
+
# Checks if the layout specified in the document actually exists
|
157
|
+
#
|
158
|
+
# layout - the layout to check
|
159
|
+
#
|
160
|
+
# Returns true if the layout is invalid, false if otherwise
|
161
|
+
def invalid_layout?(layout)
|
162
|
+
!data["layout"].nil? && data["layout"] != "none" && layout.nil? && !(self.is_a? Jekyll::Excerpt)
|
163
|
+
end
|
164
|
+
|
156
165
|
# Recursively render layouts
|
157
166
|
#
|
158
167
|
# layouts - a list of the layouts
|
@@ -163,6 +172,9 @@ module Jekyll
|
|
163
172
|
def render_all_layouts(layouts, payload, info)
|
164
173
|
# recursively render layouts
|
165
174
|
layout = layouts[data["layout"]]
|
175
|
+
|
176
|
+
Jekyll.logger.warn("Build Warning:", "Layout '#{data["layout"]}' requested in #{path} does not exist.") if invalid_layout? layout
|
177
|
+
|
166
178
|
used = Set.new([layout])
|
167
179
|
|
168
180
|
while layout
|
data/lib/jekyll/deprecator.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Jekyll
|
2
|
-
|
2
|
+
module Deprecator
|
3
3
|
def self.process(args)
|
4
4
|
no_subcommand(args)
|
5
5
|
arg_is_present? args, "--server", "The --server command has been replaced by the \
|
@@ -32,5 +32,23 @@ module Jekyll
|
|
32
32
|
def self.deprecation_message(message)
|
33
33
|
Jekyll.logger.error "Deprecation:", message
|
34
34
|
end
|
35
|
+
|
36
|
+
def self.gracefully_require(gem_name)
|
37
|
+
Array(gem_name).each do |name|
|
38
|
+
begin
|
39
|
+
require name
|
40
|
+
rescue LoadError => e
|
41
|
+
Jekyll.logger.error "Dependency Error:", <<-MSG
|
42
|
+
Yikes! It looks like you don't have #{name} or one of its dependencies installed.
|
43
|
+
In order to use Jekyll as currently contfigured, you'll need to install this gem.
|
44
|
+
|
45
|
+
The full error message from Ruby is: '#{e.message}'
|
46
|
+
|
47
|
+
If you run into trouble, you can find helpful resources at http://jekyllrb.com/help/!
|
48
|
+
MSG
|
49
|
+
raise Errors::MissingDependencyException.new(name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
35
53
|
end
|
36
54
|
end
|
data/lib/jekyll/errors.rb
CHANGED
data/lib/jekyll/excerpt.rb
CHANGED
@@ -1,147 +1,145 @@
|
|
1
1
|
module Jekyll
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
2
|
+
# This class handles custom defaults for YAML frontmatter settings.
|
3
|
+
# These are set in _config.yml and apply both to internal use (e.g. layout)
|
4
|
+
# and the data available to liquid.
|
5
|
+
#
|
6
|
+
# It is exposed via the frontmatter_defaults method on the site class.
|
7
|
+
class FrontmatterDefaults
|
8
|
+
# Initializes a new instance.
|
9
|
+
def initialize(site)
|
10
|
+
@site = site
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
13
|
+
# Finds a default value for a given setting, filtered by path and type
|
14
|
+
#
|
15
|
+
# path - the path (relative to the source) of the page, post or :draft the default is used in
|
16
|
+
# type - a symbol indicating whether a :page, a :post or a :draft calls this method
|
17
|
+
#
|
18
|
+
# Returns the default value or nil if none was found
|
19
|
+
def find(path, type, setting)
|
20
|
+
value = nil
|
21
|
+
old_scope = nil
|
22
|
+
|
23
|
+
matching_sets(path, type).each do |set|
|
24
|
+
if set['values'].has_key?(setting) && has_precedence?(old_scope, set['scope'])
|
25
|
+
value = set['values'][setting]
|
26
|
+
old_scope = set['scope']
|
29
27
|
end
|
30
|
-
value
|
31
28
|
end
|
29
|
+
value
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
32
|
+
# Collects a hash with all default values for a page or post
|
33
|
+
#
|
34
|
+
# path - the relative path of the page or post
|
35
|
+
# type - a symbol indicating the type (:post, :page or :draft)
|
36
|
+
#
|
37
|
+
# Returns a hash with all default values (an empty hash if there are none)
|
38
|
+
def all(path, type)
|
39
|
+
defaults = {}
|
40
|
+
old_scope = nil
|
41
|
+
matching_sets(path, type).each do |set|
|
42
|
+
if has_precedence?(old_scope, set['scope'])
|
43
|
+
defaults = Utils.deep_merge_hashes(defaults, set['values'])
|
44
|
+
old_scope = set['scope']
|
45
|
+
else
|
46
|
+
defaults = Utils.deep_merge_hashes(set['values'], defaults)
|
49
47
|
end
|
50
|
-
defaults
|
51
48
|
end
|
49
|
+
defaults
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
# Checks if a given default setting scope matches the given path and type
|
56
|
-
#
|
57
|
-
# scope - the hash indicating the scope, as defined in _config.yml
|
58
|
-
# path - the path to check for
|
59
|
-
# type - the type (:post, :page or :draft) to check for
|
60
|
-
#
|
61
|
-
# Returns true if the scope applies to the given path and type
|
62
|
-
def applies?(scope, path, type)
|
63
|
-
applies_path?(scope, path) && applies_type?(scope, type)
|
64
|
-
end
|
52
|
+
private
|
65
53
|
|
66
|
-
|
67
|
-
|
54
|
+
# Checks if a given default setting scope matches the given path and type
|
55
|
+
#
|
56
|
+
# scope - the hash indicating the scope, as defined in _config.yml
|
57
|
+
# path - the path to check for
|
58
|
+
# type - the type (:post, :page or :draft) to check for
|
59
|
+
#
|
60
|
+
# Returns true if the scope applies to the given path and type
|
61
|
+
def applies?(scope, path, type)
|
62
|
+
applies_path?(scope, path) && applies_type?(scope, type)
|
63
|
+
end
|
68
64
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
def applies_path?(scope, path)
|
66
|
+
return true if scope['path'].empty?
|
67
|
+
|
68
|
+
scope_path = Pathname.new(scope['path'])
|
69
|
+
Pathname.new(sanitize_path(path)).ascend do |path|
|
70
|
+
if path == scope_path
|
71
|
+
return true
|
74
72
|
end
|
75
73
|
end
|
74
|
+
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
def applies_type?(scope, type)
|
77
|
+
!scope.has_key?('type') || scope['type'] == type.to_s
|
78
|
+
end
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
# Checks if a given set of default values is valid
|
81
|
+
#
|
82
|
+
# set - the default value hash, as defined in _config.yml
|
83
|
+
#
|
84
|
+
# Returns true if the set is valid and can be used in this class
|
85
|
+
def valid?(set)
|
86
|
+
set.is_a?(Hash) && set['scope'].is_a?(Hash) && set['scope']['path'].is_a?(String) && set['values'].is_a?(Hash)
|
87
|
+
end
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
89
|
+
# Determines if a new scope has precedence over an old one
|
90
|
+
#
|
91
|
+
# old_scope - the old scope hash, or nil if there's none
|
92
|
+
# new_scope - the new scope hash
|
93
|
+
#
|
94
|
+
# Returns true if the new scope has precedence over the older
|
95
|
+
def has_precedence?(old_scope, new_scope)
|
96
|
+
return true if old_scope.nil?
|
97
|
+
|
98
|
+
new_path = sanitize_path(new_scope['path'])
|
99
|
+
old_path = sanitize_path(old_scope['path'])
|
100
|
+
|
101
|
+
if new_path.length != old_path.length
|
102
|
+
new_path.length >= old_path.length
|
103
|
+
elsif new_scope.has_key? 'type'
|
104
|
+
true
|
105
|
+
else
|
106
|
+
!old_scope.has_key? 'type'
|
109
107
|
end
|
108
|
+
end
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
110
|
+
# Collects a list of sets that match the given path and type
|
111
|
+
#
|
112
|
+
# Returns an array of hashes
|
113
|
+
def matching_sets(path, type)
|
114
|
+
valid_sets.select do |set|
|
115
|
+
applies?(set['scope'], path, type)
|
118
116
|
end
|
117
|
+
end
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
134
|
-
valid?(set)
|
119
|
+
# Returns a list of valid sets
|
120
|
+
#
|
121
|
+
# This is not cached to allow plugins to modify the configuration
|
122
|
+
# and have their changes take effect
|
123
|
+
#
|
124
|
+
# Returns an array of hashes
|
125
|
+
def valid_sets
|
126
|
+
sets = @site.config['defaults']
|
127
|
+
return [] unless sets.is_a?(Array)
|
128
|
+
|
129
|
+
sets.select do |set|
|
130
|
+
unless valid?(set)
|
131
|
+
Jekyll.logger.warn "Default:", "An invalid default set was found"
|
135
132
|
end
|
133
|
+
valid?(set)
|
136
134
|
end
|
135
|
+
end
|
137
136
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
137
|
+
# Sanitizes the given path by removing a leading and addding a trailing slash
|
138
|
+
def sanitize_path(path)
|
139
|
+
if path.nil? || path.empty?
|
140
|
+
""
|
141
|
+
else
|
142
|
+
path.gsub(/\A\//, '').gsub(/([^\/])\z/, '\1/')
|
145
143
|
end
|
146
144
|
end
|
147
145
|
end
|
data/lib/jekyll/post.rb
CHANGED
@@ -159,6 +159,8 @@ module Jekyll
|
|
159
159
|
# Returns nothing.
|
160
160
|
def process(name)
|
161
161
|
m, cats, date, slug, ext = *name.match(MATCHER)
|
162
|
+
self.categories ||= []
|
163
|
+
self.categories += (cats || '').downcase.split('/')
|
162
164
|
self.date = Time.parse(date)
|
163
165
|
self.slug = slug
|
164
166
|
self.ext = ext
|
@@ -166,7 +168,7 @@ module Jekyll
|
|
166
168
|
path = File.join(@dir || "", name)
|
167
169
|
msg = "Post '#{path}' does not have a valid date.\n"
|
168
170
|
msg << "Fix the date, or exclude the file or directory from being processed"
|
169
|
-
raise FatalException.new(msg)
|
171
|
+
raise Errors::FatalException.new(msg)
|
170
172
|
end
|
171
173
|
|
172
174
|
# The generated directory into which the post will be placed
|
data/lib/jekyll/renderer.rb
CHANGED
@@ -92,6 +92,15 @@ module Jekyll
|
|
92
92
|
raise e
|
93
93
|
end
|
94
94
|
|
95
|
+
# Checks if the layout specified in the document actually exists
|
96
|
+
#
|
97
|
+
# layout - the layout to check
|
98
|
+
#
|
99
|
+
# Returns true if the layout is invalid, false if otherwise
|
100
|
+
def invalid_layout?(layout)
|
101
|
+
!document.data["layout"].nil? && layout.nil?
|
102
|
+
end
|
103
|
+
|
95
104
|
# Render layouts and place given content inside.
|
96
105
|
#
|
97
106
|
# content - the content to be placed in the layout
|
@@ -101,6 +110,9 @@ module Jekyll
|
|
101
110
|
def place_in_layouts(content, payload, info)
|
102
111
|
output = content.dup
|
103
112
|
layout = site.layouts[document.data["layout"]]
|
113
|
+
|
114
|
+
Jekyll.logger.warn("Build Warning:", "Layout '#{document.data["layout"]}' requested in #{document.relative_path} does not exist.") if invalid_layout? layout
|
115
|
+
|
104
116
|
used = Set.new([layout])
|
105
117
|
|
106
118
|
while layout
|
data/lib/jekyll/site.rb
CHANGED
@@ -80,7 +80,7 @@ module Jekyll
|
|
80
80
|
dest_pathname = Pathname.new(dest)
|
81
81
|
Pathname.new(source).ascend do |path|
|
82
82
|
if path == dest_pathname
|
83
|
-
raise FatalException.new "Destination directory cannot be or contain the Source directory."
|
83
|
+
raise Errors::FatalException.new "Destination directory cannot be or contain the Source directory."
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -443,7 +443,7 @@ module Jekyll
|
|
443
443
|
end
|
444
444
|
|
445
445
|
def frontmatter_defaults
|
446
|
-
@frontmatter_defaults ||=
|
446
|
+
@frontmatter_defaults ||= FrontmatterDefaults.new(self)
|
447
447
|
end
|
448
448
|
|
449
449
|
private
|
@@ -44,9 +44,11 @@ eos
|
|
44
44
|
suffix = context["highlighter_suffix"] || ""
|
45
45
|
code = super.to_s.strip
|
46
46
|
|
47
|
+
is_safe = !!context.registers[:site].safe
|
48
|
+
|
47
49
|
output = case context.registers[:site].highlighter
|
48
50
|
when 'pygments'
|
49
|
-
render_pygments(code)
|
51
|
+
render_pygments(code, is_safe)
|
50
52
|
when 'rouge'
|
51
53
|
render_rouge(code)
|
52
54
|
else
|
@@ -57,11 +59,30 @@ eos
|
|
57
59
|
prefix + rendered_output + suffix
|
58
60
|
end
|
59
61
|
|
60
|
-
def
|
62
|
+
def sanitized_opts(opts, is_safe)
|
63
|
+
if is_safe
|
64
|
+
Hash[[
|
65
|
+
[:startinline, opts.fetch(:startinline, nil)],
|
66
|
+
[:hl_linenos, opts.fetch(:hl_linenos, nil)],
|
67
|
+
[:linenos, opts.fetch(:linenos, nil)],
|
68
|
+
[:encoding, opts.fetch(:encoding, 'utf-8')],
|
69
|
+
[:cssclass, opts.fetch(:cssclass, nil)]
|
70
|
+
].reject {|f| f.last.nil? }]
|
71
|
+
else
|
72
|
+
opts
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def render_pygments(code, is_safe)
|
61
77
|
require 'pygments'
|
78
|
+
|
62
79
|
@options[:encoding] = 'utf-8'
|
63
80
|
|
64
|
-
highlighted_code = Pygments.highlight(
|
81
|
+
highlighted_code = Pygments.highlight(
|
82
|
+
code,
|
83
|
+
:lexer => @lang,
|
84
|
+
:options => sanitized_opts(@options, is_safe)
|
85
|
+
)
|
65
86
|
|
66
87
|
if highlighted_code.nil?
|
67
88
|
Jekyll.logger.error "There was an error highlighting your code:"
|