mirror of
https://github.com/jekyll/jekyll.git
synced 2026-04-28 03:01:03 -04:00
merge lastest from mojombo/jekyll master
This commit is contained in:
@@ -46,47 +46,50 @@ require_all 'jekyll/generators'
|
||||
require_all 'jekyll/tags'
|
||||
|
||||
module Jekyll
|
||||
VERSION = '0.11.2'
|
||||
VERSION = '0.12.0'
|
||||
|
||||
# Default options. Overriden by values in _config.yml or command-line opts.
|
||||
# (Strings rather symbols used for compatability with YAML).
|
||||
# Strings rather than symbols are used for compatability with YAML.
|
||||
DEFAULTS = {
|
||||
'safe' => false,
|
||||
'auto' => false,
|
||||
'server' => false,
|
||||
'server_port' => 4000,
|
||||
|
||||
'source' => Dir.pwd,
|
||||
'destination' => File.join(Dir.pwd, '_site'),
|
||||
'plugins' => File.join(Dir.pwd, '_plugins'),
|
||||
'source' => Dir.pwd,
|
||||
'destination' => File.join(Dir.pwd, '_site'),
|
||||
'plugins' => File.join(Dir.pwd, '_plugins'),
|
||||
'layouts' => '_layouts',
|
||||
'keep_files' => ['.git','.svn'],
|
||||
'layouts' => '_layouts',
|
||||
|
||||
'future' => true,
|
||||
'lsi' => false,
|
||||
'pygments' => false,
|
||||
'markdown' => 'maruku',
|
||||
'permalink' => 'date',
|
||||
'include' => ['.htaccess'],
|
||||
'future' => true,
|
||||
'lsi' => false,
|
||||
'pygments' => false,
|
||||
'markdown' => 'maruku',
|
||||
'permalink' => 'date',
|
||||
'include' => ['.htaccess'],
|
||||
'paginate_path' => 'page:num',
|
||||
|
||||
'markdown_ext' => 'markdown,mkd,mkdn,md',
|
||||
'textile_ext' => 'textile',
|
||||
'markdown_ext' => 'markdown,mkd,mkdn,md',
|
||||
'textile_ext' => 'textile',
|
||||
|
||||
'maruku' => {
|
||||
'maruku' => {
|
||||
'use_tex' => false,
|
||||
'use_divs' => false,
|
||||
'png_engine' => 'blahtex',
|
||||
'png_dir' => 'images/latex',
|
||||
'png_url' => '/images/latex'
|
||||
},
|
||||
'rdiscount' => {
|
||||
|
||||
'rdiscount' => {
|
||||
'extensions' => []
|
||||
},
|
||||
'redcarpet' => {
|
||||
|
||||
'redcarpet' => {
|
||||
'extensions' => []
|
||||
},
|
||||
'kramdown' => {
|
||||
|
||||
'kramdown' => {
|
||||
'auto_ids' => true,
|
||||
'footnote_nr' => 1,
|
||||
'entity_output' => 'as_char',
|
||||
@@ -103,8 +106,9 @@ module Jekyll
|
||||
'coderay_css' => 'style'
|
||||
}
|
||||
},
|
||||
'redcloth' => {
|
||||
'hard_breaks' => true
|
||||
|
||||
'redcloth' => {
|
||||
'hard_breaks' => true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,28 @@ module Jekyll
|
||||
|
||||
def setup
|
||||
return if @setup
|
||||
# Set the Markdown interpreter (and Maruku self.config, if necessary)
|
||||
case @config['markdown']
|
||||
when 'redcarpet'
|
||||
begin
|
||||
require 'redcarpet'
|
||||
@redcarpet_extensions = @config['redcarpet']['extensions'].map { |e| e.to_sym }
|
||||
|
||||
@renderer ||= Class.new(Redcarpet::Render::HTML) do
|
||||
def block_code(code, lang)
|
||||
lang = lang && lang.split.first || "text"
|
||||
output = add_code_tags(
|
||||
Pygments.highlight(code, :lexer => lang, :options => { :encoding => 'utf-8' }),
|
||||
lang
|
||||
)
|
||||
end
|
||||
|
||||
def add_code_tags(code, lang)
|
||||
code = code.sub(/<pre>/,'<pre><code class="' + lang + '">')
|
||||
code = code.sub(/<\/pre>/,"</code></pre>")
|
||||
end
|
||||
end
|
||||
|
||||
@redcarpet_extensions = {}
|
||||
@config['redcarpet']['extensions'].each { |e| @redcarpet_extensions[e.to_sym] = true }
|
||||
rescue LoadError
|
||||
STDERR.puts 'You are missing a library required for Markdown. Please run:'
|
||||
STDERR.puts ' $ [sudo] gem install redcarpet'
|
||||
@@ -30,8 +46,6 @@ module Jekyll
|
||||
when 'rdiscount'
|
||||
begin
|
||||
require 'rdiscount'
|
||||
|
||||
# Load rdiscount extensions
|
||||
@rdiscount_extensions = @config['rdiscount']['extensions'].map { |e| e.to_sym }
|
||||
rescue LoadError
|
||||
STDERR.puts 'You are missing a library required for Markdown. Please run:'
|
||||
@@ -88,7 +102,10 @@ module Jekyll
|
||||
setup
|
||||
case @config['markdown']
|
||||
when 'redcarpet'
|
||||
Redcarpet.new(content, *@redcarpet_extensions).to_html
|
||||
@redcarpet_extensions[:fenced_code_blocks] = !@redcarpet_extensions[:no_fenced_code_blocks]
|
||||
@renderer.send :include, Redcarpet::Render::SmartyPants if @redcarpet_extensions[:smart]
|
||||
markdown = Redcarpet::Markdown.new(@renderer.new(@redcarpet_extensions), @redcarpet_extensions)
|
||||
markdown.render(content)
|
||||
when 'kramdown'
|
||||
# Check for use of coderay
|
||||
if @config['kramdown']['use_coderay']
|
||||
|
||||
@@ -25,15 +25,17 @@ module Jekyll
|
||||
#
|
||||
# Returns nothing.
|
||||
def read_yaml(base, name)
|
||||
self.content = File.read(File.join(base, name))
|
||||
|
||||
begin
|
||||
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
||||
self.content = File.read(File.join(base, name))
|
||||
|
||||
if self.content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
||||
self.content = $POSTMATCH
|
||||
self.data = YAML.load($1)
|
||||
end
|
||||
rescue => e
|
||||
puts "YAML Exception reading #{name}: #{e.message}"
|
||||
puts "Error reading file #{File.join(base, name)}: #{e.message}"
|
||||
rescue SyntaxError => e
|
||||
puts "YAML Exception reading #{File.join(base, name)}: #{e.message}"
|
||||
end
|
||||
|
||||
self.data ||= {}
|
||||
@@ -76,9 +78,13 @@ module Jekyll
|
||||
payload["pygments_suffix"] = converter.pygments_suffix
|
||||
|
||||
begin
|
||||
self.content = Liquid::Template.parse(self.content).render(payload, info)
|
||||
self.content = Liquid::Template.parse(self.content).render!(payload, info)
|
||||
rescue => e
|
||||
puts "Liquid Exception: #{e.message} in #{self.name}"
|
||||
e.backtrace.each do |backtrace|
|
||||
puts backtrace
|
||||
end
|
||||
abort("Build Failed")
|
||||
end
|
||||
|
||||
self.transform
|
||||
@@ -94,9 +100,13 @@ module Jekyll
|
||||
payload = payload.deep_merge({"content" => self.output, "page" => layout.data})
|
||||
|
||||
begin
|
||||
self.output = Liquid::Template.parse(layout.content).render(payload, info)
|
||||
self.output = Liquid::Template.parse(layout.content).render!(payload, info)
|
||||
rescue => e
|
||||
puts "Liquid Exception: #{e.message} in #{self.data["layout"]}"
|
||||
e.backtrace.each do |backtrace|
|
||||
puts backtrace
|
||||
end
|
||||
abort("Build Failed")
|
||||
end
|
||||
|
||||
if layout = layouts[layout.data["layout"]]
|
||||
|
||||
@@ -57,6 +57,17 @@ module Jekyll
|
||||
date.xmlschema
|
||||
end
|
||||
|
||||
# XML escape a string for use. Replaces any special characters with
|
||||
# appropriate HTML entity replacements.
|
||||
#
|
||||
# input - The String to escape.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# xml_escape('foo "bar" <baz>')
|
||||
# # => "foo "bar" <baz>"
|
||||
#
|
||||
# Returns the escaped String.
|
||||
def xml_escape(input)
|
||||
CGI.escapeHTML(input)
|
||||
end
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
require 'rubygems'
|
||||
require 'jekyll'
|
||||
require 'fileutils'
|
||||
require 'net/http'
|
||||
require 'net/https'
|
||||
require 'open-uri'
|
||||
require 'uri'
|
||||
require "json"
|
||||
|
||||
# ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, api_key, blog)'
|
||||
# ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, api_token, blog, tags_key)'
|
||||
# You can find your api token in posterous api page - http://posterous.com/api . Click on any of the 'view token' links to see your token.
|
||||
# blog is optional, by default it is the primary one
|
||||
|
||||
module Jekyll
|
||||
module Posterous
|
||||
@@ -14,6 +17,9 @@ module Jekyll
|
||||
raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0
|
||||
|
||||
response = nil
|
||||
|
||||
puts uri_str
|
||||
puts '-------'
|
||||
Net::HTTP.start('posterous.com') do |http|
|
||||
req = Net::HTTP::Get.new(uri_str)
|
||||
req.basic_auth @email, @pass
|
||||
@@ -23,36 +29,50 @@ module Jekyll
|
||||
case response
|
||||
when Net::HTTPSuccess then response
|
||||
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
||||
when Net::HTTPForbidden then
|
||||
retry_after = response.to_hash['retry-after'][0]
|
||||
puts "We have been told to try again after #{retry_after} seconds"
|
||||
sleep(retry_after.to_i + 1)
|
||||
fetch(uri_str, limit - 1)
|
||||
else response.error!
|
||||
end
|
||||
end
|
||||
|
||||
def self.process(email, pass, api_token, blog = 'primary')
|
||||
def self.process(email, pass, api_token, blog = 'primary', tags_key = 'categories')
|
||||
@email, @pass, @api_token = email, pass, api_token
|
||||
FileUtils.mkdir_p "_posts"
|
||||
|
||||
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}").body)
|
||||
posts = JSON.parse(self.fetch("/api/2/sites/#{blog}/posts?api_token=#{@api_token}").body)
|
||||
page = 1
|
||||
|
||||
while posts.any?
|
||||
posts.each do |post|
|
||||
title = post["title"]
|
||||
slug = title.gsub(/[^[:alnum:]]+/, '-').downcase
|
||||
slug = title.gsub(/[^[:alnum:]]+/, '-').gsub(/^-+|-+$/, '').downcase
|
||||
posterous_slug = post["slug"]
|
||||
date = Date.parse(post["display_date"])
|
||||
content = post["body_html"]
|
||||
published = !post["is_private"]
|
||||
name = "%02d-%02d-%02d-%s.html" % [date.year, date.month, date.day, slug]
|
||||
tags = []
|
||||
post["tags"].each do |tag|
|
||||
tags.push(tag["name"])
|
||||
end
|
||||
|
||||
# Get the relevant fields as a hash, delete empty fields and convert
|
||||
# to YAML for the header
|
||||
data = {
|
||||
'layout' => 'post',
|
||||
'title' => title.to_s,
|
||||
'published' => published
|
||||
'published' => published,
|
||||
tags_key => tags,
|
||||
'posterous_url' => post["full_url"],
|
||||
'posterous_slug' => posterous_slug
|
||||
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
|
||||
|
||||
# Write out the data and content to file
|
||||
File.open("_posts/#{name}", "w") do |f|
|
||||
puts name
|
||||
f.puts data
|
||||
f.puts "---"
|
||||
f.puts content
|
||||
@@ -60,7 +80,7 @@ module Jekyll
|
||||
end
|
||||
|
||||
page += 1
|
||||
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body)
|
||||
posts = JSON.parse(self.fetch("/api/2/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,12 +8,13 @@ module Jekyll
|
||||
attr_accessor :lsi
|
||||
end
|
||||
|
||||
# Valid post name regex.
|
||||
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
|
||||
|
||||
# Post name validator. Post filenames must be like:
|
||||
# 2008-11-05-my-awesome-post.textile
|
||||
# 2008-11-05-my-awesome-post.textile
|
||||
#
|
||||
# Returns <Bool>
|
||||
# Returns true if valid, false if not.
|
||||
def self.valid?(name)
|
||||
name =~ MATCHER
|
||||
end
|
||||
@@ -25,12 +26,13 @@ module Jekyll
|
||||
attr_reader :name
|
||||
|
||||
# Initialize this Post instance.
|
||||
# +site+ is the Site
|
||||
# +base+ is the String path to the dir containing 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>
|
||||
# site - The Site.
|
||||
# base - The String path to the dir containing the post file.
|
||||
# name - The String filename of the post file.
|
||||
# categories - An Array of Strings for the categories for this post.
|
||||
#
|
||||
# Returns the new Post.
|
||||
def initialize(site, source, dir, name)
|
||||
@site = site
|
||||
@base = File.join(source, dir, '_posts')
|
||||
@@ -38,10 +40,14 @@ module Jekyll
|
||||
|
||||
self.categories = dir.split('/').reject { |x| x.empty? }
|
||||
self.process(name)
|
||||
self.read_yaml(@base, name)
|
||||
begin
|
||||
self.read_yaml(@base, name)
|
||||
rescue Exception => msg
|
||||
raise FatalException.new("#{msg} in #{@base}/#{name}")
|
||||
end
|
||||
|
||||
#If we've added a date and time to the yaml, use that instead of the filename date
|
||||
#Means we'll sort correctly.
|
||||
# If we've added a date and time to the YAML, use that instead of the
|
||||
# filename date. Means we'll sort correctly.
|
||||
if self.data.has_key?('date')
|
||||
# ensure Time via to_s and reparse
|
||||
self.date = Time.parse(self.data["date"].to_s)
|
||||
@@ -60,7 +66,10 @@ module Jekyll
|
||||
end
|
||||
end
|
||||
|
||||
# Spaceship is based on Post#date, slug
|
||||
# Compares Post objects. First compares the Post date. If the dates are
|
||||
# equal, it compares the Post slugs.
|
||||
#
|
||||
# other - The other Post we are comparing to.
|
||||
#
|
||||
# Returns -1, 0, 1
|
||||
def <=>(other)
|
||||
@@ -71,10 +80,11 @@ module Jekyll
|
||||
return cmp
|
||||
end
|
||||
|
||||
# Extract information from the post filename
|
||||
# +name+ is the String filename of the post file
|
||||
# Extract information from the post filename.
|
||||
#
|
||||
# Returns nothing
|
||||
# name - The String filename of the post file.
|
||||
#
|
||||
# Returns nothing.
|
||||
def process(name)
|
||||
m, cats, date, slug, ext = *name.match(MATCHER)
|
||||
self.date = Time.parse(date)
|
||||
@@ -87,18 +97,17 @@ module Jekyll
|
||||
# The generated directory into which the post will be placed
|
||||
# upon generation. This is derived from the permalink or, if
|
||||
# permalink is absent, set to the default date
|
||||
# e.g. "/2008/11/05/" if the permalink style is :date, otherwise nothing
|
||||
# e.g. "/2008/11/05/" if the permalink style is :date, otherwise nothing.
|
||||
#
|
||||
# Returns <String>
|
||||
# Returns the String directory.
|
||||
def dir
|
||||
File.dirname(url)
|
||||
end
|
||||
|
||||
# The full path and filename of the post.
|
||||
# Defined in the YAML of the post body
|
||||
# (Optional)
|
||||
# The full path and filename of the post. Defined in the YAML of the post
|
||||
# body (optional).
|
||||
#
|
||||
# Returns <String>
|
||||
# Returns the String permalink.
|
||||
def permalink
|
||||
self.data && self.data['permalink']
|
||||
end
|
||||
@@ -116,10 +125,10 @@ module Jekyll
|
||||
end
|
||||
end
|
||||
|
||||
# The generated relative url of this post
|
||||
# The generated relative url of this post.
|
||||
# e.g. /2008/11/05/my-awesome-post.html
|
||||
#
|
||||
# Returns <String>
|
||||
# Returns the String URL.
|
||||
def url
|
||||
return @url if @url
|
||||
|
||||
@@ -146,17 +155,17 @@ module Jekyll
|
||||
@url
|
||||
end
|
||||
|
||||
# The UID for this post (useful in feeds)
|
||||
# The UID for this post (useful in feeds).
|
||||
# e.g. /2008/11/05/my-awesome-post
|
||||
#
|
||||
# Returns <String>
|
||||
# Returns the String UID.
|
||||
def id
|
||||
File.join(self.dir, self.slug)
|
||||
end
|
||||
|
||||
# Calculate related posts.
|
||||
#
|
||||
# Returns [<Post>]
|
||||
# Returns an Array of related Posts.
|
||||
def related_posts(posts)
|
||||
return [] unless posts.size > 1
|
||||
|
||||
@@ -176,11 +185,12 @@ module Jekyll
|
||||
end
|
||||
end
|
||||
|
||||
# Add any necessary layouts to this post
|
||||
# +layouts+ is a Hash of {"name" => "layout"}
|
||||
# +site_payload+ is the site payload hash
|
||||
# Add any necessary layouts to this post.
|
||||
#
|
||||
# Returns nothing
|
||||
# layouts - A Hash of {"name" => "layout"}.
|
||||
# site_payload - The site payload hash.
|
||||
#
|
||||
# Returns nothing.
|
||||
def render(layouts, site_payload)
|
||||
# construct payload
|
||||
payload = {
|
||||
@@ -192,9 +202,10 @@ module Jekyll
|
||||
end
|
||||
|
||||
# Obtain destination path.
|
||||
# +dest+ is the String path to the destination dir
|
||||
#
|
||||
# Returns destination file path.
|
||||
# dest - The String path to the destination dir.
|
||||
#
|
||||
# Returns destination file path String.
|
||||
def destination(dest)
|
||||
# The url needs to be unescaped in order to preserve the correct filename
|
||||
path = File.join(dest, CGI.unescape(self.url))
|
||||
@@ -203,9 +214,10 @@ module Jekyll
|
||||
end
|
||||
|
||||
# Write the generated post file to the destination directory.
|
||||
# +dest+ is the String path to the destination dir
|
||||
#
|
||||
# Returns nothing
|
||||
# dest - The String path to the destination dir.
|
||||
#
|
||||
# Returns nothing.
|
||||
def write(dest)
|
||||
path = destination(dest)
|
||||
FileUtils.mkdir_p(File.dirname(path))
|
||||
@@ -216,7 +228,7 @@ module Jekyll
|
||||
|
||||
# Convert this post into a Hash for use in Liquid templates.
|
||||
#
|
||||
# Returns <Hash>
|
||||
# Returns the representative Hash.
|
||||
def to_liquid
|
||||
self.data.deep_merge({
|
||||
"title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
|
||||
@@ -230,6 +242,7 @@ module Jekyll
|
||||
"content" => self.content })
|
||||
end
|
||||
|
||||
# Returns the shorthand String identifier of this Post.
|
||||
def inspect
|
||||
"<Post: #{self.id}>"
|
||||
end
|
||||
|
||||
@@ -72,6 +72,12 @@ module Jekyll
|
||||
def setup
|
||||
require 'classifier' if self.lsi
|
||||
|
||||
# Check that the destination dir isn't the source dir or a directory
|
||||
# parent to the source dir.
|
||||
if self.source =~ /^#{self.dest}/
|
||||
raise FatalException.new "Destination directory cannot be or contain the Source directory."
|
||||
end
|
||||
|
||||
# If safe mode is off, load in any Ruby files under the plugins
|
||||
# directory.
|
||||
unless self.safe
|
||||
@@ -244,7 +250,6 @@ module Jekyll
|
||||
files.merge(dirs)
|
||||
|
||||
obsolete_files = dest_files - files
|
||||
|
||||
FileUtils.rm_rf(obsolete_files.to_a)
|
||||
end
|
||||
|
||||
@@ -329,7 +334,7 @@ module Jekyll
|
||||
#
|
||||
# Returns the Array of filtered entries.
|
||||
def filter_entries(entries)
|
||||
entries = entries.reject do |e|
|
||||
entries.reject do |e|
|
||||
unless self.include.include?(e)
|
||||
['.', '_', '#'].include?(e[0..0]) ||
|
||||
e[-1..-1] == '~' ||
|
||||
|
||||
Reference in New Issue
Block a user