jekyll 3.1.6 → 3.2.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/.rubocop.yml +200 -74
- data/README.markdown +13 -13
- data/lib/jekyll.rb +12 -8
- data/lib/jekyll/cleaner.rb +11 -8
- data/lib/jekyll/collection.rb +3 -3
- data/lib/jekyll/commands/build.rb +15 -12
- data/lib/jekyll/commands/clean.rb +15 -16
- data/lib/jekyll/commands/doctor.rb +7 -7
- data/lib/jekyll/commands/help.rb +4 -3
- data/lib/jekyll/commands/new.rb +49 -14
- data/lib/jekyll/commands/new_theme.rb +33 -0
- data/lib/jekyll/commands/serve.rb +33 -27
- data/lib/jekyll/commands/serve/servlet.rb +2 -3
- data/lib/jekyll/configuration.rb +10 -34
- data/lib/jekyll/converter.rb +6 -2
- data/lib/jekyll/converters/markdown.rb +1 -1
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -0
- data/lib/jekyll/convertible.rb +6 -9
- data/lib/jekyll/document.rb +5 -1
- data/lib/jekyll/drops/document_drop.rb +7 -33
- data/lib/jekyll/drops/drop.rb +2 -26
- data/lib/jekyll/drops/jekyll_drop.rb +0 -12
- data/lib/jekyll/drops/site_drop.rb +1 -1
- data/lib/jekyll/entry_filter.rb +61 -15
- data/lib/jekyll/errors.rb +6 -0
- data/lib/jekyll/excerpt.rb +5 -2
- data/lib/jekyll/filters.rb +49 -8
- data/lib/jekyll/frontmatter_defaults.rb +2 -2
- data/lib/jekyll/hooks.rb +1 -0
- data/lib/jekyll/layout.rb +16 -1
- data/lib/jekyll/page.rb +1 -0
- data/lib/jekyll/plugin.rb +1 -1
- data/lib/jekyll/plugin_manager.rb +5 -5
- data/lib/jekyll/publisher.rb +4 -4
- data/lib/jekyll/readers/data_reader.rb +3 -2
- data/lib/jekyll/readers/layout_reader.rb +19 -3
- data/lib/jekyll/readers/post_reader.rb +5 -1
- data/lib/jekyll/regenerator.rb +5 -3
- data/lib/jekyll/renderer.rb +4 -6
- data/lib/jekyll/site.rb +47 -18
- data/lib/jekyll/static_file.rb +5 -1
- data/lib/jekyll/tags/include.rb +33 -31
- data/lib/jekyll/tags/link.rb +26 -0
- data/lib/jekyll/tags/post_url.rb +18 -8
- data/lib/jekyll/theme.rb +56 -0
- data/lib/jekyll/theme_builder.rb +117 -0
- data/lib/jekyll/utils.rb +2 -14
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/_config.yml +8 -2
- data/lib/site_template/_includes/footer.html +3 -3
- data/lib/site_template/_includes/head.html +2 -2
- data/lib/site_template/_includes/header.html +3 -3
- data/lib/site_template/_layouts/default.html +3 -3
- data/lib/site_template/_layouts/page.html +1 -1
- data/lib/site_template/_layouts/post.html +1 -1
- data/lib/site_template/_sass/_base.scss +11 -17
- data/lib/site_template/index.html +1 -1
- data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
- data/lib/theme_template/Gemfile +2 -0
- data/lib/theme_template/LICENSE.txt.erb +21 -0
- data/lib/theme_template/README.md.erb +46 -0
- data/lib/theme_template/Rakefile.erb +74 -0
- data/lib/theme_template/example/_config.yml.erb +1 -0
- data/lib/theme_template/example/_post.md +13 -0
- data/lib/theme_template/example/index.html +14 -0
- data/lib/theme_template/example/style.scss +7 -0
- data/lib/theme_template/theme.gemspec.erb +22 -0
- metadata +34 -7
- data/lib/jekyll/drops/excerpt_drop.rb +0 -15
data/lib/jekyll/static_file.rb
CHANGED
@@ -80,7 +80,11 @@ module Jekyll
|
|
80
80
|
|
81
81
|
FileUtils.mkdir_p(File.dirname(dest_path))
|
82
82
|
FileUtils.rm(dest_path) if File.exist?(dest_path)
|
83
|
-
|
83
|
+
if @site.safe || Jekyll.env == "production"
|
84
|
+
FileUtils.cp(path, dest_path)
|
85
|
+
else
|
86
|
+
FileUtils.copy_entry(path, dest_path)
|
87
|
+
end
|
84
88
|
File.utime(@@mtimes[path], @@mtimes[path], dest_path)
|
85
89
|
|
86
90
|
true
|
data/lib/jekyll/tags/include.rb
CHANGED
@@ -12,8 +12,6 @@ module Jekyll
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class IncludeTag < Liquid::Tag
|
15
|
-
attr_reader :includes_dir
|
16
|
-
|
17
15
|
VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
18
16
|
VARIABLE_SYNTAX = /(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)(?<params>.*)/
|
19
17
|
|
@@ -98,20 +96,29 @@ eos
|
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
101
|
-
def
|
102
|
-
context.registers[:site].
|
99
|
+
def tag_includes_dirs(context)
|
100
|
+
context.registers[:site].includes_load_paths.freeze
|
101
|
+
end
|
102
|
+
|
103
|
+
def locate_include_file(context, file, safe)
|
104
|
+
includes_dirs = tag_includes_dirs(context)
|
105
|
+
includes_dirs.each do |dir|
|
106
|
+
path = File.join(dir, file)
|
107
|
+
return path if valid_include_file?(path, dir, safe)
|
108
|
+
end
|
109
|
+
raise IOError, "Could not locate the included file '#{file}' in any of #{includes_dirs}." \
|
110
|
+
" Ensure it exists in one of those directories and, if it is a symlink, " \
|
111
|
+
"does not point outside your site source."
|
103
112
|
end
|
104
113
|
|
105
114
|
def render(context)
|
106
115
|
site = context.registers[:site]
|
107
|
-
@includes_dir = tag_includes_dir(context)
|
108
|
-
dir = resolved_includes_dir(context)
|
109
116
|
|
110
117
|
file = render_variable(context) || @file
|
111
118
|
validate_file_name(file)
|
112
119
|
|
113
|
-
path =
|
114
|
-
|
120
|
+
path = locate_include_file(context, file, site.safe)
|
121
|
+
return unless path
|
115
122
|
|
116
123
|
# Add include to dependency tree
|
117
124
|
if context.registers[:page] && context.registers[:page].key?("path")
|
@@ -121,16 +128,16 @@ eos
|
|
121
128
|
)
|
122
129
|
end
|
123
130
|
|
124
|
-
begin
|
131
|
+
#begin
|
125
132
|
partial = load_cached_partial(path, context)
|
126
133
|
|
127
134
|
context.stack do
|
128
135
|
context['include'] = parse_params(context) if @params
|
129
136
|
partial.render!(context)
|
130
137
|
end
|
131
|
-
|
132
|
-
raise IncludeTagError.new e.message,
|
133
|
-
|
138
|
+
#rescue => e
|
139
|
+
#raise IncludeTagError.new e.message, path
|
140
|
+
#end
|
134
141
|
end
|
135
142
|
|
136
143
|
def load_cached_partial(path, context)
|
@@ -144,24 +151,18 @@ eos
|
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
|
-
def
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
def validate_path(path, dir, safe)
|
152
|
-
if safe && !realpath_prefixed_with?(path, dir)
|
153
|
-
raise IOError.new "The included file '#{path}' should exist and should not be a symlink"
|
154
|
-
elsif !File.exist?(path)
|
155
|
-
raise IOError.new "Included file '#{path_relative_to_source(dir, path)}' not found"
|
156
|
-
end
|
154
|
+
def valid_include_file?(path, dir, safe)
|
155
|
+
!(outside_site_source?(path, dir, safe) || !File.exist?(path))
|
157
156
|
end
|
158
157
|
|
159
|
-
def
|
160
|
-
|
158
|
+
def outside_site_source?(path, dir, safe)
|
159
|
+
safe && !realpath_prefixed_with?(path, dir)
|
161
160
|
end
|
162
161
|
|
163
162
|
def realpath_prefixed_with?(path, dir)
|
164
163
|
File.exist?(path) && File.realpath(path).start_with?(dir)
|
164
|
+
rescue
|
165
|
+
false
|
165
166
|
end
|
166
167
|
|
167
168
|
# This method allows to modify the file content by inheriting from the class.
|
@@ -171,16 +172,17 @@ eos
|
|
171
172
|
end
|
172
173
|
|
173
174
|
class IncludeRelativeTag < IncludeTag
|
174
|
-
def
|
175
|
-
|
175
|
+
def tag_includes_dirs(context)
|
176
|
+
Array(page_path(context)).freeze
|
176
177
|
end
|
177
178
|
|
178
179
|
def page_path(context)
|
179
|
-
context.registers[:page].nil?
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
180
|
+
if context.registers[:page].nil?
|
181
|
+
context.registers[:site].source
|
182
|
+
else
|
183
|
+
current_doc_dir = File.dirname(context.registers[:page]["path"])
|
184
|
+
context.registers[:site].in_source_dir current_doc_dir
|
185
|
+
end
|
184
186
|
end
|
185
187
|
end
|
186
188
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Tags
|
3
|
+
class Link < Liquid::Tag
|
4
|
+
TagName = 'link'
|
5
|
+
|
6
|
+
def initialize(tag_name, relative_path, tokens)
|
7
|
+
super
|
8
|
+
|
9
|
+
@relative_path = relative_path.strip
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(context)
|
13
|
+
site = context.registers[:site]
|
14
|
+
|
15
|
+
site.docs_to_write.each do |document|
|
16
|
+
return document.url if document.relative_path == @relative_path
|
17
|
+
end
|
18
|
+
|
19
|
+
raise ArgumentError, "Could not find document '#{@relative_path}' in tag '#{TagName}'.\n\n" \
|
20
|
+
"Make sure the document exists and the path is correct."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Liquid::Template.register_tag(Jekyll::Tags::Link::TagName, Jekyll::Tags::Link)
|
data/lib/jekyll/tags/post_url.rb
CHANGED
@@ -7,22 +7,30 @@ module Jekyll
|
|
7
7
|
|
8
8
|
def initialize(name)
|
9
9
|
@name = name
|
10
|
+
|
10
11
|
all, @path, @date, @slug = *name.sub(/^\//, "").match(MATCHER)
|
11
|
-
|
12
|
+
unless all
|
13
|
+
raise Jekyll::Errors::InvalidPostNameError,
|
14
|
+
"'#{name}' does not contain valid date and/or title."
|
15
|
+
end
|
12
16
|
|
13
17
|
@name_regex = /^#{path}#{date}-#{slug}\.[^.]+/
|
14
18
|
end
|
15
19
|
|
20
|
+
def post_date
|
21
|
+
@post_date ||= Utils.parse_date(date,
|
22
|
+
"\"#{date}\" does not contain valid date and/or title.")
|
23
|
+
end
|
24
|
+
|
16
25
|
def ==(other)
|
17
26
|
other.basename.match(@name_regex)
|
18
27
|
end
|
19
28
|
|
20
29
|
def deprecated_equality(other)
|
21
|
-
date = Utils.parse_date(name, "'#{name}' does not contain valid date and/or title.")
|
22
30
|
slug == post_slug(other) &&
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
post_date.year == other.date.year &&
|
32
|
+
post_date.month == other.date.month &&
|
33
|
+
post_date.day == other.date.day
|
26
34
|
end
|
27
35
|
|
28
36
|
private
|
@@ -47,11 +55,13 @@ module Jekyll
|
|
47
55
|
@orig_post = post.strip
|
48
56
|
begin
|
49
57
|
@post = PostComparer.new(@orig_post)
|
50
|
-
rescue
|
51
|
-
raise
|
58
|
+
rescue => e
|
59
|
+
raise Jekyll::Errors::PostURLError, <<-eos
|
52
60
|
Could not parse name of post "#{@orig_post}" in tag 'post_url'.
|
53
61
|
|
54
62
|
Make sure the post exists and the name is correct.
|
63
|
+
|
64
|
+
#{e.class}: #{e.message}
|
55
65
|
eos
|
56
66
|
end
|
57
67
|
end
|
@@ -75,7 +85,7 @@ eos
|
|
75
85
|
return p.url
|
76
86
|
end
|
77
87
|
|
78
|
-
raise
|
88
|
+
raise Jekyll::Errors::PostURLError, <<-eos
|
79
89
|
Could not find post "#{@orig_post}" in tag 'post_url'.
|
80
90
|
|
81
91
|
Make sure the post exists and the name is correct.
|
data/lib/jekyll/theme.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class Theme
|
3
|
+
extend Forwardable
|
4
|
+
attr_reader :name
|
5
|
+
def_delegator :gemspec, :version, :version
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name.downcase.strip
|
9
|
+
configure_sass
|
10
|
+
end
|
11
|
+
|
12
|
+
def root
|
13
|
+
@root ||= gemspec.full_gem_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def includes_path
|
17
|
+
path_for :includes
|
18
|
+
end
|
19
|
+
|
20
|
+
def layouts_path
|
21
|
+
path_for :layouts
|
22
|
+
end
|
23
|
+
|
24
|
+
def sass_path
|
25
|
+
path_for :sass
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure_sass
|
29
|
+
return unless sass_path
|
30
|
+
require 'sass'
|
31
|
+
Sass.load_paths << sass_path
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def path_for(folder)
|
37
|
+
resolved_dir = realpath_for(folder)
|
38
|
+
return unless resolved_dir
|
39
|
+
|
40
|
+
path = Jekyll.sanitized_path(root, resolved_dir)
|
41
|
+
path if Dir.exists?(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def realpath_for(folder)
|
45
|
+
File.realpath(Jekyll.sanitized_path(root, "_#{folder}"))
|
46
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def gemspec
|
51
|
+
@gemspec ||= Gem::Specification.find_by_name(name)
|
52
|
+
rescue Gem::LoadError
|
53
|
+
raise Jekyll::Errors::MissingDependencyException, "The #{name} theme could not be found."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class Jekyll::ThemeBuilder
|
2
|
+
SCAFFOLD_DIRECTORIES = %w(
|
3
|
+
_layouts _includes _sass example example/_posts
|
4
|
+
).freeze
|
5
|
+
|
6
|
+
attr_reader :name, :path
|
7
|
+
|
8
|
+
def initialize(theme_name)
|
9
|
+
@name = theme_name.to_s.tr(" ", "_").gsub(/_+/, "_")
|
10
|
+
@path = Pathname.new(File.expand_path(name, Dir.pwd))
|
11
|
+
end
|
12
|
+
|
13
|
+
def create!
|
14
|
+
create_directories
|
15
|
+
create_gemspec
|
16
|
+
create_accessories
|
17
|
+
create_example_site
|
18
|
+
initialize_git_repo
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def root
|
24
|
+
@root ||= Pathname.new(File.expand_path("../", __dir__))
|
25
|
+
end
|
26
|
+
|
27
|
+
def template_file(filename)
|
28
|
+
[
|
29
|
+
root.join("theme_template", "#{filename}.erb"),
|
30
|
+
root.join("theme_template", filename.to_s)
|
31
|
+
].find(&:exist?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def template(filename)
|
35
|
+
erb.render(template_file(filename).read)
|
36
|
+
end
|
37
|
+
|
38
|
+
def erb
|
39
|
+
@erb ||= ERBRenderer.new(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def mkdir_p(directories)
|
43
|
+
Array(directories).each do |directory|
|
44
|
+
full_path = path.join(directory)
|
45
|
+
Jekyll.logger.info "create", full_path.to_s
|
46
|
+
FileUtils.mkdir_p(full_path)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_file(filename, contents)
|
51
|
+
full_path = path.join(filename)
|
52
|
+
Jekyll.logger.info "create", full_path.to_s
|
53
|
+
File.write(full_path, contents)
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_directories
|
57
|
+
mkdir_p(SCAFFOLD_DIRECTORIES)
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_gemspec
|
61
|
+
write_file("Gemfile", template("Gemfile"))
|
62
|
+
write_file("#{name}.gemspec", template("theme.gemspec"))
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_accessories
|
66
|
+
%w(README.md Rakefile CODE_OF_CONDUCT.md LICENSE.txt).each do |filename|
|
67
|
+
write_file(filename, template(filename))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_example_site
|
72
|
+
%w(example/_config.yml example/index.html example/style.scss).each do |filename|
|
73
|
+
write_file(filename, template(filename))
|
74
|
+
end
|
75
|
+
write_file(
|
76
|
+
"example/_posts/#{Time.now.strftime("%Y-%m-%d")}-my-example-post.md",
|
77
|
+
template("example/_post.md")
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize_git_repo
|
82
|
+
Jekyll.logger.info "initialize", path.join(".git").to_s
|
83
|
+
Dir.chdir(path.to_s) { `git init` }
|
84
|
+
end
|
85
|
+
|
86
|
+
def user_name
|
87
|
+
@user_name ||= `git config user.name`.chomp
|
88
|
+
end
|
89
|
+
|
90
|
+
def user_email
|
91
|
+
@user_email ||= `git config user.email`.chomp
|
92
|
+
end
|
93
|
+
|
94
|
+
class ERBRenderer
|
95
|
+
extend Forwardable
|
96
|
+
|
97
|
+
def_delegator :@theme_builder, :name, :theme_name
|
98
|
+
def_delegator :@theme_builder, :user_name, :user_name
|
99
|
+
def_delegator :@theme_builder, :user_email, :user_email
|
100
|
+
|
101
|
+
def initialize(theme_builder)
|
102
|
+
@theme_builder = theme_builder
|
103
|
+
end
|
104
|
+
|
105
|
+
def jekyll_pessimistic_version
|
106
|
+
Jekyll::VERSION.split(".").take(2).join(".")
|
107
|
+
end
|
108
|
+
|
109
|
+
def theme_directories
|
110
|
+
SCAFFOLD_DIRECTORIES
|
111
|
+
end
|
112
|
+
|
113
|
+
def render(contents)
|
114
|
+
ERB.new(contents).result binding
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/jekyll/utils.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
module Jekyll
|
2
3
|
module Utils
|
3
4
|
extend self
|
@@ -53,10 +54,6 @@ module Jekyll
|
|
53
54
|
target.default_proc = overwrite.default_proc
|
54
55
|
end
|
55
56
|
|
56
|
-
target.each do |key, val|
|
57
|
-
target[key] = val.dup if val.frozen? && duplicable?(val)
|
58
|
-
end
|
59
|
-
|
60
57
|
target
|
61
58
|
end
|
62
59
|
|
@@ -64,15 +61,6 @@ module Jekyll
|
|
64
61
|
value.is_a?(Hash) || value.is_a?(Drops::Drop)
|
65
62
|
end
|
66
63
|
|
67
|
-
def duplicable?(obj)
|
68
|
-
case obj
|
69
|
-
when nil, false, true, Symbol, Numeric
|
70
|
-
false
|
71
|
-
else
|
72
|
-
true
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
64
|
# Read array from the supplied hash favouring the singular key
|
77
65
|
# and then the plural key, and handling any nil entries.
|
78
66
|
#
|
@@ -139,7 +127,7 @@ module Jekyll
|
|
139
127
|
def parse_date(input, msg = "Input could not be parsed.")
|
140
128
|
Time.parse(input).localtime
|
141
129
|
rescue ArgumentError
|
142
|
-
raise Errors::
|
130
|
+
raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}"
|
143
131
|
end
|
144
132
|
|
145
133
|
# Determines whether a given file has
|
data/lib/jekyll/version.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
# Welcome to Jekyll!
|
2
2
|
#
|
3
3
|
# This config file is meant for settings that affect your whole blog, values
|
4
|
-
# which you are expected to set up once and rarely
|
4
|
+
# which you are expected to set up once and rarely edit after that. If you find
|
5
|
+
# yourself editing these this file very often, consider using Jekyll's data files
|
6
|
+
# feature for the data you need to update frequently.
|
5
7
|
# For technical reasons, this file is *NOT* reloaded automatically when you use
|
6
8
|
# 'jekyll serve'. If you change this file, please restart the server process.
|
7
9
|
|
8
10
|
# Site settings
|
11
|
+
# These are used to personalize your new site. If you look in the HTML files,
|
12
|
+
# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
|
13
|
+
# You can create any custom variable you would like, and they will be accessible
|
14
|
+
# in the templates via {{ site.myvariable }}.
|
9
15
|
title: Your awesome title
|
10
16
|
email: your-email@domain.com
|
11
17
|
description: > # this means to ignore newlines until "baseurl:"
|
@@ -13,7 +19,7 @@ description: > # this means to ignore newlines until "baseurl:"
|
|
13
19
|
line in _config.yml. It will appear in your document head meta (for
|
14
20
|
Google search results) and in your feed.xml site description.
|
15
21
|
baseurl: "" # the subpath of your site, e.g. /blog
|
16
|
-
url: "http://
|
22
|
+
url: "http://example.com" # the base hostname & protocol for your site
|
17
23
|
twitter_username: jekyllrb
|
18
24
|
github_username: jekyll
|
19
25
|
|