diff --git a/History.txt b/History.txt index e4b7dacf..395d8e71 100644 --- a/History.txt +++ b/History.txt @@ -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 diff --git a/README.textile b/README.textile index c07e6f67..6459aa1f 100644 --- a/README.textile +++ b/README.textile @@ -53,12 +53,11 @@ filename is used to construct the URL in the generated site. The example post, for instance, ends up at http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html. -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 diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index 76f3cf85..53bcbb22 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -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 - 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 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 diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index f511fba7..bbd73391 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -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, diff --git a/test/test_post.rb b/test/test_post.rb index d7e8eed8..01e1dd8b 100644 --- a/test/test_post.rb +++ b/test/test_post.rb @@ -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 "<<<

url: /test/source/2008/11/21/complex.html
\ndate: #{Time.parse("2008-11-21")}
\nid: /test/source/2008/11/21/complex

>>>", p.output + assert_equal "<<<

url: /2008/11/21/complex.html
\ndate: #{Time.parse("2008-11-21")}
\nid: /2008/11/21/complex

>>>", 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" => []}}) diff --git a/test/test_site.rb b/test/test_site.rb index bde6a008..52c1ca83 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -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