mojombo-jekyll 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,15 @@
1
+ == 0.5.1
2
+ * Major Enhancements
3
+ * Next/previous posts in site payload [github.com/pantulis, github.com/tomo]
4
+ * Permalink templating system
5
+ * Moved most of the README out to the GitHub wiki
6
+ * Exclude option in configuration so specified files won't be brought over with generated site [github.com/duritong]
7
+ * Bug Fixes
8
+ * Making sure config.yaml references are all gone, using only config.yml
9
+ * Fixed syntax highlighting breaking for UTF-8 code [github.com/henrik]
10
+ * Worked around RDiscount bug that prevents Markdown from getting parsed after highlight [github.com/henrik]
11
+ * CGI escaped post titles [github.com/Chrononaut]
12
+
1
13
  == 0.5.0 / 2009-04-07
2
14
  * Minor Enhancements
3
15
  * Ability to set post categories via YAML [github.com/qrush]
@@ -1,523 +1,32 @@
1
1
  h1. Jekyll
2
2
 
3
- Jekyll is a simple, blog aware, static site generator. It takes a template
4
- directory (representing the raw form of a website), runs it through Textile or
5
- Markdown and Liquid converters, and spits out a complete, static website
6
- suitable for serving with Apache or your favorite web server. Visit
7
- "http://tom.preston-werner.com":http://tom.preston-werner.com to see an
8
- example of a Jekyll generated blog.
3
+ By Tom Preston-Werner, Nick Quaranto, and many awesome contributors!
9
4
 
10
- To understand how this all works, open up my
11
- "TPW":http://github.com/mojombo/tpw repo in a new browser window. I'll be
12
- referencing the code there.
5
+ Jekyll is a simple, blog aware, static site generator. It takes a template directory (representing the raw form of a website), runs it through Textile or Markdown and Liquid converters, and spits out a complete, static website suitable for serving with Apache or your favorite web server. This is also the engine behind "GitHub Pages":http://pages.github.com, which you can use to host your project's page or blog right here from GitHub.
13
6
 
14
- Take a look at
15
- "index.html":http://github.com/mojombo/tpw/tree/master/index.html. This file
16
- represents the homepage of the site. At the top of the file is a chunk of YAML
17
- that contains metadata about the file. This data tells Jekyll what layout to
18
- give the file, what the page's title should be, etc. In this case, I specify
19
- that the "default" template should be used. You can find the layout files in
20
- the "_layouts":http://github.com/mojombo/tpw/tree/master/_layouts directory.
21
- If you open
22
- "default.html":http://github.com/mojombo/tpw/tree/master/_layouts/default.html
23
- you can see that the homepage is constructed by wrapping index.html with this
24
- layout.
7
+ h2. Getting Started
25
8
 
26
- You'll also notice Liquid templating code in these files.
27
- "Liquid":http://www.liquidmarkup.org/ is a simple, extensible templating
28
- language that makes it easy to embed data in your templates. For my homepage I
29
- wanted to have a list of all my blog posts. Jekyll hands me a Hash containing
30
- various data about my site. A reverse chronological list of all my blog posts
31
- can be found in <code>site.posts</code>. Each post, in turn, contains various
32
- fields such as <code>title</code> and <code>date</code>.
9
+ * "Install":http://wiki.github.com/mojombo/jekyll/install the gem
10
+ * Read up about its "Usage":http://wiki.github.com/mojombo/jekyll/usage and "Configuration":http://wiki.github.com/mojombo/jekyll/configuration
11
+ * Take a gander at some existing "Sites":http://wiki.github.com/mojombo/jekyll/sites
12
+ * Fork and "Contribute":http://wiki.github.com/mojombo/jekyll/contribute your own modifications
33
13
 
34
- Jekyll gets the list of blog posts by parsing the files in any
35
- "_posts":http://github.com/mojombo/tpw/tree/master/_posts directory found in
36
- subdirectories below the root.
37
- Each post's filename contains (by default) the publishing date and slug (what shows up in the
38
- URL) that the final HTML file should have. Open up the file corresponding to a
39
- blog post:
40
- "2008-11-17-blogging-like-a-hacker.textile":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile.
41
- GitHub renders textile files by default, so to better understand the file,
42
- click on the
43
- "raw":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile?raw=true
44
- view to see the original file. Here I've specified the <code>post</code>
45
- layout. If you look at that file you'll see an example of a nested layout.
46
- Layouts can contain other layouts allowing you a great deal of flexibility in
47
- how pages are assembled. In my case I use a nested layout in order to show
48
- related posts for each blog entry. The YAML also specifies the post's title
49
- which is then embedded in the post's body via Liquid.
14
+ h2. Diving In
50
15
 
51
- Posts are handled in a special way by Jekyll. The date you specify in the
52
- filename is used to construct the URL in the generated site. The example post,
53
- for instance, ends up at
54
- <code>http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html</code>.
16
+ * "Migrate":http://wiki.github.com/mojombo/jekyll/blog-migrations from your previous system
17
+ * Learn how the "YAML Front Matter":http://wiki.github.com/mojombo/jekyll/yaml-front-matter works
18
+ * Put information on your site with "Template Data":http://wiki.github.com/mojombo/jekyll/template-data
19
+ * Customize the "Permalinks":http://wiki.github.com/mojombo/jekyll/permalinks your posts are generated with
20
+ * Use the built-in "Liquid Extensions":http://wiki.github.com/mojombo/jekyll/liquid-extensions to make your life easier
55
21
 
56
- Categories for posts are derived from the directory structure the posts were
57
- found within. A post that appears in the directory foo/bar/_posts is placed in
58
- the categories 'foo' and 'bar'. By selecting posts from particular categories
59
- in your Liquid templates, you will be able to host multiple blogs within a
60
- site.
22
+ h2. Dependencies
61
23
 
62
- Files that do not reside in directories prefixed with an underscore are
63
- mirrored into a corresponding directory structure in the generated site. If a
64
- file does not have a YAML preface, it is not run through the Liquid
65
- interpreter. Binary files are copied over unmodified.
66
-
67
- Jekyll is still a very young project. I've only developed the exact
68
- functionality that I've needed. As time goes on I'd like to see the project
69
- mature and support additional features. If you end up using Jekyll for your
70
- own blog, drop me a line and let me know what you'd like to see in future
71
- versions. Better yet, fork the project over at GitHub and hack in the features
72
- yourself!
73
-
74
- h2. Example Proto-Site
75
-
76
- My own personal site/blog is generated with Jekyll.
77
-
78
- The proto-site repo
79
- ("http://github.com/mojombo/tpw":http://github.com/mojombo/tpw) is converted
80
- into the actual site
81
- ("http://tom.preston-werner.com/":http://tom.preston-werner.com)
82
-
83
- h2. Install
84
-
85
- The best way to install Jekyll is via RubyGems:
86
-
87
- $ sudo gem install mojombo-jekyll -s http://gems.github.com/
88
-
89
- Jekyll requires the gems `directory_watcher`, `liquid`, `open4`,
90
- and `maruku` (for markdown support). These are automatically
91
- installed by the gem install command.
92
-
93
- Maruku comes with optional support for LaTeX to PNG rendering via
94
- "blahtex":http://gva.noekeon.org/blahtexml/ (Version 0.6) which must be in
95
- your $PATH along with `dvips`.
96
-
97
- (NOTE: the version of maruku I am using is `remi-maruku` on GitHub as it
98
- does not assume a fixed location for `dvips`.)
99
-
100
- h2. Run
101
-
102
- $ cd /path/to/proto/site
103
- $ jekyll
104
-
105
- This will generate the site and place it in /path/to/proto/site/_site. If
106
- you'd like the generated site placed somewhere else:
107
-
108
- $ jekyll /path/to/place/generated/site
109
-
110
- And if you don't want to be in the proto site root to run Jekyll:
111
-
112
- $ jekyll /path/to/proto/site /path/to/place/generated/site
113
-
114
- h2. Run Options
115
-
116
- h3. Autobuild
117
-
118
- There is an autobuild feature that will regenerate your site if any of the
119
- files change. The autobuild feature can be used on any of the invocations:
120
-
121
- $ jekyll --auto
122
-
123
- h3. Related Posts
124
-
125
- By default, the "related posts" functionality will produce crappy results.
126
- In order to get high quality results with a true LSI algorithm, you must
127
- enable it (it may take some time to run if you have many posts):
128
-
129
- $ jekyll --lsi
130
-
131
- h3. Code Highlighting
132
-
133
- For static code highlighting, you can install Pygments (see below) and then
134
- use that to make your code blocks look pretty. To activate Pygments support
135
- during the conversion:
136
-
137
- $ jekyll --pygments
138
-
139
- h3. Markdown Processor
140
-
141
- By default, Jekyll uses "Maruku":http://maruku.rubyforge.org (pure Ruby) for
142
- Markdown support. If you'd like to use RDiscount (faster, but requires
143
- compilation), you must install it (gem install rdiscount) and then you can
144
- have it used instead:
145
-
146
- $ jekyll --rdiscount
147
-
148
- h3. Local Server
149
-
150
- When previewing complex sites locally, simply opening the site in a web
151
- browser (using file://) can cause problems with links that are relative to
152
- the site root (e.g., "/stylesheets/style.css"). To get around this, Jekyll
153
- can launch a simple WEBrick server (works well in conjunction with --auto).
154
- Default port is 4000:
155
-
156
- $ jekyll --server [PORT]
157
-
158
- h3. Permalink Style
159
-
160
- By default, the permalink for each post begins with its date in 'YYYY/MM/DD'
161
- format.
162
-
163
- If you do not wish to have the date appear in the URL of each post,
164
- you can change the permalink style to 'none' so that only the 'slug' part of
165
- the filename is used. For example, with the permalink style set to 'none' the
166
- file '2009-01-01-happy-new-year.markdown' will have a permalink like
167
- 'http://yoursite.com/happy-new-year.html'. The date of the post will still be
168
- read from the filename (and is required!) to be used elsewhere in Jekyll.
169
-
170
- If you want WordPress-style pretty URLs that leave off the .html, you can
171
- change the permalink style to 'pretty' and directories corresponding to the
172
- date parts and post name will be made and an index.html will be placed in the
173
- leaf directory resulting in URLs like 2008/11/17/blogging-like-a-hacker/.
174
-
175
- $ jekyll --permalink [date|none|pretty]
176
-
177
- h2. Configuration File
178
-
179
- All of the options listed above can be specified on a site-by-site basis in
180
- a '_config.yml' file at the root of the site's source. As the filename
181
- suggests, the configuration is given in "YAML":http://www.yaml.org/. As
182
- well as all of the options discussed in the last section, there are a few
183
- additional options:
184
-
185
- destination: [PATH] # Specify where the site should be rendered
186
- markdown: [maruku|rdiscount] # Which markdown renderer to use?
187
-
188
- maruku: # This is a YAML hash for Maruku settings
189
- use_divs: [BOOLEAN] # Use the div element Maruku extension
190
- use_tex: [BOOLEAN] # Use the LaTeX extension to Maruku
191
- png_dir: [PATH] # Where should the math PNGs be stored?
192
- png_url: [URL] # A relative URL for the PNGs
193
-
194
- The default configuration is shown below as in YAML format:
195
-
196
- destination: ./_site
197
- auto: false
198
- lsi: false
199
- server_port: 4000
200
- pygments: false
201
- markdown: maruku
202
- permalink: date
203
-
204
- maruku:
205
- use_tex: false
206
- use_divs: false
207
- png_dir: images/latex
208
- png_url: /images/latex
209
-
210
- Parameters set in a configuration file override the default values. Parameters
211
- set using command line options override both the default values and those set
212
- in a configuration file.
213
-
214
- h2. Data
215
-
216
- Jekyll traverses your site looking for files to process. Any files with YAML
217
- front matter (see below) are subject to processing. For each of these files,
218
- Jekyll makes a variety of data available to the pages via the Liquid
219
- templating system. The following is a reference of the available data.
220
-
221
- h3. Global
222
-
223
- site
224
- Sitewide information.
225
-
226
- page
227
- For Posts, this is the union of the data in the YAML front matter and the
228
- computed data (such as URL and date). For regular pages, this is just the
229
- YAML front matter.
230
-
231
- content
232
- In layout files, this contains the content of the subview(s). In Posts or
233
- Pages, this is undefined.
234
-
235
- h3. Site
236
-
237
- site.time
238
- The current Time (when you run the jekyll command).
239
-
240
- site.posts
241
- A reverse chronological list of all Posts.
242
-
243
- site.related_posts
244
- If the page being processed is a Post, this contains a list of up to ten
245
- related Posts. By default, these are low quality but fast to compute. For
246
- high quality but slow to compute results, run the jekyll command with the
247
- --lsi (latent semantic indexing) option.
248
-
249
- site.categories.CATEGORY
250
- The list of all Posts in category CATEGORY.
251
-
252
- h3. Post
253
-
254
- post.title
255
- The title of the Post.
256
-
257
- post.url
258
- The URL of the Post without the domain.
259
- e.g. /2008/12/14/my-post.html
260
-
261
- post.date
262
- The Date assigned to the Post.
263
-
264
- post.id
265
- An identifier unique to the Post (useful in RSS feeds).
266
- e.g. /2008/12/14/my-post
267
-
268
- post.categories
269
- The list of categories to which this post belongs. Categories are
270
- derived from the directory structure above the _posts directory. For
271
- example, a post at /work/code/_posts/2008-12-24-closures.textile
272
- would have this field set to ['work', 'code'].
273
-
274
- post.topics
275
- The list of topics for this Post. Topics are derived from the directory
276
- structure beneath the _posts directory. For example, a post at
277
- /_posts/music/metal/2008-12-24-metalocalypse.textile would have this field
278
- set to ['music', 'metal'].
279
-
280
- post.content
281
- The content of the Post.
282
-
283
- h2. YAML Front Matter
284
-
285
- Any files that contain a YAML front matter block will be processed by Jekyll
286
- as special files. The front matter must be the first thing in the file and
287
- takes the form of:
288
-
289
- <pre>
290
- ---
291
- layout: post
292
- title: Blogging Like a Hacker
293
- ---
294
- </pre>
295
-
296
- Between the triple-dashed lines, you can set predefined variables (see below
297
- for a reference) or custom data of your own.
298
-
299
- h3. Predefined Global Variables
300
-
301
- layout
302
- If set, this specifies the layout file to use. Use the layout file
303
- name without file extension. Layout files must be placed in the
304
- <code>_layouts</code> directory.
305
-
306
- h3. Predefined Post Variables
307
-
308
- permalink
309
- If you need your processed URLs to be something other than the default
310
- /year/month/day/title.html then you can set this variable and it will
311
- be used as the final URL.
312
-
313
- published
314
- Set to false if you don't want a post to show up when the site is
315
- generated.
316
-
317
- category/categories
318
- Instead of placing posts inside of folders, you can specify one or more
319
- categories that the post belongs to. When the site is generated the post
320
- will act as though it had been set with these categories normally.
321
-
322
- h3. Custom Variables
323
-
324
- Any variables in the front matter that are not predefined are mixed into the
325
- data that is sent to the Liquid templating engine during the conversion. For
326
- instance, if you set a <code>title</code>, you can use that in your layout to
327
- set the page title:
328
-
329
- <pre>
330
- <title>{{ page.title }}</title>
331
- </pre>
332
-
333
- h2. Filters, Tags, and Blocks
334
-
335
- In addition to the built-in Liquid filters, tags, and blocks, Jekyll provides
336
- some additional items that you can use in your site.
337
-
338
- h3. Date to XML Schema (Filter)
339
-
340
- Convert a Time into XML Schema format.
341
-
342
- {{ site.time | date_to_xmlschema }}
343
-
344
- becomes
345
-
346
- 2008-11-17T13:07:54-08:00
347
-
348
- h3. XML Escape (Filter)
349
-
350
- Escape some text for use in XML.
351
-
352
- {{ post.content | xml_escape }}
353
-
354
- h3. Number of Words (Filter)
355
-
356
- Count the number of words in some text.
357
-
358
- {{ post.content | number_of_words }}
359
-
360
- becomes
361
-
362
- 1337
363
-
364
- h3. Array to Sentence String
365
-
366
- Convert an array into a sentence.
367
-
368
- {{ page.tags | array_to_sentence_string }}
369
-
370
- becomes
371
-
372
- foo, bar, and baz
373
-
374
- h3. Textilize
375
-
376
- Convert a Textile-formatted string into HTML, formatted via RedCloth
377
-
378
- {{ page.excerpt | textilize }}
379
-
380
- h3. Include (Tag)
381
-
382
- If you have small page fragments that you wish to include in multiple places
383
- on your site, you can use the <code>include</code> tag.
384
-
385
- <pre>{% include sig.textile %}</pre>
386
-
387
- Jekyll expects all include files to be placed in an <code>_includes</code>
388
- directory at the root of your source dir. So this will embed the contents of
389
- <code>/path/to/proto/site/_includes/sig.textile</code> into the calling file.
390
-
391
- h3. Code Highlighting (Block)
392
-
393
- Jekyll has built in support for syntax highlighting of over "100
394
- languages":http://pygments.org/languages/ via "Pygments":http://pygments.org/.
395
- In order to take advantage of this you'll need to have Pygments installed, and
396
- the pygmentize binary must be in your path. When you run Jekyll, make sure you
397
- run it with Pygments support:
398
-
399
- $ jekyll --pygments
400
-
401
- To denote a code block that should be highlighted:
402
-
403
- <pre>
404
- {% highlight ruby %}
405
- def foo
406
- puts 'foo'
407
- end
408
- {% endhighlight %}
409
- </pre>
410
-
411
- The argument to <code>highlight</code> is the language identifier. To find the
412
- appropriate identifier to use for your favorite language, look for the "short
413
- name" on the "Lexers":http://pygments.org/docs/lexers/ page.
414
-
415
- There is a second argument to <code>highlight</code> called
416
- <code>linenos</code> that is optional. Including the <code>linenos</code>
417
- argument will force the highlighted code to include line numbers. For
418
- instance, the following code block would include line numbers next to each
419
- line:
420
-
421
- <pre>
422
- {% highlight ruby linenos %}
423
- def foo
424
- puts 'foo'
425
- end
426
- {% endhighlight %}
427
- </pre>
428
-
429
- In order for the highlighting to show up, you'll need to include a
430
- highlighting stylesheet. For an example stylesheet you can look at
431
- "syntax.css":http://github.com/mojombo/tpw/tree/master/css/syntax.css. These
432
- are the same styles as used by GitHub and you are free to use them for your
433
- own site. If you use linenos, you might want to include an additional CSS
434
- class definition for <code>lineno</code> in syntax.css to distinguish the line
435
- numbers from the highlighted code.
436
-
437
- h2. Categories
438
-
439
- Posts are placed into categories based on the directory structure they are
440
- found within (see above for an example). The categories can be accessed from
441
- within a Liquid template as follows:
442
-
443
- <pre>
444
- {% for post in site.categories.foo %}
445
- <li><span>{{ post.date | date_to_string }}</span> - {{ post.title }}</li>
446
- {% endfor %}
447
- </pre>
448
-
449
- This would list all the posts in the category 'foo' by date and title.
450
-
451
- The posts within each category are sorted in reverse chronological order.
452
-
453
- h2. Blog migrations
454
-
455
- h3. Movable Type
456
-
457
- To migrate your MT blog into Jekyll, you'll need read access to the database.
458
- The lib/jekyll/converters/mt.rb module provides a simple convert to create
459
- .markdown files in a _posts directory based on the entries contained therein.
460
-
461
- $ export DB=my_mtdb
462
- $ export USER=dbuser
463
- $ export PASS=dbpass
464
- $ ruby -r './lib/jekyll/converters/mt' -e 'Jekyll::MT.process( \
465
- "#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")'
466
-
467
- You may need to adjust the SQL query used to retrieve MT entries. Left alone,
468
- it will attempt to pull all entries across all blogs regardless of status.
469
- Please check the results and verify the posts before publishing.
470
-
471
- h3. Typo 4+
472
-
473
- To migrate your Typo blog into Jekyll, you'll need read access to the MySQL
474
- database. The lib/jekyll/converters/typo.rb module provides a simple convert
475
- to create .html, .textile, or .markdown files in a _posts directory based on
476
- the entries contained therein.
477
-
478
- $ export DB=my_typo_db
479
- $ export USER=dbuser
480
- $ export PASS=dbpass
481
- $ ruby -r './lib/jekyll/converters/typo' -e 'Jekyll::Typo.process( \
482
- "#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")'
483
-
484
- You may need to adjust the code used to filter Typo entries. Left alone,
485
- it will attempt to pull all entries across all blogs that were published.
486
- This code also has only been tested with Typo version 4+. Previous versions
487
- of Typo may not convert correctly. Please check the results and verify the
488
- posts before publishing.
489
-
490
- h3. TextPattern 4
491
-
492
- To migrate your TextPattern blog into Jekyll, you'll need read access to the MySQL
493
- database. The lib/jekyll/converters/textpattern.rb module provides a simple convert to create .textile files in a _posts directory based on
494
- the entries contained therein.
495
-
496
- $ ruby -r './lib/jekyll/converters/textpattern' -e 'Jekyll::TextPattern.process( \
497
- "database_name", "username", "password", "hostname")'
498
-
499
- The hostname defaults to _localhost_, all other variables are needed
500
- You may need to adjust the code used to filter entries. Left alone,
501
- it will attempt to pull all entries that are live or sticky.
502
-
503
- h2. Contribute
504
-
505
- If you'd like to hack on Jekyll, start by forking my repo on GitHub:
506
-
507
- http://github.com/mojombo/jekyll
508
-
509
- To get all of the dependencies, install the gem first. The best way to get
510
- your changes merged back into core is as follows:
511
-
512
- # Clone down your fork
513
- # Create a topic branch to contain your change
514
- # Hack away
515
- # Add tests and make sure everything still passes by running `rake`
516
- # If you are adding new functionality, document it in README.textile
517
- # Do not change the version number, I will do that on my end
518
- # If necessary, rebase your commits into logical chunks, without errors
519
- # Push the branch up to GitHub
520
- # Send me (mojombo) a pull request for your branch
24
+ * RedCloth 4.1.0: Textile support. This version obeys <notextile> tags. The latest version will still work, but tests will fail.
25
+ * Liquid: Templating system
26
+ * Classifier: Generating related posts
27
+ * Maruku: Default markdown engine
28
+ * Directory Watcher: Auto-regeneration of sites
29
+ * Open4: Talking to pygments for syntax highlighting
521
30
 
522
31
  h2. License
523
32
 
@@ -525,21 +34,8 @@ h2. License
525
34
 
526
35
  Copyright (c) 2008 Tom Preston-Werner
527
36
 
528
- Permission is hereby granted, free of charge, to any person obtaining
529
- a copy of this software and associated documentation files (the
530
- 'Software'), to deal in the Software without restriction, including
531
- without limitation the rights to use, copy, modify, merge, publish,
532
- distribute, sublicense, and/or sell copies of the Software, and to
533
- permit persons to whom the Software is furnished to do so, subject to
534
- the following conditions:
37
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
535
38
 
536
- The above copyright notice and this permission notice shall be
537
- included in all copies or substantial portions of the Software.
39
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
538
40
 
539
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
540
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
541
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
542
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
543
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
544
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
545
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ begin
15
15
  s.rubyforge_project = "jekyll"
16
16
  s.files.exclude 'test/dest'
17
17
  s.test_files.exclude 'test/dest'
18
- s.add_dependency('RedCloth', '>= 4.0.4')
18
+ s.add_dependency('RedCloth', '= 4.1.0')
19
19
  s.add_dependency('liquid', '>= 1.9.0')
20
20
  s.add_dependency('classifier', '>= 1.3.1')
21
21
  s.add_dependency('maruku', '>= 0.5.9')
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 5
4
- :patch: 0
4
+ :patch: 1
data/bin/jekyll CHANGED
@@ -10,7 +10,7 @@ Basic Command Line Usage:
10
10
  jekyll <path to write generated site> # . -> <path>
11
11
  jekyll <path to source> <path to write generated site> # <path> -> <path>
12
12
 
13
- Configuration is read from '<source>/_config.yaml' but can be overriden
13
+ Configuration is read from '<source>/_config.yml' but can be overriden
14
14
  using the following options:
15
15
 
16
16
  HELP
@@ -137,4 +137,4 @@ if options['server']
137
137
 
138
138
  trap("INT") { s.shutdown }
139
139
  t.join()
140
- end
140
+ end
@@ -27,7 +27,7 @@ require 'jekyll/tags/include'
27
27
  require 'jekyll/albino'
28
28
 
29
29
  module Jekyll
30
- # Default options. Overriden by values in _config.yaml or command-line opts.
30
+ # Default options. Overriden by values in _config.yml or command-line opts.
31
31
  # (Strings rather symbols used for compatability with YAML)
32
32
  DEFAULTS = {
33
33
  'auto' => false,
@@ -61,7 +61,7 @@ module Jekyll
61
61
  # then, we need to know where to look for _config.yml
62
62
  source = override['source'] || Jekyll::DEFAULTS['source']
63
63
 
64
- # Get configuration from <source>/_config.yaml
64
+ # Get configuration from <source>/_config.yml
65
65
  config = {}
66
66
  config_file = File.join(source, '_config.yml')
67
67
  begin
@@ -56,7 +56,7 @@ class Albino
56
56
 
57
57
  def initialize(target, lexer = :text, format = :html)
58
58
  @target = File.exists?(target) ? File.read(target) : target rescue target
59
- @options = { :l => lexer, :f => format }
59
+ @options = { :l => lexer, :f => format, :O => 'encoding=utf-8' }
60
60
  end
61
61
 
62
62
  def execute(command)
@@ -71,7 +71,9 @@ class Albino
71
71
  end
72
72
 
73
73
  def colorize(options = {})
74
- execute @@bin + convert_options(options)
74
+ html = execute(@@bin + convert_options(options))
75
+ # Work around an RDiscount bug: http://gist.github.com/97682
76
+ html.to_s.sub(%r{</pre></div>\Z}, "</pre>\n</div>")
75
77
  end
76
78
  alias_method :to_s, :colorize
77
79
 
@@ -18,7 +18,11 @@ module Jekyll
18
18
  end
19
19
 
20
20
  def xml_escape(input)
21
- input.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
21
+ CGI.escapeHTML(input)
22
+ end
23
+
24
+ def cgi_escape(input)
25
+ CGI::escape(input)
22
26
  end
23
27
 
24
28
  def number_of_words(input)
@@ -18,9 +18,12 @@ module Jekyll
18
18
  name =~ MATCHER
19
19
  end
20
20
 
21
- attr_accessor :site
22
- attr_accessor :date, :slug, :ext, :categories, :topics, :published
23
- attr_accessor :data, :content, :output
21
+ attr_accessor :site, :date, :slug, :ext, :topics, :published, :data, :content, :output
22
+ attr_writer :categories
23
+
24
+ def categories
25
+ @categories ||= []
26
+ end
24
27
 
25
28
  # Initialize this Post instance.
26
29
  # +site+ is the Site
@@ -88,16 +91,7 @@ module Jekyll
88
91
  #
89
92
  # Returns <String>
90
93
  def dir
91
- if permalink
92
- permalink.to_s.split("/")[0..-2].join("/") + '/'
93
- else
94
- prefix = self.categories.empty? ? '' : '/' + self.categories.join('/')
95
- if [:date, :pretty].include?(self.site.permalink_style)
96
- prefix + date.strftime("/%Y/%m/%d/")
97
- else
98
- prefix + '/'
99
- end
100
- end
94
+ File.dirname(url)
101
95
  end
102
96
 
103
97
  # The full path and filename of the post.
@@ -109,13 +103,35 @@ module Jekyll
109
103
  self.data && self.data['permalink']
110
104
  end
111
105
 
106
+ def template
107
+ case self.site.permalink_style
108
+ when :pretty
109
+ "/:categories/:year/:month/:day/:title"
110
+ when :none
111
+ "/:categories/:title.html"
112
+ when :date
113
+ "/:categories/:year/:month/:day/:title.html"
114
+ else
115
+ self.site.permalink_style.to_s
116
+ end
117
+ end
118
+
112
119
  # The generated relative url of this post
113
120
  # e.g. /2008/11/05/my-awesome-post.html
114
121
  #
115
122
  # Returns <String>
116
123
  def url
117
- ext = self.site.permalink_style == :pretty ? '' : '.html'
118
- permalink || self.id + ext
124
+ return permalink if permalink
125
+
126
+ @url ||= {
127
+ "year" => date.strftime("%Y"),
128
+ "month" => date.strftime("%m"),
129
+ "day" => date.strftime("%d"),
130
+ "title" => CGI.escape(slug),
131
+ "categories" => categories.sort.join('/')
132
+ }.inject(template) { |result, token|
133
+ result.gsub(/:#{token.first}/, token.last)
134
+ }.gsub(/\/\//, "/")
119
135
  end
120
136
 
121
137
  # The UID for this post (useful in feeds)
@@ -123,7 +139,7 @@ module Jekyll
123
139
  #
124
140
  # Returns <String>
125
141
  def id
126
- self.dir + self.slug
142
+ File.join(self.dir, self.slug)
127
143
  end
128
144
 
129
145
  # Calculate related posts.
@@ -172,9 +188,10 @@ module Jekyll
172
188
  def write(dest)
173
189
  FileUtils.mkdir_p(File.join(dest, dir))
174
190
 
175
- path = File.join(dest, self.url)
191
+ # The url needs to be unescaped in order to preserve the correct filename
192
+ path = File.join(dest, CGI.unescape(self.url))
176
193
 
177
- if self.site.permalink_style == :pretty
194
+ if template[/\.html$/].nil?
178
195
  FileUtils.mkdir_p(path)
179
196
  path = File.join(path, "index.html")
180
197
  end
@@ -194,12 +211,33 @@ module Jekyll
194
211
  "id" => self.id,
195
212
  "topics" => self.topics,
196
213
  "categories" => self.categories,
214
+ "next" => self.next,
215
+ "previous" => self.previous,
197
216
  "content" => self.content }.deep_merge(self.data)
198
217
  end
199
218
 
200
219
  def inspect
201
220
  "<Post: #{self.id}>"
202
221
  end
222
+
223
+ def next
224
+ pos = self.site.posts.index(self)
225
+
226
+ if pos && pos < self.site.posts.length-1
227
+ self.site.posts[pos+1]
228
+ else
229
+ nil
230
+ end
231
+ end
232
+
233
+ def previous
234
+ pos = self.site.posts.index(self)
235
+ if pos && pos > 0
236
+ self.site.posts[pos-1]
237
+ else
238
+ nil
239
+ end
240
+ end
203
241
  end
204
242
 
205
243
  end
@@ -1,7 +1,7 @@
1
1
  module Jekyll
2
2
 
3
3
  class Site
4
- attr_accessor :config, :layouts, :posts, :categories
4
+ attr_accessor :config, :layouts, :posts, :categories, :exclude
5
5
  attr_accessor :source, :dest, :lsi, :pygments, :permalink_style
6
6
 
7
7
  # Initialize the site
@@ -16,6 +16,7 @@ module Jekyll
16
16
  self.lsi = config['lsi']
17
17
  self.pygments = config['pygments']
18
18
  self.permalink_style = config['permalink'].to_sym
19
+ self.exclude = config['exclude'] || []
19
20
 
20
21
  self.reset
21
22
  self.setup
@@ -41,7 +42,6 @@ module Jekyll
41
42
  RDiscount.new(content).to_html
42
43
  end
43
44
 
44
- puts 'Using rdiscount for Markdown'
45
45
  rescue LoadError
46
46
  puts 'You must have the rdiscount gem installed first'
47
47
  end
@@ -130,12 +130,13 @@ module Jekyll
130
130
  end
131
131
  end
132
132
 
133
+ self.posts.sort!
134
+
133
135
  # second pass renders each post now that full site payload is available
134
136
  self.posts.each do |post|
135
137
  post.render(self.layouts, site_payload)
136
138
  end
137
139
 
138
- self.posts.sort!
139
140
  self.categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
140
141
  rescue Errno::ENOENT => e
141
142
  # ignore missing layout dir
@@ -228,11 +229,9 @@ module Jekyll
228
229
  def filter_entries(entries)
229
230
  entries = entries.reject do |e|
230
231
  unless ['_posts', '.htaccess'].include?(e)
231
- # Reject backup/hidden
232
- ['.', '_', '#'].include?(e[0..0]) or e[-1..-1] == '~'
232
+ ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
233
233
  end
234
234
  end
235
235
  end
236
-
237
236
  end
238
237
  end
@@ -30,9 +30,9 @@ module Jekyll
30
30
  end
31
31
 
32
32
  def render_pygments(context, code)
33
- if context["content_type"] == :markdown
33
+ if context["content_type"] == "markdown"
34
34
  return "\n" + Albino.new(code, @lang).to_s(@options) + "\n"
35
- elsif context["content_type"] == :textile
35
+ elsif context["content_type"] == "textile"
36
36
  return "<notextile>" + Albino.new(code, @lang).to_s(@options) + "</notextile>"
37
37
  else
38
38
  return Albino.new(code, @lang).to_s(@options)
@@ -1,3 +1,6 @@
1
+ require 'rubygems'
2
+ gem 'RedCloth', '= 4.1.0'
3
+
1
4
  require File.join(File.dirname(__FILE__), *%w[.. lib jekyll])
2
5
 
3
6
  require 'test/unit'
@@ -0,0 +1,6 @@
1
+ ---
2
+ layout: default
3
+ title: Hash #1
4
+ ---
5
+
6
+ Hashes are nice
@@ -37,5 +37,13 @@ class TestFilters < Test::Unit::TestCase
37
37
  assert_equal "AT&amp;T", @filter.xml_escape("AT&T")
38
38
  assert_equal "&lt;code&gt;command &amp;lt;filename&amp;gt;&lt;/code&gt;", @filter.xml_escape("<code>command &lt;filename&gt;</code>")
39
39
  end
40
+
41
+ should "escape space as plus" do
42
+ assert_equal "my+things", @filter.cgi_escape("my things")
43
+ end
44
+
45
+ should "escape special characters" do
46
+ assert_equal "hey%21", @filter.cgi_escape("hey!")
47
+ end
40
48
  end
41
49
  end
@@ -18,7 +18,7 @@ class TestGeneratedSite < Test::Unit::TestCase
18
18
  end
19
19
 
20
20
  should "render post.content" do
21
- latest_post = Dir[source_dir('_posts', '*')].last
21
+ latest_post = Dir[source_dir('_posts', '*')].sort.last
22
22
  post = Post.new(@site, source_dir, '', File.basename(latest_post))
23
23
  post.transform
24
24
  assert @index.include?(post.content)
@@ -25,6 +25,7 @@ class TestPost < Test::Unit::TestCase
25
25
  assert !Post.valid?("blah")
26
26
  end
27
27
 
28
+
28
29
  context "processing posts" do
29
30
  setup do
30
31
  @post = Post.allocate
@@ -41,6 +42,8 @@ class TestPost < Test::Unit::TestCase
41
42
  assert_equal Time.parse("2008-10-19"), @post.date
42
43
  assert_equal "foo-bar", @post.slug
43
44
  assert_equal ".textile", @post.ext
45
+ assert_equal "/2008/10/19", @post.dir
46
+ assert_equal "/2008/10/19/foo-bar", @post.id
44
47
  end
45
48
 
46
49
  should "create url based on date and title" do
@@ -49,16 +52,101 @@ class TestPost < Test::Unit::TestCase
49
52
  assert_equal "/2008/10/19/foo-bar.html", @post.url
50
53
  end
51
54
 
52
- should "respect permalink" do
55
+ should "CGI escape urls" do
56
+ @post.categories = []
57
+ @post.process("2009-03-12-hash-#1.markdown")
58
+ assert_equal "/2009/03/12/hash-%231.html", @post.url
59
+ assert_equal "/2009/03/12/hash-#1", @post.id
60
+ end
61
+
62
+ should "respect permalink in yaml front matter" do
53
63
  file = "2008-12-03-permalinked-post.textile"
54
64
  @post.process(file)
55
65
  @post.read_yaml(@source, file)
56
66
 
57
67
  assert_equal "my_category/permalinked-post", @post.permalink
58
- assert_equal "my_category/", @post.dir
68
+ assert_equal "my_category", @post.dir
59
69
  assert_equal "my_category/permalinked-post", @post.url
60
70
  end
61
71
 
72
+ context "with site wide permalink" do
73
+ setup do
74
+ @post.categories = []
75
+ end
76
+
77
+ context "with unspecified (date) style" do
78
+ setup do
79
+ @post.process(@fake_file)
80
+ end
81
+
82
+ should "process the url correctly" do
83
+ assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
84
+ assert_equal "/2008/10/19/foo-bar.html", @post.url
85
+ end
86
+ end
87
+
88
+ context "with unspecified (date) style and a category" do
89
+ setup do
90
+ @post.categories << "beer"
91
+ @post.process(@fake_file)
92
+ end
93
+
94
+ should "process the url correctly" do
95
+ assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
96
+ assert_equal "/beer/2008/10/19/foo-bar.html", @post.url
97
+ end
98
+ end
99
+
100
+ context "with unspecified (date) style and categories" do
101
+ setup do
102
+ @post.categories << "food"
103
+ @post.categories << "beer"
104
+ @post.process(@fake_file)
105
+ end
106
+
107
+ should "process the url correctly" do
108
+ assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
109
+ assert_equal "/beer/food/2008/10/19/foo-bar.html", @post.url
110
+ end
111
+ end
112
+
113
+ context "with none style" do
114
+ setup do
115
+ @post.site.permalink_style = :none
116
+ @post.process(@fake_file)
117
+ end
118
+
119
+ should "process the url correctly" do
120
+ assert_equal "/:categories/:title.html", @post.template
121
+ assert_equal "/foo-bar.html", @post.url
122
+ end
123
+ end
124
+
125
+ context "with pretty style" do
126
+ setup do
127
+ @post.site.permalink_style = :pretty
128
+ @post.process(@fake_file)
129
+ end
130
+
131
+ should "process the url correctly" do
132
+ assert_equal "/:categories/:year/:month/:day/:title", @post.template
133
+ assert_equal "/2008/10/19/foo-bar", @post.url
134
+ end
135
+ end
136
+
137
+ context "with prefix style and no extension" do
138
+ setup do
139
+ @post.site.permalink_style = "/prefix/:title"
140
+ @post.process(@fake_file)
141
+ end
142
+
143
+ should "process the url correctly" do
144
+ assert_equal "/prefix/:title", @post.template
145
+ assert_equal "/prefix/foo-bar", @post.url
146
+ end
147
+ end
148
+ end
149
+
62
150
  should "read yaml front-matter" do
63
151
  @post.read_yaml(@source, @real_file)
64
152
 
@@ -75,6 +163,32 @@ class TestPost < Test::Unit::TestCase
75
163
  end
76
164
  end
77
165
 
166
+ context "when in a site" do
167
+ setup do
168
+ clear_dest
169
+ stub(Jekyll).configuration { Jekyll::DEFAULTS }
170
+ @site = Site.new(Jekyll.configuration)
171
+ @site.posts = [setup_post('2008-02-02-published.textile'),
172
+ setup_post('2009-01-27-categories.textile')]
173
+ end
174
+
175
+ should "have next post" do
176
+ assert_equal(@site.posts.last, @site.posts.first.next)
177
+ end
178
+
179
+ should "have previous post" do
180
+ assert_equal(@site.posts.first, @site.posts.last.previous)
181
+ end
182
+
183
+ should "not have previous post if first" do
184
+ assert_equal(nil, @site.posts.first.previous)
185
+ end
186
+
187
+ should "not have next post if last" do
188
+ assert_equal(nil, @site.posts.last.next)
189
+ end
190
+ end
191
+
78
192
  context "initializing posts" do
79
193
  should "publish when published yaml is no specified" do
80
194
  post = setup_post("2008-02-02-published.textile")
@@ -118,6 +232,16 @@ class TestPost < Test::Unit::TestCase
118
232
  assert File.exists?(File.join(dest_dir, '2008', '10', '18', 'foo-bar.html'))
119
233
  end
120
234
 
235
+ should "write properly without html extension" do
236
+ post = setup_post("2008-10-18-foo-bar.textile")
237
+ post.site.permalink_style = ":title"
238
+ do_render(post)
239
+ post.write(dest_dir)
240
+
241
+ assert File.directory?(dest_dir)
242
+ assert File.exists?(File.join(dest_dir, 'foo-bar', 'index.html'))
243
+ end
244
+
121
245
  should "insert data" do
122
246
  post = setup_post("2008-11-21-complex.textile")
123
247
  do_render(post)
@@ -53,5 +53,13 @@ class TestSite < Test::Unit::TestCase
53
53
  assert_equal %w[foo.markdown bar.markdown baz.markdown], @site.filter_entries(ent1)
54
54
  assert_equal ent2, @site.filter_entries(ent2)
55
55
  end
56
+
57
+ should "filter entries with exclude" do
58
+ excludes = %w[README TODO]
59
+ includes = %w[index.html site.css]
60
+
61
+ @site.exclude = excludes
62
+ assert_equal includes, @site.filter_entries(excludes + includes)
63
+ end
56
64
  end
57
65
  end
@@ -1,35 +1,116 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
3
  class TestTags < Test::Unit::TestCase
4
- context "tagging" do
5
- setup do
6
- @content = <<CONTENT
4
+
5
+ def create_post(content, override = {}, markdown = true)
6
+ stub(Jekyll).configuration do
7
+ Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override)
8
+ end
9
+ site = Site.new(Jekyll.configuration)
10
+ info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
11
+
12
+ if markdown
13
+ payload = {"content_type" => "markdown"}
14
+ else
15
+ payload = {"content_type" => "textile"}
16
+ end
17
+
18
+ @result = Liquid::Template.parse(content).render(payload, info)
19
+
20
+ if markdown
21
+ @result = site.markdown(@result)
22
+ else
23
+ @result = site.textile(@result)
24
+ end
25
+ end
26
+
27
+ def fill_post(code, override = {})
28
+ content = <<CONTENT
7
29
  ---
8
- layout: post
9
30
  title: This is a test
10
-
11
31
  ---
32
+
12
33
  This document results in a markdown error with maruku
13
34
 
14
- {% highlight ruby %}
15
- puts "hi"
35
+ {% highlight text %}
36
+ #{code}
37
+ {% endhighlight %}
38
+ CONTENT
39
+ create_post(content, override)
40
+ end
41
+
42
+ context "post content has highlight tag" do
43
+ setup do
44
+ fill_post("test")
45
+ end
46
+
47
+ should "not cause a markdown error" do
48
+ assert_no_match /markdown\-html\-error/, @result
49
+ end
50
+
51
+ should "render markdown with pygments line handling" do
52
+ assert_match %{<pre>test\n</pre>}, @result
53
+ end
54
+ end
16
55
 
17
- puts "bye"
56
+ context "post content has highlight tag with UTF character" do
57
+ setup do
58
+ fill_post("Æ")
59
+ end
60
+
61
+ should "render markdown with pygments line handling" do
62
+ assert_match %{<pre>Æ\n</pre>}, @result
63
+ end
64
+ end
65
+
66
+ context "simple post with markdown and pre tags" do
67
+ setup do
68
+ @content = <<CONTENT
69
+ ---
70
+ title: Maruku vs. RDiscount
71
+ ---
72
+
73
+ _FIGHT!_
74
+
75
+ {% highlight ruby %}
76
+ puts "3..2..1.."
18
77
  {% endhighlight %}
19
78
 
79
+ *FINISH HIM*
20
80
  CONTENT
21
81
  end
22
82
 
23
- should "render markdown with pygments line handling" do
24
- stub(Jekyll).configuration do
25
- Jekyll::DEFAULTS.merge({'pygments' => true})
83
+ context "using Textile" do
84
+ setup do
85
+ create_post(@content, {}, false)
86
+ end
87
+
88
+ # Broken in RedCloth 4.1.9
89
+ should "not textilize highlight block" do
90
+ assert_no_match %r{3\.\.2\.\.1\.\.&quot;</span><br />}, @result
91
+ end
92
+ end
93
+
94
+ context "using Maruku" do
95
+ setup do
96
+ create_post(@content)
26
97
  end
27
- site = Site.new(Jekyll.configuration)
28
- info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
29
98
 
30
- result = Liquid::Template.parse(@content).render({}, info)
31
- result = site.markdown(result)
32
- assert_no_match(/markdown\-html\-error/,result)
99
+ should "parse correctly" do
100
+ assert_match %r{<em>FIGHT!</em>}, @result
101
+ assert_match %r{<em>FINISH HIM</em>}, @result
102
+ end
103
+ end
104
+
105
+ context "using RDiscount" do
106
+ setup do
107
+ create_post(@content, 'markdown' => 'rdiscount')
108
+ end
109
+
110
+ should "parse correctly" do
111
+ assert_match %r{<em>FIGHT!</em>}, @result
112
+ assert_match %r{<em>FINISH HIM</em>}, @result
113
+ end
33
114
  end
34
115
  end
35
116
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mojombo-jekyll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Preston-Werner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-07 00:00:00 -07:00
12
+ date: 2009-05-06 00:00:00 -07:00
13
13
  default_executable: jekyll
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -18,9 +18,9 @@ dependencies:
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - ">="
21
+ - - "="
22
22
  - !ruby/object:Gem::Version
23
- version: 4.0.4
23
+ version: 4.1.0
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: liquid
@@ -116,6 +116,7 @@ files:
116
116
  - test/source/_posts/2009-01-27-array-categories.textile
117
117
  - test/source/_posts/2009-01-27-categories.textile
118
118
  - test/source/_posts/2009-01-27-category.textile
119
+ - test/source/_posts/2009-03-12-hash-#1.markdown
119
120
  - test/source/category/_posts/2008-9-23-categories.textile
120
121
  - test/source/css/screen.css
121
122
  - test/source/foo/_posts/bar/2008-12-12-topical-post.textile