More TomDoc and formatting cleanup.

This commit is contained in:
Tom Preston-Werner 2011-05-08 23:40:35 -07:00
parent aa0d82fa96
commit 82bd83fe7f
5 changed files with 163 additions and 100 deletions

View File

@ -94,8 +94,8 @@ module Jekyll
}
}
# Generate a Jekyll configuration Hash by merging the default options
# with anything in _config.yml, and adding the given options on top.
# Public: Generate a Jekyll configuration Hash by merging the default
# options with anything in _config.yml, and adding the given options on top.
#
# override - A Hash of config directives that override any options in both
# the defaults and the config file. See Jekyll::DEFAULTS for a

View File

@ -1,8 +1,14 @@
module Jekyll
class Pagination < Generator
# This generator is safe from arbitrary code execution.
safe true
# Generate paginated pages if necessary.
#
# site - The Site.
#
# Returns nothing.
def generate(site)
site.pages.dup.each do |page|
paginate(site, page) if Pager.pagination_enabled?(site.config, page.name)
@ -10,9 +16,11 @@ module Jekyll
end
# Paginates the blog's posts. Renders the index.html file into paginated
# directories, ie: page2/index.html, page3/index.html, etc and adds more
# directories, e.g.: page2/index.html, page3/index.html, etc and adds more
# site-wide data.
# +page+ is the index.html Page that requires pagination
#
# site - The Site.
# page - The index.html Page that requires pagination.
#
# {"paginator" => { "page" => <Number>,
# "per_page" => <Number>,
@ -36,22 +44,40 @@ module Jekyll
end
end
end
end
class Pager
attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page
# Calculate the number of pages.
#
# all_posts - The Array of all Posts.
# per_page - The Integer of entries per page.
#
# Returns the Integer number of pages.
def self.calculate_pages(all_posts, per_page)
num_pages = all_posts.size / per_page.to_i
num_pages = num_pages + 1 if all_posts.size % per_page.to_i != 0
num_pages
end
# Determine if pagination is enabled for a given file.
#
# config - The configuration Hash.
# file - The String filename of the file.
#
# Returns true if pagination is enabled, false otherwise.
def self.pagination_enabled?(config, file)
file == 'index.html' && !config['paginate'].nil?
end
# Initialize a new Pager.
#
# config - The Hash configuration of the site.
# page - The Integer page number.
# all_posts - The Array of all the site's Posts.
# num_pages - The Integer number of pages or nil if you'd like the number
# of pages calculated.
def initialize(config, page, all_posts, num_pages = nil)
@page = page
@per_page = config['paginate'].to_i
@ -70,6 +96,9 @@ module Jekyll
@next_page = @page != @total_pages ? @page + 1 : nil
end
# Convert this Pager's data to a Hash suitable for use by Liquid.
#
# Returns the Hash representation of this Pager.
def to_liquid
{
'page' => page,
@ -83,5 +112,4 @@ module Jekyll
end
end
end

View File

@ -9,10 +9,9 @@ module Jekyll
attr_accessor :converters, :generators
# Initialize the site
# +config+ is a Hash containing site configurations details
# Public: Initialize a new Site.
#
# Returns <Site>
# config - A Hash containing site configuration details.
def initialize(config)
self.config = config.clone
@ -31,6 +30,21 @@ module Jekyll
self.setup
end
# Public: Read, process, and write this Site to output.
#
# Returns nothing.
def process
self.reset
self.read
self.generate
self.render
self.cleanup
self.write
end
# Reset Site details.
#
# Returns nothing
def reset
self.time = if self.config['time']
Time.parse(self.config['time'].to_s)
@ -44,13 +58,18 @@ module Jekyll
self.categories = Hash.new { |hash, key| hash[key] = [] }
self.tags = Hash.new { |hash, key| hash[key] = [] }
raise ArgumentError, "Limit posts must be nil or >= 1" if !self.limit_posts.nil? && self.limit_posts < 1
if !self.limit_posts.nil? && self.limit_posts < 1
raise ArgumentError, "Limit posts must be nil or >= 1"
end
end
# Load necessary libraries, plugins, converters, and generators.
#
# Returns nothing.
def setup
require 'classifier' if self.lsi
# If safe mode is off, load in any ruby files under the plugins
# If safe mode is off, load in any Ruby files under the plugins
# directory.
unless self.safe
Dir[File.join(self.plugins, "**/*.rb")].each do |f|
@ -71,29 +90,18 @@ module Jekyll
end
end
# Do the actual work of processing the site and generating the
# real deal. 5 phases; reset, read, generate, render, write. This allows
# rendering to have full site payload available.
# Read Site data from disk and load it into internal data structures.
#
# Returns nothing
def process
self.reset
self.read
self.generate
self.render
self.cleanup
self.write
end
# Returns nothing.
def read
self.read_layouts # existing implementation did this at top level only so preserved that
self.read_layouts
self.read_directories
end
# Read all the files in <source>/<dir>/_layouts and create a new Layout
# object with each one.
#
# Returns nothing
# Returns nothing.
def read_layouts(dir = '')
base = File.join(self.source, dir, "_layouts")
return unless File.exists?(base)
@ -106,10 +114,44 @@ module Jekyll
end
end
# Recursively traverse directories to find posts, pages and static files
# that will become part of the site according to the rules in
# filter_entries.
#
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_directories(dir = '')
base = File.join(self.source, dir)
entries = Dir.chdir(base) { filter_entries(Dir['*']) }
self.read_posts(dir)
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)
first3 = File.open(f_abs) { |fd| fd.read(3) }
if first3 == "---"
# file appears to have a YAML header so process it as a page
pages << Page.new(self, self.source, dir, f)
else
# otherwise treat it as a static file
static_files << StaticFile.new(self, self.source, dir, f)
end
end
end
end
# Read all the files in <source>/<dir>/_posts and create a new Post
# object with each one.
#
# Returns nothing
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_posts(dir)
base = File.join(self.source, dir, '_posts')
return unless File.exists?(base)
@ -134,12 +176,18 @@ module Jekyll
self.posts = self.posts[-limit_posts, limit_posts] if limit_posts
end
# Run each of the Generators.
#
# Returns nothing.
def generate
self.generators.each do |generator|
generator.generate(self)
end
end
# Render the site to the destination.
#
# Returns nothing.
def render
self.posts.each do |post|
post.render(self.layouts, site_payload)
@ -149,15 +197,15 @@ module Jekyll
page.render(self.layouts, site_payload)
end
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } }
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a } }
rescue Errno::ENOENT => e
# ignore missing layout dir
end
# Remove orphaned files and empty directories in destination
# Remove orphaned files and empty directories in destination.
#
# Returns nothing
# Returns nothing.
def cleanup
# all files and directories in destination, including hidden ones
dest_files = Set.new
@ -187,9 +235,9 @@ module Jekyll
FileUtils.rm_rf(obsolete_files.to_a)
end
# Write static files, pages and posts
# Write static files, pages, and posts.
#
# Returns nothing
# Returns nothing.
def write
self.posts.each do |post|
post.write(self.dest)
@ -202,59 +250,45 @@ module Jekyll
end
end
# 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
# Constructs a Hash of Posts indexed by the specified Post attribute.
#
# Returns nothing
def read_directories(dir = '')
base = File.join(self.source, dir)
entries = Dir.chdir(base){ filter_entries(Dir['*']) }
self.read_posts(dir)
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)
first3 = File.open(f_abs) { |fd| fd.read(3) }
if first3 == "---"
# file appears to have a YAML header so process it as a page
pages << Page.new(self, self.source, dir, f)
else
# otherwise treat it as a static file
static_files << StaticFile.new(self, self.source, dir, f)
end
end
end
end
# Constructs a hash map of Posts indexed by the specified Post attribute
# post_attr - The String name of the Post attribute.
#
# Returns {post_attr => [<Post>]}
# Examples
#
# post_attr_hash('categories')
# # => { 'tech' => [<Post A>, <Post B>],
# # 'ruby' => [<Post B>] }
#
# Returns the Hash: { attr => posts } where
# attr - One of the values for the requested attribute.
# posts - The Array of Posts with the given attr value.
def post_attr_hash(post_attr)
# Build a hash map based on the specified post attribute ( post attr => array of posts )
# then sort each array in reverse order
# Build a hash map based on the specified post attribute ( post attr =>
# array of posts ) then sort each array in reverse order.
hash = Hash.new { |hash, key| hash[key] = Array.new }
self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
return hash
hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a } }
hash
end
# The Hash payload containing site-wide data
# The Hash payload containing site-wide data.
#
# Returns {"site" => {"time" => <Time>,
# "posts" => [<Post>],
# "pages" => [<Page>],
# "categories" => [<Post>]}
# Returns the Hash: { "site" => data } where data is a Hash with keys:
# "time" - The Time as specified in the configuration or the
# current time if none was specified.
# "posts" - The Array of Posts, sorted chronologically by post date
# and then title.
# "pages" - The Array of all Pages.
# "html_pages" - The Array of HTML Pages.
# "categories" - The Hash of category values and Posts.
# See Site#post_attr_hash for type info.
# "tags" - The Hash of tag values and Posts.
# See Site#post_attr_hash for type info.
def site_payload
{"site" => self.config.merge({
"time" => self.time,
"posts" => self.posts.sort { |a,b| b <=> a },
"posts" => self.posts.sort { |a, b| b <=> a },
"pages" => self.pages,
"html_pages" => self.pages.reject { |page| !page.html? },
"categories" => post_attr_hash('categories'),
@ -264,7 +298,11 @@ module Jekyll
# Filter out any files/directories that are hidden or backup files (start
# 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'
# files such as '.htaccess'.
#
# entries - The Array of file/directory entries to filter.
#
# Returns the Array of filtered entries.
def filter_entries(entries)
entries = entries.reject do |e|
unless ['.htaccess'].include?(e)

View File

@ -1,15 +1,15 @@
module Jekyll
class StaticFile
@@mtimes = Hash.new # the cache of last modification times [path] -> mtime
# The cache of last modification times [path] -> mtime.
@@mtimes = Hash.new
# Initialize a new StaticFile.
# +site+ is the Site
# +base+ is the String path to the <source>
# +dir+ is the String path between <source> and the file
# +name+ is the String filename of the file
#
# Returns <StaticFile>
# site - The Site.
# base - The String path to the <source>.
# dir - The String path between <source> and the file.
# name - The String filename of the file.
def initialize(site, base, dir, name)
@site = site
@base = base
@ -17,24 +17,21 @@ module Jekyll
@name = name
end
# Obtains source file path.
#
# Returns source file path.
def path
File.join(@base, @dir, @name)
end
# Obtain destination path.
# +dest+ is the String path to the destination dir
#
# dest - The String path to the destination dir.
#
# Returns destination file path.
def destination(dest)
File.join(dest, @dir, @name)
end
# Obtain mtime of the source path.
#
# Returns last modifiaction time for this file.
# Returns last modification time for this file.
def mtime
File.stat(path).mtime.to_i
end
@ -47,13 +44,14 @@ module Jekyll
end
# Write the static file to the destination directory (if modified).
# +dest+ is the String path to the destination dir
#
# dest - The String path to the destination dir.
#
# Returns false if the file was not modified since last time (no-op).
def write(dest)
dest_path = destination(dest)
return false if File.exist? dest_path and !modified?
return false if File.exist?(dest_path) and !modified?
@@mtimes[path] = mtime
FileUtils.mkdir_p(File.dirname(dest_path))
@ -67,7 +65,6 @@ module Jekyll
# Returns nothing.
def self.reset_cache
@@mtimes = Hash.new
nil
end
end

View File

@ -3,7 +3,7 @@ module Jekyll
class HighlightBlock < Liquid::Block
include Liquid::StandardFilters
# we need a language, but the linenos argument is optional.
# We need a language, but the linenos argument is optional.
SYNTAX = /(\w+)\s?([\w\s=]+)*/
def initialize(tag_name, markup, tokens)
@ -24,7 +24,7 @@ module Jekyll
tmp_options[key] = value
end
tmp_options = tmp_options.to_a.collect { |opt| opt.join('=') }
# additional options to pass to Albino.
# additional options to pass to Albino
@options = { 'O' => tmp_options.join(',') }
else
@options = {}
@ -50,7 +50,7 @@ module Jekyll
end
def render_codehighlighter(context, code)
#The div is required because RDiscount blows ass
#The div is required because RDiscount blows ass
<<-HTML
<div>
<pre>