jekyll 1.0.4 → 1.1.1

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 (90) hide show
  1. checksums.yaml +14 -6
  2. data/{CONTRIBUTING.md → CONTRIBUTING.markdown} +19 -1
  3. data/History.markdown +172 -85
  4. data/README.markdown +45 -0
  5. data/Rakefile +43 -18
  6. data/bin/jekyll +31 -1
  7. data/features/create_sites.feature +18 -0
  8. data/features/include_tag.feature +35 -0
  9. data/features/pagination.feature +28 -0
  10. data/features/post_excerpts.feature +50 -0
  11. data/features/step_definitions/jekyll_steps.rb +27 -11
  12. data/features/support/env.rb +9 -0
  13. data/jekyll.gemspec +32 -7
  14. data/lib/jekyll.rb +2 -1
  15. data/lib/jekyll/commands/new.rb +15 -3
  16. data/lib/jekyll/configuration.rb +23 -22
  17. data/lib/jekyll/converters/markdown/kramdown_parser.rb +4 -15
  18. data/lib/jekyll/convertible.rb +4 -0
  19. data/lib/jekyll/core_ext.rb +11 -0
  20. data/lib/jekyll/excerpt.rb +113 -0
  21. data/lib/jekyll/generators/pagination.rb +93 -23
  22. data/lib/jekyll/page.rb +1 -3
  23. data/lib/jekyll/post.rb +15 -55
  24. data/lib/jekyll/related_posts.rb +2 -1
  25. data/lib/jekyll/site.rb +33 -41
  26. data/lib/jekyll/stevenson.rb +25 -4
  27. data/lib/jekyll/tags/include.rb +46 -2
  28. data/lib/site_template/_config.yml +1 -0
  29. data/lib/site_template/css/main.css +0 -5
  30. data/site/_config.yml +1 -0
  31. data/site/_includes/docs_contents.html +12 -3
  32. data/site/_includes/docs_contents_mobile.html +7 -1
  33. data/site/_includes/news_contents.html +23 -0
  34. data/site/_includes/news_contents_mobile.html +11 -0
  35. data/site/_includes/news_item.html +24 -0
  36. data/site/_includes/primary-nav-items.html +4 -1
  37. data/site/_includes/top.html +2 -0
  38. data/site/_layouts/news.html +19 -0
  39. data/site/_layouts/news_item.html +27 -0
  40. data/site/_posts/2013-05-06-jekyll-1-0-0-released.markdown +23 -0
  41. data/site/_posts/2013-05-08-jekyll-1-0-1-released.markdown +27 -0
  42. data/site/_posts/2013-05-12-jekyll-1-0-2-released.markdown +28 -0
  43. data/site/_posts/2013-06-07-jekyll-1-0-3-released.markdown +25 -0
  44. data/site/_posts/2013-07-14-jekyll-1-1-0-released.markdown +27 -0
  45. data/site/_posts/2013-07-24-jekyll-1-1-1-released.markdown +31 -0
  46. data/site/css/style.css +125 -17
  47. data/site/docs/configuration.md +10 -1
  48. data/site/docs/contributing.md +21 -3
  49. data/site/docs/deployment-methods.md +2 -2
  50. data/site/docs/drafts.md +20 -0
  51. data/site/docs/extras.md +24 -3
  52. data/site/docs/github-pages.md +25 -0
  53. data/site/docs/history.md +150 -85
  54. data/site/docs/index.md +1 -17
  55. data/site/docs/installation.md +3 -2
  56. data/site/docs/migrations.md +2 -2
  57. data/site/docs/pagination.md +12 -0
  58. data/site/docs/plugins.md +97 -76
  59. data/site/docs/quickstart.md +32 -0
  60. data/site/docs/resources.md +0 -1
  61. data/site/docs/structure.md +15 -0
  62. data/site/docs/templates.md +26 -4
  63. data/site/docs/troubleshooting.md +22 -7
  64. data/site/docs/upgrading.md +6 -1
  65. data/site/docs/variables.md +12 -2
  66. data/site/feed.xml +36 -0
  67. data/site/freenode.txt +1 -0
  68. data/site/img/article-footer.png +0 -0
  69. data/site/img/footer-arrow.png +0 -0
  70. data/site/img/footer-logo.png +0 -0
  71. data/site/img/logo-2x.png +0 -0
  72. data/site/img/octojekyll.png +0 -0
  73. data/site/img/tube.png +0 -0
  74. data/site/img/tube1x.png +0 -0
  75. data/site/index.html +1 -1
  76. data/site/news/index.md +10 -0
  77. data/site/news/releases/index.md +10 -0
  78. data/test/source/+/foo.md +7 -0
  79. data/test/source/_includes/params.html +7 -0
  80. data/test/source/_posts/2013-07-22-post-excerpt-with-layout.markdown +23 -0
  81. data/test/test_configuration.rb +9 -0
  82. data/test/test_excerpt.rb +62 -0
  83. data/test/test_generated_site.rb +1 -1
  84. data/test/test_page.rb +9 -0
  85. data/test/test_pager.rb +31 -37
  86. data/test/test_post.rb +2 -1
  87. data/test/test_related_posts.rb +6 -1
  88. data/test/test_tags.rb +90 -0
  89. metadata +62 -23
  90. data/README.textile +0 -45
@@ -134,9 +134,7 @@ module Jekyll
134
134
  #
135
135
  # Returns the destination file path String.
136
136
  def destination(dest)
137
- # The url needs to be unescaped in order to preserve the correct
138
- # filename.
139
- path = File.join(dest, CGI.unescape(self.url))
137
+ path = File.join(dest, self.url)
140
138
  path = File.join(path, "index.html") if self.url =~ /\/$/
141
139
  path
142
140
  end
@@ -10,8 +10,7 @@ module Jekyll
10
10
  # Valid post name regex.
11
11
  MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
12
12
 
13
- # Attributes for Liquid templates
14
- ATTRIBUTES_FOR_LIQUID = %w[
13
+ EXCERPT_ATTRIBUTES_FOR_LIQUID = %w[
15
14
  title
16
15
  url
17
16
  date
@@ -20,11 +19,15 @@ module Jekyll
20
19
  next
21
20
  previous
22
21
  tags
23
- content
24
- excerpt
25
22
  path
26
23
  ]
27
24
 
25
+ # Attributes for Liquid templates
26
+ ATTRIBUTES_FOR_LIQUID = EXCERPT_ATTRIBUTES_FOR_LIQUID.concat(%w[
27
+ content
28
+ excerpt
29
+ ])
30
+
28
31
  # Post name validator. Post filenames must be like:
29
32
  # 2008-11-05-my-awesome-post.textile
30
33
  #
@@ -109,7 +112,7 @@ module Jekyll
109
112
  if self.data.has_key? 'excerpt'
110
113
  self.data['excerpt']
111
114
  else
112
- self.extracted_excerpt
115
+ self.extracted_excerpt.to_s
113
116
  end
114
117
  end
115
118
 
@@ -158,14 +161,6 @@ module Jekyll
158
161
  raise FatalException.new("Post #{name} does not have a valid date.")
159
162
  end
160
163
 
161
- # Transform the contents and excerpt based on the content type.
162
- #
163
- # Returns nothing.
164
- def transform
165
- super
166
- self.extracted_excerpt = converter.convert(self.extracted_excerpt)
167
- end
168
-
169
164
  # The generated directory into which the post will be placed
170
165
  # upon generation. This is derived from the permalink or, if
171
166
  # permalink is absent, set to the default date
@@ -257,10 +252,12 @@ module Jekyll
257
252
  # construct payload
258
253
  payload = {
259
254
  "site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) },
260
- "page" => self.to_liquid
255
+ "page" => self.to_liquid(EXCERPT_ATTRIBUTES_FOR_LIQUID)
261
256
  }.deep_merge(site_payload)
262
257
 
263
- do_layout(payload, layouts)
258
+ self.extracted_excerpt.do_layout(payload, {})
259
+
260
+ do_layout(payload.merge({"page" => self.to_liquid}), layouts)
264
261
  end
265
262
 
266
263
  # Obtain destination path.
@@ -278,8 +275,8 @@ module Jekyll
278
275
  # Convert this post into a Hash for use in Liquid templates.
279
276
  #
280
277
  # Returns the representative Hash.
281
- def to_liquid
282
- further_data = Hash[ATTRIBUTES_FOR_LIQUID.map { |attribute|
278
+ def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
279
+ further_data = Hash[attrs.map { |attribute|
283
280
  [attribute, send(attribute)]
284
281
  }]
285
282
  data.deep_merge(further_data)
@@ -311,45 +308,8 @@ module Jekyll
311
308
 
312
309
  protected
313
310
 
314
- # Internal: Extract excerpt from the content
315
- #
316
- # By default excerpt is your first paragraph of a post: everything before
317
- # the first two new lines:
318
- #
319
- # ---
320
- # title: Example
321
- # ---
322
- #
323
- # First paragraph with [link][1].
324
- #
325
- # Second paragraph.
326
- #
327
- # [1]: http://example.com/
328
- #
329
- # This is fairly good option for Markdown and Textile files. But might cause
330
- # problems for HTML posts (which is quite unusual for Jekyll). If default
331
- # excerpt delimiter is not good for you, you might want to set your own via
332
- # configuration option `excerpt_separator`. For example, following is a good
333
- # alternative for HTML posts:
334
- #
335
- # # file: _config.yml
336
- # excerpt_separator: "<!-- more -->"
337
- #
338
- # Notice that all markdown-style link references will be appended to the
339
- # excerpt. So the example post above will have this excerpt source:
340
- #
341
- # First paragraph with [link][1].
342
- #
343
- # [1]: http://example.com/
344
- #
345
- # Excerpts are rendered same time as content is rendered.
346
- #
347
- # Returns excerpt String
348
311
  def extract_excerpt
349
- separator = self.site.config['excerpt_separator']
350
- head, _, tail = self.content.partition(separator)
351
-
352
- "" << head << "\n\n" << tail.scan(/^\[[^\]]+\]:.+$/).join("\n")
312
+ Jekyll::Excerpt.new(self)
353
313
  end
354
314
  end
355
315
  end
@@ -46,7 +46,8 @@ module Jekyll
46
46
  end
47
47
 
48
48
  def most_recent_posts
49
- (self.site.posts - [self.post])[0..9]
49
+ recent_posts = self.site.posts.reverse - [self.post]
50
+ recent_posts.first(10)
50
51
  end
51
52
 
52
53
  def display(output)
@@ -138,34 +138,19 @@ module Jekyll
138
138
  entries = Dir.chdir(base) { filter_entries(Dir.entries('.')) }
139
139
 
140
140
  self.read_posts(dir)
141
-
142
- if self.show_drafts
143
- self.read_drafts(dir)
144
- end
145
-
141
+ self.read_drafts(dir) if self.show_drafts
146
142
  self.posts.sort!
147
-
148
- # limit the posts if :limit_posts option is set
149
- if limit_posts > 0
150
- limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
151
- self.posts = self.posts[-limit, limit]
152
- end
143
+ limit_posts! if limit_posts > 0 # limit the posts if :limit_posts option is set
153
144
 
154
145
  entries.each do |f|
155
146
  f_abs = File.join(base, f)
156
- f_rel = File.join(dir, f)
157
147
  if File.directory?(f_abs)
158
- next if self.dest.sub(/\/$/, '') == f_abs
159
- read_directories(f_rel)
148
+ f_rel = File.join(dir, f)
149
+ read_directories(f_rel) unless self.dest.sub(/\/$/, '') == f_abs
150
+ elsif has_yaml_header?(f_abs)
151
+ pages << Page.new(self, self.source, dir, f)
160
152
  else
161
- first3 = File.open(f_abs) { |fd| fd.read(3) }
162
- if first3 == "---"
163
- # file appears to have a YAML header so process it as a page
164
- pages << Page.new(self, self.source, dir, f)
165
- else
166
- # otherwise treat it as a static file
167
- static_files << StaticFile.new(self, self.source, dir, f)
168
- end
153
+ static_files << StaticFile.new(self, self.source, dir, f)
169
154
  end
170
155
  end
171
156
  end
@@ -255,22 +240,18 @@ module Jekyll
255
240
 
256
241
  # files to be written
257
242
  files = Set.new
258
- self.posts.each do |post|
259
- files << post.destination(self.dest)
260
- end
261
- self.pages.each do |page|
262
- files << page.destination(self.dest)
263
- end
264
- self.static_files.each do |sf|
265
- files << sf.destination(self.dest)
266
- end
243
+ each_site_file { |item| files << item.destination(self.dest) }
267
244
 
268
245
  # adding files' parent directories
269
246
  dirs = Set.new
270
247
  files.each { |file| dirs << File.dirname(file) }
271
248
  files.merge(dirs)
272
249
 
273
- obsolete_files = dest_files - files
250
+ # files that are replaced by dirs should be deleted
251
+ files_to_delete = Set.new
252
+ dirs.each { |dir| files_to_delete << dir if File.file?(dir) }
253
+
254
+ obsolete_files = dest_files - files + files_to_delete
274
255
  FileUtils.rm_rf(obsolete_files.to_a)
275
256
  end
276
257
 
@@ -290,15 +271,7 @@ module Jekyll
290
271
  #
291
272
  # Returns nothing.
292
273
  def write
293
- self.posts.each do |post|
294
- post.write(self.dest)
295
- end
296
- self.pages.each do |page|
297
- page.write(self.dest)
298
- end
299
- self.static_files.each do |sf|
300
- sf.write(self.dest)
301
- end
274
+ each_site_file { |item| item.write(self.dest) }
302
275
  end
303
276
 
304
277
  # Construct a Hash of Posts indexed by the specified Post attribute.
@@ -430,5 +403,24 @@ module Jekyll
430
403
  @deprecated_relative_permalinks = true
431
404
  end
432
405
  end
406
+
407
+ def each_site_file
408
+ %w(posts pages static_files).each do |type|
409
+ self.send(type).each do |item|
410
+ yield item
411
+ end
412
+ end
413
+ end
414
+
415
+ private
416
+
417
+ def has_yaml_header?(file)
418
+ "---" == File.open(file) { |fd| fd.read(3) }
419
+ end
420
+
421
+ def limit_posts!
422
+ limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
423
+ self.posts = self.posts[-limit, limit]
424
+ end
433
425
  end
434
426
  end
@@ -5,7 +5,7 @@ module Jekyll
5
5
  DEBUG = 0
6
6
  INFO = 1
7
7
  WARN = 2
8
- ERROR = 3
8
+ ERROR = 3
9
9
 
10
10
  # Public: Create a new instance of Stevenson, Jekyll's logger
11
11
  #
@@ -15,6 +15,16 @@ module Jekyll
15
15
  def initialize(level = INFO)
16
16
  @log_level = level
17
17
  end
18
+
19
+ # Public: Print a jekyll debug message to stdout
20
+ #
21
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
22
+ # message - the message detail
23
+ #
24
+ # Returns nothing
25
+ def debug(topic, message = nil)
26
+ $stdout.puts(message(topic, message)) if log_level <= DEBUG
27
+ end
18
28
 
19
29
  # Public: Print a jekyll message to stdout
20
30
  #
@@ -22,7 +32,7 @@ module Jekyll
22
32
  # message - the message detail
23
33
  #
24
34
  # Returns nothing
25
- def info(topic, message)
35
+ def info(topic, message = nil)
26
36
  $stdout.puts(message(topic, message)) if log_level <= INFO
27
37
  end
28
38
 
@@ -32,7 +42,7 @@ module Jekyll
32
42
  # message - the message detail
33
43
  #
34
44
  # Returns nothing
35
- def warn(topic, message)
45
+ def warn(topic, message = nil)
36
46
  $stderr.puts(message(topic, message).yellow) if log_level <= WARN
37
47
  end
38
48
 
@@ -42,10 +52,21 @@ module Jekyll
42
52
  # message - the message detail
43
53
  #
44
54
  # Returns nothing
45
- def error(topic, message)
55
+ def error(topic, message = nil)
46
56
  $stderr.puts(message(topic, message).red) if log_level <= ERROR
47
57
  end
48
58
 
59
+ # Public: Print a Jekyll error message to stderr and immediately abort the process
60
+ #
61
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
62
+ # message - the message detail (can be omitted)
63
+ #
64
+ # Returns nothing
65
+ def abort_with(topic, message = nil)
66
+ error(topic, message)
67
+ abort
68
+ end
69
+
49
70
  # Public: Build a Jekyll topic method
50
71
  #
51
72
  # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
@@ -1,9 +1,51 @@
1
1
  module Jekyll
2
2
  module Tags
3
3
  class IncludeTag < Liquid::Tag
4
- def initialize(tag_name, file, tokens)
4
+
5
+ MATCHER = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
6
+
7
+ def initialize(tag_name, markup, tokens)
5
8
  super
6
- @file = file.strip
9
+ @file, @params = markup.strip.split(' ', 2);
10
+ end
11
+
12
+ def parse_params(context)
13
+ validate_syntax
14
+
15
+ params = {}
16
+ markup = @params
17
+
18
+ while match = MATCHER.match(markup) do
19
+ markup = markup[match.end(0)..-1]
20
+
21
+ value = if match[2]
22
+ match[2].gsub(/\\"/, '"')
23
+ elsif match[3]
24
+ match[3].gsub(/\\'/, "'")
25
+ elsif match[4]
26
+ context[match[4]]
27
+ end
28
+
29
+ params[match[1]] = value
30
+ end
31
+ params
32
+ end
33
+
34
+ # ensure the entire markup string from start to end is valid syntax, and params are separated by spaces
35
+ def validate_syntax
36
+ full_matcher = Regexp.compile('\A\s*(?:' + MATCHER.to_s + '(?=\s|\z)\s*)*\z')
37
+ unless @params =~ full_matcher
38
+ raise SyntaxError.new <<-eos
39
+ Invalid syntax for include tag:
40
+
41
+ #{@params}
42
+
43
+ Valid syntax:
44
+
45
+ {% include file.ext param='value' param2="value" %}
46
+
47
+ eos
48
+ end
7
49
  end
8
50
 
9
51
  def render(context)
@@ -22,7 +64,9 @@ module Jekyll
22
64
  if choices.include?(@file)
23
65
  source = File.read(@file)
24
66
  partial = Liquid::Template.parse(source)
67
+
25
68
  context.stack do
69
+ context['include'] = parse_params(context) if @params
26
70
  partial.render(context)
27
71
  end
28
72
  else
@@ -1,2 +1,3 @@
1
1
  name: Your New Jekyll Site
2
+ markdown: redcarpet
2
3
  pygments: true
@@ -29,11 +29,6 @@ a { color: #00a; }
29
29
  a:hover { color: #000; }
30
30
  a:visited { color: #a0a; }
31
31
 
32
- table {
33
- font-size: inherit;
34
- font: 100%;
35
- }
36
-
37
32
  /*****************************************************************************/
38
33
  /*
39
34
  /* Home
@@ -1,3 +1,4 @@
1
1
  pygments: true
2
2
  relative_permalinks: false
3
3
  gauges_id: 503c5af6613f5d0f19000027
4
+ permalink: /news/:year/:month/:day/:title
@@ -5,6 +5,9 @@
5
5
  <li class="{% if page.title == "Welcome" %}current{% endif %}">
6
6
  <a href="{{ site.url }}/docs/home">Welcome</a>
7
7
  </li>
8
+ <li class="{% if page.title == "Quick-start guide" %}current{% endif %}">
9
+ <a href="{{ site.url }}/docs/quickstart">Quick-start guide</a>
10
+ </li>
8
11
  <li class="{% if page.title == "Installation" %}current{% endif %}">
9
12
  <a href="{{ site.url }}/docs/installation">Installation</a>
10
13
  </li>
@@ -26,6 +29,9 @@
26
29
  <li class="{% if page.title == "Writing posts" %}current{% endif %}">
27
30
  <a href="{{ site.url }}/docs/posts">Writing posts</a>
28
31
  </li>
32
+ <li class="{% if page.title == "Working with drafts" %}current{% endif %}">
33
+ <a href="{{ site.url }}/docs/drafts">Working with drafts</a>
34
+ </li>
29
35
  <li class="{% if page.title == "Creating pages" %}current{% endif %}">
30
36
  <a href="{{ site.url }}/docs/pages">Creating pages</a>
31
37
  </li>
@@ -65,9 +71,6 @@
65
71
  </ul>
66
72
  <h4>Miscellaneous</h4>
67
73
  <ul>
68
- <li class="{% if page.title == "Contributing" %}current{% endif %}">
69
- <a href="{{ site.url }}/docs/contributing">Contributing</a>
70
- </li>
71
74
  <li class="{% if page.title == "Troubleshooting" %}current{% endif %}">
72
75
  <a href="{{ site.url }}/docs/troubleshooting">Troubleshooting</a>
73
76
  </li>
@@ -80,6 +83,12 @@
80
83
  <li class="{% if page.title == "Upgrading" %}current{% endif %}">
81
84
  <a href="{{ site.url }}/docs/upgrading">Upgrading</a>
82
85
  </li>
86
+ </ul>
87
+ <h4>Meta</h4>
88
+ <ul>
89
+ <li class="{% if page.title == "Contributing" %}current{% endif %}">
90
+ <a href="{{ site.url }}/docs/contributing">Contributing</a>
91
+ </li>
83
92
  <li class="{% if page.title == "History" %}current{% endif %}">
84
93
  <a href="{{ site.url }}/docs/history">History</a>
85
94
  </li>