diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..416e8f3a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +rvm: + - 1.9.3 + - 1.9.2 + - 1.8.7 diff --git a/History.txt b/History.txt index 53bd41c6..e7e832b1 100644 --- a/History.txt +++ b/History.txt @@ -4,10 +4,15 @@ * Add --default-mimetype option (#279) * Allow setting of RedCloth options (#284) * 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 * Allow some special characters in highlight names * URL escape category names in URL generation (#360) * 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 * Bug Fixes diff --git a/Rakefile b/Rakefile index a1f4b161..8eb1360d 100644 --- a/Rakefile +++ b/Rakefile @@ -50,10 +50,6 @@ task :default => [:test, :features] require 'rake/testtask' 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.pattern = 'test/**/test_*.rb' test.verbose = true @@ -163,4 +159,4 @@ task :gemspec do spec = [head, manifest, tail].join(" # = MANIFEST =\n") File.open(gemspec_file, 'w') { |io| io.write(spec) } puts "Updated #{gemspec_file}" -end \ No newline at end of file +end diff --git a/bin/jekyll b/bin/jekyll index 28193a91..74cb99b0 100755 --- a/bin/jekyll +++ b/bin/jekyll @@ -106,7 +106,7 @@ opts = OptionParser.new do |opts| opts.on("--permalink [TYPE]", "Use 'date' (default) for YYYY/MM/DD") do |style| options['permalink'] = style unless style.nil? end - + opts.on("--paginate [POSTS_PER_PAGE]", "Paginate a blog's posts") do |per_page| begin options['paginate'] = per_page.to_i @@ -117,6 +117,16 @@ opts = OptionParser.new do |opts| end end + opts.on("--paginate_path [PAGINATED_URL_FORMAT]", "Leave blank for /page") 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| begin options['limit_posts'] = limit_posts.to_i @@ -152,12 +162,12 @@ if ARGV.size > 0 else migrator = migrator.downcase end - + cmd_options = [] ['file', 'dbname', 'user', 'pass', 'host', 'site'].each do |p| cmd_options << "\"#{options[p]}\"" unless options[p].nil? end - + # It's import time puts "Importing..." diff --git a/features/create_sites.feature b/features/create_sites.feature index 8496a4e2..438ee358 100644 --- a/features/create_sites.feature +++ b/features/create_sites.feature @@ -104,3 +104,9 @@ Feature: Create sites When I run jekyll Then the _site directory should exist 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" diff --git a/features/pagination.feature b/features/pagination.feature index 90b10578..cc3cf4d6 100644 --- a/features/pagination.feature +++ b/features/pagination.feature @@ -19,9 +19,36 @@ Feature: Site pagination 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 | exist | posts | not_exist | | 1 | 4 | 1 | 5 | | 2 | 2 | 2 | 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- directory should exist + And the "_site/blog/page-/index.html" file should exist + And I should see "" in "_site/blog/page-/index.html" + And the "_site/blog/page-/index.html" file should not exist + + Examples: + | exist | posts | not_exist | + | 2 | 1 | 5 | + | 3 | 1 | 6 | + | 4 | 1 | 7 | diff --git a/features/site_configuration.feature b/features/site_configuration.feature index 8d3bee5d..5a83ee80 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -131,3 +131,36 @@ Feature: Site configuration 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/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:

content for entry1.

" in "_site/2007/12/31/entry1.html" + And I should see "Post Layout:

content for entry2.

" in "_site/2020/01/31/entry2.html" diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb index 27239bd5..20128964 100644 --- a/features/step_definitions/jekyll_steps.rb +++ b/features/step_definitions/jekyll_steps.rb @@ -39,6 +39,13 @@ Given /^I have a (.*) layout that contains "(.*)"$/ do |layout, text| 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| FileUtils.mkdir_p(dir) end @@ -121,7 +128,7 @@ When /^I change "(.*)" to contain "(.*)"$/ do |file, text| end Then /^the (.*) directory should exist$/ do |dir| - assert File.directory?(dir) + assert File.directory?(dir), "The directory \"#{dir}\" does not exist" end Then /^I should see "(.*)" in "(.*)"$/ do |text, file| diff --git a/jekyll.gemspec b/jekyll.gemspec index 970a8ddc..55201ae8 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -26,8 +26,8 @@ Gem::Specification.new do |s| s.add_runtime_dependency('classifier', "~> 1.3") s.add_runtime_dependency('directory_watcher', "~> 1.1") s.add_runtime_dependency('maruku', "~> 0.5") - s.add_runtime_dependency('kramdown', "~> 0.13") - s.add_runtime_dependency('albino', "~> 1.3") + s.add_runtime_dependency('kramdown', "~> 0.13.4") + s.add_runtime_dependency('pygments.rb', "~> 0.2.12") s.add_development_dependency('rake', "~> 0.9") s.add_development_dependency('rdoc', "~> 3.11") diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 6d5afd85..65e16cdb 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -24,7 +24,7 @@ require 'English' # 3rd party require 'liquid' require 'maruku' -require 'albino' +require 'pygments' # internal requires require 'jekyll/core_ext' @@ -51,14 +51,15 @@ module Jekyll # Default options. Overriden by values in _config.yml or command-line opts. # (Strings rather symbols used for compatability with YAML). DEFAULTS = { - 'safe' => false, - 'auto' => false, - 'server' => false, - 'server_port' => 4000, + 'safe' => false, + 'auto' => false, + 'server' => false, + 'server_port' => 4000, 'source' => Dir.pwd, 'destination' => File.join(Dir.pwd, '_site'), 'plugins' => File.join(Dir.pwd, '_plugins'), + 'layouts' => '_layouts', 'future' => true, 'lsi' => false, @@ -66,6 +67,7 @@ module Jekyll 'markdown' => 'maruku', 'permalink' => 'date', 'include' => ['.htaccess'], + 'paginate_path' => 'page:num', 'markdown_ext' => 'markdown,mkd,mkdn,md', 'textile_ext' => 'textile', @@ -88,6 +90,7 @@ module Jekyll 'footnote_nr' => 1, 'entity_output' => 'as_char', 'toc_levels' => '1..6', + 'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo', 'use_coderay' => false, 'coderay' => { diff --git a/lib/jekyll/converters/markdown.rb b/lib/jekyll/converters/markdown.rb index b5655476..cb94c8d0 100644 --- a/lib/jekyll/converters/markdown.rb +++ b/lib/jekyll/converters/markdown.rb @@ -97,6 +97,7 @@ module Jekyll :footnote_nr => @config['kramdown']['footnote_nr'], :entity_output => @config['kramdown']['entity_output'], :toc_levels => @config['kramdown']['toc_levels'], + :smart_quotes => @config['kramdown']['smart_quotes'], :coderay_wrap => @config['kramdown']['coderay']['coderay_wrap'], :coderay_line_numbers => @config['kramdown']['coderay']['coderay_line_numbers'], @@ -111,11 +112,17 @@ module Jekyll :auto_ids => @config['kramdown']['auto_ids'], :footnote_nr => @config['kramdown']['footnote_nr'], :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 end 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' Maruku.new(content).to_html end diff --git a/lib/jekyll/generators/pagination.rb b/lib/jekyll/generators/pagination.rb index 847de4f8..dee5ad54 100644 --- a/lib/jekyll/generators/pagination.rb +++ b/lib/jekyll/generators/pagination.rb @@ -37,13 +37,19 @@ module Jekyll if num_page > 1 newpage = Page.new(site, site.source, page.dir, page.name) 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 else page.pager = pager end end end + + private + def paginate_path(site, num_page) + format = site.config['paginate_path'] + format.sub(':num', num_page.to_s) + end end class Pager diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index c47ccd2d..8a78e915 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -18,7 +18,7 @@ module Jekyll self.safe = config['safe'] self.source = File.expand_path(config['source']) 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.pygments = config['pygments'] 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 # directory. unless self.safe - Dir[File.join(self.plugins, "**/*.rb")].each do |f| - require f + self.plugins.each do |plugins| + Dir[File.join(plugins, "**/*.rb")].each do |f| + require f + end end end @@ -99,12 +101,12 @@ module Jekyll self.read_directories end - # Read all the files in //_layouts and create a new Layout - # object with each one. + # Read all the files in / and create a new Layout object + # with each one. # # Returns nothing. - def read_layouts(dir = '') - base = File.join(self.source, dir, "_layouts") + def read_layouts + base = File.join(self.source, self.config['layouts']) return unless File.exists?(base) entries = [] 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 # 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. def read_directories(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) @@ -193,12 +195,13 @@ module Jekyll # # Returns nothing. def render + payload = site_payload self.posts.each do |post| - post.render(self.layouts, site_payload) + post.render(self.layouts, payload) end self.pages.each do |page| - page.render(self.layouts, site_payload) + page.render(self.layouts, payload) end self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a } } @@ -254,7 +257,7 @@ module Jekyll 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. # @@ -304,7 +307,7 @@ module Jekyll # or are excluded in the site configuration, unless they are web server # 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. def filter_entries(entries) diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb index ed3a0f70..9ad69b3e 100644 --- a/lib/jekyll/tags/highlight.rb +++ b/lib/jekyll/tags/highlight.rb @@ -48,7 +48,13 @@ module Jekyll end 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 = output + context["pygments_suffix"] if context["pygments_suffix"] output diff --git a/test/test_kramdown.rb b/test/test_kramdown.rb index 99a7b454..043752c3 100644 --- a/test/test_kramdown.rb +++ b/test/test_kramdown.rb @@ -3,21 +3,31 @@ require 'helper' class TestKramdown < Test::Unit::TestCase context "kramdown" do setup do - config = { + @config = { 'markdown' => 'kramdown', 'kramdown' => { 'auto_ids' => false, 'footnote_nr' => 1, 'entity_output' => 'as_char', - 'toc_levels' => '1..6' + 'toc_levels' => '1..6', + 'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo' } } - @markdown = MarkdownConverter.new config end # http://kramdown.rubyforge.org/converter/html.html#options should "pass kramdown options" do - assert_equal "

Some Header

", @markdown.convert('# Some Header #').strip + markdown = MarkdownConverter.new(@config) + assert_equal "

Some Header

", markdown.convert('# Some Header #').strip + end + + should "convert quotes to smart quotes" do + markdown = MarkdownConverter.new(@config) + assert_equal "

“Pit’hy”

", markdown.convert(%{"Pit'hy"}).strip + + override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } } + markdown = MarkdownConverter.new(@config.deep_merge(override)) + assert_equal "

«Pit›hy»

", markdown.convert(%{"Pit'hy"}).strip end end end diff --git a/test/test_rdiscount.rb b/test/test_rdiscount.rb index 894ea18f..01f18eb3 100644 --- a/test/test_rdiscount.rb +++ b/test/test_rdiscount.rb @@ -5,8 +5,8 @@ class TestRdiscount < Test::Unit::TestCase context "rdiscount" do setup do config = { - 'rdiscount' => { 'extensions' => ['smart'] }, - 'markdown' => 'rdiscount' + 'markdown' => 'rdiscount', + 'rdiscount' => { 'extensions' => ['smart', 'generate_toc'], 'toc_token' => '{:toc}' } } @markdown = MarkdownConverter.new config end @@ -14,5 +14,9 @@ class TestRdiscount < Test::Unit::TestCase should "pass rdiscount extensions" do assert_equal "

“smart”

", @markdown.convert('"smart"').strip end + + should "render toc" do + assert_equal "

Header 1

\n\n

Header 2

\n\n

\n

\n\n

", @markdown.convert("# Header 1\n\n## Header 2\n\n{:toc}").strip + end end end diff --git a/test/test_redcarpet.rb b/test/test_redcarpet.rb index 1359c449..05596a92 100644 --- a/test/test_redcarpet.rb +++ b/test/test_redcarpet.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/helper' +require 'helper' class TestRedcarpet < Test::Unit::TestCase context "redcarpet" do diff --git a/test/test_site.rb b/test/test_site.rb index 0aa28497..712bf359 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -1,6 +1,32 @@ require 'helper' 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 setup do stub(Jekyll).configuration do diff --git a/test/test_tags.rb b/test/test_tags.rb index 1af5d58c..ab0f3188 100644 --- a/test/test_tags.rb +++ b/test/test_tags.rb @@ -6,7 +6,7 @@ class TestTags < Test::Unit::TestCase def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter) stub(Jekyll).configuration do - Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override) + Jekyll::DEFAULTS.deep_merge({'pygments' => true}).deep_merge(override) end site = Site.new(Jekyll.configuration)