jekyll 2.0.0.alpha.3 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jekyll might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CONTRIBUTING.markdown +1 -1
- data/History.markdown +10 -0
- data/features/collections.feature +49 -15
- data/features/create_sites.feature +16 -16
- data/features/data.feature +4 -4
- data/features/drafts.feature +4 -4
- data/features/embed_filters.feature +6 -6
- data/features/frontmatter_defaults.feature +79 -0
- data/features/include_tag.feature +4 -4
- data/features/markdown.feature +4 -4
- data/features/pagination.feature +3 -3
- data/features/permalinks.feature +8 -8
- data/features/post_data.feature +18 -18
- data/features/post_excerpts.feature +3 -3
- data/features/site_configuration.feature +21 -21
- data/features/site_data.feature +11 -11
- data/features/step_definitions/jekyll_steps.rb +5 -18
- data/features/support/env.rb +2 -15
- data/lib/jekyll.rb +2 -0
- data/lib/jekyll/collection.rb +30 -4
- data/lib/jekyll/configuration.rb +2 -1
- data/lib/jekyll/convertible.rb +15 -1
- data/lib/jekyll/document.rb +11 -7
- data/lib/jekyll/filters.rb +1 -1
- data/lib/jekyll/frontmatter_defaults.rb +148 -0
- data/lib/jekyll/liquid_extensions.rb +22 -0
- data/lib/jekyll/page.rb +5 -0
- data/lib/jekyll/post.rb +12 -0
- data/lib/jekyll/site.rb +42 -27
- data/lib/jekyll/version.rb +1 -1
- data/script/test +11 -0
- data/site/docs/collections.md +78 -5
- data/site/docs/configuration.md +49 -0
- data/site/docs/frontmatter.md +10 -0
- data/site/docs/plugins.md +1 -0
- data/site/docs/posts.md +9 -0
- data/site/docs/sites.md +2 -2
- data/site/docs/templates.md +1 -1
- data/test/test_collections.rb +50 -4
- data/test/test_filters.rb +4 -0
- data/test/test_liquid_extensions.rb +31 -0
- data/test/test_utils.rb +1 -0
- metadata +9 -2
data/features/site_data.feature
CHANGED
@@ -5,14 +5,14 @@ Feature: Site data
|
|
5
5
|
|
6
6
|
Scenario: Use page variable in a page
|
7
7
|
Given I have an "contact.html" page with title "Contact" that contains "{{ page.title }}: email@example.com"
|
8
|
-
When I run jekyll
|
8
|
+
When I run jekyll build
|
9
9
|
Then the _site directory should exist
|
10
10
|
And I should see "Contact: email@example.com" in "_site/contact.html"
|
11
11
|
|
12
12
|
Scenario Outline: Use page.path variable in a page
|
13
13
|
Given I have a <dir> directory
|
14
14
|
And I have a "<path>" page that contains "Source path: {{ page.path }}"
|
15
|
-
When I run jekyll
|
15
|
+
When I run jekyll build
|
16
16
|
Then the _site directory should exist
|
17
17
|
And I should see "Source path: <path>" in "_site/<path>"
|
18
18
|
|
@@ -24,13 +24,13 @@ Feature: Site data
|
|
24
24
|
|
25
25
|
Scenario: Override page.path
|
26
26
|
Given I have an "override.html" page with path "custom-override.html" that contains "Custom path: {{ page.path }}"
|
27
|
-
When I run jekyll
|
27
|
+
When I run jekyll build
|
28
28
|
Then the _site directory should exist
|
29
29
|
And I should see "Custom path: custom-override.html" in "_site/override.html"
|
30
30
|
|
31
31
|
Scenario: Use site.time variable
|
32
32
|
Given I have an "index.html" page that contains "{{ site.time }}"
|
33
|
-
When I run jekyll
|
33
|
+
When I run jekyll build
|
34
34
|
Then the _site directory should exist
|
35
35
|
And I should see today's time in "_site/index.html"
|
36
36
|
|
@@ -42,7 +42,7 @@ Feature: Site data
|
|
42
42
|
| First Post | 2009-03-25 | My First Post |
|
43
43
|
| Second Post | 2009-03-26 | My Second Post |
|
44
44
|
| Third Post | 2009-03-27 | My Third Post |
|
45
|
-
When I run jekyll
|
45
|
+
When I run jekyll build
|
46
46
|
Then the _site directory should exist
|
47
47
|
And I should see "Third Post: /2009/03/27/third-post.html" in "_site/index.html"
|
48
48
|
|
@@ -54,7 +54,7 @@ Feature: Site data
|
|
54
54
|
| First Post | 2009-03-25 | My First Post |
|
55
55
|
| Second Post | 2009-03-26 | My Second Post |
|
56
56
|
| Third Post | 2009-03-27 | My Third Post |
|
57
|
-
When I run jekyll
|
57
|
+
When I run jekyll build
|
58
58
|
Then the _site directory should exist
|
59
59
|
And I should see "Third Post Second Post First Post" in "_site/index.html"
|
60
60
|
|
@@ -65,7 +65,7 @@ Feature: Site data
|
|
65
65
|
| title | date | category | content |
|
66
66
|
| Awesome Hack | 2009-03-26 | code | puts 'Hello World' |
|
67
67
|
| Delicious Beer | 2009-03-26 | food | 1) Yuengling |
|
68
|
-
When I run jekyll
|
68
|
+
When I run jekyll build
|
69
69
|
Then the _site directory should exist
|
70
70
|
And I should see "Awesome Hack" in "_site/index.html"
|
71
71
|
|
@@ -75,7 +75,7 @@ Feature: Site data
|
|
75
75
|
And I have the following posts:
|
76
76
|
| title | date | tag | content |
|
77
77
|
| Delicious Beer | 2009-03-26 | beer | 1) Yuengling |
|
78
|
-
When I run jekyll
|
78
|
+
When I run jekyll build
|
79
79
|
Then the _site directory should exist
|
80
80
|
And I should see "Yuengling" in "_site/index.html"
|
81
81
|
|
@@ -89,19 +89,19 @@ Feature: Site data
|
|
89
89
|
| B | 2009-03-26 | B |
|
90
90
|
| C | 2009-03-26 | C |
|
91
91
|
| last | 2009-04-26 | last |
|
92
|
-
When I run jekyll
|
92
|
+
When I run jekyll build
|
93
93
|
Then the _site directory should exist
|
94
94
|
And I should see "last:C, C:B,last B:A,C A:first,B first:,A" in "_site/index.html"
|
95
95
|
|
96
96
|
Scenario: Use configuration date in site payload
|
97
97
|
Given I have an "index.html" page that contains "{{ site.url }}"
|
98
98
|
And I have a configuration file with "url" set to "http://example.com"
|
99
|
-
When I run jekyll
|
99
|
+
When I run jekyll build
|
100
100
|
Then the _site directory should exist
|
101
101
|
And I should see "http://example.com" in "_site/index.html"
|
102
102
|
|
103
103
|
Scenario: Access Jekyll version via jekyll.version
|
104
104
|
Given I have an "index.html" page that contains "{{ jekyll.version }}"
|
105
|
-
When I run jekyll
|
105
|
+
When I run jekyll build
|
106
106
|
Then the _site directory should exist
|
107
107
|
And I should see "\d+\.\d+\.\d+" in "_site/index.html"
|
@@ -139,24 +139,11 @@ end
|
|
139
139
|
#
|
140
140
|
##################
|
141
141
|
|
142
|
-
When /^I run jekyll(
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
run_jekyll_build("--safe")
|
148
|
-
end
|
149
|
-
|
150
|
-
When /^I run jekyll with drafts$/ do
|
151
|
-
run_jekyll_build("--drafts")
|
152
|
-
end
|
153
|
-
|
154
|
-
When /^I call jekyll new with test_blank --blank$/ do
|
155
|
-
run_jekyll_new("test_blank --blank")
|
156
|
-
end
|
157
|
-
|
158
|
-
When /^I debug jekyll$/ do
|
159
|
-
run_jekyll_build("--verbose")
|
142
|
+
When /^I run jekyll(.*)$/ do |args|
|
143
|
+
status = run_jekyll(args)
|
144
|
+
if !status || args.include?("--verbose")
|
145
|
+
puts jekyll_run_output
|
146
|
+
end
|
160
147
|
end
|
161
148
|
|
162
149
|
When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
|
data/features/support/env.rb
CHANGED
@@ -23,21 +23,8 @@ def jekyll_run_output
|
|
23
23
|
File.read(jekyll_output_file)
|
24
24
|
end
|
25
25
|
|
26
|
-
def run_jekyll(args
|
27
|
-
|
28
|
-
system command
|
29
|
-
end
|
30
|
-
|
31
|
-
def run_jekyll_build(build_args = "")
|
32
|
-
if !run_jekyll("build #{build_args}", jekyll_output_file) || build_args.eql?("--verbose")
|
33
|
-
puts jekyll_run_output
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def run_jekyll_new(new_args = "")
|
38
|
-
unless run_jekyll("new #{new_args}", jekyll_output_file)
|
39
|
-
puts jekyll_run_output
|
40
|
-
end
|
26
|
+
def run_jekyll(args)
|
27
|
+
system "#{JEKYLL_PATH} #{args} --trace > #{jekyll_output_file} 2>&1"
|
41
28
|
end
|
42
29
|
|
43
30
|
def slug(title)
|
data/lib/jekyll.rb
CHANGED
@@ -37,6 +37,7 @@ require 'jekyll/configuration'
|
|
37
37
|
require 'jekyll/document'
|
38
38
|
require 'jekyll/collection'
|
39
39
|
require 'jekyll/plugin_manager'
|
40
|
+
require 'jekyll/frontmatter_defaults'
|
40
41
|
require 'jekyll/site'
|
41
42
|
require 'jekyll/convertible'
|
42
43
|
require 'jekyll/url'
|
@@ -60,6 +61,7 @@ require 'jekyll/plugin'
|
|
60
61
|
require 'jekyll/converter'
|
61
62
|
require 'jekyll/generator'
|
62
63
|
require 'jekyll/command'
|
64
|
+
require 'jekyll/liquid_extensions'
|
63
65
|
|
64
66
|
require_all 'jekyll/commands'
|
65
67
|
require_all 'jekyll/converters'
|
data/lib/jekyll/collection.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Jekyll
|
2
2
|
class Collection
|
3
|
-
attr_reader :site, :label
|
3
|
+
attr_reader :site, :label, :metadata
|
4
4
|
|
5
5
|
# Create a new Collection.
|
6
6
|
#
|
@@ -9,8 +9,9 @@ module Jekyll
|
|
9
9
|
#
|
10
10
|
# Returns nothing.
|
11
11
|
def initialize(site, label)
|
12
|
-
@site
|
13
|
-
@label
|
12
|
+
@site = site
|
13
|
+
@label = sanitize_label(label)
|
14
|
+
@metadata = extract_metadata
|
14
15
|
end
|
15
16
|
|
16
17
|
# Fetch the Documents in this collection.
|
@@ -114,7 +115,32 @@ module Jekyll
|
|
114
115
|
#
|
115
116
|
# Returns a representation of this collection for use in Liquid.
|
116
117
|
def to_liquid
|
117
|
-
|
118
|
+
metadata.merge({
|
119
|
+
"label" => label,
|
120
|
+
"docs" => docs,
|
121
|
+
"directory" => directory,
|
122
|
+
"output" => write?,
|
123
|
+
"relative_directory" => relative_directory
|
124
|
+
})
|
125
|
+
end
|
126
|
+
|
127
|
+
# Whether the collection's documents ought to be written as individual
|
128
|
+
# files in the output.
|
129
|
+
#
|
130
|
+
# Returns true if the 'write' metadata is true, false otherwise.
|
131
|
+
def write?
|
132
|
+
!!metadata['output']
|
133
|
+
end
|
134
|
+
|
135
|
+
# Extract options for this collection from the site configuration.
|
136
|
+
#
|
137
|
+
# Returns the metadata for this collection
|
138
|
+
def extract_metadata
|
139
|
+
if site.config['collections'].is_a?(Hash)
|
140
|
+
site.config['collections'][label] || Hash.new
|
141
|
+
else
|
142
|
+
{}
|
143
|
+
end
|
118
144
|
end
|
119
145
|
|
120
146
|
end
|
data/lib/jekyll/configuration.rb
CHANGED
data/lib/jekyll/convertible.rb
CHANGED
@@ -14,6 +14,8 @@ require 'set'
|
|
14
14
|
# self.output=
|
15
15
|
# self.name
|
16
16
|
# self.path
|
17
|
+
# self.type -> :page, :post or :draft
|
18
|
+
|
17
19
|
module Jekyll
|
18
20
|
module Convertible
|
19
21
|
# Returns the contents as a String.
|
@@ -107,7 +109,19 @@ module Jekyll
|
|
107
109
|
further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map { |attribute|
|
108
110
|
[attribute, send(attribute)]
|
109
111
|
}]
|
110
|
-
|
112
|
+
|
113
|
+
defaults = site.frontmatter_defaults.all(relative_path, type)
|
114
|
+
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
115
|
+
end
|
116
|
+
|
117
|
+
def type
|
118
|
+
if is_a?(Post)
|
119
|
+
:post
|
120
|
+
elsif is_a?(Page)
|
121
|
+
:page
|
122
|
+
elsif is_a?(Draft)
|
123
|
+
:draft
|
124
|
+
end
|
111
125
|
end
|
112
126
|
|
113
127
|
# Recursively render layouts
|
data/lib/jekyll/document.rb
CHANGED
@@ -112,7 +112,7 @@ module Jekyll
|
|
112
112
|
#
|
113
113
|
# Returns the permalink or nil if no permalink was set in the data.
|
114
114
|
def permalink
|
115
|
-
data && data['permalink']
|
115
|
+
data && data.is_a?(Hash) && data['permalink']
|
116
116
|
end
|
117
117
|
|
118
118
|
# The computed URL for the document. See `Jekyll::URL#to_s` for more details.
|
@@ -192,12 +192,16 @@ module Jekyll
|
|
192
192
|
#
|
193
193
|
# Returns a Hash representing this Document's data.
|
194
194
|
def to_liquid
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
195
|
+
if data.is_a?(Hash)
|
196
|
+
Utils.deep_merge_hashes data, {
|
197
|
+
"content" => content,
|
198
|
+
"path" => path,
|
199
|
+
"relative_path" => relative_path,
|
200
|
+
"url" => url
|
201
|
+
}
|
202
|
+
else
|
203
|
+
data
|
204
|
+
end
|
201
205
|
end
|
202
206
|
|
203
207
|
# The inspect string for this document.
|
data/lib/jekyll/filters.rb
CHANGED
@@ -0,0 +1,148 @@
|
|
1
|
+
module Jekyll
|
2
|
+
class Configuration
|
3
|
+
# This class handles custom defaults for YAML frontmatter settings.
|
4
|
+
# These are set in _config.yml and apply both to internal use (e.g. layout)
|
5
|
+
# and the data available to liquid.
|
6
|
+
#
|
7
|
+
# It is exposed via the frontmatter_defaults method on the site class.
|
8
|
+
class FrontmatterDefaults
|
9
|
+
# Initializes a new instance.
|
10
|
+
def initialize(site)
|
11
|
+
@site = site
|
12
|
+
end
|
13
|
+
|
14
|
+
# Finds a default value for a given setting, filtered by path and type
|
15
|
+
#
|
16
|
+
# path - the path (relative to the source) of the page, post or :draft the default is used in
|
17
|
+
# type - a symbol indicating whether a :page, a :post or a :draft calls this method
|
18
|
+
#
|
19
|
+
# Returns the default value or nil if none was found
|
20
|
+
def find(path, type, setting)
|
21
|
+
value = nil
|
22
|
+
old_scope = nil
|
23
|
+
|
24
|
+
matching_sets(path, type).each do |set|
|
25
|
+
if set['values'].has_key?(setting) && has_precedence?(old_scope, set['scope'])
|
26
|
+
value = set['values'][setting]
|
27
|
+
old_scope = set['scope']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
value
|
31
|
+
end
|
32
|
+
|
33
|
+
# Collects a hash with all default values for a page or post
|
34
|
+
#
|
35
|
+
# path - the relative path of the page or post
|
36
|
+
# type - a symbol indicating the type (:post, :page or :draft)
|
37
|
+
#
|
38
|
+
# Returns a hash with all default values (an empty hash if there are none)
|
39
|
+
def all(path, type)
|
40
|
+
defaults = {}
|
41
|
+
old_scope = nil
|
42
|
+
matching_sets(path, type).each do |set|
|
43
|
+
if has_precedence?(old_scope, set['scope'])
|
44
|
+
defaults.merge! set['values']
|
45
|
+
old_scope = set['scope']
|
46
|
+
else
|
47
|
+
defaults = set['values'].merge(defaults)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
defaults
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Checks if a given default setting scope matches the given path and type
|
56
|
+
#
|
57
|
+
# scope - the hash indicating the scope, as defined in _config.yml
|
58
|
+
# path - the path to check for
|
59
|
+
# type - the type (:post, :page or :draft) to check for
|
60
|
+
#
|
61
|
+
# Returns true if the scope applies to the given path and type
|
62
|
+
def applies?(scope, path, type)
|
63
|
+
applies_path?(scope, path) && applies_type?(scope, type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def applies_path?(scope, path)
|
67
|
+
return true if scope['path'].empty?
|
68
|
+
|
69
|
+
scope_path = Pathname.new(scope['path'])
|
70
|
+
Pathname.new(sanitize_path(path)).ascend do |path|
|
71
|
+
if path == scope_path
|
72
|
+
return true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def applies_type?(scope, type)
|
78
|
+
!scope.has_key?('type') || scope['type'] == type.to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
# Checks if a given set of default values is valid
|
82
|
+
#
|
83
|
+
# set - the default value hash, as defined in _config.yml
|
84
|
+
#
|
85
|
+
# Returns true if the set is valid and can be used in this class
|
86
|
+
def valid?(set)
|
87
|
+
set.is_a?(Hash) && set['scope'].is_a?(Hash) && set['scope']['path'].is_a?(String) && set['values'].is_a?(Hash)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Determines if a new scope has precedence over an old one
|
91
|
+
#
|
92
|
+
# old_scope - the old scope hash, or nil if there's none
|
93
|
+
# new_scope - the new scope hash
|
94
|
+
#
|
95
|
+
# Returns true if the new scope has precedence over the older
|
96
|
+
def has_precedence?(old_scope, new_scope)
|
97
|
+
return true if old_scope.nil?
|
98
|
+
|
99
|
+
new_path = sanitize_path(new_scope['path'])
|
100
|
+
old_path = sanitize_path(old_scope['path'])
|
101
|
+
|
102
|
+
if new_path.length != old_path.length
|
103
|
+
new_path.length >= old_path.length
|
104
|
+
elsif new_scope.has_key? 'type'
|
105
|
+
true
|
106
|
+
else
|
107
|
+
!old_scope.has_key? 'type'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Collects a list of sets that match the given path and type
|
112
|
+
#
|
113
|
+
# Returns an array of hashes
|
114
|
+
def matching_sets(path, type)
|
115
|
+
valid_sets.select do |set|
|
116
|
+
applies?(set['scope'], path, type)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns a list of valid sets
|
121
|
+
#
|
122
|
+
# This is not cached to allow plugins to modify the configuration
|
123
|
+
# and have their changes take effect
|
124
|
+
#
|
125
|
+
# Returns an array of hashes
|
126
|
+
def valid_sets
|
127
|
+
sets = @site.config['defaults']
|
128
|
+
return [] unless sets.is_a?(Array)
|
129
|
+
|
130
|
+
sets.select do |set|
|
131
|
+
unless valid?(set)
|
132
|
+
Jekyll.logger.warn "Default:", "An invalid default set was found"
|
133
|
+
end
|
134
|
+
valid?(set)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Sanitizes the given path by removing a leading and addding a trailing slash
|
139
|
+
def sanitize_path(path)
|
140
|
+
if path.nil? || path.empty?
|
141
|
+
""
|
142
|
+
else
|
143
|
+
path.gsub(/\A\//, '').gsub(/([^\/])\z/, '\1/')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|