Added post categories based on directories containing _posts

This commit is contained in:
Mark Reid 2008-12-16 17:52:00 +11:00
parent b094b93301
commit 3a8f7a8e3a
7 changed files with 67 additions and 22 deletions

View File

@ -31,9 +31,10 @@ various data about my site. A reverse chronological list of all my blog posts
can be found in <code>site.posts</code>. Each post, in turn, contains various can be found in <code>site.posts</code>. Each post, in turn, contains various
fields such as <code>title</code> and <code>date</code>. fields such as <code>title</code> and <code>date</code>.
Jekyll gets the list of blog posts by parsing the files in the Jekyll gets the list of blog posts by parsing the files in any
"_posts":http://github.com/mojombo/tpw/tree/master/_posts directory. Each "_posts":http://github.com/mojombo/tpw/tree/master/_posts directory found in
post's filename contains the publishing date and slug (what shows up in the subdirectories below the root.
Each post's filename contains the publishing date and slug (what shows up in the
URL) that the final HTML file should have. Open up the file corresponding to a URL) that the final HTML file should have. Open up the file corresponding to a
blog post: blog post:
"2008-11-17-blogging-like-a-hacker.textile":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile. "2008-11-17-blogging-like-a-hacker.textile":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile.
@ -52,6 +53,13 @@ filename is used to construct the URL in the generated site. The example post,
for instance, ends up at for instance, ends up at
<code>http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html</code>. <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.
Files that do not reside in directories prefixed with an underscore are Files that do not reside in directories prefixed with an underscore are
mirrored into a corresponding directory structure in the generated site. If a mirrored into a corresponding directory structure in the generated site. If a
file does not have a YAML preface, it is not run through the Liquid file does not have a YAML preface, it is not run through the Liquid
@ -158,6 +166,9 @@ h3. Site
high quality but slow to compute results, run the jekyll command with the high quality but slow to compute results, run the jekyll command with the
--lsi (latent semantic indexing) option. --lsi (latent semantic indexing) option.
site.categories.CATEGORY
The list of all posts in category CATEGORY.
h3. Post h3. Post
post.title post.title
@ -177,6 +188,9 @@ h3. Post
post.content post.content
The content of the Post. The content of the Post.
post.categories
The list of categories to which this post belongs.
h2. YAML Front Matter h2. YAML Front Matter
Any files that contain a YAML front matter block will be processed by Jekyll Any files that contain a YAML front matter block will be processed by Jekyll
@ -289,6 +303,22 @@ highlighting stylesheet. For an example stylesheet you can look at
are the same styles as used by GitHub and you are free to use them for your are the same styles as used by GitHub and you are free to use them for your
own site. own site.
h2. Categories
Posts are placed into categories based on the directory structure they are found
within (see above for an example). The categories can be accessed from within
a Liquid template as follows:
<pre>
{% for post in site.categories.foo %}
<li><span>{{ post.date | date_to_string }}</span> - {{ post.title }}</li>
{% endfor %}
</pre>
This would list all the posts in the category 'foo' by date and title.
The posts within each category are sorted in reverse chronological order.
h2. Contribute h2. Contribute
If you'd like to hack on Jekyll, grab the source from GitHub. To get If you'd like to hack on Jekyll, grab the source from GitHub. To get

View File

@ -6,6 +6,7 @@ require 'rubygems'
# core # core
require 'fileutils' require 'fileutils'
require 'time' require 'time'
require 'yaml'
# stdlib # stdlib

View File

@ -15,7 +15,6 @@ module Jekyll
def number_of_words(input) def number_of_words(input)
input.split.length input.split.length
end end
end end
end end

View File

@ -3,7 +3,7 @@ module Jekyll
class Post class Post
include Comparable include Comparable
include Convertible include Convertible
class << self class << self
attr_accessor :lsi attr_accessor :lsi
end end
@ -18,17 +18,19 @@ module Jekyll
name =~ MATCHER name =~ MATCHER
end end
attr_accessor :date, :slug, :ext attr_accessor :date, :slug, :ext, :categories
attr_accessor :data, :content, :output attr_accessor :data, :content, :output
# Initialize this Post instance. # Initialize this Post instance.
# +base+ is the String path to the dir containing the post file # +base+ is the String path to the dir containing the post file
# +name+ is the String filename of the post file # +name+ is the String filename of the post file
# +categories+ is an Array of Strings for the categories for this post
# #
# Returns <Post> # Returns <Post>
def initialize(base, name) def initialize(base, name)
@base = base @base = base
@name = name @name = name
@categories = base.split('/').reject { |p| ['.', '_posts'].include? p }
self.process(name) self.process(name)
self.read_yaml(base, name) self.read_yaml(base, name)
@ -61,9 +63,10 @@ module Jekyll
# #
# Returns <String> # Returns <String>
def dir def dir
path = @categories ? '/' + @categories.join('/') : ''
permalink ? permalink ?
permalink.to_s.split("/")[0..-2].join("/") : permalink.to_s.split("/")[0..-2].join("/") :
date.strftime("/%Y/%m/%d/") "#{path}" + date.strftime("/%Y/%m/%d/")
end end
# The full path and filename of the post. # The full path and filename of the post.
@ -90,7 +93,7 @@ module Jekyll
def id def id
self.dir + self.slug self.dir + self.slug
end end
# Calculate related posts. # Calculate related posts.
# #
# Returns [<Post>] # Returns [<Post>]

View File

@ -24,9 +24,8 @@ module Jekyll
# Returns nothing # Returns nothing
def process def process
self.read_layouts self.read_layouts
self.read_posts
self.write_posts
self.transform_pages self.transform_pages
self.write_posts
end end
# Read all the files in <source>/_layouts into memory for # Read all the files in <source>/_layouts into memory for
@ -46,12 +45,11 @@ module Jekyll
# ignore missing layout dir # ignore missing layout dir
end end
# Read all the files in <source>/posts and create a new Post # Read all the files in <base>/_posts and create a new Post
# object with each one. # object with each one.
# #
# Returns nothing # Returns nothing
def read_posts def read_posts(base)
base = File.join(self.source, "_posts")
entries = Dir.entries(base) entries = Dir.entries(base)
entries = entries.reject { |e| File.directory?(e) } entries = entries.reject { |e| File.directory?(e) }
@ -76,7 +74,7 @@ module Jekyll
# Copy all regular files from <source> to <dest>/ ignoring # Copy all regular files from <source> to <dest>/ ignoring
# any files/directories that are hidden (start with ".") or contain # any files/directories that are hidden (start with ".") or contain
# site content (start with "_") # site content (start with "_") unless they are "_posts" directories
# The +dir+ String is a relative path used to call this method # The +dir+ String is a relative path used to call this method
# recursively as it descends through directories # recursively as it descends through directories
# #
@ -84,10 +82,14 @@ module Jekyll
def transform_pages(dir = '') def transform_pages(dir = '')
base = File.join(self.source, dir) base = File.join(self.source, dir)
entries = Dir.entries(base) entries = Dir.entries(base)
entries = entries.reject { |e| ['.', '_'].include?(e[0..0]) } entries = entries.reject { |e|
(e != '_posts') and ['.', '_'].include?(e[0..0])
}
entries.each do |f| entries.each do |f|
if File.directory?(File.join(base, f)) if f == '_posts'
read_posts(File.join(base, f))
elsif File.directory?(File.join(base, f))
next if self.dest.sub(/\/$/, '') == File.join(base, f) next if self.dest.sub(/\/$/, '') == File.join(base, f)
transform_pages(File.join(dir, f)) transform_pages(File.join(dir, f))
else else
@ -111,7 +113,17 @@ module Jekyll
# #
# Returns {"site" => {"time" => <Time>, "posts" => [<Post>]}} # Returns {"site" => {"time" => <Time>, "posts" => [<Post>]}}
def site_payload def site_payload
{"site" => {"time" => Time.now, "posts" => self.posts.sort.reverse}} # 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 }
self.posts.each { |p| p.categories.each { |c| categories[c] << p } }
categories.values.map { |cats| cats.sort! { |a,b| b <=> a} }
{"site" => {
"time" => Time.now,
"posts" => self.posts.sort { |a,b| b <=> a },
"categories" => categories
}}
end end
end end

View File

@ -81,7 +81,7 @@ class TestPost < Test::Unit::TestCase
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")} layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.add_layout(layouts, {"site" => {"posts" => []}}) p.add_layout(layouts, {"site" => {"posts" => []}})
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 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
end end
def test_include def test_include

View File

@ -15,9 +15,9 @@ class TestSite < Test::Unit::TestCase
assert_equal ["default", "simple"].sort, @s.layouts.keys.sort assert_equal ["default", "simple"].sort, @s.layouts.keys.sort
end end
def test_read_posts def test_read_posts
@s.read_posts @s.read_posts(File.join(@s.source, '_posts'))
assert_equal 3, @s.posts.size assert_equal 3, @s.posts.size
end end