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.

Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +200 -74
  3. data/README.markdown +13 -13
  4. data/lib/jekyll.rb +12 -8
  5. data/lib/jekyll/cleaner.rb +11 -8
  6. data/lib/jekyll/collection.rb +3 -3
  7. data/lib/jekyll/commands/build.rb +15 -12
  8. data/lib/jekyll/commands/clean.rb +15 -16
  9. data/lib/jekyll/commands/doctor.rb +7 -7
  10. data/lib/jekyll/commands/help.rb +4 -3
  11. data/lib/jekyll/commands/new.rb +49 -14
  12. data/lib/jekyll/commands/new_theme.rb +33 -0
  13. data/lib/jekyll/commands/serve.rb +33 -27
  14. data/lib/jekyll/commands/serve/servlet.rb +2 -3
  15. data/lib/jekyll/configuration.rb +10 -34
  16. data/lib/jekyll/converter.rb +6 -2
  17. data/lib/jekyll/converters/markdown.rb +1 -1
  18. data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -0
  19. data/lib/jekyll/convertible.rb +6 -9
  20. data/lib/jekyll/document.rb +5 -1
  21. data/lib/jekyll/drops/document_drop.rb +7 -33
  22. data/lib/jekyll/drops/drop.rb +2 -26
  23. data/lib/jekyll/drops/jekyll_drop.rb +0 -12
  24. data/lib/jekyll/drops/site_drop.rb +1 -1
  25. data/lib/jekyll/entry_filter.rb +61 -15
  26. data/lib/jekyll/errors.rb +6 -0
  27. data/lib/jekyll/excerpt.rb +5 -2
  28. data/lib/jekyll/filters.rb +49 -8
  29. data/lib/jekyll/frontmatter_defaults.rb +2 -2
  30. data/lib/jekyll/hooks.rb +1 -0
  31. data/lib/jekyll/layout.rb +16 -1
  32. data/lib/jekyll/page.rb +1 -0
  33. data/lib/jekyll/plugin.rb +1 -1
  34. data/lib/jekyll/plugin_manager.rb +5 -5
  35. data/lib/jekyll/publisher.rb +4 -4
  36. data/lib/jekyll/readers/data_reader.rb +3 -2
  37. data/lib/jekyll/readers/layout_reader.rb +19 -3
  38. data/lib/jekyll/readers/post_reader.rb +5 -1
  39. data/lib/jekyll/regenerator.rb +5 -3
  40. data/lib/jekyll/renderer.rb +4 -6
  41. data/lib/jekyll/site.rb +47 -18
  42. data/lib/jekyll/static_file.rb +5 -1
  43. data/lib/jekyll/tags/include.rb +33 -31
  44. data/lib/jekyll/tags/link.rb +26 -0
  45. data/lib/jekyll/tags/post_url.rb +18 -8
  46. data/lib/jekyll/theme.rb +56 -0
  47. data/lib/jekyll/theme_builder.rb +117 -0
  48. data/lib/jekyll/utils.rb +2 -14
  49. data/lib/jekyll/version.rb +1 -1
  50. data/lib/site_template/_config.yml +8 -2
  51. data/lib/site_template/_includes/footer.html +3 -3
  52. data/lib/site_template/_includes/head.html +2 -2
  53. data/lib/site_template/_includes/header.html +3 -3
  54. data/lib/site_template/_layouts/default.html +3 -3
  55. data/lib/site_template/_layouts/page.html +1 -1
  56. data/lib/site_template/_layouts/post.html +1 -1
  57. data/lib/site_template/_sass/_base.scss +11 -17
  58. data/lib/site_template/index.html +1 -1
  59. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
  60. data/lib/theme_template/Gemfile +2 -0
  61. data/lib/theme_template/LICENSE.txt.erb +21 -0
  62. data/lib/theme_template/README.md.erb +46 -0
  63. data/lib/theme_template/Rakefile.erb +74 -0
  64. data/lib/theme_template/example/_config.yml.erb +1 -0
  65. data/lib/theme_template/example/_post.md +13 -0
  66. data/lib/theme_template/example/index.html +14 -0
  67. data/lib/theme_template/example/style.scss +7 -0
  68. data/lib/theme_template/theme.gemspec.erb +22 -0
  69. metadata +34 -7
  70. data/lib/jekyll/drops/excerpt_drop.rb +0 -15
@@ -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
- FileUtils.cp(path, dest_path)
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
@@ -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 tag_includes_dir(context)
102
- context.registers[:site].config['includes_dir'].freeze
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 = File.join(dir, file)
114
- validate_path(path, dir, site.safe)
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
- rescue => e
132
- raise IncludeTagError.new e.message, File.join(@includes_dir, @file)
133
- end
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 resolved_includes_dir(context)
148
- context.registers[:site].in_source_dir(@includes_dir)
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 path_relative_to_source(dir, path)
160
- File.join(@includes_dir, path.sub(Regexp.new("^#{dir}"), ""))
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 tag_includes_dir(context)
175
- '.'.freeze
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? ? includes_dir : File.dirname(context.registers[:page]["path"])
180
- end
181
-
182
- def resolved_includes_dir(context)
183
- context.registers[:site].in_source_dir(page_path(context))
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)
@@ -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
- raise ArgumentError.new("'#{name}' does not contain valid date and/or title.") unless all
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
- date.year == other.date.year &&
24
- date.month == other.date.month &&
25
- date.day == other.date.day
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 ArgumentError.new <<-eos
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 ArgumentError.new <<-eos
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.
@@ -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
@@ -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::FatalException.new("Invalid date '#{input}': " + msg)
130
+ raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}"
143
131
  end
144
132
 
145
133
  # Determines whether a given file has
@@ -1,3 +1,3 @@
1
1
  module Jekyll
2
- VERSION = '3.1.6'
2
+ VERSION = '3.2.0.pre.beta1'
3
3
  end
@@ -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 need to edit after that.
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://yourdomain.com" # the base hostname & protocol for your site
22
+ url: "http://example.com" # the base hostname & protocol for your site
17
23
  twitter_username: jekyllrb
18
24
  github_username: jekyll
19
25