Merge branch 'master' of git://github.com/mojombo/jekyll

This commit is contained in:
Alagu 2012-10-03 19:33:21 -07:00
commit 2726a5f27c
19 changed files with 195 additions and 42 deletions

4
.travis.yml Normal file
View File

@ -0,0 +1,4 @@
rvm:
- 1.9.3
- 1.9.2
- 1.8.7

View File

@ -4,10 +4,15 @@
* Add --default-mimetype option (#279) * Add --default-mimetype option (#279)
* Allow setting of RedCloth options (#284) * Allow setting of RedCloth options (#284)
* Add post_url Liquid tag for internal post linking (#369) * Add post_url Liquid tag for internal post linking (#369)
* Allow multiple plugin dirs to be specified (#438)
* Inline TOC token support for RDiscount (#333)
* Add the option to specify the paginated url format (#342)
* Bug Fixes * Bug Fixes
* Allow some special characters in highlight names * Allow some special characters in highlight names
* URL escape category names in URL generation (#360) * URL escape category names in URL generation (#360)
* Fix error with limit_posts (#442) * Fix error with limit_posts (#442)
* Properly select dotfile during directory scan (#363, #431, #377)
* Allow setting of Kramdown smart_quotes (#482)
== 0.11.2 / 2011-12-27 == 0.11.2 / 2011-12-27
* Bug Fixes * Bug Fixes

View File

@ -50,10 +50,6 @@ task :default => [:test, :features]
require 'rake/testtask' require 'rake/testtask'
Rake::TestTask.new(:test) do |test| Rake::TestTask.new(:test) do |test|
if `which pygmentize` == ''
puts "You must have Pygments installed to run the tests."
exit 1
end
test.libs << 'lib' << 'test' test.libs << 'lib' << 'test'
test.pattern = 'test/**/test_*.rb' test.pattern = 'test/**/test_*.rb'
test.verbose = true test.verbose = true

View File

@ -117,6 +117,16 @@ opts = OptionParser.new do |opts|
end end
end end
opts.on("--paginate_path [PAGINATED_URL_FORMAT]", "Leave blank for /page<num>") do |paginate_path|
begin
options['paginate_path'] = paginate_path
raise ArgumentError if options['paginate_path'].nil?
rescue
puts 'You must specify a pagination url format'
exit 0
end
end
opts.on("--limit_posts [MAX_POSTS]", "Limit the number of posts to publish") do |limit_posts| opts.on("--limit_posts [MAX_POSTS]", "Limit the number of posts to publish") do |limit_posts|
begin begin
options['limit_posts'] = limit_posts.to_i options['limit_posts'] = limit_posts.to_i

View File

@ -104,3 +104,9 @@ Feature: Create sites
When I run jekyll When I run jekyll
Then the _site directory should exist Then the _site directory should exist
And I should see "URL: /2020/01/31/entry2/" in "_site/index.html" And I should see "URL: /2020/01/31/entry2/" in "_site/index.html"
Scenario: Basic site with whitelisted dotfile
Given I have an ".htaccess" file that contains "SomeDirective"
When I run jekyll
Then the _site directory should exist
And I should see "SomeDirective" in "_site/.htaccess"

View File

@ -25,3 +25,30 @@ Feature: Site pagination
| 1 | 4 | 1 | 5 | | 1 | 4 | 1 | 5 |
| 2 | 2 | 2 | 3 | | 2 | 2 | 2 | 3 |
| 3 | 2 | 1 | 3 | | 3 | 2 | 1 | 3 |
Scenario Outline: Setting a custom pagination path
Given I have a configuration file with:
| key | value |
| paginate | 1 |
| paginate_path | /blog/page-:num |
| permalink | /blog/:year/:month/:day/:title |
And I have a _layouts directory
And I have an "index.html" page 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 play3. |
| Wargames4 | 6/27/2009 | default | The only winning move is not to play4. |
When I run jekyll
Then the _site/blog/page-<exist> directory should exist
And the "_site/blog/page-<exist>/index.html" file should exist
And I should see "<posts>" in "_site/blog/page-<exist>/index.html"
And the "_site/blog/page-<not_exist>/index.html" file should not exist
Examples:
| exist | posts | not_exist |
| 2 | 1 | 5 |
| 3 | 1 | 6 |
| 4 | 1 | 7 |

View File

@ -131,3 +131,36 @@ Feature: Site configuration
And the "_site/2009/04/05/bananas.html" file should exist And the "_site/2009/04/05/bananas.html" file should exist
And the "_site/2009/04/01/oranges.html" file should exist And the "_site/2009/04/01/oranges.html" file should exist
And the "_site/2009/03/27/apples.html" file should not exist And the "_site/2009/03/27/apples.html" file should not exist
Scenario: Copy over normally excluded files when they are explicitly included
Given I have a ".gitignore" file that contains ".DS_Store"
And I have an ".htaccess" file that contains "SomeDirective"
And I have a configuration file with "include" set to:
| value |
| .gitignore |
| .foo |
When I run jekyll
Then the _site directory should exist
And I should see ".DS_Store" in "_site/.gitignore"
And the "_site/.htaccess" file should not exist
Scenario: Using a different layouts directory
Given I have a _theme directory
And I have a page theme that contains "Page Layout: {{ site.posts.size }} on {{ site.time | date: "%Y-%m-%d" }}"
And I have a post theme that contains "Post Layout: {{ content }}"
And I have an "index.html" page with layout "page" that contains "site index page"
And I have a configuration file with:
| key | value |
| time | 2010-01-01 |
| future | true |
| layouts | _theme |
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| entry1 | 12/31/2007 | post | content for entry1. |
| entry2 | 01/31/2020 | post | content for entry2. |
When I run jekyll
Then the _site directory should exist
And I should see "Page Layout: 2 on 2010-01-01" in "_site/index.html"
And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"

View File

@ -39,6 +39,13 @@ Given /^I have a (.*) layout that contains "(.*)"$/ do |layout, text|
end end
end end
Given /^I have a (.*) theme that contains "(.*)"$/ do |layout, text|
File.open(File.join('_theme', layout + '.html'), 'w') do |f|
f.write(text)
f.close
end
end
Given /^I have an? (.*) directory$/ do |dir| Given /^I have an? (.*) directory$/ do |dir|
FileUtils.mkdir_p(dir) FileUtils.mkdir_p(dir)
end end
@ -121,7 +128,7 @@ When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
end end
Then /^the (.*) directory should exist$/ do |dir| Then /^the (.*) directory should exist$/ do |dir|
assert File.directory?(dir) assert File.directory?(dir), "The directory \"#{dir}\" does not exist"
end end
Then /^I should see "(.*)" in "(.*)"$/ do |text, file| Then /^I should see "(.*)" in "(.*)"$/ do |text, file|

View File

@ -26,8 +26,8 @@ Gem::Specification.new do |s|
s.add_runtime_dependency('classifier', "~> 1.3") s.add_runtime_dependency('classifier', "~> 1.3")
s.add_runtime_dependency('directory_watcher', "~> 1.1") s.add_runtime_dependency('directory_watcher', "~> 1.1")
s.add_runtime_dependency('maruku', "~> 0.5") s.add_runtime_dependency('maruku', "~> 0.5")
s.add_runtime_dependency('kramdown', "~> 0.13") s.add_runtime_dependency('kramdown', "~> 0.13.4")
s.add_runtime_dependency('albino', "~> 1.3") s.add_runtime_dependency('pygments.rb', "~> 0.2.12")
s.add_development_dependency('rake', "~> 0.9") s.add_development_dependency('rake', "~> 0.9")
s.add_development_dependency('rdoc', "~> 3.11") s.add_development_dependency('rdoc', "~> 3.11")

View File

@ -24,7 +24,7 @@ require 'English'
# 3rd party # 3rd party
require 'liquid' require 'liquid'
require 'maruku' require 'maruku'
require 'albino' require 'pygments'
# internal requires # internal requires
require 'jekyll/core_ext' require 'jekyll/core_ext'
@ -51,14 +51,15 @@ module Jekyll
# Default options. Overriden by values in _config.yml or command-line opts. # Default options. Overriden by values in _config.yml or command-line opts.
# (Strings rather symbols used for compatability with YAML). # (Strings rather symbols used for compatability with YAML).
DEFAULTS = { DEFAULTS = {
'safe' => false, 'safe' => false,
'auto' => false, 'auto' => false,
'server' => false, 'server' => false,
'server_port' => 4000, 'server_port' => 4000,
'source' => Dir.pwd, 'source' => Dir.pwd,
'destination' => File.join(Dir.pwd, '_site'), 'destination' => File.join(Dir.pwd, '_site'),
'plugins' => File.join(Dir.pwd, '_plugins'), 'plugins' => File.join(Dir.pwd, '_plugins'),
'layouts' => '_layouts',
'future' => true, 'future' => true,
'lsi' => false, 'lsi' => false,
@ -66,6 +67,7 @@ module Jekyll
'markdown' => 'maruku', 'markdown' => 'maruku',
'permalink' => 'date', 'permalink' => 'date',
'include' => ['.htaccess'], 'include' => ['.htaccess'],
'paginate_path' => 'page:num',
'markdown_ext' => 'markdown,mkd,mkdn,md', 'markdown_ext' => 'markdown,mkd,mkdn,md',
'textile_ext' => 'textile', 'textile_ext' => 'textile',
@ -88,6 +90,7 @@ module Jekyll
'footnote_nr' => 1, 'footnote_nr' => 1,
'entity_output' => 'as_char', 'entity_output' => 'as_char',
'toc_levels' => '1..6', 'toc_levels' => '1..6',
'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo',
'use_coderay' => false, 'use_coderay' => false,
'coderay' => { 'coderay' => {

View File

@ -97,6 +97,7 @@ module Jekyll
:footnote_nr => @config['kramdown']['footnote_nr'], :footnote_nr => @config['kramdown']['footnote_nr'],
:entity_output => @config['kramdown']['entity_output'], :entity_output => @config['kramdown']['entity_output'],
:toc_levels => @config['kramdown']['toc_levels'], :toc_levels => @config['kramdown']['toc_levels'],
:smart_quotes => @config['kramdown']['smart_quotes'],
:coderay_wrap => @config['kramdown']['coderay']['coderay_wrap'], :coderay_wrap => @config['kramdown']['coderay']['coderay_wrap'],
:coderay_line_numbers => @config['kramdown']['coderay']['coderay_line_numbers'], :coderay_line_numbers => @config['kramdown']['coderay']['coderay_line_numbers'],
@ -111,11 +112,17 @@ module Jekyll
:auto_ids => @config['kramdown']['auto_ids'], :auto_ids => @config['kramdown']['auto_ids'],
:footnote_nr => @config['kramdown']['footnote_nr'], :footnote_nr => @config['kramdown']['footnote_nr'],
:entity_output => @config['kramdown']['entity_output'], :entity_output => @config['kramdown']['entity_output'],
:toc_levels => @config['kramdown']['toc_levels'] :toc_levels => @config['kramdown']['toc_levels'],
:smart_quotes => @config['kramdown']['smart_quotes']
}).to_html }).to_html
end end
when 'rdiscount' when 'rdiscount'
RDiscount.new(content, *@rdiscount_extensions).to_html rd = RDiscount.new(content, *@rdiscount_extensions)
html = rd.to_html
if rd.generate_toc and html.include?(@config['rdiscount']['toc_token'])
html.gsub!(@config['rdiscount']['toc_token'], rd.toc_content)
end
html
when 'maruku' when 'maruku'
Maruku.new(content).to_html Maruku.new(content).to_html
end end

View File

@ -37,13 +37,19 @@ module Jekyll
if num_page > 1 if num_page > 1
newpage = Page.new(site, site.source, page.dir, page.name) newpage = Page.new(site, site.source, page.dir, page.name)
newpage.pager = pager newpage.pager = pager
newpage.dir = File.join(page.dir, "page#{num_page}") newpage.dir = File.join(page.dir, paginate_path(site, num_page))
site.pages << newpage site.pages << newpage
else else
page.pager = pager page.pager = pager
end end
end end
end end
private
def paginate_path(site, num_page)
format = site.config['paginate_path']
format.sub(':num', num_page.to_s)
end
end end
class Pager class Pager

View File

@ -18,7 +18,7 @@ module Jekyll
self.safe = config['safe'] self.safe = config['safe']
self.source = File.expand_path(config['source']) self.source = File.expand_path(config['source'])
self.dest = File.expand_path(config['destination']) self.dest = File.expand_path(config['destination'])
self.plugins = File.expand_path(config['plugins']) self.plugins = Array(config['plugins']).map { |d| File.expand_path(d) }
self.lsi = config['lsi'] self.lsi = config['lsi']
self.pygments = config['pygments'] self.pygments = config['pygments']
self.permalink_style = config['permalink'].to_sym self.permalink_style = config['permalink'].to_sym
@ -73,8 +73,10 @@ module Jekyll
# 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. # directory.
unless self.safe unless self.safe
Dir[File.join(self.plugins, "**/*.rb")].each do |f| self.plugins.each do |plugins|
require f Dir[File.join(plugins, "**/*.rb")].each do |f|
require f
end
end end
end end
@ -99,12 +101,12 @@ module Jekyll
self.read_directories self.read_directories
end end
# Read all the files in <source>/<dir>/_layouts and create a new Layout # Read all the files in <source>/<layouts> and create a new Layout object
# object with each one. # with each one.
# #
# Returns nothing. # Returns nothing.
def read_layouts(dir = '') def read_layouts
base = File.join(self.source, dir, "_layouts") base = File.join(self.source, self.config['layouts'])
return unless File.exists?(base) return unless File.exists?(base)
entries = [] entries = []
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) } Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
@ -119,12 +121,12 @@ module Jekyll
# that will become part of the site according to the rules in # that will become part of the site according to the rules in
# filter_entries. # filter_entries.
# #
# dir - The String relative path of the directory to read. # dir - The String relative path of the directory to read. Default: ''.
# #
# Returns nothing. # Returns nothing.
def read_directories(dir = '') def read_directories(dir = '')
base = File.join(self.source, dir) base = File.join(self.source, dir)
entries = Dir.chdir(base) { filter_entries(Dir['*']) } entries = Dir.chdir(base) { filter_entries(Dir.entries('.')) }
self.read_posts(dir) self.read_posts(dir)
@ -193,12 +195,13 @@ module Jekyll
# #
# Returns nothing. # Returns nothing.
def render def render
payload = site_payload
self.posts.each do |post| self.posts.each do |post|
post.render(self.layouts, site_payload) post.render(self.layouts, payload)
end end
self.pages.each do |page| self.pages.each do |page|
page.render(self.layouts, site_payload) page.render(self.layouts, payload)
end end
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } } self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } }
@ -254,7 +257,7 @@ module Jekyll
end end
end end
# Constructs a Hash of Posts indexed by the specified Post attribute. # Construct a Hash of Posts indexed by the specified Post attribute.
# #
# post_attr - The String name of the Post attribute. # post_attr - The String name of the Post attribute.
# #
@ -304,7 +307,7 @@ module Jekyll
# or are excluded in the site configuration, unless they are web server # 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. # entries - The Array of String file/directory entries to filter.
# #
# Returns the Array of filtered entries. # Returns the Array of filtered entries.
def filter_entries(entries) def filter_entries(entries)

View File

@ -48,7 +48,13 @@ module Jekyll
end end
def render_pygments(context, code) def render_pygments(context, code)
output = add_code_tags(Albino.new(code, @lang).to_s(@options), @lang) @options[:encoding] = 'utf-8'
output = add_code_tags(
Pygments.highlight(code, :lexer => @lang, :options => @options),
@lang
)
output = context["pygments_prefix"] + output if context["pygments_prefix"] output = context["pygments_prefix"] + output if context["pygments_prefix"]
output = output + context["pygments_suffix"] if context["pygments_suffix"] output = output + context["pygments_suffix"] if context["pygments_suffix"]
output output

View File

@ -3,21 +3,31 @@ require 'helper'
class TestKramdown < Test::Unit::TestCase class TestKramdown < Test::Unit::TestCase
context "kramdown" do context "kramdown" do
setup do setup do
config = { @config = {
'markdown' => 'kramdown', 'markdown' => 'kramdown',
'kramdown' => { 'kramdown' => {
'auto_ids' => false, 'auto_ids' => false,
'footnote_nr' => 1, 'footnote_nr' => 1,
'entity_output' => 'as_char', 'entity_output' => 'as_char',
'toc_levels' => '1..6' 'toc_levels' => '1..6',
'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo'
} }
} }
@markdown = MarkdownConverter.new config
end end
# http://kramdown.rubyforge.org/converter/html.html#options # http://kramdown.rubyforge.org/converter/html.html#options
should "pass kramdown options" do should "pass kramdown options" do
assert_equal "<h1>Some Header</h1>", @markdown.convert('# Some Header #').strip markdown = MarkdownConverter.new(@config)
assert_equal "<h1>Some Header</h1>", markdown.convert('# Some Header #').strip
end
should "convert quotes to smart quotes" do
markdown = MarkdownConverter.new(@config)
assert_equal "<p>&ldquo;Pit&rsquo;hy&rdquo;</p>", markdown.convert(%{"Pit'hy"}).strip
override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } }
markdown = MarkdownConverter.new(@config.deep_merge(override))
assert_equal "<p>&laquo;Pit&rsaquo;hy&raquo;</p>", markdown.convert(%{"Pit'hy"}).strip
end end
end end
end end

View File

@ -5,8 +5,8 @@ class TestRdiscount < Test::Unit::TestCase
context "rdiscount" do context "rdiscount" do
setup do setup do
config = { config = {
'rdiscount' => { 'extensions' => ['smart'] }, 'markdown' => 'rdiscount',
'markdown' => 'rdiscount' 'rdiscount' => { 'extensions' => ['smart', 'generate_toc'], 'toc_token' => '{:toc}' }
} }
@markdown = MarkdownConverter.new config @markdown = MarkdownConverter.new config
end end
@ -14,5 +14,9 @@ class TestRdiscount < Test::Unit::TestCase
should "pass rdiscount extensions" do should "pass rdiscount extensions" do
assert_equal "<p>&ldquo;smart&rdquo;</p>", @markdown.convert('"smart"').strip assert_equal "<p>&ldquo;smart&rdquo;</p>", @markdown.convert('"smart"').strip
end end
should "render toc" do
assert_equal "<h1 id=\"Header+1\">Header 1</h1>\n\n<h2 id=\"Header+2\">Header 2</h2>\n\n<p>\n <ul>\n <li><a href=\"#Header+1\">Header 1</a>\n <ul>\n <li><a href=\"#Header+2\">Header 2</a> </li>\n </ul>\n </li>\n </ul>\n\n</p>", @markdown.convert("# Header 1\n\n## Header 2\n\n{:toc}").strip
end
end end
end end

View File

@ -1,4 +1,4 @@
require File.dirname(__FILE__) + '/helper' require 'helper'
class TestRedcarpet < Test::Unit::TestCase class TestRedcarpet < Test::Unit::TestCase
context "redcarpet" do context "redcarpet" do

View File

@ -1,6 +1,32 @@
require 'helper' require 'helper'
class TestSite < Test::Unit::TestCase class TestSite < Test::Unit::TestCase
context "configuring sites" do
should "have an array for plugins by default" do
site = Site.new(Jekyll::DEFAULTS)
assert_equal [File.join(Dir.pwd, '_plugins')], site.plugins
end
should "have an array for plugins if passed as a string" do
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => '/tmp/plugins'}))
assert_equal ['/tmp/plugins'], site.plugins
end
should "have an array for plugins if passed as an array" do
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => ['/tmp/plugins', '/tmp/otherplugins']}))
assert_equal ['/tmp/plugins', '/tmp/otherplugins'], site.plugins
end
should "have an empty array for plugins if nothing is passed" do
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => []}))
assert_equal [], site.plugins
end
should "have an empty array for plugins if nil is passed" do
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => nil}))
assert_equal [], site.plugins
end
end
context "creating sites" do context "creating sites" do
setup do setup do
stub(Jekyll).configuration do stub(Jekyll).configuration do

View File

@ -6,7 +6,7 @@ class TestTags < Test::Unit::TestCase
def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter) def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter)
stub(Jekyll).configuration do stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override) Jekyll::DEFAULTS.deep_merge({'pygments' => true}).deep_merge(override)
end end
site = Site.new(Jekyll.configuration) site = Site.new(Jekyll.configuration)