diff --git a/.travis.yml b/.travis.yml
index 7e970a6d..4c50a297 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,8 @@ rvm:
script: bundle exec rake
notifications:
irc:
+ on_success: change
+ on_failure: change
channels:
- "irc.freenode.org#jekyll"
#on_success: change
diff --git a/CONTRIBUTING.markdown b/CONTRIBUTING.markdown
index 95ae0c8f..6df99625 100644
--- a/CONTRIBUTING.markdown
+++ b/CONTRIBUTING.markdown
@@ -11,14 +11,20 @@ following in mind:
[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
+ where appropriate. Also, whipping up some documentation in your fork's `site`
would be appreciated, and once merged it will be transferred over to the main
- wiki.
+ `site`, jekyllrb.com.
* If your contribution changes any Jekyll behavior, make sure to update the
documentation. It lives in `site/docs`. If the docs are missing information,
please feel free to add it in. Great docs make a great project!
* Please follow the [GitHub Ruby Styleguide](https://github.com/styleguide/ruby)
when modifying Ruby code.
+* Please do your best to submit **small pull requests**. The easier the proposed
+ change is to review, the more likely it will be merged.
+* When submitting a pull request, please make judicious use of the pull request
+ body. A description of what changes were made, the motivations behind the
+ changes and [any tasks completed or left to complete](http://git.io/gfm-tasks)
+ will also speed up review time.
Test Dependencies
-----------------
@@ -32,8 +38,8 @@ you're all set!
Before you start, run the tests and make sure that they pass (to confirm your
environment is configured properly):
- $ rake test
- $ rake features
+ $ bundle exec rake test
+ $ bundle exec rake features
Workflow
--------
@@ -65,8 +71,7 @@ All documentation pull requests should be directed at `master`. Pull
requests directed at another branch will not be accepted.
The [Jekyll wiki](https://github.com/mojombo/jekyll/wiki) on GitHub
-can be freely updated without a pull request as all
-GitHub users have access.
+can be freely updated without a pull request as all GitHub users have access.
Gotchas
-------
diff --git a/Gemfile b/Gemfile
index 851fabc2..d9266971 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,2 +1,2 @@
source 'https://rubygems.org'
-gemspec
+gemspec
\ No newline at end of file
diff --git a/History.markdown b/History.markdown
index 3e2d583c..5592a1d7 100644
--- a/History.markdown
+++ b/History.markdown
@@ -1,23 +1,78 @@
## HEAD
### Major Enhancements
+ * Add support for adding data as YAML files under a site's `_data`
+ directory (#1003)
+ * Allow variables to be used with `include` tags (#1495)
### Minor Enhancements
+ * Decrease the specificity in the site template CSS (#1574)
+ * Add `encoding` configuration option (#1449)
+ * Provide better error handling for Jekyll's custom Liquid tags
+ (#1514)
+ * If an included file causes a Liquid error, add the path to the
+ include file that caused the error to the error message (#1596)
+ * If a layout causes a Liquid error, change the error message so that
+ we know it comes from the layout (#1601)
+ * Update Kramdown dependency to `~> 1.2` (#1610)
+ * Update `safe_yaml` dependency to `~> 0.9.7` (#1602)
+ * Allow layouts to be in subfolders like includes (#1622)
+
+### Bug Fixes
+ * Fix up matching against source and destination when the two
+ locations are similar (#1556)
+ * Fix the missing `pathname` require in certain cases (#1255)
+ * Use `+` instead of `Array#concat` when building `Post` attribute list (#1571)
+ * Print server address when launching a server (#1586)
+ * Downgrade to Maruku `~> 0.6.0` in order to avoid changes in rendering (#1598)
+ * Fix error with failing include tag when variable was file name (#1613)
+ * Downcase lexers before passing them to pygments (#1615)
+
+### Development Fixes
+ * Add coverage reporting with Coveralls (#1539)
+ * Refactor the Liquid `include` tag (#1490)
+ * Update launchy dependency to `~> 2.3` (#1608)
+ * Update rr dependency to `~> 1.1` (#1604)
+ * Update cucumber dependency to `~> 1.3` (#1607)
+ * Update coveralls dependency to `~> 0.7.0` (#1606)
+ * Update rake dependency to `~> 10.1` (#1603)
+ * Clean up `site.rb` comments to be more concise/uniform (#1616)
+
+### Site Enhancements
+ * Fix params for `JekyllImport::WordPress.process` arguments (#1554)
+ * Add `jekyll-suggested-tweet` to list of third-party plugins (#1555)
+ * Link to Liquid's docs for tags and filters (#1553)
+ * Add note about installing Xcode on the Mac in the Installation docs (#1561)
+ * Simplify/generalize pagination docs (#1577)
+ * Add documentation for the new data sources feature (#1503)
+ * Add more information on how to create generators (#1590, #1592)
+ * Improve the instructions for mimicking GitHub Flavored Markdown
+ (#1614)
+ * Add `jekyll-import` warning note of missing dependencies (#1626)
+
+## 1.2.1 / 2013-09-14
+
+### Minor Enhancements
+ * Print better messages for detached server. Mute output on detach. (#1518)
* Disable reverse lookup when running `jekyll serve` (#1363)
* Upgrade RedCarpet dependency to `~> 2.3.0` (#1515)
+ * Upgrade to Liquid `>= 2.5.2, < 2.6` (#1536)
### Bug Fixes
* Fix file discrepancy in gemspec (#1522)
+ * Force rendering of Include tag (#1525)
### Development Fixes
* Add a rake task to generate a new release post (#1404)
+ * Mute LSI output in tests (#1531)
+ * Update contributor documentation (#1537)
### Site Enhancements
* Fix a couple of validation errors on the site (#1511)
* Make navigation menus reusable (#1507)
* Fix link to History page from Release v1.2.0 notes post.
* Fix markup in History file for command line options (#1512)
-
+ * Expand 1.2 release post title to 1.2.0 (#1516)
## 1.2.0 / 2013-09-06
diff --git a/README.markdown b/README.markdown
index 9bfe0e80..94080ed1 100644
--- a/README.markdown
+++ b/README.markdown
@@ -5,6 +5,7 @@
[](https://travis-ci.org/mojombo/jekyll)
[](https://codeclimate.com/github/mojombo/jekyll)
[](https://gemnasium.com/mojombo/jekyll)
+[](https://coveralls.io/r/mojombo/jekyll)
By Tom Preston-Werner, Nick Quaranto, and many awesome contributors!
diff --git a/Rakefile b/Rakefile
index 2f973cda..b65b2dd2 100644
--- a/Rakefile
+++ b/Rakefile
@@ -84,7 +84,14 @@ end
#
#############################################################################
-task :default => [:test, :features]
+if RUBY_VERSION > '1.9' && ENV["TRAVIS"] == "true"
+ require 'coveralls/rake/task'
+ Coveralls::RakeTask.new
+
+ task :default => [:test, :features, 'coveralls:push']
+else
+ task :default => [:test, :features]
+end
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
@@ -217,6 +224,7 @@ namespace :site do
task :new, :version do |t, args|
raise "Specify a version: rake site:releases:new['1.2.3']" unless args.version
today = Time.new.strftime('%Y-%m-%d')
+ release = args.version.to_s
filename = "site/_posts/#{today}-jekyll-#{release.split('.').join('-')}-released.markdown"
File.open(filename, "wb") do |post|
diff --git a/bin/jekyll b/bin/jekyll
index 53ce267e..ee497c25 100755
--- a/bin/jekyll
+++ b/bin/jekyll
@@ -65,6 +65,7 @@ command :build do |c|
c.option '-w', '--watch', 'Watch for changes and rebuild'
c.option '--lsi', 'Use LSI for improved related posts'
c.option '-D', '--drafts', 'Render posts in the _drafts folder'
+ c.option '-v', '--verbose', 'Print verbose output.'
c.action do |args, options|
options = normalize_options(options.__hash__)
@@ -84,6 +85,7 @@ command :serve do |c|
c.option '--lsi', 'Use LSI for improved related posts'
c.option '-B', '--detach', 'Run the server in the background (detach)'
c.option '-D', '--drafts', 'Render posts in the _drafts folder'
+ c.option '-v', '--verbose', 'Print verbose output.'
c.option '-P', '--port [PORT]', 'Port to listen on'
c.option '-H', '--host [HOST]', 'Host to bind to'
diff --git a/features/create_sites.feature b/features/create_sites.feature
index 16e733b1..a25a0d32 100644
--- a/features/create_sites.feature
+++ b/features/create_sites.feature
@@ -44,6 +44,17 @@ Feature: Create sites
Then the _site directory should exist
And I should see "Post Layout:
The only winning move is not to play.
" in "_site/2009/03/27/wargames.html"
+ Scenario: Basic site with layout inside a subfolder and a post
+ Given I have a _layouts directory
+ And I have a _posts directory
+ And I have the following posts:
+ | title | date | layout | content |
+ | Wargames | 2009-03-27 | post/simple | The only winning move is not to play. |
+ And I have a post/simple layout that contains "Post Layout: {{ content }}"
+ When I run jekyll
+ Then the _site directory should exist
+ And I should see "Post Layout:
The only winning move is not to play.
" in "_site/2009/03/27/wargames.html"
+
Scenario: Basic site with layouts, pages, posts and files
Given I have a _layouts directory
And I have a page layout that contains "Page {{ page.title }}: {{ content }}"
diff --git a/features/data.feature b/features/data.feature
new file mode 100644
index 00000000..33adfaad
--- /dev/null
+++ b/features/data.feature
@@ -0,0 +1,65 @@
+Feature: Data
+ In order to use well-formatted data in my blog
+ As a blog's user
+ I want to use _data directory in my site
+
+ Scenario: autoload *.yaml files in _data directory
+ Given I have a _data directory
+ And I have a "_data/products.yaml" file with content:
+ """
+ - name: sugar
+ price: 5.3
+ - name: salt
+ price: 2.5
+ """
+ And I have an "index.html" page that contains "{% for product in site.data.products %}{{product.name}}{% endfor %}"
+ When I run jekyll
+ Then the "_site/index.html" file should exist
+ And I should see "sugar" in "_site/index.html"
+ And I should see "salt" in "_site/index.html"
+
+ Scenario: autoload *.yml files in _data directory
+ Given I have a _data directory
+ And I have a "_data/members.yml" file with content:
+ """
+ - name: Jack
+ age: 28
+ - name: Leon
+ age: 34
+ """
+ And I have an "index.html" page that contains "{% for member in site.data.members %}{{member.name}}{% endfor %}"
+ When I run jekyll
+ Then the "_site/index.html" file should exist
+ And I should see "Jack" in "_site/index.html"
+ And I should see "Leon" in "_site/index.html"
+
+ Scenario: autoload *.yml files in _data directory with space in file name
+ Given I have a _data directory
+ And I have a "_data/team members.yml" file with content:
+ """
+ - name: Jack
+ age: 28
+ - name: Leon
+ age: 34
+ """
+ And I have an "index.html" page that contains "{% for member in site.data.team_members %}{{member.name}}{% endfor %}"
+ When I run jekyll
+ Then the "_site/index.html" file should exist
+ And I should see "Jack" in "_site/index.html"
+ And I should see "Leon" in "_site/index.html"
+
+ Scenario: should be backward compatible with site.data in _config.yml
+ Given I have a "_config.yml" file with content:
+ """
+ data:
+ - name: Jack
+ age: 28
+ - name: Leon
+ age: 34
+ """
+ And I have an "index.html" page that contains "{% for member in site.data %}{{member.name}}{% endfor %}"
+ When I run jekyll
+ Then the "_site/index.html" file should exist
+ And I should see "Jack" in "_site/index.html"
+ And I should see "Leon" in "_site/index.html"
+
diff --git a/features/include_tag.feature b/features/include_tag.feature
index 66f9d4a6..3abff4c7 100644
--- a/features/include_tag.feature
+++ b/features/include_tag.feature
@@ -33,3 +33,16 @@ Feature: Include tags
And I should see "
param1_or_2 = value
" in "_site/2013/04/12/parameter-syntax.html"
And I should see "
local = some text
" in "_site/2013/06/22/pass-a-variable.html"
And I should see "
layout = default
" in "_site/2013/06/22/pass-a-variable.html"
+
+ Scenario: Include a file from a variable
+ Given I have an _includes directory
+ And I have an "_includes/snippet.html" file that contains "a snippet"
+ And I have an "_includes/parametrized.html" file that contains "works with {{include.what}}"
+ And I have a configuration file with:
+ | key | value |
+ | include_file1 | snippet.html |
+ | include_file2 | parametrized.html |
+ And I have an "index.html" page that contains "{% include {{site.include_file1}} %} that {% include {{site.include_file2}} what='parameters' %}"
+ When I run jekyll
+ Then the _site directory should exist
+ And I should see "a snippet that works with parameters" in "_site/index.html"
diff --git a/features/site_configuration.feature b/features/site_configuration.feature
index 706e5b66..89324cb1 100644
--- a/features/site_configuration.feature
+++ b/features/site_configuration.feature
@@ -18,6 +18,27 @@ Feature: Site configuration
Then the _mysite directory should exist
And I should see "Changing destination directory" in "_mysite/index.html"
+ Scenario Outline: Similarly named source and destination
+ Given I have a blank site in ""
+ And I have an "/index.md" page that contains "markdown"
+ And I have a configuration file with:
+ | key | value |
+ | source | |
+ | destination | |
+ When I run jekyll
+ Then the directory should exist
+ And the "/index.html" file should exist
+ And I should see "markdown" in "/index.md"
+
+ Examples:
+ | source | dest | file_exist |
+ | mysite_source | mysite | |
+ | mysite | mysite_dest | |
+ | mysite/ | mysite | not |
+ | mysite | ./mysite | not |
+ | mysite/source | mysite | not |
+ | mysite | mysite/dest | |
+
Scenario: Exclude files inline
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"
diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb
index a1a1b797..4e11aad9 100644
--- a/features/step_definitions/jekyll_steps.rb
+++ b/features/step_definitions/jekyll_steps.rb
@@ -7,7 +7,7 @@ end
World(Test::Unit::Assertions)
Given /^I have a blank site in "(.*)"$/ do |path|
- FileUtils.mkdir(path)
+ FileUtils.mkdir_p(path)
end
Given /^I do not have a "(.*)" directory$/ do |path|
@@ -38,7 +38,18 @@ Given /^I have an? (.*) (layout|theme) that contains "(.*)"$/ do |name, type, te
else
'_theme'
end
- File.open(File.join(folder, name + '.html'), 'w') do |f|
+ destination_file = File.join(folder, name + '.html')
+ destination_path = File.dirname(destination_file)
+ unless File.exist?(destination_path)
+ FileUtils.mkdir_p(destination_path)
+ end
+ File.open(destination_file, 'w') do |f|
+ f.write(text)
+ end
+end
+
+Given /^I have an? "(.*)" file with content:$/ do |file, text|
+ File.open(file, 'w') do |f|
f.write(text)
end
end
@@ -137,10 +148,14 @@ When /^I delete the file "(.*)"$/ do |file|
File.delete(file)
end
-Then /^the (.*) directory should exist$/ do |dir|
+Then /^the (.*) directory should +exist$/ do |dir|
assert File.directory?(dir), "The directory \"#{dir}\" does not exist"
end
+Then /^the (.*) directory should not exist$/ do |dir|
+ assert !File.directory?(dir), "The directory \"#{dir}\" exists"
+end
+
Then /^I should see "(.*)" in "(.*)"$/ do |text, file|
assert Regexp.new(text).match(File.open(file).readlines.join)
end
@@ -157,12 +172,12 @@ Then /^I should see escaped "(.*)" in "(.*)"$/ do |text, file|
assert Regexp.new(Regexp.escape(text)).match(File.open(file).readlines.join)
end
-Then /^the "(.*)" file should exist$/ do |file|
- assert File.file?(file)
+Then /^the "(.*)" file should +exist$/ do |file|
+ assert File.file?(file), "The file \"#{file}\" does not exist"
end
Then /^the "(.*)" file should not exist$/ do |file|
- assert !File.exists?(file)
+ assert !File.exists?(file), "The file \"#{file}\" exists"
end
Then /^I should see today's time in "(.*)"$/ do |file|
diff --git a/features/support/env.rb b/features/support/env.rb
index efe6b1b6..5c7db508 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,3 +1,8 @@
+if RUBY_VERSION > '1.9'
+ require 'coveralls'
+ Coveralls.wear_merged!
+end
+
require 'fileutils'
require 'rr'
require 'test/unit'
diff --git a/jekyll.gemspec b/jekyll.gemspec
index 25a83d53..35368433 100644
--- a/jekyll.gemspec
+++ b/jekyll.gemspec
@@ -4,9 +4,9 @@ Gem::Specification.new do |s|
s.rubygems_version = '1.3.5'
s.name = 'jekyll'
- s.version = '1.2.0'
+ s.version = '1.2.1'
s.license = 'MIT'
- s.date = '2013-09-06'
+ s.date = '2013-09-14'
s.rubyforge_project = 'jekyll'
s.summary = "A simple, blog aware, static site generator."
@@ -23,28 +23,29 @@ Gem::Specification.new do |s|
s.rdoc_options = ["--charset=UTF-8"]
s.extra_rdoc_files = %w[README.markdown LICENSE]
- s.add_runtime_dependency('liquid', "~> 2.5.1")
+ s.add_runtime_dependency('liquid', "~> 2.5.2")
s.add_runtime_dependency('classifier', "~> 1.3")
s.add_runtime_dependency('directory_watcher', "~> 1.4.1")
- s.add_runtime_dependency('maruku', "~> 0.5")
+ s.add_runtime_dependency('maruku', "~> 0.6.0")
s.add_runtime_dependency('pygments.rb', "~> 0.5.0")
s.add_runtime_dependency('commander', "~> 4.1.3")
- s.add_runtime_dependency('safe_yaml', "~> 0.7.0")
+ s.add_runtime_dependency('safe_yaml', "~> 0.9.7")
s.add_runtime_dependency('colorator', "~> 0.1")
s.add_runtime_dependency('redcarpet', "~> 2.3.0")
- s.add_development_dependency('rake', "~> 10.0.3")
+ s.add_development_dependency('rake', "~> 10.1")
s.add_development_dependency('rdoc', "~> 3.11")
s.add_development_dependency('redgreen', "~> 1.2")
s.add_development_dependency('shoulda', "~> 3.3.2")
- s.add_development_dependency('rr', "~> 1.0.0")
- s.add_development_dependency('cucumber', "~> 1.2.1", '!= 1.2.4')
+ s.add_development_dependency('rr', "~> 1.1")
+ s.add_development_dependency('cucumber', "~> 1.3")
s.add_development_dependency('RedCloth', "~> 4.2")
- s.add_development_dependency('kramdown', "~> 1.0.2")
+ s.add_development_dependency('kramdown', "~> 1.2")
s.add_development_dependency('rdiscount', "~> 1.6")
- s.add_development_dependency('launchy', "~> 2.1.2")
+ s.add_development_dependency('launchy', "~> 2.3")
s.add_development_dependency('simplecov', "~> 0.7")
s.add_development_dependency('simplecov-gem-adapter', "~> 1.0.1")
+ s.add_development_dependency('coveralls', "~> 0.7.0")
s.add_development_dependency('activesupport', '~> 3.2.13')
# = MANIFEST =
@@ -58,6 +59,7 @@ Gem::Specification.new do |s|
bin/jekyll
cucumber.yml
features/create_sites.feature
+ features/data.feature
features/drafts.feature
features/embed_filters.feature
features/include_tag.feature
@@ -149,6 +151,7 @@ Gem::Specification.new do |s|
site/_posts/2013-07-25-jekyll-1-0-4-released.markdown
site/_posts/2013-07-25-jekyll-1-1-2-released.markdown
site/_posts/2013-09-06-jekyll-1-2-0-released.markdown
+ site/_posts/2013-09-14-jekyll-1-2-1-released.markdown
site/css/gridism.css
site/css/normalize.css
site/css/pygments.css
@@ -201,6 +204,7 @@ Gem::Specification.new do |s|
test/helper.rb
test/source/+/foo.md
test/source/.htaccess
+ test/source/_data/members.yaml
test/source/_includes/params.html
test/source/_includes/sig.markdown
test/source/_layouts/default.html
diff --git a/lib/jekyll.rb b/lib/jekyll.rb
index fa2e87dd..639d8e47 100644
--- a/lib/jekyll.rb
+++ b/lib/jekyll.rb
@@ -20,6 +20,7 @@ require 'fileutils'
require 'time'
require 'safe_yaml'
require 'English'
+require 'pathname'
# 3rd party
require 'liquid'
@@ -61,7 +62,7 @@ require_all 'jekyll/tags'
SafeYAML::OPTIONS[:suppress_warnings] = true
module Jekyll
- VERSION = '1.2.0'
+ VERSION = '1.2.1'
# Public: Generate a Jekyll configuration Hash by merging the default
# options with anything in _config.yml, and adding the given options on top.
diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb
index a933b9e2..e3a89b4b 100644
--- a/lib/jekyll/cleaner.rb
+++ b/lib/jekyll/cleaner.rb
@@ -2,7 +2,7 @@ require 'set'
module Jekyll
class Site
- # Handles the cleanup of a site's destination before the site is built.
+ # Handles the cleanup of a site's destination before it is built.
class Cleaner
def initialize(site)
@site = site
@@ -15,14 +15,14 @@ module Jekyll
private
- # Private: The list of files and directories to be deleted during the cleanup process
+ # Private: The list of files and directories to be deleted during cleanup process
#
- # Returns an Array with the file and directory paths
+ # Returns an Array of the file and directory paths
def obsolete_files
(existing_files - new_files - new_dirs + replaced_files).to_a
end
- # Private: The list of existing files, except those included in keep_files and hidden files.
+ # Private: The list of existing files, apart from those included in keep_files and hidden files.
#
# Returns a Set with the file paths
def existing_files
@@ -33,7 +33,7 @@ module Jekyll
files
end
- # Private: The list of files to be created when the site is built.
+ # Private: The list of files to be created when site is built.
#
# Returns a Set with the file paths
def new_files
@@ -42,7 +42,7 @@ module Jekyll
files
end
- # Private: The list of directories to be created when the site is built.
+ # Private: The list of directories to be created when site is built.
# These are the parent directories of the files in #new_files.
#
# Returns a Set with the directory paths
@@ -57,7 +57,7 @@ module Jekyll
new_dirs.select { |dir| File.file?(dir) }.to_set
end
- # Private: creates a regular expression from the config's keep_files array
+ # Private: Creates a regular expression from the config's keep_files array
#
# Examples
# ['.git','.svn'] creates the following regex: /\/(\.git|\/.svn)/
@@ -70,4 +70,4 @@ module Jekyll
end
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/jekyll/commands/serve.rb b/lib/jekyll/commands/serve.rb
index 82bbc947..8e8d00bb 100644
--- a/lib/jekyll/commands/serve.rb
+++ b/lib/jekyll/commands/serve.rb
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- encoding: utf-8 -*-
module Jekyll
module Commands
class Serve < Command
@@ -10,32 +10,56 @@ module Jekyll
FileUtils.mkdir_p(destination)
- mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
- mime_types = WEBrick::HTTPUtils::load_mime_types(mime_types_file)
-
# recreate NondisclosureName under utf-8 circumstance
fh_option = WEBrick::Config::FileHandler
fh_option[:NondisclosureName] = ['.ht*','~*']
- s = HTTPServer.new(
- :Port => options['port'],
- :BindAddress => options['host'],
- :MimeTypes => mime_types,
- :DoNotReverseLookup => true
- )
+ s = HTTPServer.new(webrick_options(options))
s.mount(options['baseurl'], HTTPServlet::FileHandler, destination, fh_option)
+ Jekyll.logger.info "Server address:", "http://#{s.config[:BindAddress]}:#{s.config[:Port]}"
+
if options['detach'] # detach the server
- pid = Process.fork {s.start}
+ pid = Process.fork { s.start }
Process.detach(pid)
- pid
+ Jekyll.logger.info "Server detatched with pid '#{pid}'.", "Run `kill -9 #{pid}' to stop the server."
else # create a new server thread, then join it with current terminal
t = Thread.new { s.start }
trap("INT") { s.shutdown }
t.join()
end
end
+
+ def self.webrick_options(config)
+ opts = {
+ :Port => config['port'],
+ :BindAddress => config['host'],
+ :MimeTypes => self.mime_types,
+ :DoNotReverseLookup => true,
+ :StartCallback => start_callback(config['detach'])
+ }
+
+ if !config['verbose']
+ opts.merge!({
+ :AccessLog => [],
+ :Logger => Log::new([], Log::WARN)
+ })
+ end
+
+ opts
+ end
+
+ def self.start_callback(detached)
+ unless detached
+ Proc.new { Jekyll.logger.info "Server running...", "press ctrl-c to stop." }
+ end
+ end
+
+ def self.mime_types
+ mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
+ WEBrick::HTTPUtils::load_mime_types(mime_types_file)
+ end
end
end
end
diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb
index 453c5427..993ef9e0 100644
--- a/lib/jekyll/configuration.rb
+++ b/lib/jekyll/configuration.rb
@@ -10,10 +10,13 @@ module Jekyll
'destination' => File.join(Dir.pwd, '_site'),
'plugins' => '_plugins',
'layouts' => '_layouts',
+ 'data_source' => '_data',
'keep_files' => ['.git','.svn'],
'timezone' => nil, # use the local timezone
+ 'encoding' => nil, # use the system encoding
+
'safe' => false,
'detach' => false, # default to not detaching the server
'show_drafts' => nil,
diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb
index ecfa0f6a..7a1b6eed 100644
--- a/lib/jekyll/convertible.rb
+++ b/lib/jekyll/convertible.rb
@@ -21,16 +21,23 @@ module Jekyll
self.content || ''
end
+ # Returns merged optin hash for File.read of self.site (if exists)
+ # and a given param
+ def merged_file_read_opts(opts)
+ (self.site ? self.site.file_read_opts : {}).merge(opts)
+ end
+
# Read the YAML frontmatter.
#
# base - The String path to the dir containing the file.
# name - The String filename of the file.
+ # opts - optional parameter to File.read, default at site configs
#
# Returns nothing.
- def read_yaml(base, name)
+ def read_yaml(base, name, opts = {})
begin
- self.content = File.read(File.join(base, name))
-
+ self.content = File.read_with_options(File.join(base, name),
+ merged_file_read_opts(opts))
if self.content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
self.content = $POSTMATCH
self.data = YAML.safe_load($1)
@@ -78,10 +85,13 @@ module Jekyll
# info - the info for Liquid
#
# Returns the converted content
- def render_liquid(content, payload, info)
+ def render_liquid(content, payload, info, path = nil)
Liquid::Template.parse(content).render!(payload, info)
+ rescue Tags::IncludeTagError => e
+ Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{e.path}"
+ raise e
rescue Exception => e
- Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{self.path}"
+ Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{path || self.path}"
raise e
end
@@ -113,7 +123,8 @@ module Jekyll
self.output = self.render_liquid(layout.content,
payload,
- info)
+ info,
+ File.join(self.site.config['layouts'], layout.name))
if layout = layouts[layout.data["layout"]]
if used.include?(layout)
diff --git a/lib/jekyll/core_ext.rb b/lib/jekyll/core_ext.rb
index c3bec80d..f6244c85 100644
--- a/lib/jekyll/core_ext.rb
+++ b/lib/jekyll/core_ext.rb
@@ -83,3 +83,18 @@ module Enumerable
any? { |exp| File.fnmatch?(exp, e) }
end
end
+
+# Ruby 1.8's File.read don't support option.
+# read_with_options ignore optional parameter for 1.8,
+# and act as alias for 1.9 or later.
+class File
+ if RUBY_VERSION < '1.9'
+ def self.read_with_options(path, opts = {})
+ self.read(path)
+ end
+ else
+ def self.read_with_options(path, opts = {})
+ self.read(path, opts)
+ end
+ end
+end
diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb
index f1a3a6a9..b03c31f3 100644
--- a/lib/jekyll/post.rb
+++ b/lib/jekyll/post.rb
@@ -19,10 +19,10 @@ module Jekyll
]
# Attributes for Liquid templates
- ATTRIBUTES_FOR_LIQUID = EXCERPT_ATTRIBUTES_FOR_LIQUID.concat(%w[
+ ATTRIBUTES_FOR_LIQUID = EXCERPT_ATTRIBUTES_FOR_LIQUID + %w[
content
excerpt
- ])
+ ]
# Post name validator. Post filenames must be like:
# 2008-11-05-my-awesome-post.textile
diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb
index ae2d2b56..090efa7a 100644
--- a/lib/jekyll/site.rb
+++ b/lib/jekyll/site.rb
@@ -3,7 +3,7 @@ module Jekyll
attr_accessor :config, :layouts, :posts, :pages, :static_files,
:categories, :exclude, :include, :source, :dest, :lsi, :pygments,
:permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts,
- :show_drafts, :keep_files, :baseurl
+ :show_drafts, :keep_files, :baseurl, :data, :file_read_opts
attr_accessor :converters, :generators
@@ -22,6 +22,9 @@ module Jekyll
self.plugins = plugins_path
self.permalink_style = config['permalink'].to_sym
+ self.file_read_opts = {}
+ self.file_read_opts[:encoding] = config['encoding'] if config['encoding']
+
self.reset
self.setup
end
@@ -53,6 +56,7 @@ module Jekyll
self.static_files = []
self.categories = Hash.new { |hash, key| hash[key] = [] }
self.tags = Hash.new { |hash, key| hash[key] = [] }
+ self.data = {}
if self.limit_posts < 0
raise ArgumentError, "limit_posts must be a non-negative number"
@@ -63,11 +67,7 @@ module Jekyll
#
# Returns nothing.
def setup
- # Check that the destination dir isn't the source dir or a directory
- # parent to the source dir.
- if self.source =~ /^#{self.dest}/
- raise FatalException.new "Destination directory cannot be or contain the Source directory."
- end
+ ensure_not_in_dest
# If safe mode is off, load in any Ruby files under the plugins
# directory.
@@ -83,6 +83,17 @@ module Jekyll
self.generators = instantiate_subclasses(Jekyll::Generator)
end
+ # Check that the destination dir isn't the source dir or a directory
+ # parent to the source dir.
+ def ensure_not_in_dest
+ dest = Pathname.new(self.dest)
+ Pathname.new(self.source).ascend do |path|
+ if path == dest
+ raise FatalException.new "Destination directory cannot be or contain the Source directory."
+ end
+ end
+ end
+
# Internal: Setup the plugin search path
#
# Returns an Array of plugin search paths
@@ -100,6 +111,7 @@ module Jekyll
def read
self.read_layouts
self.read_directories
+ self.read_data(config['data_source'])
end
# Read all the files in / and create a new Layout object
@@ -110,7 +122,7 @@ module Jekyll
base = File.join(self.source, self.config['layouts'])
return unless File.exists?(base)
entries = []
- Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
+ Dir.chdir(base) { entries = filter_entries(Dir['**/*.*']) }
entries.each do |f|
name = f.split(".")[0..-2].join(".")
@@ -187,6 +199,25 @@ module Jekyll
end
end
+ # Read and parse all yaml files under /
+ #
+ # Returns nothing
+ def read_data(dir)
+ base = File.join(self.source, dir)
+ return unless File.directory?(base) && (!self.safe || !File.symlink?(base))
+
+ entries = Dir.chdir(base) { Dir['*.{yaml,yml}'] }
+ entries.delete_if { |e| File.directory?(File.join(base, e)) }
+
+ entries.each do |entry|
+ path = File.join(self.source, dir, entry)
+ next if File.symlink?(path) && self.safe
+
+ key = sanitize_filename(File.basename(entry, '.*'))
+ self.data[key] = YAML.safe_load_file(path)
+ end
+ end
+
# Run each of the Generators.
#
# Returns nothing.
@@ -252,6 +283,14 @@ module Jekyll
hash
end
+ # Prepare site data for site payload. The method maintains backward compatibility
+ # if the key 'data' is already used in _config.yml.
+ #
+ # Returns the Hash to be hooked to site.data.
+ def site_data
+ self.config['data'] || self.data
+ end
+
# The Hash payload containing site-wide data.
#
# Returns the Hash: { "site" => data } where data is a Hash with keys:
@@ -273,7 +312,8 @@ module Jekyll
"pages" => self.pages,
"html_pages" => self.pages.reject { |page| !page.html? },
"categories" => post_attr_hash('categories'),
- "tags" => post_attr_hash('tags')})}
+ "tags" => post_attr_hash('tags'),
+ "data" => site_data})}
end
# Filter out any files/directories that are hidden or backup files (start
@@ -387,5 +427,11 @@ module Jekyll
def site_cleaner
@site_cleaner ||= Cleaner.new(self)
end
+
+ def sanitize_filename(name)
+ name = name.gsub(/[^\w\s_-]+/, '')
+ name = name.gsub(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2')
+ name = name.gsub(/\s+/, '_')
+ end
end
end
diff --git a/lib/jekyll/tags/gist.rb b/lib/jekyll/tags/gist.rb
index d69499af..f4f32880 100644
--- a/lib/jekyll/tags/gist.rb
+++ b/lib/jekyll/tags/gist.rb
@@ -12,7 +12,15 @@ module Jekyll
gist_id, filename = tag_contents[0], tag_contents[1]
gist_script_tag(gist_id, filename)
else
- "Error parsing gist id"
+ raise ArgumentError.new <<-eos
+Syntax error in tag 'gist' while parsing the following markup:
+
+ #{@markup}
+
+Valid syntax:
+ for public gists: {% gist 1234567 %}
+ for private gists: {% gist user/1234567 %}
+eos
end
end
diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb
index e8059edb..2ea144df 100644
--- a/lib/jekyll/tags/highlight.rb
+++ b/lib/jekyll/tags/highlight.rb
@@ -14,7 +14,7 @@ module Jekyll
def initialize(tag_name, markup, tokens)
super
if markup.strip =~ SYNTAX
- @lang = $1
+ @lang = $1.downcase
@options = {}
if defined?($2) && $2 != ''
$2.split.each do |opt|
diff --git a/lib/jekyll/tags/include.rb b/lib/jekyll/tags/include.rb
index d98df06f..d26ea7b4 100644
--- a/lib/jekyll/tags/include.rb
+++ b/lib/jekyll/tags/include.rb
@@ -1,21 +1,33 @@
module Jekyll
module Tags
+ class IncludeTagError < StandardError
+ attr_accessor :path
+
+ def initialize(msg, path)
+ super(msg)
+ @path = path
+ end
+ end
+
class IncludeTag < Liquid::Tag
- MATCHER = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
+ SYNTAX_EXAMPLE = "{% include file.ext param='value' param2='value' %}"
+
+ VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
+
+ INCLUDES_DIR = '_includes'
def initialize(tag_name, markup, tokens)
super
@file, @params = markup.strip.split(' ', 2);
+ validate_params if @params
end
def parse_params(context)
- validate_syntax
-
params = {}
markup = @params
- while match = MATCHER.match(markup) do
+ while match = VALID_SYNTAX.match(markup) do
markup = markup[match.end(0)..-1]
value = if match[2]
@@ -31,55 +43,91 @@ module Jekyll
params
end
- # ensure the entire markup string from start to end is valid syntax, and params are separated by spaces
- def validate_syntax
- full_matcher = Regexp.compile('\A\s*(?:' + MATCHER.to_s + '(?=\s|\z)\s*)*\z')
- unless @params =~ full_matcher
- raise SyntaxError.new <<-eos
+ def validate_file_name
+ if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
+ raise ArgumentError.new <<-eos
+Invalid syntax for include tag. File contains invalid characters or sequences:
+
+ #{@file}
+
+Valid syntax:
+
+ #{SYNTAX_EXAMPLE}
+
+eos
+ end
+ end
+
+ def validate_params
+ full_valid_syntax = Regexp.compile('\A\s*(?:' + VALID_SYNTAX.to_s + '(?=\s|\z)\s*)*\z')
+ unless @params =~ full_valid_syntax
+ raise ArgumentError.new <<-eos
Invalid syntax for include tag:
#{@params}
Valid syntax:
- {% include file.ext param='value' param2="value" %}
+ #{SYNTAX_EXAMPLE}
eos
end
end
- def render(context)
- includes_dir = File.join(context.registers[:site].source, '_includes')
+ # Grab file read opts in the context
+ def file_read_opts(context)
+ context.registers[:site].file_read_opts
+ end
- if error = validate_file(includes_dir)
- return error
- end
-
- source = File.read(File.join(includes_dir, @file))
- partial = Liquid::Template.parse(source)
-
- context.stack do
- context['include'] = parse_params(context) if @params
- partial.render(context)
+ def retrieve_variable(context)
+ if /\{\{([\w\-\.]+)\}\}/ =~ @file
+ raise ArgumentError.new("No variable #{$1} was found in include tag") if context[$1].nil?
+ @file = context[$1]
end
end
- def validate_file(includes_dir)
- if File.symlink?(includes_dir)
- return "Includes directory '#{includes_dir}' cannot be a symlink"
- end
+ def render(context)
+ dir = File.join(context.registers[:site].source, INCLUDES_DIR)
+ validate_dir(dir, context.registers[:site].safe)
- if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
- return "Include file '#{@file}' contains invalid characters or sequences"
- end
+ retrieve_variable(context)
+ validate_file_name
- file = File.join(includes_dir, @file)
+ file = File.join(dir, @file)
+ validate_file(file, context.registers[:site].safe)
+
+ partial = Liquid::Template.parse(source(file, context))
+
+ context.stack do
+ context['include'] = parse_params(context) if @params
+ partial.render!(context)
+ end
+ rescue => e
+ raise IncludeTagError.new e.message, File.join(INCLUDES_DIR, @file)
+ end
+
+ def validate_dir(dir, safe)
+ if File.symlink?(dir) && safe
+ raise IOError.new "Includes directory '#{dir}' cannot be a symlink"
+ end
+ end
+
+ def validate_file(file, safe)
if !File.exists?(file)
- return "Included file #{@file} not found in _includes directory"
- elsif File.symlink?(file)
- return "The included file '_includes/#{@file}' should not be a symlink"
+ raise IOError.new "Included file '#{@file}' not found in '#{INCLUDES_DIR}' directory"
+ elsif File.symlink?(file) && safe
+ raise IOError.new "The included file '#{INCLUDES_DIR}/#{@file}' should not be a symlink"
end
end
+
+ def blank?
+ false
+ end
+
+ # This method allows to modify the file content by inheriting from the class.
+ def source(file, context)
+ File.read_with_options(file, file_read_opts(context))
+ end
end
end
end
diff --git a/lib/jekyll/tags/post_url.rb b/lib/jekyll/tags/post_url.rb
index 51b3b605..063e22a4 100644
--- a/lib/jekyll/tags/post_url.rb
+++ b/lib/jekyll/tags/post_url.rb
@@ -50,9 +50,11 @@ module Jekyll
end
end
- puts "ERROR: post_url: \"#{@orig_post}\" could not be found"
+ raise ArgumentError.new <<-eos
+Could not find post "#{@orig_post}" in tag 'post_url'.
- return "#"
+Make sure the post exists and the name is correct.
+eos
end
end
end
diff --git a/lib/site_template/css/main.css b/lib/site_template/css/main.css
index 50a81804..1a2c013f 100755
--- a/lib/site_template/css/main.css
+++ b/lib/site_template/css/main.css
@@ -34,16 +34,16 @@ a:visited { color: #a0a; }
/* Home
/*
/*****************************************************************************/
-ul.posts {
+.posts {
list-style-type: none;
margin-bottom: 2em;
}
-ul.posts li {
+.posts li {
line-height: 1.75em;
}
-ul.posts span {
+.posts span {
color: #aaa;
font-family: Monaco, "Courier New", monospace;
font-size: 80%;
@@ -63,38 +63,38 @@ ul.posts span {
line-height: 1.5em;
}
-.site .header a {
+.header a {
font-weight: bold;
text-decoration: none;
}
-.site .header h1.title {
+.title {
display: inline-block;
margin-bottom: 2em;
}
-.site .header h1.title a {
+.title a {
color: #a00;
}
-.site .header h1.title a:hover {
+.title a:hover {
color: #000;
}
-.site .header a.extra {
+.header a.extra {
color: #aaa;
margin-left: 1em;
}
-.site .header a.extra:hover {
+.header a.extra:hover {
color: #000;
}
-.site .meta {
+.meta {
color: #aaa;
}
-.site .footer {
+.footer {
font-size: 80%;
color: #666;
border-top: 4px solid #eee;
@@ -102,22 +102,22 @@ ul.posts span {
overflow: hidden;
}
-.site .footer .contact {
+.footer .contact {
float: left;
margin-right: 3em;
}
-.site .footer .contact a {
+.footer .contact a {
color: #8085C1;
}
-.site .footer .rss {
+.footer .rss {
margin-top: 1.1em;
margin-right: -.2em;
float: right;
}
-.site .footer .rss img {
+.footer .rss img {
border: 0;
}
diff --git a/site/_includes/docs_contents.html b/site/_includes/docs_contents.html
index 0df6c0a4..523b5227 100644
--- a/site/_includes/docs_contents.html
+++ b/site/_includes/docs_contents.html
@@ -3,7 +3,7 @@
Getting Started
{% include docs_ul.html items='home quickstart installation usage structure configuration' %}