jekyll 2.0.0.alpha.2 → 2.0.0.alpha.3
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 +35 -0
- data/Rakefile +1 -1
- data/features/collections.feature +38 -0
- data/features/create_sites.feature +17 -0
- data/features/step_definitions/jekyll_steps.rb +15 -7
- data/features/support/env.rb +6 -1
- data/lib/jekyll.rb +6 -1
- data/lib/jekyll/cleaner.rb +5 -3
- data/lib/jekyll/collection.rb +121 -0
- data/lib/jekyll/command.rb +2 -0
- data/lib/jekyll/commands/build.rb +5 -1
- data/lib/jekyll/commands/serve.rb +1 -1
- data/lib/jekyll/configuration.rb +2 -0
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +11 -12
- data/lib/jekyll/convertible.rb +1 -1
- data/lib/jekyll/document.rb +228 -0
- data/lib/jekyll/entry_filter.rb +4 -1
- data/lib/jekyll/layout_reader.rb +1 -1
- data/lib/jekyll/page.rb +1 -1
- data/lib/jekyll/plugin_manager.rb +76 -0
- data/lib/jekyll/post.rb +3 -3
- data/lib/jekyll/publisher.rb +21 -0
- data/lib/jekyll/renderer.rb +132 -0
- data/lib/jekyll/site.rb +84 -68
- data/lib/jekyll/tags/highlight.rb +8 -6
- data/lib/jekyll/url.rb +43 -3
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/_includes/head.html +3 -3
- data/script/console +38 -0
- data/site/_config.yml +1 -0
- data/site/_data/docs.yml +1 -0
- data/site/_includes/css/style.css +12 -12
- data/site/_includes/news_item.html +3 -3
- data/site/_includes/primary-nav-items.html +4 -1
- data/site/_includes/top.html +7 -3
- data/site/_layouts/news_item.html +3 -3
- data/site/_posts/2014-03-27-jekyll-1-5-1-released.markdown +26 -0
- data/site/docs/collections.md +126 -0
- data/site/docs/configuration.md +3 -2
- data/site/docs/datafiles.md +1 -1
- data/site/docs/history.md +6 -0
- data/site/docs/plugins.md +1 -1
- data/site/docs/troubleshooting.md +7 -3
- data/site/docs/variables.md +1 -1
- data/site/favicon.ico +0 -0
- data/site/feed.xml +27 -14
- data/site/img/logo-rss.png +0 -0
- data/site/js/html5shiv.js +8 -0
- data/site/js/respond.min.js +5 -0
- data/test/source/+/%# +.md +6 -0
- data/test/source/_methods/_do_not_read_me.md +5 -0
- data/test/source/_methods/configuration.md +8 -0
- data/test/source/_methods/sanitized_path.md +5 -0
- data/test/source/_methods/site/_dont_include_me_either.md +5 -0
- data/test/source/_methods/site/generate.md +6 -0
- data/test/source/_methods/site/initialize.md +5 -0
- data/test/source/_methods/um_hi.md +6 -0
- data/test/source/_posts/2014-03-03-yaml-with-dots.md +5 -0
- data/test/source/_posts/2014-03-22-escape-+ %20[].markdown +6 -0
- data/test/source/pgp.key +2 -0
- data/test/test_coffeescript.rb +1 -1
- data/test/test_collections.rb +129 -0
- data/test/test_command.rb +17 -0
- data/test/test_document.rb +48 -0
- data/test/test_filters.rb +1 -1
- data/test/test_generated_site.rb +5 -4
- data/test/test_new_command.rb +4 -4
- data/test/test_page.rb +22 -8
- data/test/test_path_sanitization.rb +4 -0
- data/test/test_post.rb +42 -13
- data/test/test_site.rb +11 -17
- data/test/test_tags.rb +10 -6
- metadata +42 -7
- data/lib/site_template/_posts/0000-00-00-this-post-demonstrates-post-content-styles.md +0 -88
- data/site/favicon.png +0 -0
- data/site/img/tube.png +0 -0
- data/site/img/tube1x.png +0 -0
- data/site/js/modernizr-2.7.1.min.js +0 -4
@@ -0,0 +1,132 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class Renderer
|
3
|
+
|
4
|
+
attr_reader :document, :site
|
5
|
+
|
6
|
+
def initialize(site, document)
|
7
|
+
@site = site
|
8
|
+
@document = document
|
9
|
+
end
|
10
|
+
|
11
|
+
# Determine which converters to use based on this document's
|
12
|
+
# extension.
|
13
|
+
#
|
14
|
+
# Returns an array of Converter instances.
|
15
|
+
def converters
|
16
|
+
@converters ||= site.converters.select { |c| c.matches(document.extname) }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Determine the extname the outputted file should have
|
20
|
+
#
|
21
|
+
# Returns the output extname including the leading period.
|
22
|
+
def output_ext
|
23
|
+
converters.first.output_ext(document.extname)
|
24
|
+
end
|
25
|
+
|
26
|
+
######################
|
27
|
+
## DAT RENDER THO
|
28
|
+
######################
|
29
|
+
|
30
|
+
def run
|
31
|
+
payload = Utils.deep_merge_hashes({
|
32
|
+
"page" => document.to_liquid
|
33
|
+
}, site.site_payload)
|
34
|
+
|
35
|
+
info = {
|
36
|
+
filters: [Jekyll::Filters],
|
37
|
+
registers: { :site => site, :page => payload['page'] }
|
38
|
+
}
|
39
|
+
|
40
|
+
# render and transform content (this becomes the final content of the object)
|
41
|
+
payload["highlighter_prefix"] = converters.first.highlighter_prefix
|
42
|
+
payload["highlighter_suffix"] = converters.first.highlighter_suffix
|
43
|
+
|
44
|
+
output = document.content
|
45
|
+
|
46
|
+
if document.render_with_liquid?
|
47
|
+
output = render_liquid(output, payload, info)
|
48
|
+
end
|
49
|
+
|
50
|
+
place_in_layouts(
|
51
|
+
convert(output),
|
52
|
+
payload,
|
53
|
+
info
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Convert the given content using the converters which match this renderer's document.
|
58
|
+
#
|
59
|
+
# content - the raw, unconverted content
|
60
|
+
#
|
61
|
+
# Returns the converted content.
|
62
|
+
def convert(content)
|
63
|
+
converters.reduce(content) do |output, converter|
|
64
|
+
begin
|
65
|
+
converter.convert output
|
66
|
+
rescue => e
|
67
|
+
Jekyll.logger.error "Conversion error:", "#{converter.class} encountered an error converting '#{document.relative_path}'."
|
68
|
+
raise e
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Render the given content with the payload and info
|
74
|
+
#
|
75
|
+
# content -
|
76
|
+
# payload -
|
77
|
+
# info -
|
78
|
+
# path - (optional) the path to the file, for use in ex
|
79
|
+
#
|
80
|
+
# Returns the content, rendered by Liquid.
|
81
|
+
def render_liquid(content, payload, info, path = nil)
|
82
|
+
Liquid::Template.parse(content).render!(payload, info)
|
83
|
+
rescue Tags::IncludeTagError => e
|
84
|
+
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || document.relative_path}"
|
85
|
+
raise e
|
86
|
+
rescue Exception => e
|
87
|
+
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{path || document.relative_path}"
|
88
|
+
raise e
|
89
|
+
end
|
90
|
+
|
91
|
+
# Render layouts and place given content inside.
|
92
|
+
#
|
93
|
+
# content - the content to be placed in the layout
|
94
|
+
#
|
95
|
+
#
|
96
|
+
# Returns the content placed in the Liquid-rendered layouts
|
97
|
+
def place_in_layouts(content, payload, info)
|
98
|
+
output = content.dup
|
99
|
+
layout = site.layouts[document.data["layout"]]
|
100
|
+
used = Set.new([layout])
|
101
|
+
|
102
|
+
while layout
|
103
|
+
payload = Utils.deep_merge_hashes(
|
104
|
+
payload,
|
105
|
+
{
|
106
|
+
"content" => output,
|
107
|
+
"page" => document.to_liquid,
|
108
|
+
"layout" => layout.data
|
109
|
+
}
|
110
|
+
)
|
111
|
+
|
112
|
+
output = render_liquid(
|
113
|
+
layout.content,
|
114
|
+
payload,
|
115
|
+
info,
|
116
|
+
File.join(site.config['layouts'], layout.name)
|
117
|
+
)
|
118
|
+
|
119
|
+
if layout = site.layouts[layout.data["layout"]]
|
120
|
+
if used.include?(layout)
|
121
|
+
layout = nil # avoid recursive chain
|
122
|
+
else
|
123
|
+
used << layout
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
output
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
data/lib/jekyll/site.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Jekyll
|
2
2
|
class Site
|
3
3
|
attr_accessor :config, :layouts, :posts, :pages, :static_files,
|
4
|
-
:
|
5
|
-
:permalink_style, :
|
6
|
-
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts, :gems
|
4
|
+
:exclude, :include, :source, :dest, :lsi, :highlighter,
|
5
|
+
:permalink_style, :time, :future, :unpublished, :safe, :plugins, :limit_posts,
|
6
|
+
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts, :gems,
|
7
|
+
:plugin_manager, :collections
|
7
8
|
|
8
9
|
attr_accessor :converters, :generators
|
9
10
|
|
@@ -13,15 +14,18 @@ module Jekyll
|
|
13
14
|
def initialize(config)
|
14
15
|
self.config = config.clone
|
15
16
|
|
16
|
-
%w[safe lsi highlighter baseurl exclude include future
|
17
|
+
%w[safe lsi highlighter baseurl exclude include future unpublished
|
18
|
+
show_drafts limit_posts keep_files gems].each do |opt|
|
17
19
|
self.send("#{opt}=", config[opt])
|
18
20
|
end
|
19
21
|
|
20
|
-
self.source
|
21
|
-
self.dest
|
22
|
-
self.plugins = plugins_path
|
22
|
+
self.source = File.expand_path(config['source'])
|
23
|
+
self.dest = File.expand_path(config['destination'])
|
23
24
|
self.permalink_style = config['permalink'].to_sym
|
24
25
|
|
26
|
+
self.plugin_manager = Jekyll::PluginManager.new(self)
|
27
|
+
self.plugins = plugin_manager.plugins_path
|
28
|
+
|
25
29
|
self.file_read_opts = {}
|
26
30
|
self.file_read_opts[:encoding] = config['encoding'] if config['encoding']
|
27
31
|
|
@@ -50,8 +54,6 @@ module Jekyll
|
|
50
54
|
self.posts = []
|
51
55
|
self.pages = []
|
52
56
|
self.static_files = []
|
53
|
-
self.categories = Hash.new { |hash, key| hash[key] = [] }
|
54
|
-
self.tags = Hash.new { |hash, key| hash[key] = [] }
|
55
57
|
self.data = {}
|
56
58
|
|
57
59
|
if limit_posts < 0
|
@@ -65,17 +67,7 @@ module Jekyll
|
|
65
67
|
def setup
|
66
68
|
ensure_not_in_dest
|
67
69
|
|
68
|
-
|
69
|
-
# directory.
|
70
|
-
unless safe
|
71
|
-
plugins.each do |plugins|
|
72
|
-
Dir[File.join(plugins, "**/*.rb")].sort.each do |f|
|
73
|
-
require f
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
require_gems
|
70
|
+
plugin_manager.conscientious_require
|
79
71
|
|
80
72
|
self.converters = instantiate_subclasses(Jekyll::Converter)
|
81
73
|
self.generators = instantiate_subclasses(Jekyll::Generator)
|
@@ -92,31 +84,24 @@ module Jekyll
|
|
92
84
|
end
|
93
85
|
end
|
94
86
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
87
|
+
# The list of collections and their corresponding Jekyll::Collection instances.
|
88
|
+
# If config['collections'] is set, a new instance is created for each item in the collection.
|
89
|
+
# If config['collections'] is not set, a new hash is returned.
|
90
|
+
#
|
91
|
+
# Returns a Hash containing collection name-to-instance pairs.
|
92
|
+
def collections
|
93
|
+
@collections ||= if config['collections']
|
94
|
+
Hash[config['collections'].map { |coll| [coll, Jekyll::Collection.new(self, coll)] } ]
|
95
|
+
else
|
96
|
+
Hash.new
|
100
97
|
end
|
101
98
|
end
|
102
99
|
|
103
|
-
|
104
|
-
whitelist.include?(gem_name) || !safe
|
105
|
-
end
|
106
|
-
|
107
|
-
def whitelist
|
108
|
-
@whitelist ||= Array[config['whitelist']].flatten
|
109
|
-
end
|
110
|
-
|
111
|
-
# Internal: Setup the plugin search path
|
100
|
+
# The list of collections to render.
|
112
101
|
#
|
113
|
-
#
|
114
|
-
def
|
115
|
-
|
116
|
-
[File.join(source, config['plugins'])]
|
117
|
-
else
|
118
|
-
Array(config['plugins']).map { |d| File.expand_path(d) }
|
119
|
-
end
|
102
|
+
# The array of collection labels to render.
|
103
|
+
def to_render
|
104
|
+
@to_render ||= (config['render'] || Array.new)
|
120
105
|
end
|
121
106
|
|
122
107
|
# Read Site data from disk and load it into internal data structures.
|
@@ -126,6 +111,7 @@ module Jekyll
|
|
126
111
|
self.layouts = LayoutReader.new(self).read
|
127
112
|
read_directories
|
128
113
|
read_data(config['data_source'])
|
114
|
+
read_collections
|
129
115
|
end
|
130
116
|
|
131
117
|
# Recursively traverse directories to find posts, pages and static files
|
@@ -151,7 +137,7 @@ module Jekyll
|
|
151
137
|
read_directories(f_rel) unless dest.sub(/\/$/, '') == f_abs
|
152
138
|
elsif has_yaml_header?(f_abs)
|
153
139
|
page = Page.new(self, source, dir, f)
|
154
|
-
pages << page if
|
140
|
+
pages << page if publisher.publish?(page)
|
155
141
|
else
|
156
142
|
static_files << StaticFile.new(self, source, dir, f)
|
157
143
|
end
|
@@ -170,11 +156,9 @@ module Jekyll
|
|
170
156
|
posts = read_content(dir, '_posts', Post)
|
171
157
|
|
172
158
|
posts.each do |post|
|
173
|
-
if
|
174
|
-
aggregate_post_info(post)
|
175
|
-
end
|
159
|
+
aggregate_post_info(post) if publisher.publish?(post)
|
176
160
|
end
|
177
|
-
|
161
|
+
end
|
178
162
|
|
179
163
|
# Read all the files in <source>/<dir>/_drafts and create a new Post
|
180
164
|
# object with each one.
|
@@ -204,21 +188,27 @@ module Jekyll
|
|
204
188
|
#
|
205
189
|
# Returns nothing
|
206
190
|
def read_data(dir)
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
entries.delete_if { |e| File.directory?(File.join(base, e)) }
|
191
|
+
unless dir.to_s.eql?("_data")
|
192
|
+
Jekyll.logger.error "Error:", "Data source directories other than '_data' have been removed.\n" +
|
193
|
+
"Please move your YAML files to `_data` and remove the `data_source` key from your `_config.yml`."
|
194
|
+
end
|
212
195
|
|
213
|
-
|
214
|
-
|
215
|
-
next if File.symlink?(path) && safe
|
196
|
+
collections['data'] = Jekyll::Collection.new(self, "data")
|
197
|
+
collections['data'].read
|
216
198
|
|
217
|
-
|
218
|
-
|
199
|
+
collections['data'].docs.each do |doc|
|
200
|
+
key = sanitize_filename(doc.basename(".*"))
|
201
|
+
self.data[key] = doc.data
|
219
202
|
end
|
220
203
|
end
|
221
204
|
|
205
|
+
# Read in all collections specified in the configuration
|
206
|
+
#
|
207
|
+
# Returns nothing.
|
208
|
+
def read_collections
|
209
|
+
collections.each { |_, collection| collection.read }
|
210
|
+
end
|
211
|
+
|
222
212
|
# Run each of the Generators.
|
223
213
|
#
|
224
214
|
# Returns nothing.
|
@@ -234,13 +224,16 @@ module Jekyll
|
|
234
224
|
def render
|
235
225
|
relative_permalinks_deprecation_method
|
236
226
|
|
227
|
+
to_render.each do |label|
|
228
|
+
collections[label].docs.each do |document|
|
229
|
+
document.output = Jekyll::Renderer.new(self, document).run
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
237
233
|
payload = site_payload
|
238
234
|
[posts, pages].flatten.each do |page_or_post|
|
239
235
|
page_or_post.render(layouts, payload)
|
240
236
|
end
|
241
|
-
|
242
|
-
categories.values.map { |ps| ps.sort! { |a, b| b <=> a } }
|
243
|
-
tags.values.map { |ps| ps.sort! { |a, b| b <=> a } }
|
244
237
|
rescue Errno::ENOENT => e
|
245
238
|
# ignore missing layout dir
|
246
239
|
end
|
@@ -275,12 +268,20 @@ module Jekyll
|
|
275
268
|
def post_attr_hash(post_attr)
|
276
269
|
# Build a hash map based on the specified post attribute ( post attr =>
|
277
270
|
# array of posts ) then sort each array in reverse order.
|
278
|
-
hash = Hash.new { |
|
271
|
+
hash = Hash.new { |h, key| h[key] = [] }
|
279
272
|
posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
|
280
|
-
hash.values.
|
273
|
+
hash.values.each { |posts| posts.sort!.reverse! }
|
281
274
|
hash
|
282
275
|
end
|
283
276
|
|
277
|
+
def tags
|
278
|
+
post_attr_hash('tags')
|
279
|
+
end
|
280
|
+
|
281
|
+
def categories
|
282
|
+
post_attr_hash('categories')
|
283
|
+
end
|
284
|
+
|
284
285
|
# Prepare site data for site payload. The method maintains backward compatibility
|
285
286
|
# if the key 'data' is already used in _config.yml.
|
286
287
|
#
|
@@ -304,7 +305,8 @@ module Jekyll
|
|
304
305
|
# See Site#post_attr_hash for type info.
|
305
306
|
def site_payload
|
306
307
|
{"jekyll" => { "version" => Jekyll::VERSION },
|
307
|
-
"site"
|
308
|
+
"site" => Utils.deep_merge_hashes(config,
|
309
|
+
Utils.deep_merge_hashes(collections, {
|
308
310
|
"time" => time,
|
309
311
|
"posts" => posts.sort { |a, b| b <=> a },
|
310
312
|
"pages" => pages,
|
@@ -312,7 +314,9 @@ module Jekyll
|
|
312
314
|
"html_pages" => pages.reject { |page| !page.html? },
|
313
315
|
"categories" => post_attr_hash('categories'),
|
314
316
|
"tags" => post_attr_hash('tags'),
|
315
|
-
"data" => site_data
|
317
|
+
"data" => site_data
|
318
|
+
}))
|
319
|
+
}
|
316
320
|
end
|
317
321
|
|
318
322
|
# Filter out any files/directories that are hidden or backup files (start
|
@@ -364,7 +368,7 @@ module Jekyll
|
|
364
368
|
# Returns the list of entries to process
|
365
369
|
def get_entries(dir, subfolder)
|
366
370
|
base = File.join(source, dir, subfolder)
|
367
|
-
return [] unless File.
|
371
|
+
return [] unless File.exist?(base)
|
368
372
|
entries = Dir.chdir(base) { filter_entries(Dir['**/*'], base) }
|
369
373
|
entries.delete_if { |e| File.directory?(File.join(base, e)) }
|
370
374
|
end
|
@@ -376,8 +380,6 @@ module Jekyll
|
|
376
380
|
# Returns nothing
|
377
381
|
def aggregate_post_info(post)
|
378
382
|
posts << post
|
379
|
-
post.categories.each { |c| categories[c] << post }
|
380
|
-
post.tags.each { |c| tags[c] << post }
|
381
383
|
end
|
382
384
|
|
383
385
|
def relative_permalinks_deprecation_method
|
@@ -392,8 +394,18 @@ module Jekyll
|
|
392
394
|
end
|
393
395
|
end
|
394
396
|
|
397
|
+
def documents
|
398
|
+
collections.reduce(Set.new) do |docs, (label, coll)|
|
399
|
+
if to_render.include?(label)
|
400
|
+
docs.merge(coll.docs)
|
401
|
+
else
|
402
|
+
docs
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
395
407
|
def each_site_file
|
396
|
-
%w(posts pages static_files).each do |type|
|
408
|
+
%w(posts pages static_files documents).each do |type|
|
397
409
|
send(type).each do |item|
|
398
410
|
yield item
|
399
411
|
end
|
@@ -407,7 +419,7 @@ module Jekyll
|
|
407
419
|
end
|
408
420
|
|
409
421
|
def has_yaml_header?(file)
|
410
|
-
|
422
|
+
!!(File.open(file).read =~ /\A---\r?\n/)
|
411
423
|
end
|
412
424
|
|
413
425
|
def limit_posts!
|
@@ -424,5 +436,9 @@ module Jekyll
|
|
424
436
|
name.gsub!(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2')
|
425
437
|
name.gsub(/\s+/, '_')
|
426
438
|
end
|
439
|
+
|
440
|
+
def publisher
|
441
|
+
@publisher ||= Publisher.new(self)
|
442
|
+
end
|
427
443
|
end
|
428
444
|
end
|
@@ -41,14 +41,15 @@ eos
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def render(context)
|
44
|
+
code = super.to_s.strip
|
44
45
|
case context.registers[:site].highlighter
|
45
46
|
when 'pygments'
|
46
|
-
render_pygments(context,
|
47
|
+
render_pygments(context, code)
|
47
48
|
when 'rouge'
|
48
|
-
render_rouge(context,
|
49
|
+
render_rouge(context, code)
|
49
50
|
else
|
50
|
-
render_codehighlighter(context,
|
51
|
-
end
|
51
|
+
render_codehighlighter(context, code)
|
52
|
+
end.strip
|
52
53
|
end
|
53
54
|
|
54
55
|
def render_pygments(context, code)
|
@@ -106,8 +107,9 @@ eos
|
|
106
107
|
|
107
108
|
def add_code_tags(code, lang)
|
108
109
|
# Add nested <code> tags to code blocks
|
109
|
-
code = code.sub(/<pre
|
110
|
-
code = code.sub(
|
110
|
+
code = code.sub(/<pre>\n*/,'<pre><code class="' + lang.to_s.gsub("+", "-") + '">')
|
111
|
+
code = code.sub(/\n*<\/pre>/,"</code></pre>")
|
112
|
+
code.strip
|
111
113
|
end
|
112
114
|
|
113
115
|
end
|