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.
- checksums.yaml +4 -4
- data/README.markdown +1 -1
- data/lib/jekyll.rb +6 -5
- data/lib/jekyll/cleaner.rb +1 -1
- data/lib/jekyll/collection.rb +8 -11
- data/lib/jekyll/commands/clean.rb +2 -2
- data/lib/jekyll/commands/doctor.rb +23 -1
- data/lib/jekyll/commands/serve.rb +148 -103
- data/lib/jekyll/commands/serve/servlet.rb +61 -0
- data/lib/jekyll/configuration.rb +26 -46
- data/lib/jekyll/converters/markdown.rb +51 -36
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -17
- data/lib/jekyll/convertible.rb +5 -4
- data/lib/jekyll/document.rb +19 -63
- data/lib/jekyll/drops/collection_drop.rb +24 -0
- data/lib/jekyll/drops/document_drop.rb +28 -0
- data/lib/jekyll/drops/drop.rb +128 -0
- data/lib/jekyll/drops/jekyll_drop.rb +21 -0
- data/lib/jekyll/drops/site_drop.rb +39 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +26 -0
- data/lib/jekyll/drops/url_drop.rb +51 -0
- data/lib/jekyll/entry_filter.rb +1 -1
- data/lib/jekyll/errors.rb +3 -4
- data/lib/jekyll/excerpt.rb +0 -2
- data/lib/jekyll/external.rb +1 -0
- data/lib/jekyll/filters.rb +10 -0
- data/lib/jekyll/frontmatter_defaults.rb +8 -1
- data/lib/jekyll/liquid_renderer/file.rb +1 -1
- data/lib/jekyll/page.rb +15 -11
- data/lib/jekyll/plugin_manager.rb +4 -10
- data/lib/jekyll/renderer.rb +12 -19
- data/lib/jekyll/site.rb +2 -20
- data/lib/jekyll/tags/highlight.rb +5 -5
- data/lib/jekyll/tags/include.rb +13 -2
- data/lib/jekyll/url.rb +22 -12
- data/lib/jekyll/utils.rb +48 -8
- data/lib/jekyll/utils/ansi.rb +59 -0
- data/lib/jekyll/utils/platforms.rb +2 -1
- data/lib/jekyll/version.rb +1 -1
- metadata +14 -5
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Drops
|
5
|
+
class UrlDrop < Drop
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
mutable false
|
9
|
+
|
10
|
+
def_delegator :@obj, :cleaned_relative_path, :path
|
11
|
+
def_delegator :@obj, :output_ext, :output_ext
|
12
|
+
|
13
|
+
def collection
|
14
|
+
@obj.collection.label
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
Utils.slugify(@obj.basename_without_ext)
|
19
|
+
end
|
20
|
+
|
21
|
+
def title
|
22
|
+
Utils.slugify(@obj.data['slug'], mode: "pretty", cased: true) ||
|
23
|
+
Utils.slugify(@obj.basename_without_ext, mode: "pretty", cased: true)
|
24
|
+
end
|
25
|
+
|
26
|
+
def slug
|
27
|
+
Utils.slugify(@obj.data['slug']) || Utils.slugify(@obj.basename_without_ext)
|
28
|
+
end
|
29
|
+
|
30
|
+
def categories
|
31
|
+
category_set = Set.new
|
32
|
+
Array(@obj.data['categories']).each do |category|
|
33
|
+
category_set << category.to_s.downcase
|
34
|
+
end
|
35
|
+
category_set.to_a.join('/')
|
36
|
+
end
|
37
|
+
|
38
|
+
def year; @obj.date.strftime("%Y"); end
|
39
|
+
def month; @obj.date.strftime("%m"); end
|
40
|
+
def day; @obj.date.strftime("%d"); end
|
41
|
+
def hour; @obj.date.strftime("%H"); end
|
42
|
+
def minute; @obj.date.strftime("%M"); end
|
43
|
+
def second; @obj.date.strftime("%S"); end
|
44
|
+
def i_day; @obj.date.strftime("%-d"); end
|
45
|
+
def i_month; @obj.date.strftime("%-m"); end
|
46
|
+
def short_month; @obj.date.strftime("%b"); end
|
47
|
+
def short_year; @obj.date.strftime("%y"); end
|
48
|
+
def y_day; @obj.date.strftime("%j"); end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/jekyll/entry_filter.rb
CHANGED
@@ -47,7 +47,7 @@ module Jekyll
|
|
47
47
|
|
48
48
|
def excluded?(entry)
|
49
49
|
excluded = glob_include?(site.exclude, relative_to_source(entry))
|
50
|
-
Jekyll.logger.debug "EntryFilter:", "excluded
|
50
|
+
Jekyll.logger.debug "EntryFilter:", "excluded?(#{relative_to_source(entry)}) ==> #{excluded}"
|
51
51
|
excluded
|
52
52
|
end
|
53
53
|
|
data/lib/jekyll/errors.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
module Jekyll
|
2
2
|
module Errors
|
3
|
-
|
4
|
-
end
|
3
|
+
FatalException = Class.new(::RuntimeError)
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
MissingDependencyException = Class.new(FatalException)
|
6
|
+
DropMutationException = Class.new(FatalException)
|
8
7
|
end
|
9
8
|
end
|
data/lib/jekyll/excerpt.rb
CHANGED
data/lib/jekyll/external.rb
CHANGED
data/lib/jekyll/filters.rb
CHANGED
@@ -281,6 +281,16 @@ module Jekyll
|
|
281
281
|
new_ary
|
282
282
|
end
|
283
283
|
|
284
|
+
def sample(input, num = 1)
|
285
|
+
return input unless input.respond_to?(:sample)
|
286
|
+
n = num.to_i rescue 1
|
287
|
+
if n == 1
|
288
|
+
input.sample
|
289
|
+
else
|
290
|
+
input.sample(n)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
284
294
|
# Convert an object into its String representation for debugging
|
285
295
|
#
|
286
296
|
# input - The Object to be converted
|
@@ -30,6 +30,13 @@ module Jekyll
|
|
30
30
|
set
|
31
31
|
end
|
32
32
|
|
33
|
+
def ensure_time!(set)
|
34
|
+
return set unless set.key?('values') && set['values'].key?('date')
|
35
|
+
return set if set['values']['date'].is_a?(Time)
|
36
|
+
set['values']['date'] = Utils.parse_date(set['values']['date'], "An invalid date format was found in a front-matter default set: #{set}")
|
37
|
+
set
|
38
|
+
end
|
39
|
+
|
33
40
|
# Finds a default value for a given setting, filtered by path and type
|
34
41
|
#
|
35
42
|
# path - the path (relative to the source) of the page, post or :draft the default is used in
|
@@ -159,7 +166,7 @@ module Jekyll
|
|
159
166
|
|
160
167
|
sets.map do |set|
|
161
168
|
if valid?(set)
|
162
|
-
update_deprecated_types(set)
|
169
|
+
ensure_time!(update_deprecated_types(set))
|
163
170
|
else
|
164
171
|
Jekyll.logger.warn "Defaults:", "An invalid front-matter default set was found:"
|
165
172
|
Jekyll.logger.warn "#{set}"
|
data/lib/jekyll/page.rb
CHANGED
@@ -16,6 +16,15 @@ module Jekyll
|
|
16
16
|
url
|
17
17
|
]
|
18
18
|
|
19
|
+
# A set of extensions that are considered HTML or HTML-like so we
|
20
|
+
# should not alter them, this includes .xhtml through XHTM5.
|
21
|
+
|
22
|
+
HTML_EXTENSIONS = %W(
|
23
|
+
.html
|
24
|
+
.xhtml
|
25
|
+
.htm
|
26
|
+
)
|
27
|
+
|
19
28
|
# Initialize a new Page.
|
20
29
|
#
|
21
30
|
# site - The Site object.
|
@@ -108,12 +117,10 @@ module Jekyll
|
|
108
117
|
#
|
109
118
|
# Returns nothing.
|
110
119
|
def render(layouts, site_payload)
|
111
|
-
|
112
|
-
|
113
|
-
'paginator' => pager.to_liquid
|
114
|
-
}, site_payload)
|
120
|
+
site_payload.page = to_liquid
|
121
|
+
site_payload.paginator = pager.to_liquid
|
115
122
|
|
116
|
-
do_layout(
|
123
|
+
do_layout(site_payload, layouts)
|
117
124
|
end
|
118
125
|
|
119
126
|
# The path to the source file
|
@@ -135,11 +142,8 @@ module Jekyll
|
|
135
142
|
# Returns the destination file path String.
|
136
143
|
def destination(dest)
|
137
144
|
path = site.in_dest_dir(dest, URL.unescape_path(url))
|
138
|
-
if url.end_with?
|
139
|
-
|
140
|
-
else
|
141
|
-
path << output_ext unless path.end_with?(output_ext)
|
142
|
-
end
|
145
|
+
path = File.join(path, "index") if url.end_with?("/")
|
146
|
+
path << output_ext unless path.end_with?(output_ext)
|
143
147
|
path
|
144
148
|
end
|
145
149
|
|
@@ -150,7 +154,7 @@ module Jekyll
|
|
150
154
|
|
151
155
|
# Returns the Boolean of whether this Page is HTML or not.
|
152
156
|
def html?
|
153
|
-
output_ext
|
157
|
+
HTML_EXTENSIONS.include?(output_ext)
|
154
158
|
end
|
155
159
|
|
156
160
|
# Returns the Boolean of whether this Page is an index file or not.
|
@@ -24,12 +24,7 @@ module Jekyll
|
|
24
24
|
#
|
25
25
|
# Returns nothing.
|
26
26
|
def require_gems
|
27
|
-
site.gems.
|
28
|
-
if plugin_allowed?(gem)
|
29
|
-
Jekyll.logger.debug("PluginManager:", "Requiring #{gem}")
|
30
|
-
require gem
|
31
|
-
end
|
32
|
-
end
|
27
|
+
Jekyll::External.require_with_graceful_fail(site.gems.select { |gem| plugin_allowed?(gem) })
|
33
28
|
end
|
34
29
|
|
35
30
|
def self.require_from_bundler
|
@@ -70,10 +65,9 @@ module Jekyll
|
|
70
65
|
# Returns nothing.
|
71
66
|
def require_plugin_files
|
72
67
|
unless site.safe
|
73
|
-
plugins_path.each do |
|
74
|
-
|
75
|
-
|
76
|
-
end
|
68
|
+
plugins_path.each do |plugin_search_path|
|
69
|
+
plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb"))
|
70
|
+
Jekyll::External.require_with_graceful_fail(plugin_files)
|
77
71
|
end
|
78
72
|
end
|
79
73
|
end
|
data/lib/jekyll/renderer.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
module Jekyll
|
4
4
|
class Renderer
|
5
5
|
|
6
|
-
attr_reader :document, :site, :
|
6
|
+
attr_reader :document, :site, :payload
|
7
7
|
|
8
8
|
def initialize(site, document, site_payload = nil)
|
9
|
-
@site
|
10
|
-
@document
|
11
|
-
@site_payload
|
9
|
+
@site = site
|
10
|
+
@document = document
|
11
|
+
@payload = site_payload || site.site_payload
|
12
12
|
end
|
13
13
|
|
14
14
|
# Determine which converters to use based on this document's
|
@@ -33,12 +33,10 @@ module Jekyll
|
|
33
33
|
def run
|
34
34
|
Jekyll.logger.debug "Rendering:", document.relative_path
|
35
35
|
|
36
|
-
payload =
|
37
|
-
"page" => document.to_liquid
|
38
|
-
}, site_payload || site.site_payload)
|
36
|
+
payload.page = document.to_liquid
|
39
37
|
|
40
38
|
if document.collection.label == 'posts' && document.is_a?(Document)
|
41
|
-
payload
|
39
|
+
payload.site['related_posts'] = document.related_posts
|
42
40
|
end
|
43
41
|
|
44
42
|
Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path
|
@@ -46,12 +44,12 @@ module Jekyll
|
|
46
44
|
|
47
45
|
info = {
|
48
46
|
filters: [Jekyll::Filters],
|
49
|
-
registers: { :site => site, :page => payload
|
47
|
+
registers: { :site => site, :page => payload.page }
|
50
48
|
}
|
51
49
|
|
52
50
|
# render and transform content (this becomes the final content of the object)
|
53
|
-
payload
|
54
|
-
payload
|
51
|
+
payload.highlighter_prefix = converters.first.highlighter_prefix
|
52
|
+
payload.highlighter_suffix = converters.first.highlighter_suffix
|
55
53
|
|
56
54
|
output = document.content
|
57
55
|
|
@@ -135,14 +133,9 @@ module Jekyll
|
|
135
133
|
used = Set.new([layout])
|
136
134
|
|
137
135
|
while layout
|
138
|
-
payload =
|
139
|
-
|
140
|
-
|
141
|
-
"content" => output,
|
142
|
-
"page" => document.to_liquid,
|
143
|
-
"layout" => layout.data
|
144
|
-
}
|
145
|
-
)
|
136
|
+
payload.content = output
|
137
|
+
payload.page = document.to_liquid
|
138
|
+
payload.layout = layout.data
|
146
139
|
|
147
140
|
output = render_liquid(
|
148
141
|
layout.content,
|
data/lib/jekyll/site.rb
CHANGED
@@ -224,7 +224,7 @@ module Jekyll
|
|
224
224
|
# Build a hash map based on the specified post attribute ( post attr =>
|
225
225
|
# array of posts ) then sort each array in reverse order.
|
226
226
|
hash = Hash.new { |h, key| h[key] = [] }
|
227
|
-
posts.docs.each { |p| p.data[post_attr].each { |t| hash[t] << p }
|
227
|
+
posts.docs.each { |p| p.data[post_attr].each { |t| hash[t] << p } }
|
228
228
|
hash.values.each { |posts| posts.sort!.reverse! }
|
229
229
|
hash
|
230
230
|
end
|
@@ -259,25 +259,7 @@ module Jekyll
|
|
259
259
|
# "tags" - The Hash of tag values and Posts.
|
260
260
|
# See Site#post_attr_hash for type info.
|
261
261
|
def site_payload
|
262
|
-
|
263
|
-
"jekyll" => {
|
264
|
-
"version" => Jekyll::VERSION,
|
265
|
-
"environment" => Jekyll.env
|
266
|
-
},
|
267
|
-
"site" => Utils.deep_merge_hashes(config,
|
268
|
-
Utils.deep_merge_hashes(Hash[collections.map{|label, coll| [label, coll.docs]}], {
|
269
|
-
"time" => time,
|
270
|
-
"posts" => posts.docs.sort { |a, b| b <=> a },
|
271
|
-
"pages" => pages,
|
272
|
-
"static_files" => static_files,
|
273
|
-
"html_pages" => pages.select { |page| page.html? || page.url.end_with?("/") },
|
274
|
-
"categories" => post_attr_hash('categories'),
|
275
|
-
"tags" => post_attr_hash('tags'),
|
276
|
-
"collections" => collections.values.sort_by(&:label).map(&:to_liquid),
|
277
|
-
"documents" => documents,
|
278
|
-
"data" => site_data
|
279
|
-
}))
|
280
|
-
}
|
262
|
+
Drops::UnifiedPayloadDrop.new self
|
281
263
|
end
|
282
264
|
|
283
265
|
# Get the implementation class for the given Converter.
|
@@ -14,7 +14,7 @@ module Jekyll
|
|
14
14
|
super
|
15
15
|
if markup.strip =~ SYNTAX
|
16
16
|
@lang = $1.downcase
|
17
|
-
@
|
17
|
+
@highlight_options = {}
|
18
18
|
if defined?($2) && $2 != ''
|
19
19
|
# Split along 3 possible forms -- key="<quoted list>", key=value, or key
|
20
20
|
$2.scan(/(?:\w="[^"]*"|\w=\w|\w)+/) do |opt|
|
@@ -24,10 +24,10 @@ module Jekyll
|
|
24
24
|
value.gsub!(/"/, "")
|
25
25
|
value = value.split
|
26
26
|
end
|
27
|
-
@
|
27
|
+
@highlight_options[key.to_sym] = value || true
|
28
28
|
end
|
29
29
|
end
|
30
|
-
@
|
30
|
+
@highlight_options[:linenos] = "inline" if @highlight_options.key?(:linenos) and @highlight_options[:linenos] == true
|
31
31
|
else
|
32
32
|
raise SyntaxError.new <<-eos
|
33
33
|
Syntax Error in tag 'highlight' while parsing the following markup:
|
@@ -80,7 +80,7 @@ eos
|
|
80
80
|
highlighted_code = Pygments.highlight(
|
81
81
|
code,
|
82
82
|
:lexer => @lang,
|
83
|
-
:options => sanitized_opts(@
|
83
|
+
:options => sanitized_opts(@highlight_options, is_safe)
|
84
84
|
)
|
85
85
|
|
86
86
|
if highlighted_code.nil?
|
@@ -99,7 +99,7 @@ eos
|
|
99
99
|
|
100
100
|
def render_rouge(code)
|
101
101
|
Jekyll::External.require_with_graceful_fail('rouge')
|
102
|
-
formatter = Rouge::Formatters::HTML.new(line_numbers: @
|
102
|
+
formatter = Rouge::Formatters::HTML.new(line_numbers: @highlight_options[:linenos], wrap: false)
|
103
103
|
lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
|
104
104
|
formatter.format(lexer.lex(code))
|
105
105
|
end
|
data/lib/jekyll/tags/include.rb
CHANGED
@@ -16,7 +16,7 @@ module Jekyll
|
|
16
16
|
attr_reader :includes_dir
|
17
17
|
|
18
18
|
VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
19
|
-
VARIABLE_SYNTAX = /(?<variable>[^{]
|
19
|
+
VARIABLE_SYNTAX = /(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)(?<params>.*)/
|
20
20
|
|
21
21
|
def initialize(tag_name, markup, tokens)
|
22
22
|
super
|
@@ -123,7 +123,7 @@ eos
|
|
123
123
|
end
|
124
124
|
|
125
125
|
begin
|
126
|
-
partial =
|
126
|
+
partial = load_cached_partial(path, context)
|
127
127
|
|
128
128
|
context.stack do
|
129
129
|
context['include'] = parse_params(context) if @params
|
@@ -134,6 +134,17 @@ eos
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
|
+
def load_cached_partial(path, context)
|
138
|
+
context.registers[:cached_partials] ||= {}
|
139
|
+
cached_partial = context.registers[:cached_partials]
|
140
|
+
|
141
|
+
if cached_partial.has_key?(path)
|
142
|
+
cached_partial[path]
|
143
|
+
else
|
144
|
+
cached_partial[path] = context.registers[:site].liquid_renderer.file(path).parse(read_file(path, context))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
137
148
|
def resolved_includes_dir(context)
|
138
149
|
context.registers[:site].in_source_dir(@includes_dir)
|
139
150
|
end
|
data/lib/jekyll/url.rb
CHANGED
@@ -59,6 +59,14 @@ module Jekyll
|
|
59
59
|
#
|
60
60
|
# Returns the unsanitized String URL
|
61
61
|
def generate_url(template)
|
62
|
+
if @placeholders.is_a? Drops::UrlDrop
|
63
|
+
generate_url_from_drop(template)
|
64
|
+
else
|
65
|
+
generate_url_from_hash(template)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def generate_url_from_hash(template)
|
62
70
|
@placeholders.inject(template) do |result, token|
|
63
71
|
break result if result.index(':').nil?
|
64
72
|
if token.last.nil?
|
@@ -70,20 +78,22 @@ module Jekyll
|
|
70
78
|
end
|
71
79
|
end
|
72
80
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
def generate_url_from_drop(template)
|
82
|
+
template.gsub(/:([a-z_]+)/) do |match|
|
83
|
+
replacement = @placeholders.public_send(match.sub(':', ''))
|
84
|
+
if replacement.nil?
|
85
|
+
''.freeze
|
86
|
+
else
|
87
|
+
self.class.escape_path(replacement)
|
88
|
+
end
|
89
|
+
end.gsub(/\/\//, '/')
|
90
|
+
end
|
82
91
|
|
83
|
-
|
84
|
-
|
92
|
+
# Returns a sanitized String URL, stripping "../../" and multiples of "/",
|
93
|
+
# as well as the beginning "/" so we can enforce and ensure it.
|
85
94
|
|
86
|
-
|
95
|
+
def sanitize_url(str)
|
96
|
+
"/" + str.gsub(/\/{2,}/, "/").gsub(%r!\.+\/|\A/+!, "")
|
87
97
|
end
|
88
98
|
|
89
99
|
# Escapes a path to be a valid URL path segment
|