diff --git a/cucumber.yml b/cucumber.yml
deleted file mode 100644
index 78342a17..00000000
--- a/cucumber.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-default: --format pretty
-travis: --format progress
-html_report: --format progress --format html --out=features_report.html
diff --git a/features/support/overview.rb b/features/support/overview.rb
new file mode 100644
index 00000000..493ef6a6
--- /dev/null
+++ b/features/support/overview.rb
@@ -0,0 +1,183 @@
+require 'fileutils'
+require 'colorator'
+require 'cucumber/formatter/console'
+require 'cucumber/formatter/io'
+require 'gherkin/formatter/escaping'
+
+module Features
+ module Support
+ # The formatter used for --format pretty (the default formatter).
+ #
+ # This formatter prints features to plain text - exactly how they were parsed,
+ # just prettier. That means with proper indentation and alignment of table columns.
+ #
+ # If the output is STDOUT (and not a file), there are bright colours to watch too.
+ #
+ class Overview
+ include FileUtils
+ include Cucumber::Formatter::Console
+ include Cucumber::Formatter::Io
+ include Gherkin::Formatter::Escaping
+ attr_writer :indent
+ attr_reader :runtime
+
+ def initialize(runtime, path_or_io, options)
+ @runtime, @io, @options = runtime, ensure_io(path_or_io, "pretty"), options
+ @exceptions = []
+ @indent = 0
+ @prefixes = options[:prefixes] || {}
+ @delayed_messages = []
+ end
+
+ def before_features(features)
+ print_profile_information
+ end
+
+ def after_features(features)
+ print_summary(features)
+ end
+
+ def before_feature(feature)
+ @exceptions = []
+ @indent = 0
+ end
+
+ def comment_line(comment_line)
+ end
+
+ def after_tags(tags)
+ end
+
+ def tag_name(tag_name)
+ end
+
+ def before_feature_element(feature_element)
+ @indent = 2
+ @scenario_indent = 2
+ end
+
+ def after_feature_element(feature_element)
+ end
+
+ def before_background(background)
+ @indent = 2
+ @scenario_indent = 2
+ @in_background = true
+ end
+
+ def after_background(background)
+ @in_background = nil
+ end
+
+ def background_name(keyword, name, file_colon_line, source_indent)
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
+ end
+
+ def before_examples_array(examples_array)
+ end
+
+ def examples_name(keyword, name)
+ end
+
+ def before_outline_table(outline_table)
+ end
+
+ def after_outline_table(outline_table)
+ end
+
+ def scenario_name(keyword, name, file_colon_line, source_indent)
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
+ end
+
+ def before_step(step)
+ @current_step = step
+ end
+
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
+ @hide_this_step = false
+ if exception
+ if @exceptions.include?(exception)
+ @hide_this_step = true
+ return
+ end
+ @exceptions << exception
+ end
+ if status != :failed && @in_background ^ background
+ @hide_this_step = true
+ return
+ end
+ @status = status
+ end
+
+ CHARS = {
+ :failed => "x".red,
+ :pending => "?".yellow,
+ :undefined => "x".red,
+ :passed => ".".green,
+ :skipped => "-".blue
+ }
+
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
+ @io.print CHARS[status]
+ end
+
+ def doc_string(string)
+ return if @options[:no_multiline] || @hide_this_step
+ s = %{"""\n#{string}\n"""}.indent(@indent)
+ s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
+ @io.puts(format_string(s, @current_step.status))
+ @io.flush
+ end
+
+ def exception(exception, status)
+ return if @hide_this_step
+ print_exception(exception, status, @indent)
+ @io.flush
+ end
+
+ def before_multiline_arg(multiline_arg)
+ end
+
+ def after_multiline_arg(multiline_arg)
+ end
+
+ def before_table_row(table_row)
+ end
+
+ def after_table_row(table_row)
+ end
+
+ def after_table_cell(cell)
+ end
+
+ def table_cell_value(value, status)
+ end
+
+ private
+
+ def print_feature_element_name(keyword, name, file_colon_line, source_indent)
+ @io.puts
+ names = name.empty? ? [name] : name.split("\n")
+ line = " #{keyword}: #{names[0]}"
+ if @options[:source]
+ line_comment = "#{file_colon_line}"
+ @io.print(line_comment)
+ end
+ @io.print(line)
+ @io.print " "
+ @io.flush
+ end
+
+ def cell_prefix(status)
+ @prefixes[status]
+ end
+
+ def print_summary(features)
+ @io.puts
+ print_stats(features, @options)
+ print_snippets(@options)
+ print_passing_wip(@options)
+ end
+ end
+ end
+end
diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb
index 8db6c54c..5edfeef6 100644
--- a/lib/jekyll/collection.rb
+++ b/lib/jekyll/collection.rb
@@ -22,14 +22,28 @@ module Jekyll
@docs ||= []
end
+ # Fetch the static files in this collection.
+ # Defaults to an empty array if no static files have been read in.
+ #
+ # Returns an array of Jekyll::StaticFile objects.
+ def files
+ @files ||= []
+ end
+
# Read the allowed documents into the collection's array of docs.
#
# Returns the sorted array of docs.
def read
filtered_entries.each do |file_path|
- doc = Jekyll::Document.new(Jekyll.sanitized_path(directory, file_path), { site: site, collection: self })
- doc.read
- docs << doc
+ full_path = Jekyll.sanitized_path(directory, file_path)
+ if Utils.has_yaml_header? full_path
+ doc = Jekyll::Document.new(full_path, { site: site, collection: self })
+ doc.read
+ docs << doc
+ else
+ relative_dir = File.join(relative_directory, File.dirname(file_path)).chomp("/.")
+ files << StaticFile.new(site, site.source, relative_dir, File.basename(full_path), self)
+ end
end
docs.sort!
end
@@ -118,6 +132,7 @@ module Jekyll
metadata.merge({
"label" => label,
"docs" => docs,
+ "files" => files,
"directory" => directory,
"output" => write?,
"relative_directory" => relative_directory
diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb
index dc2fdb13..891610fa 100644
--- a/lib/jekyll/document.rb
+++ b/lib/jekyll/document.rb
@@ -97,20 +97,12 @@ module Jekyll
'.coffee'.eql?(extname)
end
- # Determine whether the document has a YAML header.
- #
- # Returns true if the file starts with three dashes
- def has_yaml_header?
- @has_yaml_header unless @has_yaml_header.nil?
- @has_yaml_header = !!(File.open(path, 'rb') { |f| f.read(5) } =~ /\A---\r?\n/)
- end
-
# Determine whether the file should be rendered with Liquid.
#
# Returns false if the document is either an asset file or a yaml file,
# true otherwise.
def render_with_liquid?
- !(coffeescript_file? || yaml_file?) && has_yaml_header?
+ !(coffeescript_file? || yaml_file?)
end
# Determine whether the file should be placed into layouts.
@@ -118,7 +110,7 @@ module Jekyll
# Returns false if the document is either an asset file or a yaml file,
# true otherwise.
def place_in_layout?
- !(asset_file? || yaml_file?) && has_yaml_header?
+ !(asset_file? || yaml_file?)
end
# The URL template where the document would be accessible.
@@ -214,7 +206,7 @@ module Jekyll
unless defaults.empty?
@data = defaults
end
- @content = File.open(path, "rb", merged_file_read_opts(opts)) { |f| f.read }
+ @content = File.read(path, merged_file_read_opts(opts))
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
@content = $POSTMATCH
data_file = SafeYAML.load($1)
diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb
index a656b088..5aee3e72 100644
--- a/lib/jekyll/site.rb
+++ b/lib/jekyll/site.rb
@@ -144,7 +144,7 @@ module Jekyll
if File.directory?(f_abs)
f_rel = File.join(dir, f)
read_directories(f_rel) unless dest.sub(/\/$/, '') == f_abs
- elsif has_yaml_header?(f_abs)
+ elsif Utils.has_yaml_header?(f_abs)
page = Page.new(self, source, dir, f)
pages << page if publisher.publish?(page)
else
@@ -432,7 +432,7 @@ module Jekyll
def documents
collections.reduce(Set.new) do |docs, (_, collection)|
- docs.merge(collection.docs)
+ docs + collection.docs + collection.files
end.to_a
end
@@ -454,10 +454,6 @@ module Jekyll
pages.any? { |page| page.uses_relative_permalinks }
end
- def has_yaml_header?(file)
- !!(File.open(file, 'rb') { |f| f.read(5) } =~ /\A---\r?\n/)
- end
-
def limit_posts!
limit = posts.length < limit_posts ? posts.length : limit_posts
self.posts = posts[-limit, limit]
diff --git a/lib/jekyll/static_file.rb b/lib/jekyll/static_file.rb
index 2382d03c..02087e49 100644
--- a/lib/jekyll/static_file.rb
+++ b/lib/jekyll/static_file.rb
@@ -9,11 +9,12 @@ module Jekyll
# base - The String path to the .
# dir - The String path between and the file.
# name - The String filename of the file.
- def initialize(site, base, dir, name)
+ def initialize(site, base, dir, name, collection = nil)
@site = site
@base = base
@dir = dir
@name = name
+ @collection = collection
end
# Returns source file path.
@@ -23,7 +24,11 @@ module Jekyll
# Returns the source file path relative to the site source
def relative_path
- @relative_path ||= path.sub(/\A#{@site.source}/, '')
+ @relative_path ||= File.join(*[@dir, @name].compact)
+ end
+
+ def extname
+ File.extname(path)
end
# Obtain destination path.
@@ -32,7 +37,15 @@ module Jekyll
#
# Returns destination file path.
def destination(dest)
- File.join(*[dest, @dir, @name].compact)
+ File.join(*[dest, destination_rel_dir, @name].compact)
+ end
+
+ def destination_rel_dir
+ if @collection
+ @dir.gsub(/\A_/, '')
+ else
+ @dir
+ end
end
# Returns last modification time for this file.
@@ -47,6 +60,13 @@ module Jekyll
@@mtimes[path] != mtime
end
+ # Whether to write the file to the filesystem
+ #
+ # Returns true.
+ def write?
+ true
+ end
+
# Write the static file to the destination directory (if modified).
#
# dest - The String path to the destination dir.
@@ -75,7 +95,7 @@ module Jekyll
def to_liquid
{
- "path" => relative_path,
+ "path" => File.join("", relative_path),
"modified_time" => mtime.to_s,
"extname" => File.extname(relative_path)
}
diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb
index dc190297..f3dbf9d7 100644
--- a/lib/jekyll/utils.rb
+++ b/lib/jekyll/utils.rb
@@ -1,100 +1,106 @@
module Jekyll
module Utils
- class << self
+ extend self
- # Merges a master hash with another hash, recursively.
- #
- # master_hash - the "parent" hash whose values will be overridden
- # other_hash - the other hash whose values will be persisted after the merge
- #
- # This code was lovingly stolen from some random gem:
- # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
- #
- # Thanks to whoever made it.
- def deep_merge_hashes(master_hash, other_hash)
- target = master_hash.dup
+ # Merges a master hash with another hash, recursively.
+ #
+ # master_hash - the "parent" hash whose values will be overridden
+ # other_hash - the other hash whose values will be persisted after the merge
+ #
+ # This code was lovingly stolen from some random gem:
+ # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
+ #
+ # Thanks to whoever made it.
+ def deep_merge_hashes(master_hash, other_hash)
+ target = master_hash.dup
- other_hash.keys.each do |key|
- if other_hash[key].is_a? Hash and target[key].is_a? Hash
- target[key] = Utils.deep_merge_hashes(target[key], other_hash[key])
- next
- end
-
- target[key] = other_hash[key]
+ other_hash.keys.each do |key|
+ if other_hash[key].is_a? Hash and target[key].is_a? Hash
+ target[key] = Utils.deep_merge_hashes(target[key], other_hash[key])
+ next
end
- target
- end
-
- # Read array from the supplied hash favouring the singular key
- # and then the plural key, and handling any nil entries.
- #
- # hash - the hash to read from
- # singular_key - the singular key
- # plural_key - the plural key
- #
- # Returns an array
- def pluralized_array_from_hash(hash, singular_key, plural_key)
- [].tap do |array|
- array << (value_from_singular_key(hash, singular_key) || value_from_plural_key(hash, plural_key))
- end.flatten.compact
- end
-
- def value_from_singular_key(hash, key)
- hash[key] if (hash.key?(key) || (hash.default_proc && hash[key]))
- end
-
- def value_from_plural_key(hash, key)
- if hash.key?(key) || (hash.default_proc && hash[key])
- val = hash[key]
- case val
- when String
- val.split
- when Array
- val.compact
- end
- end
- end
-
- def transform_keys(hash)
- result = {}
- hash.each_key do |key|
- result[yield(key)] = hash[key]
- end
- result
- end
-
- # Apply #to_sym to all keys in the hash
- #
- # hash - the hash to which to apply this transformation
- #
- # Returns a new hash with symbolized keys
- def symbolize_hash_keys(hash)
- transform_keys(hash) { |key| key.to_sym rescue key }
- end
-
- # Apply #to_s to all keys in the Hash
- #
- # hash - the hash to which to apply this transformation
- #
- # Returns a new hash with stringified keys
- def stringify_hash_keys(hash)
- transform_keys(hash) { |key| key.to_s rescue key }
- end
-
- # Parse a date/time and throw an error if invalid
- #
- # input - the date/time to parse
- # msg - (optional) the error message to show the user
- #
- # Returns the parsed date if successful, throws a FatalException
- # if not
- def parse_date(input, msg = "Input could not be parsed.")
- Time.parse(input)
- rescue ArgumentError
- raise Errors::FatalException.new("Invalid date '#{input}': " + msg)
+ target[key] = other_hash[key]
end
+ target
end
+
+ # Read array from the supplied hash favouring the singular key
+ # and then the plural key, and handling any nil entries.
+ #
+ # hash - the hash to read from
+ # singular_key - the singular key
+ # plural_key - the plural key
+ #
+ # Returns an array
+ def pluralized_array_from_hash(hash, singular_key, plural_key)
+ [].tap do |array|
+ array << (value_from_singular_key(hash, singular_key) || value_from_plural_key(hash, plural_key))
+ end.flatten.compact
+ end
+
+ def value_from_singular_key(hash, key)
+ hash[key] if (hash.key?(key) || (hash.default_proc && hash[key]))
+ end
+
+ def value_from_plural_key(hash, key)
+ if hash.key?(key) || (hash.default_proc && hash[key])
+ val = hash[key]
+ case val
+ when String
+ val.split
+ when Array
+ val.compact
+ end
+ end
+ end
+
+ def transform_keys(hash)
+ result = {}
+ hash.each_key do |key|
+ result[yield(key)] = hash[key]
+ end
+ result
+ end
+
+ # Apply #to_sym to all keys in the hash
+ #
+ # hash - the hash to which to apply this transformation
+ #
+ # Returns a new hash with symbolized keys
+ def symbolize_hash_keys(hash)
+ transform_keys(hash) { |key| key.to_sym rescue key }
+ end
+
+ # Apply #to_s to all keys in the Hash
+ #
+ # hash - the hash to which to apply this transformation
+ #
+ # Returns a new hash with stringified keys
+ def stringify_hash_keys(hash)
+ transform_keys(hash) { |key| key.to_s rescue key }
+ end
+
+ # Parse a date/time and throw an error if invalid
+ #
+ # input - the date/time to parse
+ # msg - (optional) the error message to show the user
+ #
+ # Returns the parsed date if successful, throws a FatalException
+ # if not
+ def parse_date(input, msg = "Input could not be parsed.")
+ Time.parse(input)
+ rescue ArgumentError
+ raise Errors::FatalException.new("Invalid date '#{input}': " + msg)
+ end
+
+ # Determines whether a given file has
+ #
+ # Returns true if the YAML front matter is present.
+ def has_yaml_header?(file)
+ !!(File.open(file, 'rb') { |f| f.read(5) } =~ /\A---\r?\n/)
+ end
+
end
end
diff --git a/script/cibuild b/script/cibuild
index acc4b70e..d2dd4ae4 100755
--- a/script/cibuild
+++ b/script/cibuild
@@ -2,6 +2,15 @@
set -e
+parallelize_tests() {
+ ls -1 script/{test,cucumber,proof} | xargs -P 3 -L 1 /bin/bash
+}
+
+serialize_tests() {
+ script/proof
+ script/test
+ script/cucumber
+}
+
script/branding
-script/proof
-script/test
+time parallelize_tests
diff --git a/script/cucumber b/script/cucumber
new file mode 100755
index 00000000..c6957356
--- /dev/null
+++ b/script/cucumber
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+time bundle exec cucumber \
+ -f Features::Support::Overview \
+ "$@"
diff --git a/script/test b/script/test
index a97bd1c4..7bb742ef 100755
--- a/script/test
+++ b/script/test
@@ -2,16 +2,19 @@
#
# Usage:
# script/test
-# script/test
-
-set -x
+# script/test
if [ -z "$1" ]; then
- TEST_FILES="test/test_*.rb"
+ TEST_FILES="./test/test_*.rb"
else
TEST_FILES="$@"
fi
+RAKE_LIB_DIR=$(ruby -e "puts Gem::Specification.find_by_name('rake').gem_dir + '/lib'")
+
set -x
-bundle exec rake
+time bundle exec ruby -I"lib:test" \
+ -I"${RAKE_LIB_DIR}" \
+ "${RAKE_LIB_DIR}/rake/rake_test_loader.rb" \
+ $TEST_FILES
diff --git a/test/source/_slides/example-slide-1.html b/test/source/_slides/example-slide-1.html
index fcd89b3c..52dd1ab4 100644
--- a/test/source/_slides/example-slide-1.html
+++ b/test/source/_slides/example-slide-1.html
@@ -2,3 +2,5 @@
title: Example slide
layout: slide
---
+
+Wooot
diff --git a/test/source/_with.dots/file.with.dots.md b/test/source/_with.dots/file.with.dots.md
index e69de29b..211dfb5b 100644
--- a/test/source/_with.dots/file.with.dots.md
+++ b/test/source/_with.dots/file.with.dots.md
@@ -0,0 +1,4 @@
+---
+---
+
+I'm a file with dots.
diff --git a/test/test_document.rb b/test/test_document.rb
index 3e3397c6..b352a050 100644
--- a/test/test_document.rb
+++ b/test/test_document.rb
@@ -62,7 +62,7 @@ class TestDocument < Test::Unit::TestCase
}]
}))
@site.process
- @document = @site.collections["slides"].docs.first
+ @document = @site.collections["slides"].docs.select{|d| d.is_a?(Document) }.first
end
should "know the frontmatter defaults" do
@@ -199,20 +199,24 @@ class TestDocument < Test::Unit::TestCase
"destination" => dest_dir
}))
@site.process
- @document = @site.collections["slides"].docs.find { |doc| doc.relative_path == "_slides/octojekyll.png" }
+ @document = @site.collections["slides"].files.find { |doc| doc.relative_path == "_slides/octojekyll.png" }
@dest_file = dest_dir("slides/octojekyll.png")
end
- should "be a document" do
- assert !@document.nil?
+ should "be a static file" do
+ assert_equal true, @document.is_a?(StaticFile)
end
- should "not be rendered with Liquid" do
- assert !@document.render_with_liquid?
+ should "be set to write" do
+ assert @document.write?
+ end
+
+ should "be in the list of docs_to_write" do
+ assert @site.docs_to_write.include?(@document)
end
should "be output in the correct place" do
- assert File.file? @dest_file
+ assert_equal true, File.file?(@dest_file)
end
end
diff --git a/test/test_site.rb b/test/test_site.rb
index a343b1c9..97111971 100644
--- a/test/test_site.rb
+++ b/test/test_site.rb
@@ -190,12 +190,12 @@ class TestSite < Test::Unit::TestCase
should "read pages with yaml front matter" do
abs_path = File.expand_path("about.html", @site.source)
- assert_equal true, @site.send(:has_yaml_header?, abs_path)
+ assert_equal true, Utils.has_yaml_header?(abs_path)
end
should "enforce a strict 3-dash limit on the start of the YAML front-matter" do
abs_path = File.expand_path("pgp.key", @site.source)
- assert_equal false, @site.send(:has_yaml_header?, abs_path)
+ assert_equal false, Utils.has_yaml_header?(abs_path)
end
should "expose jekyll version to site payload" do