jberkel-jekyll 0.5.4 → 0.5.7
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.
- data/History.txt +37 -0
- data/README.textile +15 -8
- data/VERSION.yml +3 -2
- data/bin/jekyll +5 -1
- data/features/create_sites.feature +49 -1
- data/features/embed_filters.feature +3 -3
- data/features/markdown.feature +30 -0
- data/features/pagination.feature +12 -25
- data/features/post_data.feature +18 -18
- data/features/step_definitions/jekyll_steps.rb +8 -8
- data/jekyll.gemspec +14 -4
- data/lib/jekyll.rb +4 -3
- data/lib/jekyll/convertible.rb +6 -2
- data/lib/jekyll/core_ext.rb +22 -0
- data/lib/jekyll/page.rb +5 -1
- data/lib/jekyll/pager.rb +1 -1
- data/lib/jekyll/post.rb +13 -25
- data/lib/jekyll/site.rb +82 -68
- data/lib/jekyll/static_file.rb +28 -0
- data/lib/jekyll/tags/highlight.rb +14 -8
- data/test/helper.rb +1 -1
- data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
- data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
- data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
- data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
- data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
- data/test/source/_posts/2010-01-09-date-override.textile +5 -0
- data/test/source/_posts/2010-01-09-time-override.textile +5 -0
- data/test/test_configuration.rb +5 -5
- data/test/test_core_ext.rb +66 -0
- data/test/test_generated_site.rb +4 -0
- data/test/test_pager.rb +92 -26
- data/test/test_post.rb +46 -3
- data/test/test_site.rb +8 -2
- data/test/test_tags.rb +2 -2
- metadata +71 -30
- data/lib/jekyll/converters/marley.rb +0 -53
data/lib/jekyll.rb
CHANGED
@@ -26,6 +26,7 @@ require 'jekyll/filters'
|
|
26
26
|
require 'jekyll/tags/highlight'
|
27
27
|
require 'jekyll/tags/include'
|
28
28
|
require 'jekyll/albino'
|
29
|
+
require 'jekyll/static_file'
|
29
30
|
|
30
31
|
module Jekyll
|
31
32
|
# Default options. Overriden by values in _config.yml or command-line opts.
|
@@ -68,10 +69,10 @@ module Jekyll
|
|
68
69
|
begin
|
69
70
|
config = YAML.load_file(config_file)
|
70
71
|
raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
|
71
|
-
|
72
|
+
$stdout.puts "Configuration from #{config_file}"
|
72
73
|
rescue => err
|
73
|
-
|
74
|
-
|
74
|
+
$stderr.puts "WARNING: Could not read configuration. Using defaults (and options)."
|
75
|
+
$stderr.puts "\t" + err.to_s
|
75
76
|
config = {}
|
76
77
|
end
|
77
78
|
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
#
|
4
4
|
# Requires
|
5
5
|
# self.site -> Jekyll::Site
|
6
|
+
# self.content=
|
7
|
+
# self.data=
|
8
|
+
# self.ext=
|
9
|
+
# self.output=
|
6
10
|
module Jekyll
|
7
11
|
module Convertible
|
8
12
|
# Return the contents as a string
|
@@ -20,7 +24,7 @@ module Jekyll
|
|
20
24
|
|
21
25
|
self.data ||= {}
|
22
26
|
|
23
|
-
if self.content =~ /^(---\s*\n.*?\n?)(
|
27
|
+
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
24
28
|
self.content = self.content[($1.size + $2.size)..-1]
|
25
29
|
self.data = self.data.deep_merge(YAML.load($1) || {})
|
26
30
|
end
|
@@ -52,7 +56,7 @@ module Jekyll
|
|
52
56
|
case self.ext[1..-1]
|
53
57
|
when /textile/i
|
54
58
|
return 'textile'
|
55
|
-
when /markdown/i, /mkdn/i, /md/i
|
59
|
+
when /markdown/i, /mkdn/i, /md/i, /mkd/i
|
56
60
|
return 'markdown'
|
57
61
|
when /haml/i
|
58
62
|
return 'haml'
|
data/lib/jekyll/core_ext.rb
CHANGED
@@ -19,6 +19,28 @@ class Hash
|
|
19
19
|
|
20
20
|
target
|
21
21
|
end
|
22
|
+
|
23
|
+
# Read array from the supplied hash favouring the singular key
|
24
|
+
# and then the plural key, and handling any nil entries.
|
25
|
+
# +hash+ the hash to read from
|
26
|
+
# +singular_key+ the singular key
|
27
|
+
# +plural_key+ the singular key
|
28
|
+
#
|
29
|
+
# Returns an array
|
30
|
+
def pluralized_array(singular_key, plural_key)
|
31
|
+
hash = self
|
32
|
+
if hash.has_key?(singular_key)
|
33
|
+
array = [hash[singular_key]] if hash[singular_key]
|
34
|
+
elsif hash.has_key?(plural_key)
|
35
|
+
case hash[plural_key]
|
36
|
+
when String
|
37
|
+
array = hash[plural_key].split
|
38
|
+
when Array
|
39
|
+
array = hash[plural_key].compact
|
40
|
+
end
|
41
|
+
end
|
42
|
+
array || []
|
43
|
+
end
|
22
44
|
end
|
23
45
|
|
24
46
|
|
data/lib/jekyll/page.rb
CHANGED
@@ -4,7 +4,7 @@ module Jekyll
|
|
4
4
|
include Convertible
|
5
5
|
|
6
6
|
attr_accessor :site
|
7
|
-
attr_accessor :name, :ext, :basename
|
7
|
+
attr_accessor :name, :ext, :basename, :dir
|
8
8
|
attr_accessor :data, :content, :output
|
9
9
|
|
10
10
|
# Initialize a new Page.
|
@@ -101,6 +101,10 @@ module Jekyll
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
+
def inspect
|
105
|
+
"#<Jekyll:Page @name=#{self.name.inspect}>"
|
106
|
+
end
|
107
|
+
|
104
108
|
private
|
105
109
|
|
106
110
|
def index?
|
data/lib/jekyll/pager.rb
CHANGED
data/lib/jekyll/post.rb
CHANGED
@@ -20,12 +20,9 @@ module Jekyll
|
|
20
20
|
name =~ MATCHER
|
21
21
|
end
|
22
22
|
|
23
|
-
attr_accessor :site
|
24
|
-
|
25
|
-
|
26
|
-
def categories
|
27
|
-
@categories ||= []
|
28
|
-
end
|
23
|
+
attr_accessor :site
|
24
|
+
attr_accessor :data, :content, :output, :ext
|
25
|
+
attr_accessor :date, :slug, :published, :tags, :categories
|
29
26
|
|
30
27
|
# Initialize this Post instance.
|
31
28
|
# +site+ is the Site
|
@@ -46,6 +43,13 @@ module Jekyll
|
|
46
43
|
self.read_yaml(@base, name)
|
47
44
|
|
48
45
|
extract_title_from_first_header_or_slug
|
46
|
+
#
|
47
|
+
#If we've added a date and time to the yaml, use that instead of the filename date
|
48
|
+
#Means we'll sort correctly.
|
49
|
+
if self.data.has_key?('date')
|
50
|
+
# ensure Time via to_s and reparse
|
51
|
+
self.date = Time.parse(self.data["date"].to_s)
|
52
|
+
end
|
49
53
|
|
50
54
|
if self.data.has_key?('published') && self.data['published'] == false
|
51
55
|
self.published = false
|
@@ -53,26 +57,10 @@ module Jekyll
|
|
53
57
|
self.published = true
|
54
58
|
end
|
55
59
|
|
56
|
-
|
57
|
-
self.tags = [self.data["tag"]]
|
58
|
-
elsif self.data.has_key?("tags")
|
59
|
-
self.tags = self.data['tags']
|
60
|
-
else
|
61
|
-
self.tags = []
|
62
|
-
end
|
60
|
+
self.tags = self.data.pluralized_array("tag", "tags")
|
63
61
|
|
64
62
|
if self.categories.empty?
|
65
|
-
|
66
|
-
self.categories << self.data['category']
|
67
|
-
elsif self.data.has_key?('categories')
|
68
|
-
# Look for categories in the YAML-header, either specified as
|
69
|
-
# an array or a string.
|
70
|
-
if self.data['categories'].kind_of? String
|
71
|
-
self.categories = self.data['categories'].split
|
72
|
-
else
|
73
|
-
self.categories = self.data['categories']
|
74
|
-
end
|
75
|
-
end
|
63
|
+
self.categories = self.data.pluralized_array('category', 'categories')
|
76
64
|
end
|
77
65
|
end
|
78
66
|
|
@@ -143,7 +131,7 @@ module Jekyll
|
|
143
131
|
"month" => date.strftime("%m"),
|
144
132
|
"day" => date.strftime("%d"),
|
145
133
|
"title" => CGI.escape(slug),
|
146
|
-
"categories" => categories.
|
134
|
+
"categories" => categories.join('/')
|
147
135
|
}.inject(template) { |result, token|
|
148
136
|
result.gsub(/:#{token.first}/, token.last)
|
149
137
|
}.gsub("//", "/")
|
data/lib/jekyll/site.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Jekyll
|
2
2
|
|
3
3
|
class Site
|
4
|
-
attr_accessor :config, :layouts, :posts, :categories, :exclude,
|
4
|
+
attr_accessor :config, :layouts, :posts, :pages, :static_files, :categories, :exclude,
|
5
5
|
:source, :dest, :lsi, :pygments, :permalink_style, :tags
|
6
|
-
|
6
|
+
|
7
7
|
attr_accessor :sass, :post_defaults, :collated_posts
|
8
8
|
|
9
9
|
|
@@ -14,7 +14,7 @@ module Jekyll
|
|
14
14
|
def initialize(config)
|
15
15
|
self.config = config.clone
|
16
16
|
|
17
|
-
self.source = config['source']
|
17
|
+
self.source = File.expand_path(config['source'])
|
18
18
|
self.dest = config['destination']
|
19
19
|
self.lsi = config['lsi']
|
20
20
|
self.pygments = config['pygments']
|
@@ -30,6 +30,8 @@ module Jekyll
|
|
30
30
|
self.layouts = {}
|
31
31
|
self.posts = []
|
32
32
|
self.collated_posts = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = [] } } }
|
33
|
+
self.pages = []
|
34
|
+
self.static_files = []
|
33
35
|
self.categories = Hash.new { |hash, key| hash[key] = [] }
|
34
36
|
self.tags = Hash.new { |hash, key| hash[key] = [] }
|
35
37
|
end
|
@@ -37,7 +39,7 @@ module Jekyll
|
|
37
39
|
def setup
|
38
40
|
# Check to see if LSI is enabled.
|
39
41
|
require 'classifier' if self.lsi
|
40
|
-
|
42
|
+
|
41
43
|
if self.config['sass']
|
42
44
|
begin
|
43
45
|
require 'sass'
|
@@ -47,7 +49,7 @@ module Jekyll
|
|
47
49
|
puts 'You must have the haml gem installed first'
|
48
50
|
end
|
49
51
|
end
|
50
|
-
|
52
|
+
|
51
53
|
if self.config['haml']
|
52
54
|
begin
|
53
55
|
require 'haml'
|
@@ -55,11 +57,11 @@ module Jekyll
|
|
55
57
|
helpers = File.join(source, '_helpers.rb')
|
56
58
|
require helpers if File.exist?(helpers)
|
57
59
|
puts 'Enabled Haml'
|
58
|
-
rescue LoadError
|
59
|
-
|
60
|
+
rescue LoadError
|
61
|
+
puts 'You must have the haml gem installed first'
|
60
62
|
end
|
61
63
|
end
|
62
|
-
|
64
|
+
|
63
65
|
# Set the Markdown interpreter (and Maruku self.config, if necessary)
|
64
66
|
case self.config['markdown']
|
65
67
|
when 'rdiscount'
|
@@ -114,22 +116,30 @@ module Jekyll
|
|
114
116
|
end
|
115
117
|
|
116
118
|
# Do the actual work of processing the site and generating the
|
117
|
-
# real deal.
|
119
|
+
# real deal. Now has 4 phases; reset, read, render, write. This allows
|
120
|
+
# rendering to have full site payload available.
|
118
121
|
#
|
119
122
|
# Returns nothing
|
120
123
|
def process
|
121
124
|
self.reset
|
122
|
-
self.
|
123
|
-
self.
|
125
|
+
self.read
|
126
|
+
self.render
|
127
|
+
self.write
|
124
128
|
self.transform_sass if self.sass
|
125
|
-
self.write_posts
|
126
129
|
end
|
127
130
|
|
128
|
-
|
131
|
+
def read
|
132
|
+
self.read_layouts # existing implementation did this at top level only so preserved that
|
133
|
+
self.read_directories
|
134
|
+
end
|
135
|
+
|
136
|
+
# Read all the files in <source>/<dir>/_layouts and create a new Layout
|
137
|
+
# object with each one.
|
129
138
|
#
|
130
139
|
# Returns nothing
|
131
|
-
def read_layouts
|
132
|
-
base = File.join(self.source, "_layouts")
|
140
|
+
def read_layouts(dir = '')
|
141
|
+
base = File.join(self.source, dir, "_layouts")
|
142
|
+
return unless File.exists?(base)
|
133
143
|
entries = []
|
134
144
|
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
|
135
145
|
|
@@ -137,17 +147,16 @@ module Jekyll
|
|
137
147
|
name = f.split(".")[0..-2].join(".")
|
138
148
|
self.layouts[name] = Layout.new(self, base, f)
|
139
149
|
end
|
140
|
-
rescue Errno::ENOENT => e
|
141
|
-
# ignore missing layout dir
|
142
150
|
end
|
143
151
|
|
144
|
-
# Read all the files in <
|
152
|
+
# Read all the files in <source>/<dir>/_posts and create a new Post
|
153
|
+
# object with each one.
|
145
154
|
#
|
146
155
|
# Returns nothing
|
147
156
|
def read_posts(dir)
|
148
157
|
base = File.join(self.source, dir, '_posts')
|
149
|
-
|
150
|
-
Dir.chdir(base) {
|
158
|
+
return unless File.exists?(base)
|
159
|
+
entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
|
151
160
|
|
152
161
|
# first pass processes, but does not yet render post content
|
153
162
|
entries.each do |f|
|
@@ -163,69 +172,69 @@ module Jekyll
|
|
163
172
|
end
|
164
173
|
|
165
174
|
self.posts.sort!
|
175
|
+
end
|
166
176
|
|
167
|
-
|
177
|
+
def render
|
168
178
|
self.posts.each do |post|
|
169
179
|
post.render(self.layouts, site_payload)
|
170
180
|
self.collated_posts[post.date.year][post.date.month][post.date.day].unshift(post)
|
171
181
|
end
|
172
182
|
|
183
|
+
self.pages.dup.each do |page|
|
184
|
+
if Pager.pagination_enabled?(self.config, page.name)
|
185
|
+
paginate(page)
|
186
|
+
else
|
187
|
+
page.render(self.layouts, site_payload)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
173
191
|
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
174
192
|
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
175
193
|
rescue Errno::ENOENT => e
|
176
194
|
# ignore missing layout dir
|
177
195
|
end
|
178
196
|
|
179
|
-
# Write
|
197
|
+
# Write static files, pages and posts
|
180
198
|
#
|
181
199
|
# Returns nothing
|
182
|
-
def
|
200
|
+
def write
|
183
201
|
self.posts.each do |post|
|
184
202
|
post.write(self.dest)
|
185
203
|
end
|
204
|
+
self.pages.each do |page|
|
205
|
+
page.write(self.dest)
|
206
|
+
end
|
207
|
+
self.static_files.each do |sf|
|
208
|
+
sf.write(self.dest)
|
209
|
+
end
|
186
210
|
end
|
187
211
|
|
188
|
-
#
|
189
|
-
#
|
190
|
-
# with "." or "#" or end with "~") or contain site content (start with "_")
|
191
|
-
# unless they are "_posts" directories or web server files such as
|
192
|
-
# '.htaccess'
|
212
|
+
# Reads the directories and finds posts, pages and static files that will
|
213
|
+
# become part of the valid site according to the rules in +filter_entries+.
|
193
214
|
# The +dir+ String is a relative path used to call this method
|
194
215
|
# recursively as it descends through directories
|
195
216
|
#
|
196
217
|
# Returns nothing
|
197
|
-
def
|
218
|
+
def read_directories(dir = '')
|
198
219
|
base = File.join(self.source, dir)
|
199
220
|
entries = filter_entries(Dir.entries(base))
|
200
|
-
directories = entries.select { |e| File.directory?(File.join(base, e)) }
|
201
|
-
files = entries.reject { |e| File.directory?(File.join(base, e)) || File.symlink?(File.join(base, e)) }
|
202
221
|
|
203
|
-
|
204
|
-
# might not be available yet to other templates as {{ site.posts }}
|
205
|
-
if directories.include?('_posts')
|
206
|
-
directories.delete('_posts')
|
207
|
-
read_posts(dir)
|
208
|
-
end
|
222
|
+
self.read_posts(dir)
|
209
223
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
224
|
+
entries.each do |f|
|
225
|
+
f_abs = File.join(base, f)
|
226
|
+
f_rel = File.join(dir, f)
|
227
|
+
if File.directory?(f_abs)
|
228
|
+
next if self.dest.sub(/\/$/, '') == f_abs
|
229
|
+
read_directories(f_rel)
|
230
|
+
elsif !File.symlink?(f_abs)
|
231
|
+
first3 = File.open(f_abs) { |fd| fd.read(3) }
|
232
|
+
if first3 == "---"
|
233
|
+
# file appears to have a YAML header so process it as a page
|
234
|
+
pages << Page.new(self, self.source, dir, f)
|
217
235
|
else
|
218
|
-
|
219
|
-
|
220
|
-
# file appears to have a YAML header so process it as a page
|
221
|
-
page = Page.new(self, self.source, dir, f)
|
222
|
-
page.render(self.layouts, site_payload)
|
223
|
-
page.write(self.dest)
|
224
|
-
else
|
225
|
-
# otherwise copy the file without transforming it
|
226
|
-
FileUtils.mkdir_p(File.join(self.dest, dir))
|
227
|
-
FileUtils.cp(File.join(self.source, dir, f), File.join(self.dest, dir, f))
|
228
|
-
end
|
236
|
+
# otherwise treat it as a static file
|
237
|
+
static_files << StaticFile.new(self, self.source, dir, f)
|
229
238
|
end
|
230
239
|
end
|
231
240
|
end
|
@@ -279,19 +288,21 @@ module Jekyll
|
|
279
288
|
end
|
280
289
|
|
281
290
|
# Filter out any files/directories that are hidden or backup files (start
|
282
|
-
# with "." or "#" or end with "~") or contain site content (start with "_")
|
283
|
-
#
|
284
|
-
# '.htaccess'
|
291
|
+
# with "." or "#" or end with "~"), or contain site content (start with "_"),
|
292
|
+
# or are excluded in the site configuration, unless they are web server
|
293
|
+
# files such as '.htaccess'
|
285
294
|
def filter_entries(entries)
|
286
295
|
entries = entries.reject do |e|
|
287
|
-
unless ['
|
296
|
+
unless ['.htaccess'].include?(e)
|
288
297
|
['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
|
289
298
|
end
|
290
299
|
end
|
291
300
|
end
|
292
301
|
|
293
|
-
# Paginates the blog's posts. Renders the index.html file into paginated
|
294
|
-
# and adds more
|
302
|
+
# Paginates the blog's posts. Renders the index.html file into paginated
|
303
|
+
# directories, ie: page2/index.html, page3/index.html, etc and adds more
|
304
|
+
# site-wide data.
|
305
|
+
# +page+ is the index.html Page that requires pagination
|
295
306
|
#
|
296
307
|
# {"paginator" => { "page" => <Number>,
|
297
308
|
# "per_page" => <Number>,
|
@@ -300,16 +311,19 @@ module Jekyll
|
|
300
311
|
# "total_pages" => <Number>,
|
301
312
|
# "previous_page" => <Number>,
|
302
313
|
# "next_page" => <Number> }}
|
303
|
-
def
|
304
|
-
all_posts =
|
314
|
+
def paginate(page)
|
315
|
+
all_posts = site_payload['site']['posts']
|
305
316
|
pages = Pager.calculate_pages(all_posts, self.config['paginate'].to_i)
|
306
|
-
pages += 1
|
307
317
|
(1..pages).each do |num_page|
|
308
318
|
pager = Pager.new(self.config, num_page, all_posts, pages)
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
319
|
+
if num_page > 1
|
320
|
+
newpage = Page.new(self, self.source, page.dir, page.name)
|
321
|
+
newpage.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
|
322
|
+
newpage.dir = File.join(page.dir, "page#{num_page}")
|
323
|
+
self.pages << newpage
|
324
|
+
else
|
325
|
+
page.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
|
326
|
+
end
|
313
327
|
end
|
314
328
|
end
|
315
329
|
end
|