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
data/lib/jekyll/configuration.rb
CHANGED
@@ -13,6 +13,7 @@ module Jekyll
|
|
13
13
|
'data_source' => '_data',
|
14
14
|
'keep_files' => ['.git','.svn'],
|
15
15
|
'gems' => [],
|
16
|
+
'collections' => nil,
|
16
17
|
|
17
18
|
'timezone' => nil, # use the local timezone
|
18
19
|
|
@@ -24,6 +25,7 @@ module Jekyll
|
|
24
25
|
'limit_posts' => 0,
|
25
26
|
'lsi' => false,
|
26
27
|
'future' => true, # remove and make true just default
|
28
|
+
'unpublished' => false,
|
27
29
|
|
28
30
|
'relative_permalinks' => true, # backwards-compatibility with < 1.0
|
29
31
|
# will be set to false once 2.0 hits
|
@@ -16,7 +16,7 @@ module Jekyll
|
|
16
16
|
def block_code(code, lang)
|
17
17
|
require 'pygments'
|
18
18
|
lang = lang && lang.split.first || "text"
|
19
|
-
|
19
|
+
add_code_tags(
|
20
20
|
Pygments.highlight(code, :lexer => lang, :options => { :encoding => 'utf-8' }),
|
21
21
|
lang
|
22
22
|
)
|
@@ -34,21 +34,11 @@ module Jekyll
|
|
34
34
|
|
35
35
|
def block_code(code, lang)
|
36
36
|
lang = lang && lang.split.first || "text"
|
37
|
-
|
37
|
+
add_code_tags(code_wrap(code), lang)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
module WithRouge
|
42
|
-
require 'rouge'
|
43
|
-
require 'rouge/plugins/redcarpet'
|
44
|
-
|
45
|
-
if Rouge.version < '1.3.0'
|
46
|
-
abort "Please install Rouge 1.3.0 or greater and try running Jekyll again."
|
47
|
-
end
|
48
|
-
|
49
|
-
include Rouge::Plugins::Redcarpet
|
50
|
-
include CommonMethods
|
51
|
-
|
52
42
|
def block_code(code, lang)
|
53
43
|
code = "<pre>#{super}</pre>"
|
54
44
|
|
@@ -77,6 +67,15 @@ module Jekyll
|
|
77
67
|
end
|
78
68
|
when 'rouge'
|
79
69
|
Class.new(Redcarpet::Render::HTML) do
|
70
|
+
require 'rouge'
|
71
|
+
require 'rouge/plugins/redcarpet'
|
72
|
+
|
73
|
+
if Rouge.version < '1.3.0'
|
74
|
+
abort "Please install Rouge 1.3.0 or greater and try running Jekyll again."
|
75
|
+
end
|
76
|
+
|
77
|
+
include Rouge::Plugins::Redcarpet
|
78
|
+
include CommonMethods
|
80
79
|
include WithRouge
|
81
80
|
end
|
82
81
|
else
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -43,7 +43,7 @@ module Jekyll
|
|
43
43
|
begin
|
44
44
|
self.content = File.read(File.join(base, name),
|
45
45
|
merged_file_read_opts(opts))
|
46
|
-
if content =~ /\A(---\s*\n.*?\n?)^(
|
46
|
+
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
47
47
|
self.content = $POSTMATCH
|
48
48
|
self.data = SafeYAML.load($1)
|
49
49
|
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class Document
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_reader :path, :site
|
6
|
+
attr_accessor :content, :collection, :output
|
7
|
+
|
8
|
+
# Create a new Document.
|
9
|
+
#
|
10
|
+
# site - the Jekyll::Site instance to which this Document belongs
|
11
|
+
# path - the path to the file
|
12
|
+
#
|
13
|
+
# Returns nothing.
|
14
|
+
def initialize(path, relations)
|
15
|
+
@site = relations[:site]
|
16
|
+
@path = path
|
17
|
+
@collection = relations[:collection]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Fetch the Document's data.
|
21
|
+
#
|
22
|
+
# Returns a Hash containing the data. An empty hash is returned if
|
23
|
+
# no data was read.
|
24
|
+
def data
|
25
|
+
@data ||= Hash.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# The path to the document, relative to the site source.
|
29
|
+
#
|
30
|
+
# Returns a String path which represents the relative path
|
31
|
+
# from the site source to this document
|
32
|
+
def relative_path
|
33
|
+
Pathname.new(path).relative_path_from(Pathname.new(site.source)).to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
# The base filename of the document.
|
37
|
+
#
|
38
|
+
# suffix - (optional) the suffix to be removed from the end of the filename
|
39
|
+
#
|
40
|
+
# Returns the base filename of the document.
|
41
|
+
def basename(suffix = "")
|
42
|
+
File.basename(path, suffix)
|
43
|
+
end
|
44
|
+
|
45
|
+
# The extension name of the document.
|
46
|
+
#
|
47
|
+
# Returns the extension name of the document.
|
48
|
+
def extname
|
49
|
+
File.extname(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Produces a "cleaned" relative path.
|
53
|
+
# The "cleaned" relative path is the relative path without the extname
|
54
|
+
# and with the collection's directory removed as well.
|
55
|
+
# This method is useful when building the URL of the document.
|
56
|
+
#
|
57
|
+
# Examples:
|
58
|
+
# When relative_path is "_methods/site/generate.md":
|
59
|
+
# cleaned_relative_path
|
60
|
+
# # => "/site/generate"
|
61
|
+
#
|
62
|
+
# Returns the cleaned relative path of the document.
|
63
|
+
def cleaned_relative_path
|
64
|
+
relative_path[0 .. -extname.length - 1].sub(collection.relative_directory, "")
|
65
|
+
end
|
66
|
+
|
67
|
+
# Determine whether the document is a YAML file.
|
68
|
+
#
|
69
|
+
# Returns true if the extname is either .yml or .yaml, false otherwise.
|
70
|
+
def yaml_file?
|
71
|
+
%w[.yaml .yml].include?(extname)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Determine whether the document is an asset file.
|
75
|
+
# Asset files include CoffeeScript files and Sass/SCSS files.
|
76
|
+
#
|
77
|
+
# Returns true if the extname belongs to the set of extensions
|
78
|
+
# that asset files use.
|
79
|
+
def asset_file?
|
80
|
+
%w[.sass .scss .coffee].include?(extname)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Determine whether the file should be rendered with Liquid.
|
84
|
+
#
|
85
|
+
# Returns false if the document is either an asset file or a yaml file,
|
86
|
+
# true otherwise.
|
87
|
+
def render_with_liquid?
|
88
|
+
!(asset_file? || yaml_file?)
|
89
|
+
end
|
90
|
+
|
91
|
+
# The URL template where the document would be accessible.
|
92
|
+
#
|
93
|
+
# Returns the URL template for the document.
|
94
|
+
def url_template
|
95
|
+
"/:collection/:path:output_ext"
|
96
|
+
end
|
97
|
+
|
98
|
+
# Construct a Hash of key-value pairs which contain a mapping between
|
99
|
+
# a key in the URL template and the corresponding value for this document.
|
100
|
+
#
|
101
|
+
# Returns the Hash of key-value pairs for replacement in the URL.
|
102
|
+
def url_placeholders
|
103
|
+
{
|
104
|
+
collection: collection.label,
|
105
|
+
path: cleaned_relative_path,
|
106
|
+
output_ext: Jekyll::Renderer.new(site, self).output_ext
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# The permalink for this Document.
|
111
|
+
# Permalink is set via the data Hash.
|
112
|
+
#
|
113
|
+
# Returns the permalink or nil if no permalink was set in the data.
|
114
|
+
def permalink
|
115
|
+
data && data['permalink']
|
116
|
+
end
|
117
|
+
|
118
|
+
# The computed URL for the document. See `Jekyll::URL#to_s` for more details.
|
119
|
+
#
|
120
|
+
# Returns the computed URL for the document.
|
121
|
+
def url
|
122
|
+
@url ||= URL.new({
|
123
|
+
template: url_template,
|
124
|
+
placeholders: url_placeholders,
|
125
|
+
permalink: permalink
|
126
|
+
}).to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
# The full path to the output file.
|
130
|
+
#
|
131
|
+
# base_directory - the base path of the output directory
|
132
|
+
#
|
133
|
+
# Returns the full path to the output file of this document.
|
134
|
+
def destination(base_directory)
|
135
|
+
path = Jekyll.sanitized_path(base_directory, url)
|
136
|
+
path = File.join(path, "index.html") if url =~ /\/$/
|
137
|
+
path
|
138
|
+
end
|
139
|
+
|
140
|
+
# Write the generated Document file to the destination directory.
|
141
|
+
#
|
142
|
+
# dest - The String path to the destination dir.
|
143
|
+
#
|
144
|
+
# Returns nothing.
|
145
|
+
def write(dest)
|
146
|
+
path = destination(dest)
|
147
|
+
FileUtils.mkdir_p(File.dirname(path))
|
148
|
+
File.open(path, 'wb') do |f|
|
149
|
+
f.write(output)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns merged option hash for File.read of self.site (if exists)
|
154
|
+
# and a given param
|
155
|
+
#
|
156
|
+
# opts - override options
|
157
|
+
#
|
158
|
+
# Return the file read options hash.
|
159
|
+
def merged_file_read_opts(opts)
|
160
|
+
site ? site.file_read_opts.merge(opts) : opts
|
161
|
+
end
|
162
|
+
|
163
|
+
# Whether the file is published or not, as indicated in YAML front-matter
|
164
|
+
#
|
165
|
+
# Returns true if the 'published' key is specified in the YAML front-matter and not `false`.
|
166
|
+
def published?
|
167
|
+
!(data.has_key?('published') && data['published'] == false)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Read in the file and assign the content and data based on the file contents.
|
171
|
+
#
|
172
|
+
# Returns nothing.
|
173
|
+
def read(opts = {})
|
174
|
+
if yaml_file?
|
175
|
+
@data = SafeYAML.load_file(path)
|
176
|
+
else
|
177
|
+
begin
|
178
|
+
@content = File.read(path, merged_file_read_opts(opts))
|
179
|
+
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
180
|
+
@content = $POSTMATCH
|
181
|
+
@data = SafeYAML.load($1)
|
182
|
+
end
|
183
|
+
rescue SyntaxError => e
|
184
|
+
puts "YAML Exception reading #{path}: #{e.message}"
|
185
|
+
rescue Exception => e
|
186
|
+
puts "Error reading file #{path}: #{e.message}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Create a Liquid-understandable version of this Document.
|
192
|
+
#
|
193
|
+
# Returns a Hash representing this Document's data.
|
194
|
+
def to_liquid
|
195
|
+
Utils.deep_merge_hashes data, {
|
196
|
+
"content" => content,
|
197
|
+
"path" => path,
|
198
|
+
"relative_path" => relative_path,
|
199
|
+
"url" => url
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
# The inspect string for this document.
|
204
|
+
# Includes the relative path and the collection label.
|
205
|
+
#
|
206
|
+
# Returns the inspect string for this document.
|
207
|
+
def inspect
|
208
|
+
"#<Jekyll::Document #{relative_path} collection=#{collection.label}>"
|
209
|
+
end
|
210
|
+
|
211
|
+
# The string representation for this document.
|
212
|
+
#
|
213
|
+
# Returns the content of the document
|
214
|
+
def to_s
|
215
|
+
output || content
|
216
|
+
end
|
217
|
+
|
218
|
+
# Compare this document against another document.
|
219
|
+
# Comparison is a comparison between the 2 paths of the documents.
|
220
|
+
#
|
221
|
+
# Returns -1, 0, +1 or nil depending on whether this doc's path is less than,
|
222
|
+
# equal or greater than the other doc's path. See String#<=> for more details.
|
223
|
+
def <=>(anotherDocument)
|
224
|
+
path <=> anotherDocument.path
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
data/lib/jekyll/entry_filter.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Jekyll
|
2
2
|
class EntryFilter
|
3
|
+
SPECIAL_LEADING_CHARACTERS = ['.', '_', '#'].freeze
|
4
|
+
|
3
5
|
attr_reader :site
|
4
6
|
|
5
7
|
def initialize(site, base_directory = nil)
|
@@ -35,7 +37,8 @@ module Jekyll
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def special?(entry)
|
38
|
-
|
40
|
+
SPECIAL_LEADING_CHARACTERS.include?(entry[0..0]) ||
|
41
|
+
SPECIAL_LEADING_CHARACTERS.include?(File.basename(entry)[0..0])
|
39
42
|
end
|
40
43
|
|
41
44
|
def backup?(entry)
|
data/lib/jekyll/layout_reader.rb
CHANGED
data/lib/jekyll/page.rb
CHANGED
@@ -135,7 +135,7 @@ module Jekyll
|
|
135
135
|
#
|
136
136
|
# Returns the destination file path String.
|
137
137
|
def destination(dest)
|
138
|
-
path = Jekyll.sanitized_path(dest, url)
|
138
|
+
path = Jekyll.sanitized_path(dest, URL.unescape_path(url))
|
139
139
|
path = File.join(path, "index.html") if url =~ /\/$/
|
140
140
|
path
|
141
141
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class PluginManager
|
3
|
+
attr_reader :site
|
4
|
+
|
5
|
+
# Create an instance of this class.
|
6
|
+
#
|
7
|
+
# site - the instance of Jekyll::Site we're concerned with
|
8
|
+
#
|
9
|
+
# Returns nothing
|
10
|
+
def initialize(site)
|
11
|
+
@site = site
|
12
|
+
end
|
13
|
+
|
14
|
+
# Require all the plugins which are allowed.
|
15
|
+
#
|
16
|
+
# Returns nothing
|
17
|
+
def conscientious_require
|
18
|
+
require_plugin_files
|
19
|
+
require_gems
|
20
|
+
end
|
21
|
+
|
22
|
+
# Require each of the gem plugins specified.
|
23
|
+
#
|
24
|
+
# Returns nothing.
|
25
|
+
def require_gems
|
26
|
+
site.gems.each do |gem|
|
27
|
+
if plugin_allowed?(gem)
|
28
|
+
require gem
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check whether a gem plugin is allowed to be used during this build.
|
34
|
+
#
|
35
|
+
# gem_name - the name of the gem
|
36
|
+
#
|
37
|
+
# Returns true if the gem name is in the whitelist or if the site is not
|
38
|
+
# in safe mode.
|
39
|
+
def plugin_allowed?(gem_name)
|
40
|
+
!site.safe || whitelist.include?(gem_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Build an array of allowed plugin gem names.
|
44
|
+
#
|
45
|
+
# Returns an array of strings, each string being the name of a gem name
|
46
|
+
# that is allowed to be used.
|
47
|
+
def whitelist
|
48
|
+
@whitelist ||= Array[site.config['whitelist']].flatten
|
49
|
+
end
|
50
|
+
|
51
|
+
# Require all .rb files if safe mode is off
|
52
|
+
#
|
53
|
+
# Returns nothing.
|
54
|
+
def require_plugin_files
|
55
|
+
unless site.safe
|
56
|
+
plugins_path.each do |plugins|
|
57
|
+
Dir[File.join(plugins, "**", "*.rb")].sort.each do |f|
|
58
|
+
require f
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Public: Setup the plugin search path
|
65
|
+
#
|
66
|
+
# Returns an Array of plugin search paths
|
67
|
+
def plugins_path
|
68
|
+
if (site.config['plugins'] == Jekyll::Configuration::DEFAULTS['plugins'])
|
69
|
+
[Jekyll.sanitized_path(site.source, site.config['plugins'])]
|
70
|
+
else
|
71
|
+
Array(site.config['plugins']).map { |d| File.expand_path(d) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/jekyll/post.rb
CHANGED
@@ -208,10 +208,10 @@ module Jekyll
|
|
208
208
|
:year => date.strftime("%Y"),
|
209
209
|
:month => date.strftime("%m"),
|
210
210
|
:day => date.strftime("%d"),
|
211
|
-
:title =>
|
211
|
+
:title => slug,
|
212
212
|
:i_day => date.strftime("%d").to_i.to_s,
|
213
213
|
:i_month => date.strftime("%m").to_i.to_s,
|
214
|
-
:categories => (categories || []).map { |c|
|
214
|
+
:categories => (categories || []).map { |c| c.to_s }.join('/'),
|
215
215
|
:short_month => date.strftime("%b"),
|
216
216
|
:y_day => date.strftime("%j"),
|
217
217
|
:output_ext => output_ext
|
@@ -260,7 +260,7 @@ module Jekyll
|
|
260
260
|
# Returns destination file path String.
|
261
261
|
def destination(dest)
|
262
262
|
# The url needs to be unescaped in order to preserve the correct filename
|
263
|
-
path = Jekyll.sanitized_path(dest,
|
263
|
+
path = Jekyll.sanitized_path(dest, URL.unescape_path(url))
|
264
264
|
path = File.join(path, "index.html") if path[/\.html$/].nil?
|
265
265
|
path
|
266
266
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class Publisher
|
3
|
+
def initialize(site)
|
4
|
+
@site = site
|
5
|
+
end
|
6
|
+
|
7
|
+
def publish?(thing)
|
8
|
+
can_be_published?(thing) && !hidden_in_the_future?(thing)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def can_be_published?(thing)
|
14
|
+
thing.data.fetch('published', true) || @site.unpublished
|
15
|
+
end
|
16
|
+
|
17
|
+
def hidden_in_the_future?(thing)
|
18
|
+
thing.is_a?(Post) && !@site.future && thing.date > @site.time
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|