diff --git a/features/create_sites.feature b/features/create_sites.feature index d10f1625..4f5385b0 100644 --- a/features/create_sites.feature +++ b/features/create_sites.feature @@ -29,7 +29,7 @@ Feature: Create sites Scenario: Basic site with layout and a post Given I have a _layouts directory And I have a _posts directory - And I have the following post: + And I have the following posts: | title | date | layout | content | | Wargames | 3/27/2009 | default | The only winning move is not to play. | And I have a default layout that contains "Post Layout: {{ content }}" @@ -37,6 +37,36 @@ Feature: Create sites Then the _site directory should exist And I should see "Post Layout:

The only winning move is not to play.

" in "_site/2009/03/27/wargames.html" + Scenario: Basic site with layouts, pages, posts and files + Given I have a _layouts directory + And I have a page layout that contains "Page Layout: {{ site.posts.size }}" + And I have a post layout that contains "Post Layout: {{ content }}" + And I have an "index.html" page with layout "page" that contains "site index page" + And I have a blog directory + And I have a "blog/index.html" page with layout "page" that contains "category index page" + And I have an "about.html" file that contains "No replacement {{ site.posts.size }}" + And I have an "another_file" file that contains "" + And I have a _posts directory + And I have the following posts: + | title | date | layout | content | + | entry1 | 3/27/2009 | post | content for entry1. | + | entry2 | 4/27/2009 | post | content for entry2. | + And I have a category/_posts directory + And I have the following posts in "category": + | title | date | layout | content | + | entry3 | 5/27/2009 | post | content for entry3. | + | entry4 | 6/27/2009 | post | content for entry4. | + When I run jekyll + Then the _site directory should exist + And I should see "Page Layout: 4" in "_site/index.html" + And I should see "No replacement \{\{ site.posts.size \}\}" in "_site/about.html" + And I should see "" in "_site/another_file" + And I should see "Page Layout: 4" in "_site/blog/index.html" + And I should see "Post Layout:

content for entry1.

" in "_site/2009/03/27/entry1.html" + And I should see "Post Layout:

content for entry2.

" in "_site/2009/04/27/entry2.html" + And I should see "Post Layout:

content for entry3.

" in "_site/category/2009/05/27/entry3.html" + And I should see "Post Layout:

content for entry4.

" in "_site/category/2009/06/27/entry4.html" + Scenario: Basic site with include tag Given I have a _includes directory And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}" diff --git a/features/pagination.feature b/features/pagination.feature index b52ddcf2..2b1b3467 100644 --- a/features/pagination.feature +++ b/features/pagination.feature @@ -6,35 +6,22 @@ Feature: Site pagination Scenario Outline: Paginate with N posts per page Given I have a configuration file with "paginate" set to "" And I have a _layouts directory - And I have an "index.html" file that contains "Basic Site" + And I have an "index.html" file that contains "{{ paginator.posts.size }}" And I have a _posts directory And I have the following post: | title | date | layout | content | | Wargames | 3/27/2009 | default | The only winning move is not to play. | | Wargames2 | 4/27/2009 | default | The only winning move is not to play2. | - | Wargames3 | 5/27/2009 | default | The only winning move is not to play2. | + | Wargames3 | 5/27/2009 | default | The only winning move is not to play3. | + | Wargames4 | 6/27/2009 | default | The only winning move is not to play4. | When I run jekyll - Then the _site/page2 directory should exist - And the _site/page2/index.html file should exist - + Then the _site/page directory should exist + And the "_site/page/index.html" file should exist + And I should see "" in "_site/page/index.html" + And the "_site/page/index.html" file should not exist + Examples: - | num | - | 1 | - | 2 | - - Scenario: Correct liquid paginator replacements - Given I have a configuration file with "paginate" set to "1" - And I have a _layouts directory - And I have an "index.html" file that contains "{{ paginator.page }}" - And I have a _posts directory - And I have the following post: - | title | date | layout | content | - | Wargames | 3/27/2009 | default | The only winning move is not to play. | - | Wargames2 | 4/27/2009 | default | The only winning move is not to play2. | - When I run jekyll - Then the _site/index.html file should exist - And I should see "1" in "_site/index.html" - Then the _site/page2 directory should exist - And the _site/page2/index.html file should exist - And I should see "2" in "_site/page2/index.html" - \ No newline at end of file + | num | exist | posts | not_exist | + | 1 | 4 | 1 | 5 | + | 2 | 2 | 2 | 3 | + | 3 | 2 | 1 | 3 | diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb index 3bf34736..9fc91013 100644 --- a/features/step_definitions/jekyll_steps.rb +++ b/features/step_definitions/jekyll_steps.rb @@ -13,7 +13,7 @@ Given /^I have a blank site in "(.*)"$/ do |path| end # Like "I have a foo file" but gives a yaml front matter so jekyll actually processes it -Given /^I have an "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$/ do |file, key, value, text| +Given /^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$/ do |file, key, value, text| File.open(file, 'w') do |f| f.write </_layouts into memory for later use. + def read + self.read_layouts # existing implementation did this at top level only so preserved that + self.read_directories + end + + # Read all the files in //_layouts and create a new Layout + # object with each one. # # Returns nothing - def read_layouts - base = File.join(self.source, "_layouts") + def read_layouts(dir = '') + base = File.join(self.source, dir, "_layouts") + return unless File.exists?(base) entries = [] Dir.chdir(base) { entries = filter_entries(Dir['*.*']) } @@ -109,17 +119,16 @@ module Jekyll name = f.split(".")[0..-2].join(".") self.layouts[name] = Layout.new(self, base, f) end - rescue Errno::ENOENT => e - # ignore missing layout dir end - # Read all the files in /_posts and create a new Post object with each one. + # Read all the files in //_posts and create a new Post + # object with each one. # # Returns nothing def read_posts(dir) base = File.join(self.source, dir, '_posts') - entries = [] - Dir.chdir(base) { entries = filter_entries(Dir['**/*']) } + return unless File.exists?(base) + entries = Dir.chdir(base) { filter_entries(Dir['**/*']) } # first pass processes, but does not yet render post content entries.each do |f| @@ -135,10 +144,11 @@ module Jekyll end self.posts.sort! + end - # second pass renders each post now that full site payload is available - self.posts.each do |post| - post.render(self.layouts, site_payload) + def render + [self.posts, self.pages].flatten.each do |convertible| + convertible.render(self.layouts, site_payload) end self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} } @@ -147,55 +157,50 @@ module Jekyll # ignore missing layout dir end - # Write each post to //// + # Write static files, pages and posts # # Returns nothing - def write_posts + def write self.posts.each do |post| post.write(self.dest) end + self.pages.each do |page| + page.write(self.dest) + end + self.static_files.each do |sf| + sf.write(self.dest) + end end - # Copy all regular files from to / ignoring - # any files/directories that are hidden or backup files (start - # with "." or "#" or end with "~") or contain site content (start with "_") - # unless they are "_posts" directories or web server files such as - # '.htaccess' + # Reads the directories and finds posts, pages and static files that will + # become part of the valid site according to the rules in +filter_entries+. # The +dir+ String is a relative path used to call this method # recursively as it descends through directories # # Returns nothing - def transform_pages(dir = '') + def read_directories(dir = '') base = File.join(self.source, dir) entries = filter_entries(Dir.entries(base)) - directories = entries.select { |e| File.directory?(File.join(base, e)) } - files = entries.reject { |e| File.directory?(File.join(base, e)) || File.symlink?(File.join(base, e)) } - # we need to make sure to process _posts *first* otherwise they - # might not be available yet to other templates as {{ site.posts }} - if directories.include?('_posts') - directories.delete('_posts') - read_posts(dir) - end + self.read_posts(dir) - [directories, files].each do |entries| - entries.each do |f| - if File.directory?(File.join(base, f)) - next if self.dest.sub(/\/$/, '') == File.join(base, f) - transform_pages(File.join(dir, f)) - elsif Pager.pagination_enabled?(self.config, f) + entries.each do |f| + f_abs = File.join(base, f) + f_rel = File.join(dir, f) + if File.directory?(f_abs) + next if self.dest.sub(/\/$/, '') == f_abs + read_directories(f_rel) + elsif !File.symlink?(f_abs) + if Pager.pagination_enabled?(self.config, f) paginate_posts(f, dir) else - first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) } + first3 = File.open(f_abs) { |fd| fd.read(3) } if first3 == "---" # file appears to have a YAML header so process it as a page - page = Page.new(self, self.source, dir, f) - page.render(self.layouts, site_payload) - page.write(self.dest) + pages << Page.new(self, self.source, dir, f) else - # otherwise copy the file without transforming it - FileUtils.mkdir_p(File.join(self.dest, dir)) - FileUtils.cp(File.join(self.source, dir, f), File.join(self.dest, dir, f)) + # otherwise treat it as a static file + static_files << StaticFile.new(self, self.source, dir, f) end end end @@ -228,19 +233,19 @@ module Jekyll end # Filter out any files/directories that are hidden or backup files (start - # with "." or "#" or end with "~") or contain site content (start with "_") - # unless they are "_posts" directories or web server files such as - # '.htaccess' + # with "." or "#" or end with "~"), or contain site content (start with "_"), + # or are excluded in the site configuration, unless they are web server + # files such as '.htaccess' def filter_entries(entries) entries = entries.reject do |e| - unless ['_posts', '.htaccess'].include?(e) + unless ['.htaccess'].include?(e) ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e) end end end # Paginates the blog's posts. Renders the index.html file into paginated directories, ie: page2, page3... - # and adds more wite-wide data + # and adds more site-wide data # # {"paginator" => { "page" => , # "per_page" => , @@ -252,7 +257,6 @@ module Jekyll def paginate_posts(file, dir) all_posts = self.posts.sort { |a,b| b <=> a } pages = Pager.calculate_pages(all_posts, self.config['paginate'].to_i) - pages += 1 (1..pages).each do |num_page| pager = Pager.new(self.config, num_page, all_posts, pages) page = Page.new(self, self.source, dir, file) diff --git a/lib/jekyll/static_file.rb b/lib/jekyll/static_file.rb new file mode 100644 index 00000000..7dfd6b97 --- /dev/null +++ b/lib/jekyll/static_file.rb @@ -0,0 +1,28 @@ +module Jekyll + + class StaticFile + # Initialize a new StaticFile. + # +site+ is the Site + # +base+ is the String path to the + # +dir+ is the String path between and the file + # +name+ is the String filename of the file + # + # Returns + def initialize(site, base, dir, name) + @site = site + @base = base + @dir = dir + @name = name + end + + # Write the static file to the destination directory. + # +dest+ is the String path to the destination dir + # + # Returns nothing + def write(dest) + FileUtils.mkdir_p(File.join(dest, @dir)) + FileUtils.cp(File.join(@base, @dir, @name), File.join(dest, @dir, @name)) + end + end + +end diff --git a/test/test_generated_site.rb b/test/test_generated_site.rb index 45b2cc84..fe9878e9 100644 --- a/test/test_generated_site.rb +++ b/test/test_generated_site.rb @@ -13,6 +13,10 @@ class TestGeneratedSite < Test::Unit::TestCase @index = File.read(dest_dir('index.html')) end + should "ensure post count is as expected" do + assert_equal 17, @site.posts.size + end + should "insert site.posts into the index" do assert @index.include?("#{@site.posts.size} Posts") end diff --git a/test/test_pager.rb b/test/test_pager.rb index 34ffc164..ffd1aa97 100644 --- a/test/test_pager.rb +++ b/test/test_pager.rb @@ -1,11 +1,38 @@ require File.dirname(__FILE__) + '/helper' class TestPager < Test::Unit::TestCase - context "pagination enabled" do + + should "calculate number of pages" do + assert_equal(0, Pager.calculate_pages([], '2')) + assert_equal(1, Pager.calculate_pages([1], '2')) + assert_equal(1, Pager.calculate_pages([1,2], '2')) + assert_equal(2, Pager.calculate_pages([1,2,3], '2')) + assert_equal(2, Pager.calculate_pages([1,2,3,4], '2')) + assert_equal(3, Pager.calculate_pages([1,2,3,4,5], '2')) + end + + context "pagination disabled" do setup do stub(Jekyll).configuration do Jekyll::DEFAULTS.merge({ - 'source' => source_dir, + 'source' => source_dir, + 'destination' => dest_dir + }) + end + @config = Jekyll.configuration + end + + should "report that pagination is disabled" do + assert !Pager.pagination_enabled?(@config, 'index.html') + end + + end + + context "pagination enabled for 2" do + setup do + stub(Jekyll).configuration do + Jekyll::DEFAULTS.merge({ + 'source' => source_dir, 'destination' => dest_dir, 'paginate' => 2 }) @@ -13,35 +40,74 @@ class TestPager < Test::Unit::TestCase @config = Jekyll.configuration @site = Site.new(@config) - @posts = @site.read_posts('') + @site.process + @posts = @site.posts end - should "calculate number of pages" do - assert_equal(2, Pager.calculate_pages(@posts, @config['paginate'])) - end - - should "create first pager" do - pager = Pager.new(@config, 1, @posts) - assert_equal(@config['paginate'].to_i, pager.posts.size) - assert_equal(2, pager.total_pages) - assert_nil(pager.previous_page) - assert_equal(2, pager.next_page) - end - - should "create second pager" do - pager = Pager.new(@config, 2, @posts) - assert_equal(@posts.size - @config['paginate'].to_i, pager.posts.size) - assert_equal(2, pager.total_pages) - assert_equal(1, pager.previous_page) - assert_nil(pager.next_page) - end - - should "not create third pager" do - assert_raise(RuntimeError) { Pager.new(@config, 3, @posts) } - end - should "report that pagination is enabled" do assert Pager.pagination_enabled?(@config, 'index.html') end + + context "with 4 posts" do + setup do + @posts = @site.posts[1..4] # limit to 4 + end + + should "create first pager" do + pager = Pager.new(@config, 1, @posts) + assert_equal(2, pager.posts.size) + assert_equal(2, pager.total_pages) + assert_nil(pager.previous_page) + assert_equal(2, pager.next_page) + end + + should "create second pager" do + pager = Pager.new(@config, 2, @posts) + assert_equal(2, pager.posts.size) + assert_equal(2, pager.total_pages) + assert_equal(1, pager.previous_page) + assert_nil(pager.next_page) + end + + should "not create third pager" do + assert_raise(RuntimeError) { Pager.new(@config, 3, @posts) } + end + + end + + context "with 5 posts" do + setup do + @posts = @site.posts[1..5] # limit to 5 + end + + should "create first pager" do + pager = Pager.new(@config, 1, @posts) + assert_equal(2, pager.posts.size) + assert_equal(3, pager.total_pages) + assert_nil(pager.previous_page) + assert_equal(2, pager.next_page) + end + + should "create second pager" do + pager = Pager.new(@config, 2, @posts) + assert_equal(2, pager.posts.size) + assert_equal(3, pager.total_pages) + assert_equal(1, pager.previous_page) + assert_equal(3, pager.next_page) + end + + should "create third pager" do + pager = Pager.new(@config, 3, @posts) + assert_equal(1, pager.posts.size) + assert_equal(3, pager.total_pages) + assert_equal(2, pager.previous_page) + assert_nil(pager.next_page) + end + + should "not create fourth pager" do + assert_raise(RuntimeError) { Pager.new(@config, 4, @posts) } + end + + end end end diff --git a/test/test_site.rb b/test/test_site.rb index f2202c8b..b92bc496 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -19,11 +19,17 @@ class TestSite < Test::Unit::TestCase before_posts = @site.posts.length before_layouts = @site.layouts.length before_categories = @site.categories.length + before_tags = @site.tags.length + before_pages = @site.pages.length + before_static_files = @site.static_files.length @site.process assert_equal before_posts, @site.posts.length assert_equal before_layouts, @site.layouts.length assert_equal before_categories, @site.categories.length + assert_equal before_tags, @site.tags.length + assert_equal before_pages, @site.pages.length + assert_equal before_static_files, @site.static_files.length end should "read layouts" do @@ -52,10 +58,10 @@ class TestSite < Test::Unit::TestCase should "filter entries" do ent1 = %w[foo.markdown bar.markdown baz.markdown #baz.markdown# .baz.markdow foo.markdown~] - ent2 = %w[.htaccess _posts bla.bla] + ent2 = %w[.htaccess _posts _pages bla.bla] assert_equal %w[foo.markdown bar.markdown baz.markdown], @site.filter_entries(ent1) - assert_equal ent2, @site.filter_entries(ent2) + assert_equal %w[.htaccess bla.bla], @site.filter_entries(ent2) end should "filter entries with exclude" do