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.
- data/Gemfile +2 -0
- data/History.txt +20 -1
- data/README.textile +1 -1
- data/Rakefile +2 -0
- data/bin/jekyll +92 -2
- data/doc/output/book.html +574 -0
- data/doc/output/ch00-preface.asc +41 -0
- data/doc/output/ch01-quick-start.asc +153 -0
- data/doc/output/ch02-directory-layout.asc +90 -0
- data/doc/output/stylesheets/handbookish-quirks.css +0 -0
- data/doc/output/stylesheets/handbookish.css +231 -0
- data/doc/output/stylesheets/scribe-quirks.css +0 -0
- data/doc/output/stylesheets/scribe.css +177 -0
- data/features/post_data.feature +2 -2
- data/features/site_configuration.feature +7 -0
- data/features/support/env.rb +3 -0
- data/g.pl +48 -0
- data/jekyll.gemspec +35 -16
- data/lib/jekyll.rb +11 -4
- data/lib/jekyll/converters/markdown.rb +14 -2
- data/lib/jekyll/converters/textile.rb +2 -1
- data/lib/jekyll/convertible.rb +34 -19
- data/lib/jekyll/filters.rb +66 -1
- data/lib/jekyll/generators/pagination.rb +33 -7
- data/lib/jekyll/layout.rb +18 -10
- data/lib/jekyll/migrators/csv.rb +3 -3
- data/lib/jekyll/migrators/drupal.rb +12 -6
- data/lib/jekyll/migrators/enki.rb +49 -0
- data/lib/jekyll/migrators/marley.rb +0 -1
- data/lib/jekyll/migrators/mephisto.rb +17 -12
- data/lib/jekyll/migrators/mt.rb +26 -17
- data/lib/jekyll/migrators/posterous.rb +68 -0
- data/lib/jekyll/migrators/textpattern.rb +15 -8
- data/lib/jekyll/migrators/tumblr.rb +119 -0
- data/lib/jekyll/migrators/typo.rb +8 -6
- data/lib/jekyll/migrators/wordpress.rb +23 -16
- data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
- data/lib/jekyll/page.rb +56 -35
- data/lib/jekyll/plugin.rb +1 -0
- data/lib/jekyll/post.rb +25 -14
- data/lib/jekyll/site.rb +138 -80
- data/lib/jekyll/static_file.rb +12 -15
- data/lib/jekyll/tags/highlight.rb +5 -5
- data/output/stylesheets/scribe-quirks.css +0 -0
- data/output/stylesheets/scribe.css +177 -0
- data/test/helper.rb +3 -3
- data/test/source/_posts/2011-04-12-md-extension.md +7 -0
- data/test/source/_posts/2011-04-12-text-extension.text +0 -0
- data/test/suite.rb +3 -1
- data/test/test_configuration.rb +1 -1
- data/test/test_core_ext.rb +1 -1
- data/test/test_filters.rb +10 -1
- data/test/test_generated_site.rb +2 -2
- data/test/test_kramdown.rb +1 -1
- data/test/test_page.rb +1 -1
- data/test/test_pager.rb +1 -1
- data/test/test_post.rb +49 -2
- data/test/test_rdiscount.rb +1 -1
- data/test/test_redcarpet.rb +21 -0
- data/test/test_site.rb +1 -1
- data/test/test_tags.rb +14 -1
- metadata +104 -38
- data/lib/jekyll/albino.rb +0 -120
- 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
|
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
|
-
#
|
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,
|
29
|
+
# permalink is absent, we be '/'
|
30
30
|
#
|
31
|
-
# Returns
|
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
|
-
#
|
38
|
-
# (Optional)
|
36
|
+
# The full path and filename of the post. Defined in the YAML of the post
|
37
|
+
# body.
|
39
38
|
#
|
40
|
-
# Returns
|
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
|
57
|
+
# Returns the String url.
|
57
58
|
def url
|
58
|
-
return
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
-
#
|
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
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
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
11
|
-
# +config+ is a Hash containing site configurations details
|
12
|
+
# Public: Initialize a new Site.
|
12
13
|
#
|
13
|
-
#
|
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
|
-
|
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
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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 =>
|
237
|
-
# then sort each array in reverse order
|
238
|
-
hash = Hash.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
|
-
|
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" =>
|
247
|
-
#
|
248
|
-
#
|
249
|
-
#
|
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]) ||
|
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
|