jekyll 0.11.2 → 0.12.0
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.
- data/History.txt +19 -0
- data/Rakefile +1 -5
- data/bin/jekyll +22 -5
- data/features/create_sites.feature +18 -0
- data/features/pagination.feature +28 -1
- data/features/site_configuration.feature +33 -0
- data/features/step_definitions/jekyll_steps.rb +8 -1
- data/jekyll.gemspec +13 -5
- data/lib/jekyll.rb +36 -25
- data/lib/jekyll/converters/markdown.rb +31 -7
- data/lib/jekyll/converters/textile.rb +17 -1
- data/lib/jekyll/convertible.rb +16 -8
- data/lib/jekyll/generators/pagination.rb +7 -1
- data/lib/jekyll/migrators/drupal.rb +27 -16
- data/lib/jekyll/migrators/joomla.rb +53 -0
- data/lib/jekyll/migrators/posterous.rb +3 -4
- data/lib/jekyll/migrators/rss.rb +47 -0
- data/lib/jekyll/migrators/textpattern.rb +1 -0
- data/lib/jekyll/migrators/tumblr.rb +175 -99
- data/lib/jekyll/migrators/wordpress.rb +273 -41
- data/lib/jekyll/post.rb +8 -2
- data/lib/jekyll/site.rb +23 -16
- data/lib/jekyll/tags/highlight.rb +17 -6
- data/lib/jekyll/tags/post_url.rb +38 -0
- data/test/fixtures/broken_front_matter1.erb +5 -0
- data/test/fixtures/front_matter.erb +4 -0
- data/test/test_convertible.rb +22 -0
- data/test/test_kramdown.rb +14 -4
- data/test/test_post.rb +13 -0
- data/test/test_rdiscount.rb +6 -2
- data/test/test_redcarpet.rb +21 -3
- data/test/test_redcloth.rb +86 -0
- data/test/test_site.rb +36 -2
- data/test/test_tags.rb +62 -1
- metadata +42 -30
@@ -3,14 +3,19 @@ module Jekyll
|
|
3
3
|
class HighlightBlock < Liquid::Block
|
4
4
|
include Liquid::StandardFilters
|
5
5
|
|
6
|
-
#
|
7
|
-
|
6
|
+
# The regular expression syntax checker. Start with the language specifier.
|
7
|
+
# Follow that by zero or more space separated options that take one of two
|
8
|
+
# forms:
|
9
|
+
#
|
10
|
+
# 1. name
|
11
|
+
# 2. name=value
|
12
|
+
SYNTAX = /^([a-zA-Z0-9.+#-]+)((\s+\w+(=\w+)?)*)$/
|
8
13
|
|
9
14
|
def initialize(tag_name, markup, tokens)
|
10
15
|
super
|
11
|
-
if markup =~ SYNTAX
|
16
|
+
if markup.strip =~ SYNTAX
|
12
17
|
@lang = $1
|
13
|
-
if defined? $2
|
18
|
+
if defined?($2) && $2 != ''
|
14
19
|
tmp_options = {}
|
15
20
|
$2.split.each do |opt|
|
16
21
|
key, value = opt.split('=')
|
@@ -23,7 +28,7 @@ module Jekyll
|
|
23
28
|
end
|
24
29
|
tmp_options[key] = value
|
25
30
|
end
|
26
|
-
tmp_options = tmp_options.to_a.collect { |opt| opt.join('=') }
|
31
|
+
tmp_options = tmp_options.to_a.sort.collect { |opt| opt.join('=') }
|
27
32
|
# additional options to pass to Albino
|
28
33
|
@options = { 'O' => tmp_options.join(',') }
|
29
34
|
else
|
@@ -43,7 +48,13 @@ module Jekyll
|
|
43
48
|
end
|
44
49
|
|
45
50
|
def render_pygments(context, code)
|
46
|
-
|
51
|
+
@options[:encoding] = 'utf-8'
|
52
|
+
|
53
|
+
output = add_code_tags(
|
54
|
+
Pygments.highlight(code, :lexer => @lang, :options => @options),
|
55
|
+
@lang
|
56
|
+
)
|
57
|
+
|
47
58
|
output = context["pygments_prefix"] + output if context["pygments_prefix"]
|
48
59
|
output = output + context["pygments_suffix"] if context["pygments_suffix"]
|
49
60
|
output
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Jekyll
|
2
|
+
|
3
|
+
class PostComparer
|
4
|
+
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)$/
|
5
|
+
|
6
|
+
attr_accessor :date, :slug
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
who, cares, date, slug = *name.match(MATCHER)
|
10
|
+
@slug = slug
|
11
|
+
@date = Time.parse(date)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class PostUrl < Liquid::Tag
|
16
|
+
def initialize(tag_name, post, tokens)
|
17
|
+
super
|
18
|
+
@orig_post = post.strip
|
19
|
+
@post = PostComparer.new(@orig_post)
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(context)
|
23
|
+
site = context.registers[:site]
|
24
|
+
|
25
|
+
site.posts.each do |p|
|
26
|
+
if p == @post
|
27
|
+
return p.url
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "ERROR: post_url: \"#{@orig_post}\" could not be found"
|
32
|
+
|
33
|
+
return "#"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Liquid::Template.register_tag('post_url', Jekyll::PostUrl)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
class TestConvertible < Test::Unit::TestCase
|
5
|
+
context "yaml front-matter" do
|
6
|
+
setup do
|
7
|
+
@convertible = OpenStruct.new
|
8
|
+
@convertible.extend Jekyll::Convertible
|
9
|
+
@base = File.expand_path('../fixtures', __FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "parse the front-matter correctly" do
|
13
|
+
ret = @convertible.read_yaml(@base, 'front_matter.erb')
|
14
|
+
assert_equal({'test' => 'good'}, ret)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "not parse if the front-matter is not at the start of the file" do
|
18
|
+
ret = @convertible.read_yaml(@base, 'broken_front_matter1.erb')
|
19
|
+
assert_equal({}, ret)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/test_kramdown.rb
CHANGED
@@ -3,21 +3,31 @@ require 'helper'
|
|
3
3
|
class TestKramdown < Test::Unit::TestCase
|
4
4
|
context "kramdown" do
|
5
5
|
setup do
|
6
|
-
config = {
|
6
|
+
@config = {
|
7
7
|
'markdown' => 'kramdown',
|
8
8
|
'kramdown' => {
|
9
9
|
'auto_ids' => false,
|
10
10
|
'footnote_nr' => 1,
|
11
11
|
'entity_output' => 'as_char',
|
12
|
-
'toc_levels' => '1..6'
|
12
|
+
'toc_levels' => '1..6',
|
13
|
+
'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo'
|
13
14
|
}
|
14
15
|
}
|
15
|
-
@markdown = MarkdownConverter.new config
|
16
16
|
end
|
17
17
|
|
18
18
|
# http://kramdown.rubyforge.org/converter/html.html#options
|
19
19
|
should "pass kramdown options" do
|
20
|
-
|
20
|
+
markdown = MarkdownConverter.new(@config)
|
21
|
+
assert_equal "<h1>Some Header</h1>", markdown.convert('# Some Header #').strip
|
22
|
+
end
|
23
|
+
|
24
|
+
should "convert quotes to smart quotes" do
|
25
|
+
markdown = MarkdownConverter.new(@config)
|
26
|
+
assert_equal "<p>“Pit’hy”</p>", markdown.convert(%{"Pit'hy"}).strip
|
27
|
+
|
28
|
+
override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } }
|
29
|
+
markdown = MarkdownConverter.new(@config.deep_merge(override))
|
30
|
+
assert_equal "<p>«Pit›hy»</p>", markdown.convert(%{"Pit'hy"}).strip
|
21
31
|
end
|
22
32
|
end
|
23
33
|
end
|
data/test/test_post.rb
CHANGED
@@ -141,6 +141,19 @@ class TestPost < Test::Unit::TestCase
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
+
context "with space (categories)" do
|
145
|
+
setup do
|
146
|
+
@post.categories << "French cuisine"
|
147
|
+
@post.categories << "Belgian beer"
|
148
|
+
@post.process(@fake_file)
|
149
|
+
end
|
150
|
+
|
151
|
+
should "process the url correctly" do
|
152
|
+
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
|
153
|
+
assert_equal "/French%20cuisine/Belgian%20beer/2008/09/09/foo-bar.html", @post.url
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
144
157
|
context "with none style" do
|
145
158
|
setup do
|
146
159
|
@post.site.permalink_style = :none
|
data/test/test_rdiscount.rb
CHANGED
@@ -5,8 +5,8 @@ class TestRdiscount < Test::Unit::TestCase
|
|
5
5
|
context "rdiscount" do
|
6
6
|
setup do
|
7
7
|
config = {
|
8
|
-
'
|
9
|
-
'
|
8
|
+
'markdown' => 'rdiscount',
|
9
|
+
'rdiscount' => { 'extensions' => ['smart', 'generate_toc'], 'toc_token' => '{:toc}' }
|
10
10
|
}
|
11
11
|
@markdown = MarkdownConverter.new config
|
12
12
|
end
|
@@ -14,5 +14,9 @@ class TestRdiscount < Test::Unit::TestCase
|
|
14
14
|
should "pass rdiscount extensions" do
|
15
15
|
assert_equal "<p>“smart”</p>", @markdown.convert('"smart"').strip
|
16
16
|
end
|
17
|
+
|
18
|
+
should "render toc" do
|
19
|
+
assert_equal "<h1 id=\"Header+1\">Header 1</h1>\n\n<h2 id=\"Header+2\">Header 2</h2>\n\n<p>\n <ul>\n <li><a href=\"#Header+1\">Header 1</a>\n <ul>\n <li><a href=\"#Header+2\">Header 2</a> </li>\n </ul>\n </li>\n </ul>\n\n</p>", @markdown.convert("# Header 1\n\n## Header 2\n\n{:toc}").strip
|
20
|
+
end
|
17
21
|
end
|
18
22
|
end
|
data/test/test_redcarpet.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
class TestRedcarpet < Test::Unit::TestCase
|
4
4
|
context "redcarpet" do
|
5
5
|
setup do
|
6
6
|
config = {
|
7
|
-
'redcarpet' => { 'extensions' => ['smart'] },
|
7
|
+
'redcarpet' => { 'extensions' => ['smart', 'strikethrough', 'filter_html'] },
|
8
8
|
'markdown' => 'redcarpet'
|
9
9
|
}
|
10
10
|
@markdown = MarkdownConverter.new config
|
@@ -14,8 +14,26 @@ class TestRedcarpet < Test::Unit::TestCase
|
|
14
14
|
assert_equal "<h1>Some Header</h1>", @markdown.convert('# Some Header #').strip
|
15
15
|
end
|
16
16
|
|
17
|
-
should "pass redcarpet
|
17
|
+
should "pass redcarpet SmartyPants options" do
|
18
18
|
assert_equal "<p>“smart”</p>", @markdown.convert('"smart"').strip
|
19
19
|
end
|
20
|
+
|
21
|
+
should "pass redcarpet extensions" do
|
22
|
+
assert_equal "<p><del>deleted</del></p>", @markdown.convert('~~deleted~~').strip
|
23
|
+
end
|
24
|
+
|
25
|
+
should "pass redcarpet render options" do
|
26
|
+
assert_equal "<p><strong>bad code not here</strong>: i am bad</p>", @markdown.convert('**bad code not here**: <script>i am bad</script>').strip
|
27
|
+
end
|
28
|
+
|
29
|
+
should "render fenced code blocks" do
|
30
|
+
assert_equal "<div class=\"highlight\"><pre><code class=\"ruby\"><span class=\"nb\">puts</span> <span class=\"s2\">"Hello world"</span>\n</code></pre></div>", @markdown.convert(
|
31
|
+
<<-EOS
|
32
|
+
```ruby
|
33
|
+
puts "Hello world"
|
34
|
+
```
|
35
|
+
EOS
|
36
|
+
).strip
|
37
|
+
end
|
20
38
|
end
|
21
39
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestRedCloth < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "RedCloth default (no explicit config) hard_breaks enabled" do
|
6
|
+
setup do
|
7
|
+
@textile = TextileConverter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should "preserve single line breaks in HTML output" do
|
11
|
+
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "Default hard_breaks enabled w/ redcloth section, no hard_breaks value" do
|
16
|
+
setup do
|
17
|
+
config = {
|
18
|
+
'redcloth' => {}
|
19
|
+
}
|
20
|
+
@textile = TextileConverter.new config
|
21
|
+
end
|
22
|
+
|
23
|
+
should "preserve single line breaks in HTML output" do
|
24
|
+
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "RedCloth with hard_breaks enabled" do
|
29
|
+
setup do
|
30
|
+
config = {
|
31
|
+
'redcloth' => {
|
32
|
+
'hard_breaks' => true # default
|
33
|
+
}
|
34
|
+
}
|
35
|
+
@textile = TextileConverter.new config
|
36
|
+
end
|
37
|
+
|
38
|
+
should "preserve single line breaks in HTML output" do
|
39
|
+
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "RedCloth with hard_breaks disabled" do
|
44
|
+
setup do
|
45
|
+
config = {
|
46
|
+
'redcloth' => {
|
47
|
+
'hard_breaks' => false
|
48
|
+
}
|
49
|
+
}
|
50
|
+
@textile = TextileConverter.new config
|
51
|
+
end
|
52
|
+
|
53
|
+
should "not generate break tags in HTML output" do
|
54
|
+
assert_equal "<p>line1\nline2</p>", @textile.convert("p. line1\nline2").strip
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "RedCloth w/no_span_caps set to false" do
|
59
|
+
setup do
|
60
|
+
config = {
|
61
|
+
'redcloth' => {
|
62
|
+
'no_span_caps' => false
|
63
|
+
}
|
64
|
+
}
|
65
|
+
@textile = TextileConverter.new config
|
66
|
+
end
|
67
|
+
should "generate span tags around capitalized words" do
|
68
|
+
assert_equal "<p><span class=\"caps\">NSC</span></p>", @textile.convert("NSC").strip
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "RedCloth w/no_span_caps set to true" do
|
73
|
+
setup do
|
74
|
+
config = {
|
75
|
+
'redcloth' => {
|
76
|
+
'no_span_caps' => true
|
77
|
+
}
|
78
|
+
}
|
79
|
+
@textile = TextileConverter.new config
|
80
|
+
end
|
81
|
+
|
82
|
+
should "not generate span tags around capitalized words" do
|
83
|
+
assert_equal "<p>NSC</p>", @textile.convert("NSC").strip
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/test/test_site.rb
CHANGED
@@ -1,6 +1,32 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestSite < Test::Unit::TestCase
|
4
|
+
context "configuring sites" do
|
5
|
+
should "have an array for plugins by default" do
|
6
|
+
site = Site.new(Jekyll::DEFAULTS)
|
7
|
+
assert_equal [File.join(Dir.pwd, '_plugins')], site.plugins
|
8
|
+
end
|
9
|
+
|
10
|
+
should "have an array for plugins if passed as a string" do
|
11
|
+
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => '/tmp/plugins'}))
|
12
|
+
assert_equal ['/tmp/plugins'], site.plugins
|
13
|
+
end
|
14
|
+
|
15
|
+
should "have an array for plugins if passed as an array" do
|
16
|
+
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => ['/tmp/plugins', '/tmp/otherplugins']}))
|
17
|
+
assert_equal ['/tmp/plugins', '/tmp/otherplugins'], site.plugins
|
18
|
+
end
|
19
|
+
|
20
|
+
should "have an empty array for plugins if nothing is passed" do
|
21
|
+
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => []}))
|
22
|
+
assert_equal [], site.plugins
|
23
|
+
end
|
24
|
+
|
25
|
+
should "have an empty array for plugins if nil is passed" do
|
26
|
+
site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => nil}))
|
27
|
+
assert_equal [], site.plugins
|
28
|
+
end
|
29
|
+
end
|
4
30
|
context "creating sites" do
|
5
31
|
setup do
|
6
32
|
stub(Jekyll).configuration do
|
@@ -126,12 +152,20 @@ class TestSite < Test::Unit::TestCase
|
|
126
152
|
|
127
153
|
should "filter entries with exclude" do
|
128
154
|
excludes = %w[README TODO]
|
129
|
-
|
155
|
+
files = %w[index.html site.css .htaccess]
|
130
156
|
|
131
157
|
@site.exclude = excludes
|
132
|
-
assert_equal
|
158
|
+
assert_equal files, @site.filter_entries(excludes + files)
|
133
159
|
end
|
134
160
|
|
161
|
+
should "not filter entries within include" do
|
162
|
+
includes = %w[_index.html .htaccess]
|
163
|
+
files = %w[index.html _index.html .htaccess]
|
164
|
+
|
165
|
+
@site.include = includes
|
166
|
+
assert_equal files, @site.filter_entries(files)
|
167
|
+
end
|
168
|
+
|
135
169
|
context 'with orphaned files in destination' do
|
136
170
|
setup do
|
137
171
|
clear_dest
|
data/test/test_tags.rb
CHANGED
@@ -6,9 +6,14 @@ class TestTags < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter)
|
8
8
|
stub(Jekyll).configuration do
|
9
|
-
Jekyll::DEFAULTS.
|
9
|
+
Jekyll::DEFAULTS.deep_merge({'pygments' => true}).deep_merge(override)
|
10
10
|
end
|
11
11
|
site = Site.new(Jekyll.configuration)
|
12
|
+
|
13
|
+
if override['read_posts']
|
14
|
+
site.read_posts('')
|
15
|
+
end
|
16
|
+
|
12
17
|
info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
|
13
18
|
@converter = site.converters.find { |c| c.class == converter_class }
|
14
19
|
payload = { "pygments_prefix" => @converter.pygments_prefix,
|
@@ -31,6 +36,41 @@ CONTENT
|
|
31
36
|
create_post(content, override)
|
32
37
|
end
|
33
38
|
|
39
|
+
context "language name" do
|
40
|
+
should "match only the required set of chars" do
|
41
|
+
r = Jekyll::HighlightBlock::SYNTAX
|
42
|
+
assert_match r, "ruby"
|
43
|
+
assert_match r, "c#"
|
44
|
+
assert_match r, "xml+cheetah"
|
45
|
+
assert_match r, "x.y"
|
46
|
+
assert_match r, "coffee-script"
|
47
|
+
|
48
|
+
assert_no_match r, "blah^"
|
49
|
+
|
50
|
+
assert_match r, "ruby key=val"
|
51
|
+
assert_match r, "ruby a=b c=d"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "initialized tag" do
|
56
|
+
should "work" do
|
57
|
+
tag = Jekyll::HighlightBlock.new('highlight', 'ruby ', ["test", "{% endhighlight %}", "\n"])
|
58
|
+
assert_equal({}, tag.instance_variable_get(:@options))
|
59
|
+
|
60
|
+
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos ', ["test", "{% endhighlight %}", "\n"])
|
61
|
+
assert_equal({'O' => "linenos=inline"}, tag.instance_variable_get(:@options))
|
62
|
+
|
63
|
+
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table ', ["test", "{% endhighlight %}", "\n"])
|
64
|
+
assert_equal({'O' => "linenos=table"}, tag.instance_variable_get(:@options))
|
65
|
+
|
66
|
+
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table nowrap', ["test", "{% endhighlight %}", "\n"])
|
67
|
+
assert_equal({'O' => "linenos=table,nowrap=true"}, tag.instance_variable_get(:@options))
|
68
|
+
|
69
|
+
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table cssclass=hl', ["test", "{% endhighlight %}", "\n"])
|
70
|
+
assert_equal({'O' => "cssclass=hl,linenos=table"}, tag.instance_variable_get(:@options))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
34
74
|
context "post content has highlight tag" do
|
35
75
|
setup do
|
36
76
|
fill_post("test")
|
@@ -137,4 +177,25 @@ CONTENT
|
|
137
177
|
end
|
138
178
|
end
|
139
179
|
end
|
180
|
+
|
181
|
+
context "simple page with post linking" do
|
182
|
+
setup do
|
183
|
+
content = <<CONTENT
|
184
|
+
---
|
185
|
+
title: Post linking
|
186
|
+
---
|
187
|
+
|
188
|
+
{% post_url 2008-11-21-complex %}
|
189
|
+
CONTENT
|
190
|
+
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
191
|
+
end
|
192
|
+
|
193
|
+
should "not cause an error" do
|
194
|
+
assert_no_match /markdown\-html\-error/, @result
|
195
|
+
end
|
196
|
+
|
197
|
+
should "have the url to the \"complex\" post from 2008-11-21" do
|
198
|
+
assert_match %r{/2008/11/21/complex/}, @result
|
199
|
+
end
|
200
|
+
end
|
140
201
|
end
|