fix categories and add topics

This commit is contained in:
Tom Preston-Werner 2008-12-24 15:24:27 -08:00
parent 6de22b318c
commit dad9a31559
6 changed files with 52 additions and 33 deletions

View File

@ -3,6 +3,7 @@
* Added --server option to start a simple WEBrick server on destination directory [github.com/johnreilly and github.com/mchung]
* Minor Enhancements
* Added post categories based on directories containing _posts [github.com/mreid]
* Added post topics based on directories underneath _posts
* Added new date filter that shows the full month name [github.com/mreid]
* Merge Post's YAML front matter into its to_liquid payload [github.com/remi]
* Restrict includes to regular files underneath _includes

View File

@ -53,12 +53,11 @@ filename is used to construct the URL in the generated site. The example post,
for instance, ends up at
<code>http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html</code>.
Categories for posts are derived from the directory structure the posts were
found within.
A post that appears in the directory foo/bar/_posts is placed in the categories
'foo' and 'bar'.
By selecting posts from particular categories in your Liquid templates, you will
be able to host multiple blogs within a site.
Categories for posts are derived from the directory structure the posts were
found within. A post that appears in the directory foo/bar/_posts is placed in
the categories 'foo' and 'bar'. By selecting posts from particular categories
in your Liquid templates, you will be able to host multiple blogs within a
site.
Files that do not reside in directories prefixed with an underscore are
mirrored into a corresponding directory structure in the generated site. If a
@ -182,7 +181,7 @@ h3. Site
--lsi (latent semantic indexing) option.
site.categories.CATEGORY
The list of all posts in category CATEGORY.
The list of all Posts in category CATEGORY.
h3. Post
@ -200,12 +199,21 @@ h3. Post
An identifier unique to the Post (useful in RSS feeds).
e.g. /2008/12/14/my-post
post.categories
The list of categories to which this post belongs. Categories are
derived from the directory structure above the _posts directory. For
example, a post at /work/code/_posts/2008-12-24-closures.textile
would have this field set to ['work', 'code'].
post.topics
The list of topics for this Post. Topics are derived from the directory
structure beneath the _posts directory. For example, a post at
/_posts/music/metal/2008-12-24-metalocalypse.textile would have this field
set to ['music', 'metal'].
post.content
The content of the Post.
post.categories
The list of categories to which this post belongs.
h2. YAML Front Matter
Any files that contain a YAML front matter block will be processed by Jekyll

View File

@ -8,7 +8,7 @@ module Jekyll
attr_accessor :lsi
end
MATCHER = /^(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
# Post name validator. Post filenames must be like:
# 2008-11-05-my-awesome-post.textile
@ -18,7 +18,7 @@ module Jekyll
name =~ MATCHER
end
attr_accessor :date, :slug, :ext, :categories
attr_accessor :date, :slug, :ext, :categories, :topics
attr_accessor :data, :content, :output
# Initialize this Post instance.
@ -27,15 +27,17 @@ module Jekyll
# +categories+ is an Array of Strings for the categories for this post
#
# Returns <Post>
def initialize(base, name)
@base = base
def initialize(source, dir, name)
@base = File.join(source, dir, '_posts')
@name = name
@categories = base.split('/').reject { |p| ['.', '_posts'].include? p }
self.categories = dir.split('/').reject { |x| x.empty? }
parts = name.split('/')
self.topics = parts.size > 1 ? parts[0..-2] : []
self.process(name)
self.read_yaml(base, name)
#Removed to avoid munging of liquid tags, replaced in convertible.rb#48
#self.transform
self.read_yaml(@base, name)
end
# Spaceship is based on Post#date
@ -50,7 +52,7 @@ module Jekyll
#
# Returns nothing
def process(name)
m, date, slug, ext = *name.match(MATCHER)
m, cats, date, slug, ext = *name.match(MATCHER)
self.date = Time.parse(date)
self.slug = slug
self.ext = ext
@ -63,11 +65,11 @@ module Jekyll
#
# Returns <String>
def dir
path = (@categories && !@categories.empty?) ? '/' + @categories.join('/') : ''
if permalink
permalink.to_s.split("/")[0..-2].join("/")
else
"#{path}" + date.strftime("/%Y/%m/%d/")
prefix = self.categories.empty? ? '' : '/' + self.categories.join('/')
prefix + date.strftime("/%Y/%m/%d/")
end
end
@ -156,6 +158,7 @@ module Jekyll
"url" => self.url,
"date" => self.date,
"id" => self.id,
"topics" => self.topics,
"content" => self.content }.merge(self.data)
end
end

View File

@ -49,14 +49,17 @@ module Jekyll
# object with each one.
#
# Returns nothing
def read_posts(base)
entries = Dir.entries(base)
def read_posts(dir)
base = File.join(self.source, dir, '_posts')
entries = []
Dir.chdir(base) { entries = Dir['**/*'] }
entries = entries.reject { |e| File.directory?(File.join(base, e)) }
# first pass processes, but does not yet render post content
entries.each do |f|
if Post.valid?(f)
post = Post.new(base, f)
post = Post.new(self.source, dir, f)
self.posts << post
end
end
@ -98,7 +101,7 @@ module Jekyll
# might not be available yet to other templates as {{ site.posts }}
if entries.include?('_posts')
entries.delete('_posts')
read_posts(File.join(base, '_posts'))
read_posts(dir)
end
entries.each do |f|
@ -128,9 +131,9 @@ module Jekyll
def site_payload
# Build the category hash map of category ( names => arrays of posts )
# then sort each array in reverse order
categories = Hash.new { |hash,key| hash[key] = Array.new }
categories = Hash.new { |hash, key| hash[key] = Array.new }
self.posts.each { |p| p.categories.each { |c| categories[c] << p } }
categories.values.map { |cats| cats.sort! { |a,b| b <=> a} }
categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
{"site" => {
"time" => Time.now,

View File

@ -7,6 +7,9 @@ class TestPost < Test::Unit::TestCase
def test_valid
assert Post.valid?("2008-10-19-foo-bar.textile")
assert Post.valid?("foo/bar/2008-10-19-foo-bar.textile")
assert !Post.valid?("lol2008-10-19-foo-bar.textile")
assert !Post.valid?("blah")
end
@ -21,6 +24,7 @@ class TestPost < Test::Unit::TestCase
def test_url
p = Post.allocate
p.categories = []
p.process("2008-10-19-foo-bar.textile")
assert_equal "/2008/10/19/foo-bar.html", p.url
@ -60,7 +64,7 @@ class TestPost < Test::Unit::TestCase
end
def test_render
p = Post.new(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-10-18-foo-bar.textile")
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-10-18-foo-bar.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
@ -70,23 +74,23 @@ class TestPost < Test::Unit::TestCase
def test_write
clear_dest
p = Post.new(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-10-18-foo-bar.textile")
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-10-18-foo-bar.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
p.write(dest_dir)
end
def test_data
p = Post.new(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-11-21-complex.textile")
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-11-21-complex.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
assert_equal "<<< <p>url: /test/source/2008/11/21/complex.html<br />\ndate: #{Time.parse("2008-11-21")}<br />\nid: /test/source/2008/11/21/complex</p> >>>", p.output
assert_equal "<<< <p>url: /2008/11/21/complex.html<br />\ndate: #{Time.parse("2008-11-21")}<br />\nid: /2008/11/21/complex</p> >>>", p.output
end
def test_include
Jekyll.source = File.join(File.dirname(__FILE__), *%w[source])
p = Post.new(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-12-13-include.markdown")
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-12-13-include.markdown")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})

View File

@ -17,7 +17,7 @@ class TestSite < Test::Unit::TestCase
end
def test_read_posts
@s.read_posts(File.join(@s.source, '_posts'))
@s.read_posts('')
assert_equal 4, @s.posts.size
end