jekyll 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jekyll might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +6 -14
  2. data/History.markdown +71 -0
  3. data/README.markdown +13 -3
  4. data/Rakefile +11 -2
  5. data/bin/jekyll +6 -5
  6. data/features/permalinks.feature +20 -0
  7. data/features/site_data.feature +6 -0
  8. data/features/step_definitions/jekyll_steps.rb +1 -1
  9. data/jekyll.gemspec +8 -3
  10. data/lib/jekyll.rb +3 -1
  11. data/lib/jekyll/cleaner.rb +73 -0
  12. data/lib/jekyll/commands/doctor.rb +40 -2
  13. data/lib/jekyll/commands/new.rb +2 -2
  14. data/lib/jekyll/commands/serve.rb +10 -3
  15. data/lib/jekyll/configuration.rb +14 -1
  16. data/lib/jekyll/converters/markdown.rb +1 -1
  17. data/lib/jekyll/converters/markdown/kramdown_parser.rb +4 -8
  18. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +3 -1
  19. data/lib/jekyll/convertible.rb +14 -4
  20. data/lib/jekyll/core_ext.rb +0 -8
  21. data/lib/jekyll/deprecator.rb +13 -9
  22. data/lib/jekyll/generators/pagination.rb +1 -1
  23. data/lib/jekyll/page.rb +33 -34
  24. data/lib/jekyll/post.rb +48 -51
  25. data/lib/jekyll/site.rb +11 -50
  26. data/lib/jekyll/stevenson.rb +1 -1
  27. data/lib/jekyll/tags/include.rb +19 -13
  28. data/lib/jekyll/url.rb +67 -0
  29. data/lib/site_template/_layouts/default.html +20 -22
  30. data/site/_config.yml +3 -1
  31. data/site/_includes/docs_contents.html +50 -50
  32. data/site/_includes/docs_contents_mobile.html +25 -25
  33. data/site/_includes/footer.html +1 -1
  34. data/site/_includes/primary-nav-items.html +3 -3
  35. data/site/_includes/section_nav.html +2 -2
  36. data/site/_includes/top.html +1 -1
  37. data/site/_posts/2013-05-08-jekyll-1-0-1-released.markdown +1 -1
  38. data/site/_posts/2013-05-12-jekyll-1-0-2-released.markdown +1 -1
  39. data/site/_posts/2013-06-07-jekyll-1-0-3-released.markdown +1 -1
  40. data/site/_posts/2013-07-14-jekyll-1-1-0-released.markdown +2 -2
  41. data/site/_posts/2013-07-24-jekyll-1-1-1-released.markdown +4 -4
  42. data/site/_posts/2013-07-25-jekyll-1-0-4-released.markdown +7 -7
  43. data/site/_posts/2013-07-25-jekyll-1-1-2-released.markdown +6 -6
  44. data/site/_posts/2013-09-06-jekyll-1-2-0-released.markdown +23 -0
  45. data/site/css/normalize.css +1 -504
  46. data/site/docs/configuration.md +46 -6
  47. data/site/docs/contributing.md +3 -3
  48. data/site/docs/deployment-methods.md +2 -2
  49. data/site/docs/frontmatter.md +2 -2
  50. data/site/docs/github-pages.md +2 -2
  51. data/site/docs/history.md +265 -265
  52. data/site/docs/index.md +1 -1
  53. data/site/docs/installation.md +4 -4
  54. data/site/docs/migrations.md +14 -11
  55. data/site/docs/pages.md +1 -1
  56. data/site/docs/pagination.md +1 -1
  57. data/site/docs/permalinks.md +2 -2
  58. data/site/docs/plugins.md +18 -10
  59. data/site/docs/posts.md +9 -8
  60. data/site/docs/resources.md +2 -2
  61. data/site/docs/sites.md +1 -1
  62. data/site/docs/structure.md +9 -9
  63. data/site/docs/templates.md +4 -3
  64. data/site/docs/troubleshooting.md +11 -3
  65. data/site/docs/usage.md +8 -3
  66. data/site/docs/variables.md +7 -7
  67. data/site/feed.xml +1 -1
  68. data/site/index.html +3 -3
  69. data/test/source/_posts/2013-08-01-mkdn-extension.mkdn +0 -0
  70. data/test/test_configuration.rb +14 -0
  71. data/test/test_excerpt.rb +16 -0
  72. data/test/test_generated_site.rb +1 -1
  73. data/test/test_post.rb +7 -0
  74. data/test/test_url.rb +28 -0
  75. metadata +27 -21
@@ -19,7 +19,7 @@ module Jekyll
19
19
  create_sample_files new_blog_path
20
20
 
21
21
  File.open(File.expand_path(self.initialized_post_name, new_blog_path), "w") do |f|
22
- f.write(self.scaffold_post_content(site_template))
22
+ f.write(self.scaffold_post_content)
23
23
  end
24
24
  end
25
25
 
@@ -33,7 +33,7 @@ module Jekyll
33
33
  end
34
34
  end
35
35
 
36
- def self.scaffold_post_content(template_site)
36
+ def self.scaffold_post_content
37
37
  ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
38
38
  end
39
39
 
@@ -24,9 +24,16 @@ module Jekyll
24
24
  )
25
25
 
26
26
  s.mount(options['baseurl'], HTTPServlet::FileHandler, destination, fh_option)
27
- t = Thread.new { s.start }
28
- trap("INT") { s.shutdown }
29
- t.join()
27
+
28
+ if options['detach'] # detach the server
29
+ pid = Process.fork {s.start}
30
+ Process.detach(pid)
31
+ pid
32
+ else # create a new server thread, then join it with current terminal
33
+ t = Thread.new { s.start }
34
+ trap("INT") { s.shutdown }
35
+ t.join()
36
+ end
30
37
  end
31
38
  end
32
39
  end
@@ -15,6 +15,7 @@ module Jekyll
15
15
  'timezone' => nil, # use the local timezone
16
16
 
17
17
  'safe' => false,
18
+ 'detach' => false, # default to not detaching the server
18
19
  'show_drafts' => nil,
19
20
  'limit_posts' => 0,
20
21
  'lsi' => false,
@@ -150,7 +151,7 @@ module Jekyll
150
151
  $stderr.puts "#{err}"
151
152
  end
152
153
 
153
- configuration.backwards_compatibilize
154
+ configuration.fix_common_issues.backwards_compatibilize
154
155
  end
155
156
 
156
157
  # Public: Split a CSV string into an array containing its values
@@ -205,5 +206,17 @@ module Jekyll
205
206
  config
206
207
  end
207
208
 
209
+ def fix_common_issues
210
+ config = clone
211
+
212
+ if config.has_key?('paginate') && (!config['paginate'].is_a?(Integer) || config['paginate'] < 1)
213
+ Jekyll.logger.warn "Config Warning:", "The `paginate` key must be a" +
214
+ " positive integer or nil. It's currently set to '#{config['paginate'].inspect}'."
215
+ config['paginate'] = nil
216
+ end
217
+
218
+ config
219
+ end
220
+
208
221
  end
209
222
  end
@@ -26,7 +26,7 @@ module Jekyll
26
26
  end
27
27
 
28
28
  def matches(ext)
29
- rgx = '(' + @config['markdown_ext'].gsub(',','|') +')'
29
+ rgx = '^\.(' + @config['markdown_ext'].gsub(',','|') +')$'
30
30
  ext =~ Regexp.new(rgx, Regexp::IGNORECASE)
31
31
  end
32
32
 
@@ -14,14 +14,10 @@ module Jekyll
14
14
  def convert(content)
15
15
  # Check for use of coderay
16
16
  if @config['kramdown']['use_coderay']
17
- @config['kramdown'].merge!({
18
- :coderay_wrap => @config['kramdown']['coderay']['coderay_wrap'],
19
- :coderay_line_numbers => @config['kramdown']['coderay']['coderay_line_numbers'],
20
- :coderay_line_number_start => @config['kramdown']['coderay']['coderay_line_number_start'],
21
- :coderay_tab_width => @config['kramdown']['coderay']['coderay_tab_width'],
22
- :coderay_bold_every => @config['kramdown']['coderay']['coderay_bold_every'],
23
- :coderay_css => @config['kramdown']['coderay']['coderay_css']
24
- })
17
+ %w[wrap line_numbers line_numbers_start tab_width bold_every css default_lang].each do |opt|
18
+ key = "coderay_#{opt}"
19
+ @config['kramdown'][key.to_sym] = @config['kramdown']['coderay'][key] unless @config['kramdown'].has_key?(key)
20
+ end
25
21
  end
26
22
 
27
23
  Kramdown::Document.new(content, @config["kramdown"].symbolize_keys).to_html
@@ -24,7 +24,9 @@ module Jekyll
24
24
  private
25
25
  def replace_generated_toc(rd, html, toc_token)
26
26
  if rd.generate_toc && html.include?(toc_token)
27
- html.gsub(toc_token, rd.toc_content.force_encoding('utf-8'))
27
+ utf8_toc = rd.toc_content
28
+ utf8_toc.force_encoding('utf-8') if utf8_toc.respond_to?(:force_encoding)
29
+ html.gsub(toc_token, utf8_toc)
28
30
  else
29
31
  html
30
32
  end
@@ -80,10 +80,20 @@ module Jekyll
80
80
  def render_liquid(content, payload, info)
81
81
  Liquid::Template.parse(content).render!(payload, info)
82
82
  rescue Exception => e
83
- Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{payload[:file]}"
83
+ Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{self.path}"
84
84
  raise e
85
85
  end
86
86
 
87
+ # Convert this Convertible's data to a Hash suitable for use by Liquid.
88
+ #
89
+ # Returns the Hash representation of this Convertible.
90
+ def to_liquid(attrs = nil)
91
+ further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map { |attribute|
92
+ [attribute, send(attribute)]
93
+ }]
94
+ data.deep_merge(further_data)
95
+ end
96
+
87
97
  # Recursively render layouts
88
98
  #
89
99
  # layouts - a list of the layouts
@@ -100,7 +110,7 @@ module Jekyll
100
110
  payload = payload.deep_merge({"content" => self.output, "page" => layout.data})
101
111
 
102
112
  self.output = self.render_liquid(layout.content,
103
- payload.merge({:file => layout.name}),
113
+ payload,
104
114
  info)
105
115
 
106
116
  if layout = layouts[layout.data["layout"]]
@@ -127,7 +137,7 @@ module Jekyll
127
137
  payload["pygments_suffix"] = converter.pygments_suffix
128
138
 
129
139
  self.content = self.render_liquid(self.content,
130
- payload.merge({:file => self.name}),
140
+ payload,
131
141
  info)
132
142
  self.transform
133
143
 
@@ -145,7 +155,7 @@ module Jekyll
145
155
  def write(dest)
146
156
  path = destination(dest)
147
157
  FileUtils.mkdir_p(File.dirname(path))
148
- File.open(path, 'w') do |f|
158
+ File.open(path, 'wb') do |f|
149
159
  f.write(self.output)
150
160
  end
151
161
  end
@@ -69,11 +69,3 @@ module Enumerable
69
69
  any? { |exp| File.fnmatch?(exp, e) }
70
70
  end
71
71
  end
72
-
73
- if RUBY_VERSION < "1.9"
74
- class String
75
- def force_encoding(enc)
76
- self
77
- end
78
- end
79
- end
@@ -2,18 +2,18 @@ module Jekyll
2
2
  class Deprecator
3
3
  def self.process(args)
4
4
  no_subcommand(args)
5
- deprecation_message args, "--server", "The --server command has been replaced by the \
5
+ arg_is_present? args, "--server", "The --server command has been replaced by the \
6
6
  'serve' subcommand."
7
- deprecation_message args, "--no-server", "To build Jekyll without launching a server, \
7
+ arg_is_present? args, "--no-server", "To build Jekyll without launching a server, \
8
8
  use the 'build' subcommand."
9
- deprecation_message args, "--auto", "The switch '--auto' has been replaced with '--watch'."
10
- deprecation_message args, "--no-auto", "To disable auto-replication, simply leave off \
9
+ arg_is_present? args, "--auto", "The switch '--auto' has been replaced with '--watch'."
10
+ arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \
11
11
  the '--watch' switch."
12
- deprecation_message args, "--pygments", "The 'pygments' setting can only be set in \
12
+ arg_is_present? args, "--pygments", "The 'pygments' setting can only be set in \
13
13
  your config files."
14
- deprecation_message args, "--paginate", "The 'paginate' setting can only be set in your \
14
+ arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in your \
15
15
  config files."
16
- deprecation_message args, "--url", "The 'url' setting can only be set in your config files."
16
+ arg_is_present? args, "--url", "The 'url' setting can only be set in your config files."
17
17
  end
18
18
 
19
19
  def self.no_subcommand(args)
@@ -23,10 +23,14 @@ module Jekyll
23
23
  end
24
24
  end
25
25
 
26
- def self.deprecation_message(args, deprecated_argument, message)
26
+ def self.arg_is_present?(args, deprecated_argument, message)
27
27
  if args.include?(deprecated_argument)
28
- Jekyll.logger.error "Deprecation:", message
28
+ deprecation_message(message)
29
29
  end
30
30
  end
31
+
32
+ def self.deprecation_message(message)
33
+ Jekyll.logger.error "Deprecation:", message
34
+ end
31
35
  end
32
36
  end
@@ -169,7 +169,7 @@ module Jekyll
169
169
 
170
170
  # Initialize a new Pager.
171
171
  #
172
- # config - The Hash configuration of the site.
172
+ # site - the Jekyll::Site object
173
173
  # page - The Integer page number.
174
174
  # all_posts - The Array of all the site's Posts.
175
175
  # num_pages - The Integer number of pages or nil if you'd like the number
@@ -7,6 +7,13 @@ module Jekyll
7
7
  attr_accessor :name, :ext, :basename
8
8
  attr_accessor :data, :content, :output
9
9
 
10
+ # Attributes for Liquid templates
11
+ ATTRIBUTES_FOR_LIQUID = %w[
12
+ url
13
+ content
14
+ path
15
+ ]
16
+
10
17
  # Initialize a new Page.
11
18
  #
12
19
  # site - The Site object.
@@ -37,7 +44,12 @@ module Jekyll
37
44
  #
38
45
  # Returns the String permalink or nil if none has been set.
39
46
  def permalink
40
- self.data && self.data['permalink']
47
+ return nil if self.data.nil? || self.data['permalink'].nil?
48
+ if site.config['relative_permalinks']
49
+ File.join(@dir, self.data['permalink'])
50
+ else
51
+ self.data['permalink']
52
+ end
41
53
  end
42
54
 
43
55
  # The template of the permalink.
@@ -61,29 +73,21 @@ module Jekyll
61
73
  #
62
74
  # Returns the String url.
63
75
  def url
64
- return @url if @url
65
-
66
- url = if permalink
67
- if site.config['relative_permalinks']
68
- File.join(@dir, permalink)
69
- else
70
- permalink
71
- end
72
- else
73
- {
74
- "path" => @dir,
75
- "basename" => self.basename,
76
- "output_ext" => self.output_ext,
77
- }.inject(template) { |result, token|
78
- result.gsub(/:#{token.first}/, token.last)
79
- }.gsub(/\/\//, "/")
80
- end
76
+ @url ||= URL.new({
77
+ :template => template,
78
+ :placeholders => url_placeholders,
79
+ :permalink => permalink
80
+ }).to_s
81
+ end
81
82
 
82
- # sanitize url
83
- @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
84
- @url += "/" if url =~ /\/$/
85
- @url.gsub!(/\A([^\/])/, '/\1')
86
- @url
83
+ # Returns a hash of URL placeholder names (as symbols) mapping to the
84
+ # desired placeholder replacements. For details see "url.rb"
85
+ def url_placeholders
86
+ {
87
+ :path => @dir,
88
+ :basename => self.basename,
89
+ :output_ext => self.output_ext
90
+ }
87
91
  end
88
92
 
89
93
  # Extract information from the page filename.
@@ -111,21 +115,16 @@ module Jekyll
111
115
  do_layout(payload, layouts)
112
116
  end
113
117
 
114
- # Convert this Page's data to a Hash suitable for use by Liquid.
115
- #
116
- # Returns the Hash representation of this Page.
117
- def to_liquid
118
- self.data.deep_merge({
119
- "url" => self.url,
120
- "content" => self.content,
121
- "path" => self.data['path'] || path })
122
- end
123
-
124
118
  # The path to the source file
125
119
  #
126
120
  # Returns the path to the source file
127
121
  def path
128
- File.join(@dir, @name).sub(/\A\//, '')
122
+ self.data.fetch('path', self.relative_path.sub(/\A\//, ''))
123
+ end
124
+
125
+ # The path to the page source file, relative to the site source
126
+ def relative_path
127
+ File.join(@dir, @name)
129
128
  end
130
129
 
131
130
  # Obtain destination path.
@@ -3,10 +3,6 @@ module Jekyll
3
3
  include Comparable
4
4
  include Convertible
5
5
 
6
- class << self
7
- attr_accessor :lsi
8
- end
9
-
10
6
  # Valid post name regex.
11
7
  MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
12
8
 
@@ -109,18 +105,19 @@ module Jekyll
109
105
  #
110
106
  # Returns excerpt string.
111
107
  def excerpt
112
- if self.data.has_key? 'excerpt'
113
- self.data['excerpt']
114
- else
115
- self.extracted_excerpt.to_s
116
- end
108
+ self.data.fetch('excerpt', self.extracted_excerpt.to_s)
117
109
  end
118
110
 
119
111
  # Public: the Post title, from the YAML Front-Matter or from the slug
120
112
  #
121
113
  # Returns the post title
122
114
  def title
123
- self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' ')
115
+ self.data.fetch("title", self.titleized_slug)
116
+ end
117
+
118
+ # Turns the post slug into a suitable title
119
+ def titleized_slug
120
+ self.slug.split('-').select {|w| w.capitalize! || w }.join(' ')
124
121
  end
125
122
 
126
123
  # Public: the path to the post relative to the site source,
@@ -130,7 +127,12 @@ module Jekyll
130
127
  #
131
128
  # Returns the path to the file relative to the site source
132
129
  def path
133
- self.data['path'] || File.join(@dir, '_posts', @name).sub(/\A\//, '')
130
+ self.data.fetch('path', self.relative_path.sub(/\A\//, ''))
131
+ end
132
+
133
+ # The path to the post source file, relative to the site source
134
+ def relative_path
135
+ File.join(@dir, '_posts', @name)
134
136
  end
135
137
 
136
138
  # Compares Post objects. First compares the Post date. If the dates are
@@ -195,36 +197,31 @@ module Jekyll
195
197
  end
196
198
 
197
199
  # The generated relative url of this post.
198
- # e.g. /2008/11/05/my-awesome-post.html
199
200
  #
200
- # Returns the String URL.
201
+ # Returns the String url.
201
202
  def url
202
- return @url if @url
203
-
204
- url = if permalink
205
- permalink
206
- else
207
- {
208
- "year" => date.strftime("%Y"),
209
- "month" => date.strftime("%m"),
210
- "day" => date.strftime("%d"),
211
- "title" => CGI.escape(slug),
212
- "i_day" => date.strftime("%d").to_i.to_s,
213
- "i_month" => date.strftime("%m").to_i.to_s,
214
- "categories" => categories.map { |c| URI.escape(c.to_s) }.join('/'),
215
- "short_month" => date.strftime("%b"),
216
- "y_day" => date.strftime("%j"),
217
- "output_ext" => self.output_ext
218
- }.inject(template) { |result, token|
219
- result.gsub(/:#{Regexp.escape token.first}/, token.last)
220
- }.gsub(/\/\//, "/")
221
- end
203
+ @url ||= URL.new({
204
+ :template => template,
205
+ :placeholders => url_placeholders,
206
+ :permalink => permalink
207
+ }).to_s
208
+ end
222
209
 
223
- # sanitize url
224
- @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
225
- @url += "/" if url =~ /\/$/
226
- @url.gsub!(/\A([^\/])/, '/\1')
227
- @url
210
+ # Returns a hash of URL placeholder names (as symbols) mapping to the
211
+ # desired placeholder replacements. For details see "url.rb"
212
+ def url_placeholders
213
+ {
214
+ :year => date.strftime("%Y"),
215
+ :month => date.strftime("%m"),
216
+ :day => date.strftime("%d"),
217
+ :title => CGI.escape(slug),
218
+ :i_day => date.strftime("%d").to_i.to_s,
219
+ :i_month => date.strftime("%m").to_i.to_s,
220
+ :categories => (categories || []).map { |c| URI.escape(c.to_s) }.join('/'),
221
+ :short_month => date.strftime("%b"),
222
+ :y_day => date.strftime("%j"),
223
+ :output_ext => self.output_ext
224
+ }
228
225
  end
229
226
 
230
227
  # The UID for this post (useful in feeds).
@@ -255,7 +252,9 @@ module Jekyll
255
252
  "page" => self.to_liquid(EXCERPT_ATTRIBUTES_FOR_LIQUID)
256
253
  }.deep_merge(site_payload)
257
254
 
258
- self.extracted_excerpt.do_layout(payload, {})
255
+ if generate_excerpt?
256
+ self.extracted_excerpt.do_layout(payload, {})
257
+ end
259
258
 
260
259
  do_layout(payload.merge({"page" => self.to_liquid}), layouts)
261
260
  end
@@ -268,20 +267,10 @@ module Jekyll
268
267
  def destination(dest)
269
268
  # The url needs to be unescaped in order to preserve the correct filename
270
269
  path = File.join(dest, CGI.unescape(self.url))
271
- path = File.join(path, "index.html") if template[/\.html$/].nil?
270
+ path = File.join(path, "index.html") if path[/\.html$/].nil?
272
271
  path
273
272
  end
274
273
 
275
- # Convert this post into a Hash for use in Liquid templates.
276
- #
277
- # Returns the representative Hash.
278
- def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
279
- further_data = Hash[attrs.map { |attribute|
280
- [attribute, send(attribute)]
281
- }]
282
- data.deep_merge(further_data)
283
- end
284
-
285
274
  # Returns the shorthand String identifier of this Post.
286
275
  def inspect
287
276
  "<Post: #{self.id}>"
@@ -309,7 +298,15 @@ module Jekyll
309
298
  protected
310
299
 
311
300
  def extract_excerpt
312
- Jekyll::Excerpt.new(self)
301
+ if generate_excerpt?
302
+ Jekyll::Excerpt.new(self)
303
+ else
304
+ ""
305
+ end
306
+ end
307
+
308
+ def generate_excerpt?
309
+ !(site.config['excerpt_separator'].to_s.empty?)
313
310
  end
314
311
  end
315
312
  end