diff --git a/.travis.yml b/.travis.yml index 416e8f3a..b6b39b7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ +language: ruby rvm: - 1.9.3 - 1.9.2 - 1.8.7 +script: bundle exec rake diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..fa6fb807 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +Contribute +========== + +So you've got an awesome idea to throw into Jekyll. Great! Please keep the following in mind: + +* **Contributions will not be accepted without tests.** +* If you're creating a small fix or patch to an existing feature, just a simple test will do. Please stay in the confines of the current test suite and use [Shoulda](http://github.com/thoughtbot/shoulda/tree/master) and [RR](http://github.com/btakita/rr/tree/master). +* If it's a brand new feature, make sure to create a new [Cucumber](https://github.com/cucumber/cucumber/) feature and reuse steps where appropriate. Also, whipping up some documentation in your fork's wiki would be appreciated, and once merged it will be transferred over to the main wiki. + +Test Dependencies +----------------- + +To run the test suite and build the gem you'll need to install Jekyll's dependencies. Jekyll uses Bundler, so a quick run of the bundle command and you're all set! + + $ bundle + +Before you start, run the tests and make sure that they pass (to confirm your environment is configured properly): + + $ rake test + $ rake features + +Workflow +-------- + +Here's the most direct way to get your work merged into the project: +* Fork the project +* Clone down your fork ( `git clone git://github.com//jekyll.git` ) +* Create a topic branch to contain your change ( `git checkout -b my_awesome_feature` ) +* Hack away, add tests. Not necessarily in that order. +* Make sure everything still passes by running `rake` +* If necessary, rebase your commits into logical chunks, without errors +* Push the branch up ( `git push origin my_awesome_feature` ) +* Create an issue with a description and link to your branch + +Gotchas +------- + +* If you want to bump the gem version, please put that in a separate commit. This way, the maintainers can control when the gem gets released. +* Try to keep your patch(es) based from the latest commit on mojombo/jekyll. The easier it is to apply your work, the less work the maintainers have to do, which is always a good thing. +* Please don't tag your GitHub issue with [fix], [feature], etc. The maintainers actively read the issues and will label it once they come across it. + +Finally... +---------- + +Thanks! Hacking on Jekyll should be fun, and if for some reason it's a pain to do let us know so we can fix it. diff --git a/History.txt b/History.txt index d65aad87..adb70078 100644 --- a/History.txt +++ b/History.txt @@ -1,5 +1,13 @@ == HEAD + * Major Enhancements + * Refactored jekyll commands into subcommands: build, serve, and migrate. (#690) * Minor Enhancements + * Massively accelerate LSI performance (#664) + * Truncate post slugs when importing from Tumblr (#496) + * Add glob support to include, exclude option (#743) + * Layout of Page or Post defaults to 'page' or 'post', respectively (#580) + * "Keep files" feature (#685) + * Output full path & name for files that don't parse (#745) * Add source and destination directory protection (#535) * Better YAML error message (#718) * Bug Fixes diff --git a/README.textile b/README.textile index 529e1e7d..80ca6220 100644 --- a/README.textile +++ b/README.textile @@ -1,5 +1,7 @@ h1. Jekyll +!https://travis-ci.org/mojombo/jekyll.png?branch=master!:https://travis-ci.org/mojombo/jekyll + By Tom Preston-Werner, Nick Quaranto, and many awesome contributors! Jekyll is a simple, blog aware, static site generator. It takes a template directory (representing the raw form of a website), runs it through Textile or Markdown and Liquid converters, and spits out a complete, static website suitable for serving with Apache or your favorite web server. This is also the engine behind "GitHub Pages":http://pages.github.com, which you can use to host your project's page or blog right here from GitHub. diff --git a/Rakefile b/Rakefile index ff52d677..257da617 100644 --- a/Rakefile +++ b/Rakefile @@ -131,7 +131,7 @@ namespace :site do # Generate the site in server mode. puts "Running Jekyll..." Dir.chdir("site") do - sh "#{File.expand_path('bin/jekyll', File.dirname(__FILE__))} --server" + sh "#{File.expand_path('bin/jekyll', File.dirname(__FILE__))} serve --watch" end end diff --git a/bin/jekyll b/bin/jekyll index e712616b..309ffc91 100755 --- a/bin/jekyll +++ b/bin/jekyll @@ -1,299 +1,70 @@ #!/usr/bin/env ruby -$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) +$:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib }) -help = < ./_site - jekyll # . -> - jekyll # -> - jekyll import # imports posts using named import script - - Configuration is read from '/_config.yml' but can be overriden - using the following options: - -HELP - -require 'optparse' +require 'commander/import' require 'jekyll' +program :name, 'jekyll' +program :version, Jekyll::VERSION +program :description, 'Jekyll is a blog-aware, static site generator in Ruby' -exec = {} -options = {} -opts = OptionParser.new do |opts| - opts.banner = help +default_command :help - opts.on("--file [PATH]", "File to import from") do |import_file| - options['file'] = import_file - end - - opts.on("--dbname [TEXT]", "DB to import from") do |import_dbname| - options['dbname'] = import_dbname - end - - opts.on("--user [TEXT]", "Username to use when importing") do |import_user| - options['user'] = import_user - end - - opts.on("--pass [TEXT]", "Password to use when importing") do |import_pass| - options['pass'] = import_pass - end - - opts.on("--host [HOST ADDRESS]", "Host to import from") do |import_host| - options['host'] = import_host - end - - opts.on("--site [SITE NAME]", "Site to import from") do |import_site| - options['site'] = import_site - end - +global_option '-s', '--source [DIR]', 'Source directory (defaults to ./)' +global_option '-d', '--destination [DIR]', 'Destination directory (defaults to ./_site)' +global_option '--safe', 'Safe mode (defaults to false)' +global_option '--plugins', 'Plugins directory (defaults to ./_plugins)' +global_option '--layouts', 'Layouts directory (defaults to ./_layouts)' - opts.on("--[no-]safe", "Safe mode (default unsafe)") do |safe| - options['safe'] = safe - end +command :build do |c| + c.syntax = 'jekyll build [options]' + c.description = 'Build your site with the option of auto-renegeration' - opts.on("--[no-]auto", "Auto-regenerate") do |auto| - options['auto'] = auto - end + c.option '-w', '--watch', 'Watch for changes and rebuild' + c.option '--lsi', 'Use LSI for improved related posts' - opts.on("--server [PORT]", "Start web server (default port 4000)") do |port| - options['server'] = true - options['server_port'] = port unless port.nil? - end - - opts.on("--no-server", "Do not start a web server") do |part| - options['server'] = false - end - - opts.on("--base-url [BASE_URL]", "Serve website from a given base URL (default '/'") do |baseurl| - options['baseurl'] = baseurl - end - - opts.on("--default-mimetype [MT]", "Mimetype to use when no file extension (if --server)") do |mt| - options['default-mimetype'] = mt - end - - opts.on("--[no-]lsi", "Use LSI for better related posts") do |lsi| - options['lsi'] = lsi - end - - opts.on("--[no-]pygments", "Use pygments to highlight code") do |pygments| - options['pygments'] = pygments - end - - opts.on("--rdiscount", "Use rdiscount gem for Markdown") do - options['markdown'] = 'rdiscount' - end - - opts.on("--redcarpet", "Use redcarpet gem for Markdown") do - options['markdown'] = 'redcarpet' - end - - opts.on("--kramdown", "Use kramdown gem for Markdown") do - options['markdown'] = 'kramdown' - end - - opts.on("--time [TIME]", "Time to generate the site for") do |time| - options['time'] = Time.parse(time) - end - - opts.on("--[no-]future", "Render future dated posts") do |future| - options['future'] = future - end - - 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 - raise ArgumentError if options['paginate'] == 0 - rescue - puts 'you must specify a number of posts by page bigger than 0' - exit 0 - 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 - raise ArgumentError if options['limit_posts'] < 1 - rescue - puts 'you must specify a number of posts by page bigger than 0' - exit 0 - end - end - - opts.on("--url [URL]", "Set custom site.url") do |url| - options['url'] = url - end - - opts.on("--version", "Display current version") do - puts "Jekyll " + Jekyll::VERSION - exit 0 + c.action do |args, options| + options.defaults :serving => false + options = Jekyll.configuration(options.__hash__) + Jekyll::BuildCommand.process(options) end end -# Read command line options into `options` hash -opts.parse! +command :serve do |c| + c.syntax = 'jekyll serve [options]' + c.description = 'Serve your site locally with the option of auto-regeneration' + c.option '-w', '--watch', 'Watch for changes and rebuild' + c.option '--lsi', 'Use LSI for improved related posts' -# Check for import stuff -if ARGV.size > 0 - if ARGV[0] == 'import' - migrator = ARGV[1] + c.option '-p', '--port [PORT]', 'Port to listen on' + c.option '-h', '--host [HOST]', 'Host to bind to' + c.option '-b', '--baseurl [URL]', 'Base URL' - if migrator.nil? - puts "Invalid options. Run `jekyll --help` for assistance." - exit(1) - else - migrator = migrator.downcase - end + c.action do |args, options| + options.default :port => '4000', + :host => '0.0.0.0', + :baseurl => '/', + :serving => true - 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..." - - # Ideally, this shouldn't be necessary. Maybe parse the actual - # src files for the migrator name? - migrators = { - :posterous => 'Posterous', - :wordpressdotcom => 'WordpressDotCom', - :wordpress => 'WordPress', - :csv => 'CSV', - :drupal => 'Drupal', - :enki => 'Enki', - :mephisto => 'Mephisto', - :mt => 'MT', - :textpattern => 'TextPattern', - :tumblr => 'Tumblr', - :typo => 'Typo' - } - - app_root = File.join(File.dirname(__FILE__), '..') - - require "#{app_root}/lib/jekyll/migrators/#{migrator}" - - if Jekyll.const_defined?(migrators[migrator.to_sym]) - migrator_class = Jekyll.const_get(migrators[migrator.to_sym]) - migrator_class.process(*cmd_options) - else - puts "Invalid migrator. Run `jekyll --help` for assistance." - exit(1) - end - - exit(0) + options = Jekyll.configuration(options.__hash__) + Jekyll::BuildCommand.process(options) + Jekyll::ServeCommand.process(options) end end +command :import do |c| + c.syntax = 'jekyll import [options]' + c.description = 'Import your old blog to Jekyll' + c.option '--file', 'File to migrate from' + c.option '--dbname', 'Database name to migrate from' + c.option '--user', 'Username to use when migrating' + c.option '--pass', 'Password to use when migrating' + c.option '--host', 'Host address to use when migrating' -# Get source and destination from command line -case ARGV.size - when 0 - when 1 - options['destination'] = ARGV[0] - when 2 - options['source'] = ARGV[0] - options['destination'] = ARGV[1] - else - puts "Invalid options. Run `jekyll --help` for assistance." - exit(1) -end - -options = Jekyll.configuration(options) - -# Get source and destination directories (possibly set by config file) -source = options['source'] -destination = options['destination'] - -# Files to watch -def globs(source, destination) - Dir.chdir(source) do - dirs = Dir['*'].select { |x| File.directory?(x) } - dirs -= [destination] - dirs = dirs.map { |x| "#{x}/**/*" } - dirs += ['*'] + c.action do |args, options| + Jekyll::MigrateCommand.process(args.first, options) end end - -# Create the Site -site = Jekyll::Site.new(options) - -# Run the directory watcher for auto-generation, if required -if options['auto'] - require 'directory_watcher' - - puts "Auto-regenerating enabled: #{source} -> #{destination}" - - dw = DirectoryWatcher.new(source) - dw.interval = 1 - dw.glob = globs(source, destination) - - dw.add_observer do |*args| - t = Time.now.strftime("%Y-%m-%d %H:%M:%S") - puts "[#{t}] regeneration: #{args.size} files changed" - site.process - end - - dw.start - - unless options['server'] - loop { sleep 1000 } - end -else - puts "Building site: #{source} -> #{destination}" - begin - site.process - rescue Jekyll::FatalException => e - puts - puts "ERROR: YOUR SITE COULD NOT BE BUILT:" - puts "------------------------------------" - puts e.message - exit(1) - end - puts "Successfully generated site: #{source} -> #{destination}" -end - -# Run the server on the specified port, if required -if options['server'] - require 'webrick' - include WEBrick - - FileUtils.mkdir_p(destination) - - mime_types = WEBrick::HTTPUtils::DefaultMimeTypes - mime_types.store 'js', 'application/javascript' - if options['default-mimetype'] - mime_types.store(nil, options['default-mimetype']) - end - - s = HTTPServer.new( - :Port => options['server_port'], - :MimeTypes => mime_types - ) - s.mount(options['baseurl'], HTTPServlet::FileHandler, destination) - t = Thread.new { - s.start - } - - trap("INT") { s.shutdown } - t.join() -end diff --git a/cucumber.yml b/cucumber.yml index 9692830c..ff1d0580 100644 --- a/cucumber.yml +++ b/cucumber.yml @@ -1 +1,2 @@ -default: --format progress \ No newline at end of file +default: --format progress +html_report: --format progress --format html --out=features_report.html diff --git a/features/site_configuration.feature b/features/site_configuration.feature index 5a83ee80..b9a082fa 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -22,7 +22,7 @@ Feature: Site configuration Given I have an "Rakefile" file that contains "I want to be excluded" And I have an "README" file that contains "I want to be excluded" And I have an "index.html" file that contains "I want to be included" - And I have a configuration file with "exclude" set to "Rakefile", "README" + And I have a configuration file with "exclude" set to "['Rakefile', 'README']" When I run jekyll Then I should see "I want to be included" in "_site/index.html" And the "_site/Rakefile" file should not exist diff --git a/features/support/env.rb b/features/support/env.rb index 3166ce9c..1ed330a1 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -11,6 +11,7 @@ JEKYLL_PATH = File.join(ENV['PWD'], 'bin', 'jekyll') def run_jekyll(opts = {}) command = JEKYLL_PATH + command << " build" command << " >> /dev/null 2>&1" if opts[:debug].nil? system command end diff --git a/jekyll.gemspec b/jekyll.gemspec index dbbe4386..86df546b 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -29,6 +29,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('maruku', "~> 0.5") s.add_runtime_dependency('kramdown', "~> 0.13.4") s.add_runtime_dependency('pygments.rb', "~> 0.3.2") + s.add_runtime_dependency('commander', "~> 4.1.3") s.add_development_dependency('rake', "~> 0.9") s.add_development_dependency('rdoc', "~> 3.11") @@ -43,6 +44,8 @@ Gem::Specification.new do |s| # = MANIFEST = s.files = %w[ + .travis.yml + CONTRIBUTING.md Gemfile History.txt LICENSE @@ -62,6 +65,10 @@ Gem::Specification.new do |s| features/support/env.rb jekyll.gemspec lib/jekyll.rb + lib/jekyll/command.rb + lib/jekyll/commands/build.rb + lib/jekyll/commands/migrate.rb + lib/jekyll/commands/serve.rb lib/jekyll/converter.rb lib/jekyll/converters/identity.rb lib/jekyll/converters/markdown.rb @@ -96,6 +103,8 @@ Gem::Specification.new do |s| lib/jekyll/tags/include.rb lib/jekyll/tags/post_url.rb test/fixtures/broken_front_matter1.erb + test/fixtures/broken_front_matter2.erb + test/fixtures/broken_front_matter3.erb test/fixtures/front_matter.erb test/helper.rb test/source/.htaccess diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 4defe4a7..de89df83 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -41,6 +41,9 @@ require 'jekyll/errors' require 'jekyll/plugin' require 'jekyll/converter' require 'jekyll/generator' +require 'jekyll/command' + +require_all 'jekyll/commands' require_all 'jekyll/converters' require_all 'jekyll/generators' require_all 'jekyll/tags' @@ -48,26 +51,22 @@ require_all 'jekyll/tags' module Jekyll VERSION = '0.12.0' - # Default options. Overriden by values in _config.yml or command-line opts. + # Default options. Overriden by values in _config.yml. # 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' => '_plugins', 'layouts' => '_layouts', + 'keep_files' => ['.git','.svn'], - 'future' => true, - 'lsi' => false, - 'pygments' => false, - 'markdown' => 'maruku', - 'permalink' => 'date', - 'include' => ['.htaccess'], - 'paginate_path' => 'page:num', + 'future' => true, # remove and make true just default + 'pygments' => false, # remove and make true just default + + 'markdown' => 'maruku', # no longer a command option + 'permalink' => 'date', # no longer a command option + 'include' => ['.htaccess'], # no longer a command option + 'paginate_path' => 'page:num', # no longer a command option 'markdown_ext' => 'markdown,mkd,mkdn,md', 'textile_ext' => 'textile', @@ -120,6 +119,9 @@ module Jekyll # # Returns the final configuration Hash. def self.configuration(override) + # Convert any symbol keys to strings and remove the old key/values + override = override.reduce({}) { |hsh,(k,v)| hsh.merge(k.to_s => v) } + # _config.yml may override default source location, but until # then, we need to know where to look for _config.yml source = override['source'] || Jekyll::DEFAULTS['source'] diff --git a/lib/jekyll/command.rb b/lib/jekyll/command.rb new file mode 100644 index 00000000..340d457d --- /dev/null +++ b/lib/jekyll/command.rb @@ -0,0 +1,14 @@ +module Jekyll + + class Command + def self.globs(source) + Dir.chdir(source) do + dirs = Dir['*'].select { |x| File.directory?(x) } + dirs -= ['_site'] + dirs = dirs.map { |x| "#{x}/**/*" } + dirs += ['*'] + end + end + end + +end diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb new file mode 100644 index 00000000..27461101 --- /dev/null +++ b/lib/jekyll/commands/build.rb @@ -0,0 +1,76 @@ +module Jekyll + + class BuildCommand < Command + def self.process(options) + site = Jekyll::Site.new(options) + + source = options['source'] + destination = options['destination'] + + if options['watch'] + self.watch(site, options) + else + self.build(site, options) + end + end + + # Private: Build the site from source into destination. + # + # site - A Jekyll::Site instance + # options - A Hash of options passed to the command + # + # Returns nothing. + def self.build(site, options) + source = options['source'] + destination = options['destination'] + puts "Building site: #{source} -> #{destination}" + begin + site.process + rescue Jekyll::FatalException => e + puts + puts "ERROR: YOUR SITE COULD NOT BE BUILT:" + puts "------------------------------------" + puts e.message + exit(1) + end + puts "Successfully generated site: #{source} -> #{destination}" + end + + # Private: Watch for file changes and rebuild the site. + # + # site - A Jekyll::Site instance + # options - A Hash of options passed to the command + # + # Returns nothing. + def self.watch(site, options) + require 'directory_watcher' + + source = options['source'] + destination = options['destination'] + + puts "Auto-Regenerating enabled: #{source} -> #{destination}" + + dw = DirectoryWatcher.new(source) + dw.interval = 1 + dw.glob = self.globs(source) + + dw.add_observer do |*args| + t = Time.now.strftime("%Y-%m-%d %H:%M:%S") + puts "[#{t}] regeneration: #{args.size} files changed" + site.process + end + + dw.start + + unless options['serving'] + trap("INT") do + puts "Stopping auto-regeneration..." + exit 0 + end + + loop { sleep 1000 } + end + end + end + +end diff --git a/lib/jekyll/commands/migrate.rb b/lib/jekyll/commands/migrate.rb new file mode 100644 index 00000000..26937357 --- /dev/null +++ b/lib/jekyll/commands/migrate.rb @@ -0,0 +1,47 @@ +module Jekyll + + class MigrateCommand < Command + MIGRATORS = { + :csv => 'CSV', + :drupal => 'Drupal', + :enki => 'Enki', + :mephisto => 'Mephisto', + :mt => 'MT', + :posterous => 'Posterous', + :textpattern => 'TextPattern', + :tumblr => 'Tumblr', + :typo => 'Typo', + :wordpressdotcom => 'WordpressDotCom', + :wordpress => 'WordPress' + } + + def self.process(migrator, options) + abort 'missing argument. Please specify a migrator' if migrator.nil? + migrator = migrator.downcase + + cmd_options = [] + [ :file, :dbname, :user, :pass, :host, :site ].each do |p| + cmd_options << "\"#{options[p]}\"" unless options[p].nil? + end + + + if MIGRATORS.keys.include?(migrator) + app_root = File.expand_path( + File.join(File.dirname(__FILE__), '..', '..', '..') + ) + + require "#{app_root}/lib/jekyll/migrators/#{migrator}" + + if Jekyll.const_defiend?(MIGRATORS[migrator.to_sym]) + puts 'Importing...' + migrator_class = Jekyll.const_get(MIGRATORS[migrator.to_sym]) + migrator_class.process(*cmd_options) + exit 0 + end + end + + abort 'invalid migrator. Please specify a valid migrator' + end + end + +end diff --git a/lib/jekyll/commands/serve.rb b/lib/jekyll/commands/serve.rb new file mode 100644 index 00000000..df717bea --- /dev/null +++ b/lib/jekyll/commands/serve.rb @@ -0,0 +1,28 @@ +module Jekyll + + class ServeCommand < Command + def self.process(options) + require 'webrick' + include WEBrick + + destination = options['destination'] + + FileUtils.mkdir_p(destination) + + mime_types = WEBrick::HTTPUtils::DefaultMimeTypes + mime_types.store 'js', 'application/javascript' + + s = HTTPServer.new( + :Port => options['port'], + :BindAddress => options['host'], + :MimeTypes => mime_types + ) + + s.mount(options['baseurl'], HTTPServlet::FileHandler, destination) + t = Thread.new { s.start } + trap("INT") { s.shutdown } + t.join() + end + end + +end diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index dab0545c..e71fe1bf 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -33,9 +33,9 @@ module Jekyll self.data = YAML.load($1) end rescue => e - puts "Error reading file #{name}: #{e.message}" + puts "Error reading file #{File.join(base, name)}: #{e.message}" rescue SyntaxError => e - puts "YAML Exception reading #{name}: #{e.message}" + puts "YAML Exception reading #{File.join(base, name)}: #{e.message}" end self.data ||= {} diff --git a/lib/jekyll/core_ext.rb b/lib/jekyll/core_ext.rb index fc40cb38..dfc5bbf7 100644 --- a/lib/jekyll/core_ext.rb +++ b/lib/jekyll/core_ext.rb @@ -50,3 +50,11 @@ class Date strftime("%Y-%m-%dT%H:%M:%S%Z") end if RUBY_VERSION < '1.9' end + +module Enumerable + # Returns true if path matches against any glob pattern. + # Look for more detail about glob pattern in method File::fnmatch. + def glob_include?(e) + any? { |exp| File.fnmatch?(exp, e) } + end +end diff --git a/lib/jekyll/migrators/posterous.rb b/lib/jekyll/migrators/posterous.rb index f1601ba3..0a2280f2 100644 --- a/lib/jekyll/migrators/posterous.rb +++ b/lib/jekyll/migrators/posterous.rb @@ -1,14 +1,11 @@ require 'rubygems' require 'jekyll' require 'fileutils' -require 'net/https' -require 'open-uri' +require 'net/http' require 'uri' require "json" -# 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 +# ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, api_key, blog)' module Jekyll module Posterous @@ -17,9 +14,6 @@ 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 @@ -29,50 +23,36 @@ 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', tags_key = 'categories') + def self.process(email, pass, api_token, blog = 'primary') @email, @pass, @api_token = email, pass, api_token FileUtils.mkdir_p "_posts" - posts = JSON.parse(self.fetch("/api/2/sites/#{blog}/posts?api_token=#{@api_token}").body) + posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}").body) page = 1 while posts.any? posts.each do |post| title = post["title"] - slug = title.gsub(/[^[:alnum:]]+/, '-').gsub(/^-+|-+$/, '').downcase - posterous_slug = post["slug"] + slug = title.gsub(/[^[:alnum:]]+/, '-').downcase 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, - tags_key => tags, - 'posterous_url' => post["full_url"], - 'posterous_slug' => posterous_slug + 'published' => published }.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 @@ -80,7 +60,7 @@ module Jekyll end page += 1 - posts = JSON.parse(self.fetch("/api/2/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body) + posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body) end end end diff --git a/lib/jekyll/migrators/tumblr.rb b/lib/jekyll/migrators/tumblr.rb index 367a83c9..8b717d5d 100644 --- a/lib/jekyll/migrators/tumblr.rb +++ b/lib/jekyll/migrators/tumblr.rb @@ -34,6 +34,7 @@ module Jekyll post[:content] = html_to_markdown post[:content] post[:content] = add_syntax_highlights post[:content] if add_highlights end + post[:name] = truncate_post_name post[:name] if post[:name].size > 255 File.open("_posts/tumblr/#{post[:name]}", "w") do |f| f.puts post[:header].to_yaml + "---\n" + post[:content] end @@ -42,6 +43,11 @@ module Jekyll private + def self.truncate_post_name name + post = name.match(/^(.+)\.(.+)$/).captures + post[0][0..(-1 - post[1].size)] + post[1].size + end + # Converts each type of Tumblr post to a hash with all required # data for Jekyll. def self.post_to_hash(post, format) diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 82b82048..a821bb63 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -24,6 +24,18 @@ module Jekyll self.read_yaml(File.join(base, dir), name) end + # Read the YAML frontmatter. + # + # base - The String path to the dir containing the file. + # name - The String filename of the file. + # + # Returns nothing. + def read_yaml(base, name) + super(base, name) + self.data['layout'] = 'page' unless self.data.has_key?('layout') + self.data + end + # The generated directory into which the page will be placed # upon generation. This is derived from the permalink or, if # permalink is absent, we be '/' diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index a360cb8d..835f9a42 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -66,6 +66,18 @@ module Jekyll end end + # Read the YAML frontmatter. + # + # base - The String path to the dir containing the file. + # name - The String filename of the file. + # + # Returns nothing. + def read_yaml(base, name) + super(base, name) + self.data['layout'] = 'post' unless self.data.has_key?('layout') + self.data + end + # Compares Post objects. First compares the Post date. If the dates are # equal, it compares the Post slugs. # @@ -171,9 +183,12 @@ module Jekyll if self.site.lsi self.class.lsi ||= begin - puts "Running the classifier... this could take a while." - lsi = Classifier::LSI.new + puts "Starting the classifier..." + lsi = Classifier::LSI.new(:auto_rebuild => false) + $stdout.print(" Populating LSI... ");$stdout.flush posts.each { |x| $stdout.print(".");$stdout.flush;lsi.add_item(x) } + $stdout.print("\n Rebuilding LSI index... ") + lsi.build_index puts "" lsi end diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 01032722..7a33d042 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -5,7 +5,8 @@ module Jekyll class Site attr_accessor :config, :layouts, :posts, :pages, :static_files, :categories, :exclude, :include, :source, :dest, :lsi, :pygments, - :permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts + :permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts, + :keep_files attr_accessor :converters, :generators @@ -26,6 +27,7 @@ module Jekyll self.include = config['include'] || [] self.future = config['future'] self.limit_posts = config['limit_posts'] || nil + self.keep_files = config['keep_files'] || [] self.reset self.setup @@ -234,8 +236,12 @@ module Jekyll def cleanup # all files and directories in destination, including hidden ones dest_files = Set.new - Dir.glob(File.join(self.dest, "**", "*")) do |file| - dest_files << file + Dir.glob(File.join(self.dest, "**", "*"), File::FNM_DOTMATCH) do |file| + if self.keep_files.length > 0 + dest_files << file unless file =~ /\/\.{1,2}$/ || file =~ keep_file_regex + else + dest_files << file unless file =~ /\/\.{1,2}$/ + end end # files to be written @@ -256,10 +262,21 @@ module Jekyll files.merge(dirs) obsolete_files = dest_files - files - FileUtils.rm_rf(obsolete_files.to_a) end + # Private: creates a regular expression from the keep_files array + # + # Examples + # ['.git','.svn'] creates the following regex: /\/(\.git|\/.svn)/ + # + # Returns the regular expression + def keep_file_regex + or_list = self.keep_files.join("|") + pattern = "\/(#{or_list.gsub(".", "\.")})" + Regexp.new pattern + end + # Write static files, pages, and posts. # # Returns nothing. @@ -330,10 +347,10 @@ module Jekyll # Returns the Array of filtered entries. def filter_entries(entries) entries.reject do |e| - unless self.include.include?(e) + unless self.include.glob_include?(e) ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || - self.exclude.include?(e) || + self.exclude.glob_include?(e) || File.symlink?(e) end end diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb index 9ad69b3e..e16602a7 100644 --- a/lib/jekyll/tags/highlight.rb +++ b/lib/jekyll/tags/highlight.rb @@ -15,8 +15,8 @@ module Jekyll super if markup.strip =~ SYNTAX @lang = $1 + @options = {} if defined?($2) && $2 != '' - tmp_options = {} $2.split.each do |opt| key, value = opt.split('=') if value.nil? @@ -26,13 +26,8 @@ module Jekyll value = true end end - tmp_options[key] = value + @options[key] = value end - tmp_options = tmp_options.to_a.sort.collect { |opt| opt.join('=') } - # additional options to pass to Albino - @options = { 'O' => tmp_options.join(',') } - else - @options = {} end else raise SyntaxError.new("Syntax Error in 'highlight' - Valid syntax: highlight [linenos]") diff --git a/site/_includes/docs_contents.html b/site/_includes/docs_contents.html index ad3f3e16..7e7637f3 100644 --- a/site/_includes/docs_contents.html +++ b/site/_includes/docs_contents.html @@ -71,6 +71,9 @@
  • Troubleshooting
  • +
  • + Sites using Jekyll +
  • Resources
  • diff --git a/site/_posts/2012-07-01-configuration.md b/site/_posts/2012-07-01-configuration.md index a942914b..7fcb34fe 100644 --- a/site/_posts/2012-07-01-configuration.md +++ b/site/_posts/2012-07-01-configuration.md @@ -9,6 +9,8 @@ Jekyll allows you to concoct your sites in any way you can dream up, and it’s ## Configuration Settings +### Global Configuration + The table below lists the available settings for Jekyll, and the various options (specifed in the configuration file) and flags (specified on the command-line) that control them. @@ -19,6 +21,26 @@ The table below lists the available settings for Jekyll, and the various + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
    +

    Site Source

    +

    Changes the directory where Jekyll will look to transform files

    +
    +

    source: [string]

    +

    --source [source]

    +
    +

    Site Destination

    +

    Changes the directory where Jekyll will write files to

    +
    +

    destination: [string]

    +

    --destination

    +

    Safe

    @@ -29,140 +51,6 @@ The table below lists the available settings for Jekyll, and the various --safe

    -

    Regeneration

    -

    Enables or disables Jekyll from recreating the site when files are modified.

    -
    -

    auto: [boolean]

    -

    --auto

    -

    --no-auto

    -
    -

    Local Server

    -

    Fires up a server that will host your _site directory

    -
    -

    server: [boolean]

    -

    --server

    -
    -

    Local Server Port

    -

    Changes the port that the Jekyll server will run on

    -
    -

    server_port: [integer]

    -

    --server [port]

    -
    -

    Base URL

    -

    Serve website from a given base URL

    -
    -

    baseurl: [BASE_URL]

    -

    --base-url [url]

    -
    -

    URL

    -

    Sets site.url, useful for environment switching

    -
    -

    url: [URL]

    -

    --url [URL]

    -
    -

    Site Destination

    -

    Changes the directory where Jekyll will write files to

    -
    -

    destination: [dir]

    -

    jekyll [dest]

    -
    -

    Site Source

    -

    Changes the directory where Jekyll will look to transform files

    -
    -

    source: [dir]

    -

    jekyll [source] [dest]

    -
    -

    Markdown

    -

    Uses RDiscount or [engine] instead of Maruku.

    -
    -

    markdown: [engine]

    -

    --rdiscount

    -

    --kramdown

    -

    --redcarpet

    -
    -

    Pygments

    -

    Enables highlight tag with Pygments.

    -
    -

    pygments: [boolean]

    -

    --pygments

    -
    -

    Future

    -

    Publishes posts with a future date

    -
    -

    future: [boolean]

    -

    --no-future

    -

    --future

    -
    -

    LSI

    -

    Produces an index for related posts.

    -
    -

    lsi: [boolean]

    -

    --lsi

    -
    -

    Permalink

    -

    Controls the URLs that posts are generated with. Please refer to the Permalinks page for more info.

    -
    -

    permalink: [style]

    -

    --permalink=[style]

    -
    -

    Pagination

    -

    Splits your posts up over multiple subdirectories called "page2", "page3", ... "pageN"

    -
    -

    paginate: [per_page]

    -

    --paginate [per_page]

    -

    Exclude

    @@ -181,6 +69,98 @@ The table below lists the available settings for Jekyll, and the various include: [dir1, file1, dir2]

    + +### Build Command Options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SettingOptions and Flags
    +

    Regeneration

    +

    Enables auto-regeneration of the site when files are modified. Off by default.

    +
    +

    --watch

    +
    +

    URL

    +

    Sets site.url, useful for environment switching

    +
    +

    url: [URL]

    +

    --url [URL]

    +
    +

    Markdown

    +

    Uses RDiscount or [engine] instead of Maruku.

    +
    +

    markdown: [engine]

    +

    --markdown [rdiscount|kramdown|redcarpet]

    +
    +

    Pygments

    +

    Enables highlight tag with Pygments.

    +
    +

    pygments: [boolean]

    +

    --pygments

    +
    +

    Future

    +

    Publishes posts with a future date

    +
    +

    future: [boolean]

    +

    --future

    +
    +

    LSI

    +

    Produces an index for related posts.

    +
    +

    lsi: [boolean]

    +

    --lsi

    +
    +

    Permalink

    +

    Controls the URLs that posts are generated with. Please refer to the Permalinks page for more info.

    +
    +

    permalink: [style]

    +

    --permalink [style]

    +
    +

    Pagination

    +

    Splits your posts up over multiple subdirectories called "page2", "page3", ... "pageN"

    +
    +

    paginate: [per_page]

    +

    --paginate [per_page]

    +

    Limit Posts

    @@ -188,10 +168,56 @@ The table below lists the available settings for Jekyll, and the various

    limit_posts: [max_posts]

    -

    --limit_posts=[max_posts]

    +

    --limit_posts [max_posts]

    +### Serve Command Options + +In addition to the options below, the `serve` sub-command can accept any of the options +for the `build` sub-command, which are then applied to the site build which occurs right +before your site is served. + + + + + + + + + + + + + + + + + + + + +
    SettingOptions and Flags
    +

    Local Server Port

    +

    Changes the port that the Jekyll server will run on

    +
    +

    port: [integer]

    +

    --port [port]

    +
    +

    Local Server Hostname

    +

    Changes the hostname that the Jekyll server will run on

    +
    +

    host: [string]

    +

    --host [hostname]

    +
    +

    Base URL

    +

    Serve website from a given base URL

    +
    +

    baseurl: [BASE_URL]

    +

    --baseurl [url]

    +
    @@ -206,9 +232,10 @@ Jekyll runs with the following configuration options by default. Unless alternat {% highlight yaml %} safe: false -auto: false +watch: false server: false -server_port: 4000 +host: 0.0.0.0 +port: 4000 baseurl: / url: http://localhost:4000 diff --git a/site/_posts/2012-07-01-deployment-methods.md b/site/_posts/2012-07-01-deployment-methods.md index 7716e5f8..80b55ae3 100644 --- a/site/_posts/2012-07-01-deployment-methods.md +++ b/site/_posts/2012-07-01-deployment-methods.md @@ -53,7 +53,7 @@ TMP_GIT_CLONE=$HOME/tmp/myrepo PUBLIC_WWW=/var/www/myrepo git clone $GIT_REPO $TMP_GIT_CLONE -jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW +jekyll build $TMP_GIT_CLONE $PUBLIC_WWW rm -Rf $TMP_GIT_CLONE exit {% endhighlight %} diff --git a/site/_posts/2012-07-01-extras.md b/site/_posts/2012-07-01-extras.md index 1af24d10..7bbff0b9 100644 --- a/site/_posts/2012-07-01-extras.md +++ b/site/_posts/2012-07-01-extras.md @@ -91,7 +91,7 @@ sudo gem install rdiscount And then run Jekyll with the following option: {% highlight bash %} -jekyll --rdiscount +jekyll build --markdown rdiscount {% endhighlight %} Or, specify RDiscount as the markdown engine in your `_config.yml` file to have Jekyll run with that option by default (so you don’t have to specify the flag every time). diff --git a/site/_posts/2012-07-01-home.md b/site/_posts/2012-07-01-home.md index 9c27eeef..34de7bb1 100644 --- a/site/_posts/2012-07-01-home.md +++ b/site/_posts/2012-07-01-home.md @@ -19,7 +19,7 @@ For the impatient, here's how to get Jekyll up and running. ~ $ mkdir -p my/new/site ~ $ cd my/new/site ~ $ vim index.html -~/my/new/site $ jekyll --server +~/my/new/site $ jekyll serve # => Now browse to http://localhost:4000 {% endhighlight %} diff --git a/site/_posts/2012-07-01-sites.md b/site/_posts/2012-07-01-sites.md new file mode 100644 index 00000000..f28c0280 --- /dev/null +++ b/site/_posts/2012-07-01-sites.md @@ -0,0 +1,28 @@ +--- +layout: docs +title: Sites using Jekyll +prev_section: troubleshooting +next_section: resources +--- + +It’s interesting to see what designs and features others have come up +with. Below are some Jekyll-powered blogs which were hand-picked for +learning purposes. + +- [Tom Preston-Werner](http://tom.preston-werner.com/) + ([source](http://github.com/mojombo/mojombo.github.com)) +- [Nick Quaranto](http://quaran.to/) + ([source](https://github.com/qrush/qrush.github.com)) +- [Roger Chapman](http://rogchap.com/) + ([source](https://github.com/rogchap/rogchap.github.com)) +- [GitHub Official Teaching Materials](http://teach.github.com) + ([source](https://github.com/github/teach.github.com)) +- [Rasmus Andersson](http://rsms.me/) + ([source](https://github.com/rsms/rsms.github.com)) +- [Scott Chacon](http://schacon.github.com) + ([source](https://github.com/schacon/schacon.github.com)) + +If you would like to explore more examples, you can find a list of sites +and their sources on the ["Sites" page in the Jekyll wiki][jekyll-sites]. + +[jekyll-sites]: https://github.com/mojombo/jekyll/wiki/Sites diff --git a/site/_posts/2012-07-01-structure.md b/site/_posts/2012-07-01-structure.md index 78212f03..87362b44 100644 --- a/site/_posts/2012-07-01-structure.md +++ b/site/_posts/2012-07-01-structure.md @@ -88,7 +88,7 @@ An overview of what each of these does:

    Other Files/Folders

    -

    Every other directory and file except for those listed above—such as css and images folders, favicon.ico files, and so forth—will be transferred over verbatim to the generated site. There's plenty of sites already using Jekyll if you're curious as to how they're laid out.

    +

    Every other directory and file except for those listed above—such as css and images folders, favicon.ico files, and so forth—will be transferred over verbatim to the generated site. There's plenty of sites already using Jekyll if you're curious as to how they're laid out.

    diff --git a/site/_posts/2012-07-01-troubleshooting.md b/site/_posts/2012-07-01-troubleshooting.md index e6a592f2..08dac8e8 100644 --- a/site/_posts/2012-07-01-troubleshooting.md +++ b/site/_posts/2012-07-01-troubleshooting.md @@ -50,7 +50,7 @@ On Debian or Ubuntu, you may need to add /var/lib/gems/1.8/bin/ to your path in ## Base-URL Problems -If you are using base-url option like `jekyll --server --base-url '/blog'` then make sure that you access the site at `http://localhost:4000/blog/index.html`. Just accessing `http://localhost:4000/blog` will not work. +If you are using base-url option like `jekyll serve --baseurl '/blog'` then make sure that you access the site at `http://localhost:4000/blog/index.html`. Just accessing `http://localhost:4000/blog` will not work. ## Configuration problems diff --git a/site/_posts/2012-07-01-usage.md b/site/_posts/2012-07-01-usage.md index c1cfa5b1..ae1b07e1 100644 --- a/site/_posts/2012-07-01-usage.md +++ b/site/_posts/2012-07-01-usage.md @@ -8,28 +8,31 @@ next_section: structure The Jekyll gem makes a `jekyll` executable available to you in your Terminal window. You can use this command in a number of ways: {% highlight bash %} -jekyll +jekyll build #=> The current folder will get generated into ./_site -jekyll +jekyll build --destination #=> The current folder will get generated into -jekyll +jekyll build --source --destination #=> The folder will get generated into +jekyll build --watch +#=> The current folder will get generated into ./_site, +# and watch for changes and regenerate automatically. {% endhighlight %} Jekyll also comes with a built-in development server that will allow you to preview what the generated site will look like in your browser locally. {% highlight bash %} -jekyll --server +jekyll serve #=> A development server will run at http://localhost:4000/ -jekyll --server --auto +jekyll serve --watch #=> As above, but watch for changes and regenerate automatically too. {% endhighlight %} -These are just some of the many [configuration options](../configuration) available. All configuration options can either be specified as flags on the command line, or alternatively (and more commonly) they can be specified in a `_config.yml` file at the root of the source directory. Jekyll will automatically configuration options from this file when run, so placing the following two lines in the configuration file will mean that running `jekyll` would be equivalent to running `jekyll --server --auto`: +These are just some of the many [configuration options](../configuration) available. All configuration options can either be specified as flags on the command line, or alternatively (and more commonly) they can be specified in a `_config.yml` file at the root of the source directory. Jekyll will automatically configuration options from this file when run, so placing the following one line in the configuration file will mean that running `jekyll build` or `jekyll serve` would be equivalent to running `jekyll [build|serve] --source _source --destination _deploy`: {% highlight yaml %} -auto: true -server: true +source: _source +destination: _deploy {% endhighlight %} For more about the possible configuration options, see the [configuration](../configuration) page. diff --git a/site/_posts/2012-07-01-variables.md b/site/_posts/2012-07-01-variables.md index b04c14f5..01091474 100644 --- a/site/_posts/2012-07-01-variables.md +++ b/site/_posts/2012-07-01-variables.md @@ -68,7 +68,7 @@ Jekyll traverses your site looking for files to process. Any files with [YAML Fr

    site.[CONFIGURATION_DATA]

    -

    All variables set in your _config.yml are available through the site variable. For example, if you have url: http://mysite.com in your configuration file, then in your posts and pages it can be accessed using {{ "{{ site.url " }}}}. Jekyll does not parse changes to _config.yml in auto mode, you have to restart Jekyll to see changes to variables.

    +

    All variables set in your _config.yml are available through the site variable. For example, if you have url: http://mysite.com in your configuration file, then in your posts and pages it can be accessed using {{ "{{ site.url " }}}}. Jekyll does not parse changes to _config.yml in watch mode, you have to restart Jekyll to see changes to variables.

    diff --git a/site/index.html b/site/index.html index 86711cd8..c0a35828 100644 --- a/site/index.html +++ b/site/index.html @@ -16,19 +16,19 @@ overview: true

    No more databases, comment moderation, or pesky updates to install—just your content.

    - How Jekyll works → + How Jekyll works →

    Static

    Markdown (or Textile), Liquid, HTML & CSS go in. Static sites come out ready for deployment.

    - Jekyll template guide → + Jekyll template guide →

    Blog-aware

    Permalinks, categories, pages, posts, and custom layouts are all first-class citizens here.

    - Migrate your blog → + Migrate your blog →
    @@ -54,7 +54,7 @@ overview: true

    ~/my/awesome/site $ - jekyll --server + jekyll serve

    # => Now browse to http://localhost:4000 diff --git a/test/source/_posts/2013-01-12-nil-layout.textile b/test/source/_posts/2013-01-12-nil-layout.textile new file mode 100644 index 00000000..1e12fa9f --- /dev/null +++ b/test/source/_posts/2013-01-12-nil-layout.textile @@ -0,0 +1,6 @@ +--- +layout: nil +title: No layout +--- + +This post has no layout. diff --git a/test/source/_posts/2013-01-12-no-layout.textile b/test/source/_posts/2013-01-12-no-layout.textile new file mode 100644 index 00000000..1c745ae0 --- /dev/null +++ b/test/source/_posts/2013-01-12-no-layout.textile @@ -0,0 +1,5 @@ +--- +title: I have no layout +--- + +This post will be rendered with the "post" layout. diff --git a/test/test_convertible.rb b/test/test_convertible.rb index b9a9e41c..82e4d27f 100644 --- a/test/test_convertible.rb +++ b/test/test_convertible.rb @@ -20,20 +20,24 @@ class TestConvertible < Test::Unit::TestCase end should "not parse if there is syntax error in front-matter" do + name = 'broken_front_matter2.erb' out = capture_stdout do - ret = @convertible.read_yaml(@base, 'broken_front_matter2.erb') + ret = @convertible.read_yaml(@base, name) assert_equal({}, ret) end assert_match(/YAML Exception|syntax error/, out) + assert_match(/#{File.join(@base, name)}/, out) end if RUBY_VERSION >= '1.9.2' should "not parse if there is encoding error in file" do + name = 'broken_front_matter3.erb' out = capture_stdout do - ret = @convertible.read_yaml(@base, 'broken_front_matter3.erb') + ret = @convertible.read_yaml(@base, name) assert_equal({}, ret) end assert_match(/invalid byte sequence in UTF-8/, out) + assert_match(/#{File.join(@base, name)}/, out) end end end diff --git a/test/test_core_ext.rb b/test/test_core_ext.rb index c3e62cb5..0b79f33f 100644 --- a/test/test_core_ext.rb +++ b/test/test_core_ext.rb @@ -63,4 +63,26 @@ class TestCoreExt < Test::Unit::TestCase end end + + context "enumerable" do + context "glob_include?" do + should "return false with no glob patterns" do + assert ![].glob_include?("a.txt") + end + + should "return false with all not match path" do + data = ["a*", "b?"] + assert !data.glob_include?("ca.txt") + assert !data.glob_include?("ba.txt") + end + + should "return true with match path" do + data = ["a*", "b?", "**/a*"] + assert data.glob_include?("a.txt") + assert data.glob_include?("ba") + assert data.glob_include?("c/a/a.txt") + assert data.glob_include?("c/a/b/a.txt") + end + end + end end diff --git a/test/test_generated_site.rb b/test/test_generated_site.rb index 9fb7a409..552e2417 100644 --- a/test/test_generated_site.rb +++ b/test/test_generated_site.rb @@ -14,7 +14,7 @@ class TestGeneratedSite < Test::Unit::TestCase end should "ensure post count is as expected" do - assert_equal 28, @site.posts.size + assert_equal 30, @site.posts.size end should "insert site.posts into the index" do diff --git a/test/test_page.rb b/test/test_page.rb index 61278997..3c7c9fed 100644 --- a/test/test_page.rb +++ b/test/test_page.rb @@ -66,6 +66,26 @@ class TestPage < Test::Unit::TestCase assert_equal "/about/", @page.dir end end + + context "with unspecified layout" do + setup do + @page = setup_page('contacts.html') + end + + should "default to 'post' layout" do + assert_equal "page", @page.data["layout"] + end + end + + context "with specified layout of nil" do + setup do + @page = setup_page('sitemap.xml') + end + + should "layout of nil is respected" do + assert_equal "nil", @page.data["layout"] + end + end context "rendering" do setup do diff --git a/test/test_post.rb b/test/test_post.rb index 245c30b4..16aff4f1 100644 --- a/test/test_post.rb +++ b/test/test_post.rb @@ -95,7 +95,7 @@ class TestPost < Test::Unit::TestCase should "consume the embedded dashes" do @post.read_yaml(@source, @real_file) - assert_equal({"title" => "Foo --- Bar"}, @post.data) + assert_equal({"title" => "Foo --- Bar", "layout" => "post"}, @post.data) assert_equal "Triple the fun!", @post.content end end @@ -128,6 +128,30 @@ class TestPost < Test::Unit::TestCase end end + context "with unspecified layout" do + setup do + file = '2013-01-12-no-layout.textile' + @post = setup_post(file) + @post.process(file) + end + + should "default to 'post' layout" do + assert_equal "post", @post.data["layout"] + end + end + + context "with specified layout of nil" do + setup do + file = '2013-01-12-nil-layout.textile' + @post = setup_post(file) + @post.process(file) + end + + should "layout of nil is respected" do + assert_equal "nil", @post.data["layout"] + end + end + context "with unspecified (date) style and categories" do setup do @post.categories << "food" diff --git a/test/test_site.rb b/test/test_site.rb index 98a433b6..9219e102 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -155,13 +155,13 @@ class TestSite < Test::Unit::TestCase excludes = %w[README TODO] files = %w[index.html site.css .htaccess] - @site.exclude = excludes - assert_equal files, @site.filter_entries(excludes + files) + @site.exclude = excludes + ["exclude*"] + assert_equal files, @site.filter_entries(excludes + files + ["excludeA"]) end should "not filter entries within include" do - includes = %w[_index.html .htaccess] - files = %w[index.html _index.html .htaccess] + includes = %w[_index.html .htaccess include*] + files = %w[index.html _index.html .htaccess includeA] @site.include = includes assert_equal files, @site.filter_entries(files) @@ -201,12 +201,22 @@ class TestSite < Test::Unit::TestCase File.open(dest_dir('qux/obsolete.html'), 'w') # empty directory FileUtils.mkdir(dest_dir('quux')) + FileUtils.mkdir(dest_dir('.git')) + FileUtils.mkdir(dest_dir('.svn')) + FileUtils.mkdir(dest_dir('.hg')) + # single file in repository + File.open(dest_dir('.git/HEAD'), 'w') + File.open(dest_dir('.svn/HEAD'), 'w') + File.open(dest_dir('.hg/HEAD'), 'w') end teardown do FileUtils.rm_f(dest_dir('obsolete.html')) FileUtils.rm_rf(dest_dir('qux')) FileUtils.rm_f(dest_dir('quux')) + FileUtils.rm_rf(dest_dir('.git')) + FileUtils.rm_rf(dest_dir('.svn')) + FileUtils.rm_rf(dest_dir('.hg')) end should 'remove orphaned files in destination' do @@ -214,8 +224,23 @@ class TestSite < Test::Unit::TestCase assert !File.exist?(dest_dir('obsolete.html')) assert !File.exist?(dest_dir('qux')) assert !File.exist?(dest_dir('quux')) + assert File.exist?(dest_dir('.git')) + assert File.exist?(dest_dir('.git/HEAD')) end + should 'remove orphaned files in destination - keep_files .svn' do + config = Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'keep_files' => ['.svn']}) + @site = Site.new(config) + @site.process + assert !File.exist?(dest_dir('.htpasswd')) + assert !File.exist?(dest_dir('obsolete.html')) + assert !File.exist?(dest_dir('qux')) + assert !File.exist?(dest_dir('quux')) + assert !File.exist?(dest_dir('.git')) + assert !File.exist?(dest_dir('.git/HEAD')) + assert File.exist?(dest_dir('.svn')) + assert File.exist?(dest_dir('.svn/HEAD')) + end end context 'with an invalid markdown processor in the configuration' do diff --git a/test/test_tags.rb b/test/test_tags.rb index ab0f3188..816fd809 100644 --- a/test/test_tags.rb +++ b/test/test_tags.rb @@ -32,6 +32,7 @@ title: This is a test This document results in a markdown error with maruku {% highlight text %}#{code}{% endhighlight %} +{% highlight text linenos %}#{code}{% endhighlight %} CONTENT create_post(content, override) end @@ -58,16 +59,16 @@ CONTENT assert_equal({}, tag.instance_variable_get(:@options)) tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos ', ["test", "{% endhighlight %}", "\n"]) - assert_equal({'O' => "linenos=inline"}, tag.instance_variable_get(:@options)) + assert_equal({ 'linenos' => 'inline' }, tag.instance_variable_get(:@options)) tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table ', ["test", "{% endhighlight %}", "\n"]) - assert_equal({'O' => "linenos=table"}, tag.instance_variable_get(:@options)) + assert_equal({ 'linenos' => 'table' }, tag.instance_variable_get(:@options)) tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table nowrap', ["test", "{% endhighlight %}", "\n"]) - assert_equal({'O' => "linenos=table,nowrap=true"}, tag.instance_variable_get(:@options)) + assert_equal({ 'linenos' => 'table', 'nowrap' => true }, tag.instance_variable_get(:@options)) tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table cssclass=hl', ["test", "{% endhighlight %}", "\n"]) - assert_equal({'O' => "cssclass=hl,linenos=table"}, tag.instance_variable_get(:@options)) + assert_equal({ 'cssclass' => 'hl', 'linenos' => 'table' }, tag.instance_variable_get(:@options)) end end @@ -80,9 +81,13 @@ CONTENT assert_no_match /markdown\-html\-error/, @result end - should "render markdown with pygments line handling" do + should "render markdown with pygments" do assert_match %{

    test\n
    }, @result end + + should "render markdown with pygments with line numbers" do + assert_match %{
    1 test\n
    }, @result + end end context "post content has highlight with file reference" do