diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 8a27e161..cbf7c446 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -26,6 +26,7 @@ require 'jekyll/filters' require 'jekyll/tags/highlight' require 'jekyll/tags/include' require 'jekyll/albino' +require 'jekyll/static_file' module Jekyll # Default options. Overriden by values in _config.yml or command-line opts. diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 18b6664d..3d47d16e 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -1,7 +1,7 @@ module Jekyll class Site - attr_accessor :config, :layouts, :posts, :categories, :exclude, + attr_accessor :config, :layouts, :posts, :pages, :static_files, :categories, :exclude, :source, :dest, :lsi, :pygments, :permalink_style, :tags # Initialize the site @@ -25,6 +25,8 @@ module Jekyll def reset self.layouts = {} self.posts = [] + self.pages = [] + self.static_files = [] self.categories = Hash.new { |hash, key| hash[key] = [] } self.tags = Hash.new { |hash, key| hash[key] = [] } end @@ -87,21 +89,29 @@ module Jekyll end # Do the actual work of processing the site and generating the - # real deal. + # real deal. Now has 4 phases; reset, read, render, write. This allows + # rendering to have full site payload available. # # Returns nothing def process self.reset - self.read_layouts - self.transform_pages - self.write_posts + self.read + self.render + self.write end - # Read all the files in /_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" => , 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_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