Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Drafts fixup #833

Merged
merged 16 commits into from
This page is out of date. Refresh to see the latest.
View
1  History.txt
@@ -2,6 +2,7 @@
* Major Enhancements
* Refactored jekyll commands into subcommands: build, serve, and migrate. (#690)
* Removed importers/migrators from main project, migrated to jekyll-import sub-gem (#793)
+ * Added ability to render drafts in _drafts folder via command line (#833)
* Minor Enhancements
* Improve debugability of error message for a malformed highlight tag (#785)
* Allow symlinked files in unsafe mode (#824)
View
21 bin/jekyll
@@ -17,6 +17,19 @@ global_option '--safe', 'Safe mode (defaults to false)'
global_option '--plugins', 'Plugins directory (defaults to ./_plugins)'
global_option '--layouts', 'Layouts directory (defaults to ./_layouts)'
+# Option names don't always directly match the configuration value we'd like.
+# This method will rename options to match what Jekyll configuration expects.
+#
+# options - The Hash of options from Commander.
+#
+# Returns the normalized Hash.
+def normalize_options(options)
+ if drafts_state = options.delete(:drafts)
+ options[:show_drafts] = drafts_state
+ end
+ options
+end
+
command :build do |c|
c.syntax = 'jekyll build [options]'
c.description = 'Build your site'
@@ -25,10 +38,12 @@ command :build do |c|
c.option '--limit_posts MAX_POSTS', 'Limits the number of posts to parse and publish'
c.option '-w', '--watch', 'Watch for changes and rebuild'
c.option '--lsi', 'Use LSI for improved related posts'
+ c.option '--drafts', 'Render posts in the _drafts folder'
c.action do |args, options|
options.defaults :serving => false
- options = Jekyll.configuration(options.__hash__)
+ options = normalize_options(options.__hash__)
+ options = Jekyll.configuration(options)
Jekyll::Commands::Build.process(options)
end
end
@@ -41,6 +56,7 @@ command :serve do |c|
c.option '--limit_posts MAX_POSTS', 'Limits the number of posts to parse and publish'
c.option '-w', '--watch', 'Watch for changes and rebuild'
c.option '--lsi', 'Use LSI for improved related posts'
+ c.option '--drafts', 'Render posts in the _drafts folder'
c.option '-p', '--port [PORT]', 'Port to listen on'
c.option '-h', '--host [HOST]', 'Host to bind to'
@@ -52,7 +68,8 @@ command :serve do |c|
:baseurl => '/',
:serving => true
- options = Jekyll.configuration(options.__hash__)
+ options = normalize_options(options.__hash__)
+ options = Jekyll.configuration(options)
Jekyll::Commands::Build.process(options)
Jekyll::Commands::Serve.process(options)
end
View
2  features/create_sites.feature
@@ -89,7 +89,7 @@ Feature: Create sites
And I have an "_includes/about.textile" file that contains "Generated by {% include jekyll.textile %}"
And I have an "_includes/jekyll.textile" file that contains "Jekyll"
And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
- When I debug jekyll
+ When I run jekyll
Then the _site directory should exist
And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"
View
25 features/drafts.feature
@@ -0,0 +1,25 @@
+Feature: Draft Posts
+ As a hacker who likes to blog
+ I want to be able to preview drafts locally
+ In order to see if they look alright before publishing
+
+ Scenario: Preview a draft
+ Given I have a configuration file with "permalink" set to "none"
+ And I have a _drafts directory
+ And I have the following draft:
+ | title | date | layout | content |
+ | Recipe | 3/27/2009 | default | Not baked yet. |
+ When I run jekyll with drafts
+ Then the _site directory should exist
+ And I should see "Not baked yet." in "_site/recipe.html"
+
+ Scenario: Don't preview a draft
+ Given I have a configuration file with "permalink" set to "none"
+ And I have an "index.html" page that contains "Totally index"
+ And I have a _drafts directory
+ And I have the following draft:
+ | title | date | layout | content |
+ | Recipe | 3/27/2009 | default | Not baked yet. |
+ When I run jekyll
+ Then the _site directory should exist
+ And the "_site/recipe.html" file should not exist
View
16 features/step_definitions/jekyll_steps.rb
@@ -50,9 +50,8 @@
FileUtils.mkdir_p(dir)
end
-Given /^I have the following posts?(?: (.*) "(.*)")?:$/ do |direction, folder, table|
+Given /^I have the following (draft|post)s?(?: (.*) "(.*)")?:$/ do |status, direction, folder, table|
table.hashes.each do |post|
- date = Date.strptime(post['date'], '%m/%d/%Y').strftime('%Y-%m-%d')
title = post['title'].downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
if direction && direction == "in"
@@ -61,7 +60,14 @@
after = folder || '.'
end
- path = File.join(before || '.', '_posts', after || '.', "#{date}-#{title}.#{post['type'] || 'textile'}")
+ ext = post['type'] || 'textile'
+
+ if "draft" == status
+ path = File.join(before || '.', '_drafts', after || '.', "#{title}.#{ext}")
+ else
+ date = Date.strptime(post['date'], '%m/%d/%Y').strftime('%Y-%m-%d')
+ path = File.join(before || '.', '_posts', after || '.', "#{date}-#{title}.#{ext}")
+ end
matter_hash = {}
%w(title layout tag tags category categories published author).each do |key|
@@ -117,6 +123,10 @@
run_jekyll
end
+When /^I run jekyll with drafts$/ do
+ run_jekyll(:drafts => true)
+end
+
When /^I debug jekyll$/ do
run_jekyll(:debug => true)
end
View
3  features/support/env.rb
@@ -10,8 +10,9 @@
JEKYLL_PATH = File.join(ENV['PWD'], 'bin', 'jekyll')
def run_jekyll(opts = {})
- command = JEKYLL_PATH
+ command = JEKYLL_PATH.clone
command << " build"
+ command << " --drafts" if opts[:drafts]
command << " >> /dev/null 2>&1" if opts[:debug].nil?
system command
end
View
1  lib/jekyll.rb
@@ -33,6 +33,7 @@ def require_all(path)
require 'jekyll/layout'
require 'jekyll/page'
require 'jekyll/post'
+require 'jekyll/draft'
require 'jekyll/filters'
require 'jekyll/static_file'
require 'jekyll/errors'
View
35 lib/jekyll/draft.rb
@@ -0,0 +1,35 @@
+module Jekyll
+
+ class Draft < Post
+
+ # Valid post name regex (no date)
+ MATCHER = /^(.*)(\.[^.]+)$/
+
+ # Draft name validator. Draft filenames must be like:
+ # my-awesome-post.textile
+ #
+ # Returns true if valid, false if not.
+ def self.valid?(name)
+ name =~ MATCHER
+ end
+
+ # Get the full path to the directory containing the draft files
+ def containing_dir(source, dir)
+ File.join(source, dir, '_drafts')
+ end
+
+ # Extract information from the post filename.
+ #
+ # name - The String filename of the post file.
+ #
+ # Returns nothing.
+ def process(name)
+ m, slug, ext = *name.match(MATCHER)
+ self.date = File.mtime(File.join(@base, name))
+ self.slug = slug
+ self.ext = ext
+ end
+
+ end
+
+end
View
8 lib/jekyll/post.rb
@@ -29,12 +29,11 @@ def self.valid?(name)
# site - The Site.
# base - The String path to the dir containing the post file.
# name - The String filename of the post file.
- # categories - An Array of Strings for the categories for this post.
#
# Returns the new Post.
def initialize(site, source, dir, name)
@site = site
- @base = File.join(source, dir, '_posts')
+ @base = self.containing_dir(source, dir)
@name = name
self.categories = dir.split('/').reject { |x| x.empty? }
@@ -65,6 +64,11 @@ def initialize(site, source, dir, name)
end
end
+ # Get the full path to the directory containing the post files
+ def containing_dir(source, dir)
+ return File.join(source, dir, '_posts')
+ end
+
# Read the YAML frontmatter.
#
# base - The String path to the dir containing the file.
View
40 lib/jekyll/site.rb
@@ -5,7 +5,7 @@ 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,
- :keep_files
+ :show_drafts, :keep_files
attr_accessor :converters, :generators
@@ -25,6 +25,7 @@ def initialize(config)
self.exclude = config['exclude'] || []
self.include = config['include'] || []
self.future = config['future']
+ self.show_drafts = config['show_drafts'] || nil
self.limit_posts = config['limit_posts'] || nil
self.keep_files = config['keep_files'] || []
@@ -148,6 +149,18 @@ def read_directories(dir = '')
self.read_posts(dir)
+ if self.show_drafts
+ self.read_drafts(dir)
+ end
+
+ self.posts.sort!
+
+ # limit the posts if :limit_posts option is set
+ if limit_posts
+ limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
+ self.posts = self.posts[-limit, limit]
+ end
+
entries.each do |f|
f_abs = File.join(base, f)
f_rel = File.join(dir, f)
@@ -190,13 +203,28 @@ def read_posts(dir)
end
end
end
+ end
- self.posts.sort!
+ # Read all the files in <source>/<dir>/_drafts and create a new Post
+ # object with each one.
+ #
+ # dir - The String relative path of the directory to read.
+ #
+ # Returns nothing.
+ def read_drafts(dir)
+ base = File.join(self.source, dir, '_drafts')
+ return unless File.exists?(base)
+ entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
- # limit the posts if :limit_posts option is set
- if limit_posts
- limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
- self.posts = self.posts[-limit, limit]
+ # first pass processes, but does not yet render draft content
+ entries.each do |f|
+ if Draft.valid?(f)
+ draft = Draft.new(self, self.source, dir, f)
+
+ self.posts << draft
+ draft.categories.each { |c| self.categories[c] << draft }
+ draft.tags.each { |c| self.tags[c] << draft }
+ end
end
end
Something went wrong with that request. Please try again.