jekyll-reloaded 0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/Gemfile +2 -0
  2. data/History.txt +321 -0
  3. data/LICENSE +21 -0
  4. data/README.textile +41 -0
  5. data/Rakefile +161 -0
  6. data/bin/jekyll +289 -0
  7. data/cucumber.yml +1 -0
  8. data/features/create_sites.feature +112 -0
  9. data/features/embed_filters.feature +60 -0
  10. data/features/markdown.feature +30 -0
  11. data/features/pagination.feature +27 -0
  12. data/features/permalinks.feature +65 -0
  13. data/features/post_data.feature +153 -0
  14. data/features/site_configuration.feature +145 -0
  15. data/features/site_data.feature +82 -0
  16. data/features/step_definitions/jekyll_steps.rb +145 -0
  17. data/features/support/env.rb +19 -0
  18. data/jekyll.gemspec +146 -0
  19. data/lib/guard/jekyll.rb +57 -0
  20. data/lib/jekyll/converter.rb +50 -0
  21. data/lib/jekyll/converters/identity.rb +22 -0
  22. data/lib/jekyll/converters/markdown.rb +125 -0
  23. data/lib/jekyll/converters/textile.rb +50 -0
  24. data/lib/jekyll/convertible.rb +116 -0
  25. data/lib/jekyll/core_ext.rb +52 -0
  26. data/lib/jekyll/errors.rb +6 -0
  27. data/lib/jekyll/filters.rb +118 -0
  28. data/lib/jekyll/generator.rb +7 -0
  29. data/lib/jekyll/generators/pagination.rb +113 -0
  30. data/lib/jekyll/layout.rb +51 -0
  31. data/lib/jekyll/live_site.rb +216 -0
  32. data/lib/jekyll/migrators/csv.rb +26 -0
  33. data/lib/jekyll/migrators/drupal.rb +103 -0
  34. data/lib/jekyll/migrators/enki.rb +49 -0
  35. data/lib/jekyll/migrators/joomla.rb +53 -0
  36. data/lib/jekyll/migrators/marley.rb +52 -0
  37. data/lib/jekyll/migrators/mephisto.rb +84 -0
  38. data/lib/jekyll/migrators/mt.rb +86 -0
  39. data/lib/jekyll/migrators/posterous.rb +67 -0
  40. data/lib/jekyll/migrators/rss.rb +47 -0
  41. data/lib/jekyll/migrators/textpattern.rb +58 -0
  42. data/lib/jekyll/migrators/tumblr.rb +195 -0
  43. data/lib/jekyll/migrators/typo.rb +51 -0
  44. data/lib/jekyll/migrators/wordpress.rb +294 -0
  45. data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
  46. data/lib/jekyll/page.rb +160 -0
  47. data/lib/jekyll/plugin.rb +77 -0
  48. data/lib/jekyll/post.rb +262 -0
  49. data/lib/jekyll/site.rb +339 -0
  50. data/lib/jekyll/static_file.rb +77 -0
  51. data/lib/jekyll/tags/highlight.rb +118 -0
  52. data/lib/jekyll/tags/include.rb +37 -0
  53. data/lib/jekyll/tags/post_url.rb +38 -0
  54. data/lib/jekyll.rb +134 -0
  55. data/test/helper.rb +34 -0
  56. data/test/source/.htaccess +8 -0
  57. data/test/source/_includes/sig.markdown +3 -0
  58. data/test/source/_layouts/default.html +27 -0
  59. data/test/source/_layouts/simple.html +1 -0
  60. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  61. data/test/source/_posts/2008-02-02-published.textile +8 -0
  62. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  63. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  64. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  65. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  66. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  67. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  68. data/test/source/_posts/2009-01-27-category.textile +7 -0
  69. data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
  70. data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
  71. data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
  72. data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
  73. data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
  74. data/test/source/_posts/2009-05-18-tag.textile +6 -0
  75. data/test/source/_posts/2009-05-18-tags.textile +9 -0
  76. data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
  77. data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
  78. data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
  79. data/test/source/_posts/2010-01-09-date-override.textile +7 -0
  80. data/test/source/_posts/2010-01-09-time-override.textile +7 -0
  81. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  82. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  83. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  84. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  85. data/test/source/about.html +6 -0
  86. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  87. data/test/source/contacts.html +5 -0
  88. data/test/source/css/screen.css +76 -0
  89. data/test/source/deal.with.dots.html +7 -0
  90. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  91. data/test/source/index.html +22 -0
  92. data/test/source/sitemap.xml +32 -0
  93. data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
  94. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  95. data/test/suite.rb +11 -0
  96. data/test/test_configuration.rb +29 -0
  97. data/test/test_core_ext.rb +66 -0
  98. data/test/test_filters.rb +62 -0
  99. data/test/test_generated_site.rb +72 -0
  100. data/test/test_kramdown.rb +23 -0
  101. data/test/test_page.rb +117 -0
  102. data/test/test_pager.rb +113 -0
  103. data/test/test_post.rb +450 -0
  104. data/test/test_rdiscount.rb +18 -0
  105. data/test/test_redcarpet.rb +21 -0
  106. data/test/test_redcloth.rb +86 -0
  107. data/test/test_site.rb +220 -0
  108. data/test/test_tags.rb +201 -0
  109. metadata +332 -0
data/test/test_site.rb ADDED
@@ -0,0 +1,220 @@
1
+ require 'helper'
2
+
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
30
+ context "creating sites" do
31
+ setup do
32
+ stub(Jekyll).configuration do
33
+ Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
34
+ end
35
+ @site = Site.new(Jekyll.configuration)
36
+ end
37
+
38
+ should "have an empty tag hash by default" do
39
+ assert_equal Hash.new, @site.tags
40
+ end
41
+
42
+ should "reset data before processing" do
43
+ clear_dest
44
+ @site.process
45
+ before_posts = @site.posts.length
46
+ before_layouts = @site.layouts.length
47
+ before_categories = @site.categories.length
48
+ before_tags = @site.tags.length
49
+ before_pages = @site.pages.length
50
+ before_static_files = @site.static_files.length
51
+ before_time = @site.time
52
+
53
+ @site.process
54
+ assert_equal before_posts, @site.posts.length
55
+ assert_equal before_layouts, @site.layouts.length
56
+ assert_equal before_categories, @site.categories.length
57
+ assert_equal before_tags, @site.tags.length
58
+ assert_equal before_pages, @site.pages.length
59
+ assert_equal before_static_files, @site.static_files.length
60
+ assert before_time <= @site.time
61
+ end
62
+
63
+ should "write only modified static files" do
64
+ clear_dest
65
+ StaticFile.reset_cache
66
+
67
+ @site.process
68
+ some_static_file = @site.static_files[0].path
69
+ dest = File.expand_path(@site.static_files[0].destination(@site.dest))
70
+ mtime1 = File.stat(dest).mtime.to_i # first run must generate dest file
71
+
72
+ # need to sleep because filesystem timestamps have best resolution in seconds
73
+ sleep 1
74
+ @site.process
75
+ mtime2 = File.stat(dest).mtime.to_i
76
+ assert_equal mtime1, mtime2
77
+
78
+ # simulate file modification by user
79
+ FileUtils.touch some_static_file
80
+
81
+ sleep 1
82
+ @site.process
83
+ mtime3 = File.stat(dest).mtime.to_i
84
+ assert_not_equal mtime2, mtime3 # must be regenerated!
85
+
86
+ sleep 1
87
+ @site.process
88
+ mtime4 = File.stat(dest).mtime.to_i
89
+ assert_equal mtime3, mtime4 # no modifications, so must be the same
90
+ end
91
+
92
+ should "write static files if not modified but missing in destination" do
93
+ clear_dest
94
+ StaticFile.reset_cache
95
+
96
+ @site.process
97
+ some_static_file = @site.static_files[0].path
98
+ dest = File.expand_path(@site.static_files[0].destination(@site.dest))
99
+ mtime1 = File.stat(dest).mtime.to_i # first run must generate dest file
100
+
101
+ # need to sleep because filesystem timestamps have best resolution in seconds
102
+ sleep 1
103
+ @site.process
104
+ mtime2 = File.stat(dest).mtime.to_i
105
+ assert_equal mtime1, mtime2
106
+
107
+ # simulate destination file deletion
108
+ File.unlink dest
109
+
110
+ sleep 1
111
+ @site.process
112
+ mtime3 = File.stat(dest).mtime.to_i
113
+ assert_not_equal mtime2, mtime3 # must be regenerated and differ!
114
+
115
+ sleep 1
116
+ @site.process
117
+ mtime4 = File.stat(dest).mtime.to_i
118
+ assert_equal mtime3, mtime4 # no modifications, so must be the same
119
+ end
120
+
121
+ should "read layouts" do
122
+ @site.read_layouts
123
+ assert_equal ["default", "simple"].sort, @site.layouts.keys.sort
124
+ end
125
+
126
+ should "read posts" do
127
+ @site.read_posts('')
128
+ posts = Dir[source_dir('_posts', '*')]
129
+ assert_equal posts.size - 1, @site.posts.size
130
+ end
131
+
132
+ should "deploy payload" do
133
+ clear_dest
134
+ @site.process
135
+
136
+ posts = Dir[source_dir("**", "_posts", "*")]
137
+ categories = %w(bar baz category foo z_category publish_test win).sort
138
+
139
+ assert_equal posts.size - 1, @site.posts.size
140
+ assert_equal categories, @site.categories.keys.sort
141
+ assert_equal 4, @site.categories['foo'].size
142
+ end
143
+
144
+ should "filter entries" do
145
+ ent1 = %w[foo.markdown bar.markdown baz.markdown #baz.markdown#
146
+ .baz.markdow foo.markdown~]
147
+ ent2 = %w[.htaccess _posts _pages bla.bla]
148
+
149
+ assert_equal %w[foo.markdown bar.markdown baz.markdown], @site.filter_entries(ent1)
150
+ assert_equal %w[.htaccess bla.bla], @site.filter_entries(ent2)
151
+ end
152
+
153
+ should "filter entries with exclude" do
154
+ excludes = %w[README TODO]
155
+ files = %w[index.html site.css .htaccess]
156
+
157
+ @site.exclude = excludes
158
+ assert_equal files, @site.filter_entries(excludes + files)
159
+ end
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
+
169
+ context 'with orphaned files in destination' do
170
+ setup do
171
+ clear_dest
172
+ @site.process
173
+ # generate some orphaned files:
174
+ # hidden file
175
+ File.open(dest_dir('.htpasswd'), 'w')
176
+ # single file
177
+ File.open(dest_dir('obsolete.html'), 'w')
178
+ # single file in sub directory
179
+ FileUtils.mkdir(dest_dir('qux'))
180
+ File.open(dest_dir('qux/obsolete.html'), 'w')
181
+ # empty directory
182
+ FileUtils.mkdir(dest_dir('quux'))
183
+ end
184
+
185
+ teardown do
186
+ FileUtils.rm_f(dest_dir('.htpasswd'))
187
+ FileUtils.rm_f(dest_dir('obsolete.html'))
188
+ FileUtils.rm_rf(dest_dir('qux'))
189
+ FileUtils.rm_f(dest_dir('quux'))
190
+ end
191
+
192
+ should 'remove orphaned files in destination' do
193
+ @site.process
194
+ assert !File.exist?(dest_dir('.htpasswd'))
195
+ assert !File.exist?(dest_dir('obsolete.html'))
196
+ assert !File.exist?(dest_dir('qux'))
197
+ assert !File.exist?(dest_dir('quux'))
198
+ end
199
+
200
+ end
201
+
202
+ context 'with an invalid markdown processor in the configuration' do
203
+ should 'not throw an error at initialization time' do
204
+ bad_processor = 'not a processor name'
205
+ assert_nothing_raised do
206
+ Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
207
+ end
208
+ end
209
+
210
+ should 'throw FatalException at process time' do
211
+ bad_processor = 'not a processor name'
212
+ s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
213
+ assert_raise Jekyll::FatalException do
214
+ s.process
215
+ end
216
+ end
217
+ end
218
+
219
+ end
220
+ end
data/test/test_tags.rb ADDED
@@ -0,0 +1,201 @@
1
+ # coding: utf-8
2
+
3
+ require 'helper'
4
+
5
+ class TestTags < Test::Unit::TestCase
6
+
7
+ def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter)
8
+ stub(Jekyll).configuration do
9
+ Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override)
10
+ end
11
+ site = Site.new(Jekyll.configuration)
12
+
13
+ if override['read_posts']
14
+ site.read_posts('')
15
+ end
16
+
17
+ info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
18
+ @converter = site.converters.find { |c| c.class == converter_class }
19
+ payload = { "pygments_prefix" => @converter.pygments_prefix,
20
+ "pygments_suffix" => @converter.pygments_suffix }
21
+
22
+ @result = Liquid::Template.parse(content).render(payload, info)
23
+ @result = @converter.convert(@result)
24
+ end
25
+
26
+ def fill_post(code, override = {})
27
+ content = <<CONTENT
28
+ ---
29
+ title: This is a test
30
+ ---
31
+
32
+ This document results in a markdown error with maruku
33
+
34
+ {% highlight text %}#{code}{% endhighlight %}
35
+ CONTENT
36
+ create_post(content, override)
37
+ end
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
+
74
+ context "post content has highlight tag" do
75
+ setup do
76
+ fill_post("test")
77
+ end
78
+
79
+ should "not cause a markdown error" do
80
+ assert_no_match /markdown\-html\-error/, @result
81
+ end
82
+
83
+ should "render markdown with pygments line handling" do
84
+ assert_match %{<pre><code class='text'>test\n</code></pre>}, @result
85
+ end
86
+ end
87
+
88
+ context "post content has highlight with file reference" do
89
+ setup do
90
+ fill_post("./jekyll.gemspec")
91
+ end
92
+
93
+ should "not embed the file" do
94
+ assert_match %{<pre><code class='text'>./jekyll.gemspec\n</code></pre>}, @result
95
+ end
96
+ end
97
+
98
+ context "post content has highlight tag with UTF character" do
99
+ setup do
100
+ fill_post("Æ")
101
+ end
102
+
103
+ should "render markdown with pygments line handling" do
104
+ assert_match %{<pre><code class='text'>Æ\n</code></pre>}, @result
105
+ end
106
+ end
107
+
108
+ context "simple post with markdown and pre tags" do
109
+ setup do
110
+ @content = <<CONTENT
111
+ ---
112
+ title: Maruku vs. RDiscount
113
+ ---
114
+
115
+ _FIGHT!_
116
+
117
+ {% highlight ruby %}
118
+ puts "3..2..1.."
119
+ {% endhighlight %}
120
+
121
+ *FINISH HIM*
122
+ CONTENT
123
+ end
124
+
125
+ context "using Textile" do
126
+ setup do
127
+ create_post(@content, {}, Jekyll::TextileConverter)
128
+ end
129
+
130
+ # Broken in RedCloth 4.1.9
131
+ should "not textilize highlight block" do
132
+ assert_no_match %r{3\.\.2\.\.1\.\.&quot;</span><br />}, @result
133
+ end
134
+ end
135
+
136
+ context "using Maruku" do
137
+ setup do
138
+ create_post(@content)
139
+ end
140
+
141
+ should "parse correctly" do
142
+ assert_match %r{<em>FIGHT!</em>}, @result
143
+ assert_match %r{<em>FINISH HIM</em>}, @result
144
+ end
145
+ end
146
+
147
+ context "using RDiscount" do
148
+ setup do
149
+ create_post(@content, 'markdown' => 'rdiscount')
150
+ end
151
+
152
+ should "parse correctly" do
153
+ assert_match %r{<em>FIGHT!</em>}, @result
154
+ assert_match %r{<em>FINISH HIM</em>}, @result
155
+ end
156
+ end
157
+
158
+ context "using Kramdown" do
159
+ setup do
160
+ create_post(@content, 'markdown' => 'kramdown')
161
+ end
162
+
163
+ should "parse correctly" do
164
+ assert_match %r{<em>FIGHT!</em>}, @result
165
+ assert_match %r{<em>FINISH HIM</em>}, @result
166
+ end
167
+ end
168
+
169
+ context "using Redcarpet" do
170
+ setup do
171
+ create_post(@content, 'markdown' => 'redcarpet')
172
+ end
173
+
174
+ should "parse correctly" do
175
+ assert_match %r{<em>FIGHT!</em>}, @result
176
+ assert_match %r{<em>FINISH HIM</em>}, @result
177
+ end
178
+ end
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
201
+ end