jekyll 0.10.0 → 0.11.0

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 (64) hide show
  1. data/Gemfile +2 -0
  2. data/History.txt +20 -1
  3. data/README.textile +1 -1
  4. data/Rakefile +2 -0
  5. data/bin/jekyll +92 -2
  6. data/doc/output/book.html +574 -0
  7. data/doc/output/ch00-preface.asc +41 -0
  8. data/doc/output/ch01-quick-start.asc +153 -0
  9. data/doc/output/ch02-directory-layout.asc +90 -0
  10. data/doc/output/stylesheets/handbookish-quirks.css +0 -0
  11. data/doc/output/stylesheets/handbookish.css +231 -0
  12. data/doc/output/stylesheets/scribe-quirks.css +0 -0
  13. data/doc/output/stylesheets/scribe.css +177 -0
  14. data/features/post_data.feature +2 -2
  15. data/features/site_configuration.feature +7 -0
  16. data/features/support/env.rb +3 -0
  17. data/g.pl +48 -0
  18. data/jekyll.gemspec +35 -16
  19. data/lib/jekyll.rb +11 -4
  20. data/lib/jekyll/converters/markdown.rb +14 -2
  21. data/lib/jekyll/converters/textile.rb +2 -1
  22. data/lib/jekyll/convertible.rb +34 -19
  23. data/lib/jekyll/filters.rb +66 -1
  24. data/lib/jekyll/generators/pagination.rb +33 -7
  25. data/lib/jekyll/layout.rb +18 -10
  26. data/lib/jekyll/migrators/csv.rb +3 -3
  27. data/lib/jekyll/migrators/drupal.rb +12 -6
  28. data/lib/jekyll/migrators/enki.rb +49 -0
  29. data/lib/jekyll/migrators/marley.rb +0 -1
  30. data/lib/jekyll/migrators/mephisto.rb +17 -12
  31. data/lib/jekyll/migrators/mt.rb +26 -17
  32. data/lib/jekyll/migrators/posterous.rb +68 -0
  33. data/lib/jekyll/migrators/textpattern.rb +15 -8
  34. data/lib/jekyll/migrators/tumblr.rb +119 -0
  35. data/lib/jekyll/migrators/typo.rb +8 -6
  36. data/lib/jekyll/migrators/wordpress.rb +23 -16
  37. data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
  38. data/lib/jekyll/page.rb +56 -35
  39. data/lib/jekyll/plugin.rb +1 -0
  40. data/lib/jekyll/post.rb +25 -14
  41. data/lib/jekyll/site.rb +138 -80
  42. data/lib/jekyll/static_file.rb +12 -15
  43. data/lib/jekyll/tags/highlight.rb +5 -5
  44. data/output/stylesheets/scribe-quirks.css +0 -0
  45. data/output/stylesheets/scribe.css +177 -0
  46. data/test/helper.rb +3 -3
  47. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  48. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  49. data/test/suite.rb +3 -1
  50. data/test/test_configuration.rb +1 -1
  51. data/test/test_core_ext.rb +1 -1
  52. data/test/test_filters.rb +10 -1
  53. data/test/test_generated_site.rb +2 -2
  54. data/test/test_kramdown.rb +1 -1
  55. data/test/test_page.rb +1 -1
  56. data/test/test_pager.rb +1 -1
  57. data/test/test_post.rb +49 -2
  58. data/test/test_rdiscount.rb +1 -1
  59. data/test/test_redcarpet.rb +21 -0
  60. data/test/test_site.rb +1 -1
  61. data/test/test_tags.rb +14 -1
  62. metadata +104 -38
  63. data/lib/jekyll/albino.rb +0 -120
  64. data/lib/jekyll/migrators/wordpress.com.rb +0 -38
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'hpricot'
5
+ require 'fileutils'
6
+ require 'yaml'
7
+ require 'time'
8
+
9
+ module Jekyll
10
+ # This importer takes a wordpress.xml file, which can be exported from your
11
+ # wordpress.com blog (/wp-admin/export.php).
12
+ module WordpressDotCom
13
+ def self.process(filename = "wordpress.xml")
14
+ import_count = Hash.new(0)
15
+ doc = Hpricot::XML(File.read(filename))
16
+
17
+ (doc/:channel/:item).each do |item|
18
+ title = item.at(:title).inner_text.strip
19
+ permalink_title = item.at('wp:post_name').inner_text
20
+ # Fallback to "prettified" title if post_name is empty (can happen)
21
+ if permalink_title == ""
22
+ permalink_title = title.downcase.split.join('-')
23
+ end
24
+
25
+ date = Time.parse(item.at('wp:post_date').inner_text)
26
+ status = item.at('wp:status').inner_text
27
+
28
+ if status == "publish"
29
+ published = true
30
+ else
31
+ published = false
32
+ end
33
+
34
+ type = item.at('wp:post_type').inner_text
35
+ tags = (item/:category).map{|c| c.inner_text}.reject{|c| c == 'Uncategorized'}.uniq
36
+
37
+ metas = Hash.new
38
+ item.search("wp:postmeta").each do |meta|
39
+ key = meta.at('wp:meta_key').inner_text
40
+ value = meta.at('wp:meta_value').inner_text
41
+ metas[key] = value;
42
+ end
43
+
44
+ name = "#{date.strftime('%Y-%m-%d')}-#{permalink_title}.html"
45
+ header = {
46
+ 'layout' => type,
47
+ 'title' => title,
48
+ 'tags' => tags,
49
+ 'status' => status,
50
+ 'type' => type,
51
+ 'published' => published,
52
+ 'meta' => metas
53
+ }
54
+
55
+ FileUtils.mkdir_p "_#{type}s"
56
+ File.open("_#{type}s/#{name}", "w") do |f|
57
+ f.puts header.to_yaml
58
+ f.puts '---'
59
+ f.puts item.at('content:encoded').inner_text
60
+ end
61
+
62
+ import_count[type] += 1
63
+ end
64
+
65
+ import_count.each do |key, value|
66
+ puts "Imported #{value} #{key}s"
67
+ end
68
+ end
69
+ end
70
+ end
data/lib/jekyll/page.rb CHANGED
@@ -3,17 +3,17 @@ module Jekyll
3
3
  class Page
4
4
  include Convertible
5
5
 
6
+ attr_writer :dir
6
7
  attr_accessor :site, :pager
7
- attr_accessor :name, :ext, :basename, :dir
8
+ attr_accessor :name, :ext, :basename
8
9
  attr_accessor :data, :content, :output
9
10
 
10
11
  # Initialize a new Page.
11
- # +site+ is the Site
12
- # +base+ is the String path to the <source>
13
- # +dir+ is the String path between <source> and the file
14
- # +name+ is the String filename of the file
15
12
  #
16
- # Returns <Page>
13
+ # site - The Site object.
14
+ # base - The String path to the source.
15
+ # dir - The String path between the source and the file.
16
+ # name - The String filename of the file.
17
17
  def initialize(site, base, dir, name)
18
18
  @site = site
19
19
  @base = base
@@ -26,22 +26,24 @@ module Jekyll
26
26
 
27
27
  # The generated directory into which the page will be placed
28
28
  # upon generation. This is derived from the permalink or, if
29
- # permalink is absent, set to '/'
29
+ # permalink is absent, we be '/'
30
30
  #
31
- # Returns <String>
31
+ # Returns the String destination directory.
32
32
  def dir
33
33
  url[-1, 1] == '/' ? url : File.dirname(url)
34
34
  end
35
35
 
36
- # The full path and filename of the post.
37
- # Defined in the YAML of the post body
38
- # (Optional)
36
+ # The full path and filename of the post. Defined in the YAML of the post
37
+ # body.
39
38
  #
40
- # Returns <String>
39
+ # Returns the String permalink or nil if none has been set.
41
40
  def permalink
42
41
  self.data && self.data['permalink']
43
42
  end
44
43
 
44
+ # The template of the permalink.
45
+ #
46
+ # Returns the template String.
45
47
  def template
46
48
  if self.site.permalink_style == :pretty && !index? && html?
47
49
  "/:basename/"
@@ -50,35 +52,45 @@ module Jekyll
50
52
  end
51
53
  end
52
54
 
53
- # The generated relative url of this page
54
- # e.g. /about.html
55
+ # The generated relative url of this page. e.g. /about.html.
55
56
  #
56
- # Returns <String>
57
+ # Returns the String url.
57
58
  def url
58
- return permalink if permalink
59
-
60
- @url ||= {
61
- "basename" => self.basename,
62
- "output_ext" => self.output_ext,
63
- }.inject(template) { |result, token|
64
- result.gsub(/:#{token.first}/, token.last)
65
- }.gsub(/\/\//, "/")
59
+ return @url if @url
60
+
61
+ url = if permalink
62
+ permalink
63
+ else
64
+ {
65
+ "basename" => self.basename,
66
+ "output_ext" => self.output_ext,
67
+ }.inject(template) { |result, token|
68
+ result.gsub(/:#{token.first}/, token.last)
69
+ }.gsub(/\/\//, "/")
70
+ end
71
+
72
+ # sanitize url
73
+ @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
74
+ @url += "/" if url =~ /\/$/
75
+ @url
66
76
  end
67
77
 
68
- # Extract information from the page filename
69
- # +name+ is the String filename of the page file
78
+ # Extract information from the page filename.
79
+ #
80
+ # name - The String filename of the page file.
70
81
  #
71
- # Returns nothing
82
+ # Returns nothing.
72
83
  def process(name)
73
84
  self.ext = File.extname(name)
74
85
  self.basename = name[0 .. -self.ext.length-1]
75
86
  end
76
87
 
77
88
  # Add any necessary layouts to this post
78
- # +layouts+ is a Hash of {"name" => "layout"}
79
- # +site_payload+ is the site payload hash
80
89
  #
81
- # Returns nothing
90
+ # layouts - The Hash of {"name" => "layout"}.
91
+ # site_payload - The site payload Hash.
92
+ #
93
+ # Returns nothing.
82
94
  def render(layouts, site_payload)
83
95
  payload = {
84
96
  "page" => self.to_liquid,
@@ -88,27 +100,33 @@ module Jekyll
88
100
  do_layout(payload, layouts)
89
101
  end
90
102
 
103
+ # Convert this Page's data to a Hash suitable for use by Liquid.
104
+ #
105
+ # Returns the Hash representation of this Page.
91
106
  def to_liquid
92
107
  self.data.deep_merge({
93
108
  "url" => File.join(@dir, self.url),
94
109
  "content" => self.content })
95
110
  end
96
-
111
+
97
112
  # Obtain destination path.
98
- # +dest+ is the String path to the destination dir
99
113
  #
100
- # Returns destination file path.
114
+ # dest - The String path to the destination dir.
115
+ #
116
+ # Returns the destination file path String.
101
117
  def destination(dest)
102
- # The url needs to be unescaped in order to preserve the correct filename
118
+ # The url needs to be unescaped in order to preserve the correct
119
+ # filename.
103
120
  path = File.join(dest, @dir, CGI.unescape(self.url))
104
121
  path = File.join(path, "index.html") if self.url =~ /\/$/
105
122
  path
106
123
  end
107
124
 
108
125
  # Write the generated page file to the destination directory.
109
- # +dest+ is the String path to the destination dir
110
126
  #
111
- # Returns nothing
127
+ # dest - The String path to the destination dir.
128
+ #
129
+ # Returns nothing.
112
130
  def write(dest)
113
131
  path = destination(dest)
114
132
  FileUtils.mkdir_p(File.dirname(path))
@@ -117,14 +135,17 @@ module Jekyll
117
135
  end
118
136
  end
119
137
 
138
+ # Returns the object as a debug String.
120
139
  def inspect
121
140
  "#<Jekyll:Page @name=#{self.name.inspect}>"
122
141
  end
123
142
 
143
+ # Returns the Boolean of whether this Page is HTML or not.
124
144
  def html?
125
145
  output_ext == '.html'
126
146
  end
127
147
 
148
+ # Returns the Boolean of whether this Page is an index file or not.
128
149
  def index?
129
150
  basename == 'index'
130
151
  end
data/lib/jekyll/plugin.rb CHANGED
@@ -34,6 +34,7 @@ module Jekyll
34
34
  #
35
35
  # Returns the Symbol priority.
36
36
  def self.priority(priority = nil)
37
+ @priority ||= nil
37
38
  if priority && PRIORITIES.has_key?(priority)
38
39
  @priority = priority
39
40
  end
data/lib/jekyll/post.rb CHANGED
@@ -78,6 +78,8 @@ module Jekyll
78
78
  self.date = Time.parse(date)
79
79
  self.slug = slug
80
80
  self.ext = ext
81
+ rescue ArgumentError
82
+ raise FatalException.new("Post #{name} does not have a valid date.")
81
83
  end
82
84
 
83
85
  # The generated directory into which the post will be placed
@@ -117,20 +119,29 @@ module Jekyll
117
119
  #
118
120
  # Returns <String>
119
121
  def url
120
- return permalink if permalink
121
-
122
- @url ||= {
123
- "year" => date.strftime("%Y"),
124
- "month" => date.strftime("%m"),
125
- "day" => date.strftime("%d"),
126
- "title" => CGI.escape(slug),
127
- "i_day" => date.strftime("%d").to_i.to_s,
128
- "i_month" => date.strftime("%m").to_i.to_s,
129
- "categories" => categories.join('/'),
130
- "output_ext" => self.output_ext
131
- }.inject(template) { |result, token|
132
- result.gsub(/:#{Regexp.escape token.first}/, token.last)
133
- }.gsub(/\/\//, "/")
122
+ return @url if @url
123
+
124
+ url = if permalink
125
+ permalink
126
+ else
127
+ {
128
+ "year" => date.strftime("%Y"),
129
+ "month" => date.strftime("%m"),
130
+ "day" => date.strftime("%d"),
131
+ "title" => CGI.escape(slug),
132
+ "i_day" => date.strftime("%d").to_i.to_s,
133
+ "i_month" => date.strftime("%m").to_i.to_s,
134
+ "categories" => categories.join('/'),
135
+ "output_ext" => self.output_ext
136
+ }.inject(template) { |result, token|
137
+ result.gsub(/:#{Regexp.escape token.first}/, token.last)
138
+ }.gsub(/\/\//, "/")
139
+ end
140
+
141
+ # sanitize url
142
+ @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
143
+ @url += "/" if url =~ /\/$/
144
+ @url
134
145
  end
135
146
 
136
147
  # The UID for this post (useful in feeds)
data/lib/jekyll/site.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Jekyll
2
4
 
3
5
  class Site
@@ -7,10 +9,9 @@ module Jekyll
7
9
 
8
10
  attr_accessor :converters, :generators
9
11
 
10
- # Initialize the site
11
- # +config+ is a Hash containing site configurations details
12
+ # Public: Initialize a new Site.
12
13
  #
13
- # Returns <Site>
14
+ # config - A Hash containing site configuration details.
14
15
  def initialize(config)
15
16
  self.config = config.clone
16
17
 
@@ -29,6 +30,21 @@ module Jekyll
29
30
  self.setup
30
31
  end
31
32
 
33
+ # Public: Read, process, and write this Site to output.
34
+ #
35
+ # Returns nothing.
36
+ def process
37
+ self.reset
38
+ self.read
39
+ self.generate
40
+ self.render
41
+ self.cleanup
42
+ self.write
43
+ end
44
+
45
+ # Reset Site details.
46
+ #
47
+ # Returns nothing
32
48
  def reset
33
49
  self.time = if self.config['time']
34
50
  Time.parse(self.config['time'].to_s)
@@ -42,13 +58,18 @@ module Jekyll
42
58
  self.categories = Hash.new { |hash, key| hash[key] = [] }
43
59
  self.tags = Hash.new { |hash, key| hash[key] = [] }
44
60
 
45
- raise ArgumentError, "Limit posts must be nil or >= 1" if !self.limit_posts.nil? && self.limit_posts < 1
61
+ if !self.limit_posts.nil? && self.limit_posts < 1
62
+ raise ArgumentError, "Limit posts must be nil or >= 1"
63
+ end
46
64
  end
47
65
 
66
+ # Load necessary libraries, plugins, converters, and generators.
67
+ #
68
+ # Returns nothing.
48
69
  def setup
49
70
  require 'classifier' if self.lsi
50
71
 
51
- # If safe mode is off, load in any ruby files under the plugins
72
+ # If safe mode is off, load in any Ruby files under the plugins
52
73
  # directory.
53
74
  unless self.safe
54
75
  Dir[File.join(self.plugins, "**/*.rb")].each do |f|
@@ -69,29 +90,18 @@ module Jekyll
69
90
  end
70
91
  end
71
92
 
72
- # Do the actual work of processing the site and generating the
73
- # real deal. 5 phases; reset, read, generate, render, write. This allows
74
- # rendering to have full site payload available.
93
+ # Read Site data from disk and load it into internal data structures.
75
94
  #
76
- # Returns nothing
77
- def process
78
- self.reset
79
- self.read
80
- self.generate
81
- self.render
82
- self.cleanup
83
- self.write
84
- end
85
-
95
+ # Returns nothing.
86
96
  def read
87
- self.read_layouts # existing implementation did this at top level only so preserved that
97
+ self.read_layouts
88
98
  self.read_directories
89
99
  end
90
100
 
91
101
  # Read all the files in <source>/<dir>/_layouts and create a new Layout
92
102
  # object with each one.
93
103
  #
94
- # Returns nothing
104
+ # Returns nothing.
95
105
  def read_layouts(dir = '')
96
106
  base = File.join(self.source, dir, "_layouts")
97
107
  return unless File.exists?(base)
@@ -104,10 +114,44 @@ module Jekyll
104
114
  end
105
115
  end
106
116
 
117
+ # Recursively traverse directories to find posts, pages and static files
118
+ # that will become part of the site according to the rules in
119
+ # filter_entries.
120
+ #
121
+ # dir - The String relative path of the directory to read.
122
+ #
123
+ # Returns nothing.
124
+ def read_directories(dir = '')
125
+ base = File.join(self.source, dir)
126
+ entries = Dir.chdir(base) { filter_entries(Dir['*']) }
127
+
128
+ self.read_posts(dir)
129
+
130
+ entries.each do |f|
131
+ f_abs = File.join(base, f)
132
+ f_rel = File.join(dir, f)
133
+ if File.directory?(f_abs)
134
+ next if self.dest.sub(/\/$/, '') == f_abs
135
+ read_directories(f_rel)
136
+ elsif !File.symlink?(f_abs)
137
+ first3 = File.open(f_abs) { |fd| fd.read(3) }
138
+ if first3 == "---"
139
+ # file appears to have a YAML header so process it as a page
140
+ pages << Page.new(self, self.source, dir, f)
141
+ else
142
+ # otherwise treat it as a static file
143
+ static_files << StaticFile.new(self, self.source, dir, f)
144
+ end
145
+ end
146
+ end
147
+ end
148
+
107
149
  # Read all the files in <source>/<dir>/_posts and create a new Post
108
150
  # object with each one.
109
151
  #
110
- # Returns nothing
152
+ # dir - The String relative path of the directory to read.
153
+ #
154
+ # Returns nothing.
111
155
  def read_posts(dir)
112
156
  base = File.join(self.source, dir, '_posts')
113
157
  return unless File.exists?(base)
@@ -132,12 +176,18 @@ module Jekyll
132
176
  self.posts = self.posts[-limit_posts, limit_posts] if limit_posts
133
177
  end
134
178
 
179
+ # Run each of the Generators.
180
+ #
181
+ # Returns nothing.
135
182
  def generate
136
183
  self.generators.each do |generator|
137
184
  generator.generate(self)
138
185
  end
139
186
  end
140
187
 
188
+ # Render the site to the destination.
189
+ #
190
+ # Returns nothing.
141
191
  def render
142
192
  self.posts.each do |post|
143
193
  post.render(self.layouts, site_payload)
@@ -147,24 +197,24 @@ module Jekyll
147
197
  page.render(self.layouts, site_payload)
148
198
  end
149
199
 
150
- self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
151
- self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
200
+ self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } }
201
+ self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a } }
152
202
  rescue Errno::ENOENT => e
153
203
  # ignore missing layout dir
154
204
  end
155
-
156
- # Remove orphaned files and empty directories in destination
205
+
206
+ # Remove orphaned files and empty directories in destination.
157
207
  #
158
- # Returns nothing
208
+ # Returns nothing.
159
209
  def cleanup
160
210
  # all files and directories in destination, including hidden ones
161
- dest_files = []
211
+ dest_files = Set.new
162
212
  Dir.glob(File.join(self.dest, "**", "*"), File::FNM_DOTMATCH) do |file|
163
213
  dest_files << file unless file =~ /\/\.{1,2}$/
164
214
  end
165
215
 
166
216
  # files to be written
167
- files = []
217
+ files = Set.new
168
218
  self.posts.each do |post|
169
219
  files << post.destination(self.dest)
170
220
  end
@@ -174,18 +224,20 @@ module Jekyll
174
224
  self.static_files.each do |sf|
175
225
  files << sf.destination(self.dest)
176
226
  end
177
-
227
+
178
228
  # adding files' parent directories
179
- files.each { |file| files << File.dirname(file) unless files.include? File.dirname(file) }
180
-
229
+ dirs = Set.new
230
+ files.each { |file| dirs << File.dirname(file) }
231
+ files.merge(dirs)
232
+
181
233
  obsolete_files = dest_files - files
182
-
183
- FileUtils.rm_rf(obsolete_files)
234
+
235
+ FileUtils.rm_rf(obsolete_files.to_a)
184
236
  end
185
237
 
186
- # Write static files, pages and posts
238
+ # Write static files, pages, and posts.
187
239
  #
188
- # Returns nothing
240
+ # Returns nothing.
189
241
  def write
190
242
  self.posts.each do |post|
191
243
  post.write(self.dest)
@@ -198,59 +250,45 @@ module Jekyll
198
250
  end
199
251
  end
200
252
 
201
- # Reads the directories and finds posts, pages and static files that will
202
- # become part of the valid site according to the rules in +filter_entries+.
203
- # The +dir+ String is a relative path used to call this method
204
- # recursively as it descends through directories
253
+ # Constructs a Hash of Posts indexed by the specified Post attribute.
205
254
  #
206
- # Returns nothing
207
- def read_directories(dir = '')
208
- base = File.join(self.source, dir)
209
- entries = filter_entries(Dir.entries(base))
210
-
211
- self.read_posts(dir)
212
-
213
- entries.each do |f|
214
- f_abs = File.join(base, f)
215
- f_rel = File.join(dir, f)
216
- if File.directory?(f_abs)
217
- next if self.dest.sub(/\/$/, '') == f_abs
218
- read_directories(f_rel)
219
- elsif !File.symlink?(f_abs)
220
- first3 = File.open(f_abs) { |fd| fd.read(3) }
221
- if first3 == "---"
222
- # file appears to have a YAML header so process it as a page
223
- pages << Page.new(self, self.source, dir, f)
224
- else
225
- # otherwise treat it as a static file
226
- static_files << StaticFile.new(self, self.source, dir, f)
227
- end
228
- end
229
- end
230
- end
231
-
232
- # Constructs a hash map of Posts indexed by the specified Post attribute
255
+ # post_attr - The String name of the Post attribute.
233
256
  #
234
- # Returns {post_attr => [<Post>]}
257
+ # Examples
258
+ #
259
+ # post_attr_hash('categories')
260
+ # # => { 'tech' => [<Post A>, <Post B>],
261
+ # # 'ruby' => [<Post B>] }
262
+ #
263
+ # Returns the Hash: { attr => posts } where
264
+ # attr - One of the values for the requested attribute.
265
+ # posts - The Array of Posts with the given attr value.
235
266
  def post_attr_hash(post_attr)
236
- # Build a hash map based on the specified post attribute ( post attr => array of posts )
237
- # then sort each array in reverse order
238
- hash = Hash.new { |hash, key| hash[key] = Array.new }
267
+ # Build a hash map based on the specified post attribute ( post attr =>
268
+ # array of posts ) then sort each array in reverse order.
269
+ hash = Hash.new { |hsh, key| hsh[key] = Array.new }
239
270
  self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
240
- hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
241
- return hash
271
+ hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a } }
272
+ hash
242
273
  end
243
274
 
244
- # The Hash payload containing site-wide data
275
+ # The Hash payload containing site-wide data.
245
276
  #
246
- # Returns {"site" => {"time" => <Time>,
247
- # "posts" => [<Post>],
248
- # "pages" => [<Page>],
249
- # "categories" => [<Post>]}
277
+ # Returns the Hash: { "site" => data } where data is a Hash with keys:
278
+ # "time" - The Time as specified in the configuration or the
279
+ # current time if none was specified.
280
+ # "posts" - The Array of Posts, sorted chronologically by post date
281
+ # and then title.
282
+ # "pages" - The Array of all Pages.
283
+ # "html_pages" - The Array of HTML Pages.
284
+ # "categories" - The Hash of category values and Posts.
285
+ # See Site#post_attr_hash for type info.
286
+ # "tags" - The Hash of tag values and Posts.
287
+ # See Site#post_attr_hash for type info.
250
288
  def site_payload
251
289
  {"site" => self.config.merge({
252
290
  "time" => self.time,
253
- "posts" => self.posts.sort { |a,b| b <=> a },
291
+ "posts" => self.posts.sort { |a, b| b <=> a },
254
292
  "pages" => self.pages,
255
293
  "html_pages" => self.pages.reject { |page| !page.html? },
256
294
  "categories" => post_attr_hash('categories'),
@@ -260,14 +298,34 @@ module Jekyll
260
298
  # Filter out any files/directories that are hidden or backup files (start
261
299
  # with "." or "#" or end with "~"), or contain site content (start with "_"),
262
300
  # or are excluded in the site configuration, unless they are web server
263
- # files such as '.htaccess'
301
+ # files such as '.htaccess'.
302
+ #
303
+ # entries - The Array of file/directory entries to filter.
304
+ #
305
+ # Returns the Array of filtered entries.
264
306
  def filter_entries(entries)
265
307
  entries = entries.reject do |e|
266
308
  unless ['.htaccess'].include?(e)
267
- ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
309
+ ['.', '_', '#'].include?(e[0..0]) ||
310
+ e[-1..-1] == '~' ||
311
+ self.exclude.include?(e) ||
312
+ File.symlink?(e)
268
313
  end
269
314
  end
270
315
  end
271
316
 
317
+ # Get the implementation class for the given Converter.
318
+ #
319
+ # klass - The Class of the Converter to fetch.
320
+ #
321
+ # Returns the Converter instance implementing the given Converter.
322
+ def getConverterImpl(klass)
323
+ matches = self.converters.select { |c| c.class == klass }
324
+ if impl = matches.first
325
+ impl
326
+ else
327
+ raise "Converter implementation not found for #{klass}"
328
+ end
329
+ end
272
330
  end
273
331
  end