Compare commits

...

377 Commits
v0.4.0 ... book

Author SHA1 Message Date
Tom Preston-Werner
cf71631c34 More writing. 2011-03-14 00:44:43 -07:00
Tom Preston-Werner
6c0e4b37b9 Start work on the book. 2011-03-13 21:45:29 -07:00
Tom Preston-Werner
0f71bdb540 Ignore .bundle dir. 2011-03-13 16:57:35 -07:00
Tom Preston-Werner
dce4ccc5a4 Better error message for invalid post date. 2011-03-11 17:52:25 -08:00
Tom Preston-Werner
6c94db1486 TomDoc convertible.rb. 2011-03-11 16:00:32 -08:00
Tom Preston-Werner
68eaadd13a Merge remote-tracking branch 'MattHall/cli' into test 2011-03-10 23:01:18 -08:00
Tom Preston-Werner
01a90904e2 Merge remote-tracking branch 'phatblat/master' into test 2011-03-10 22:51:58 -08:00
Tom Preston-Werner
d2814cf750 Merge remote-tracking branch 'elia/master' into devel 2011-03-10 22:38:17 -08:00
Tom Preston-Werner
f58a821e20 Merge remote-tracking branch 'MattHall/posterous' into devel 2011-03-10 21:20:38 -08:00
Tom Preston-Werner
38844cd3bc Merge remote-tracking branch 'ab9/master' into devel 2011-03-10 21:17:51 -08:00
Tom Preston-Werner
a31780a1ec Move require to jekyll.rb and update history. 2011-03-10 21:15:29 -08:00
Tom Preston-Werner
5f4dfe388f Merge remote-tracking branch 'zenspider/master' into devel 2011-03-10 21:10:18 -08:00
Tom Preston-Werner
f82c51df7a Update history. 2011-03-10 21:10:12 -08:00
Aman Gupta
13cc44fb12 sanitize urls and ignore symlinks 2011-03-10 20:14:38 -08:00
Aman Gupta
be8b7715d3 speed up cleanup 2011-03-10 20:11:45 -08:00
Aman Gupta
edef0251d3 make kramdown a runtime dep so people can use it instead of maruku 2011-03-07 22:08:08 -08:00
Aman Gupta
9da714dbe1 rdiscount is a dev dependency 2011-03-07 19:13:57 -08:00
Aman Gupta
8cc7f06b36 work around cucumber issue (closes #296) 2011-03-07 18:50:02 -08:00
Aman Gupta
4b5a4e8713 open4 is not required 2011-03-06 16:32:10 -08:00
Aman Gupta
08725eb234 use the new albino gem 2011-03-06 01:57:08 -08:00
Aman Gupta
16ea3262da fix "4.2.1" versioned dev dependencies, and cleanup syntax 2011-03-06 01:47:18 -08:00
Aman Gupta
a04c270f1b Gemfile to help install the dependencies 2011-03-06 01:46:00 -08:00
Ryan Davis
bd01e647a7 Cleaned up unnecessary string munging 2011-03-02 00:24:17 -08:00
Elia Schito
034b06431e Remove double directory creation. 2011-01-27 13:13:12 +01:00
Elia Schito
c70dac3cee Take permalink name directly from worpress export file. 2011-01-27 13:12:08 +01:00
Elia Schito
ca48ea91e6 Merged wordpress.com migrator fix from 'heuripedes/jekyll' 2011-01-27 12:14:22 +01:00
Elia Schito
f68bbcbe8d The Wordpress.com migrator now works and gathers categories as tags. 2011-01-27 02:12:42 -08:00
Ben Chatelain
d61c1e930a Fix compile error by making QUERY lowercase (local instead of const) 2011-01-23 15:30:41 -07:00
Ben Chatelain
bc3771aa22 Change TABLE_PREFIX from class member to 4th parameter of process method (now lowercase)
Move QUERY into process method
2011-01-23 15:25:33 -07:00
Ben Chatelain
e902bb9c30 Change TABLE_PREFIX back to default 2011-01-23 15:21:29 -07:00
Ben Chatelain
42f63f919f Add Jekyll::WordPress.TABLE_PREFIX and inclusion in QUERY 2011-01-23 15:19:26 -07:00
Aaron Beckerman
033333f9bc fix typo in history: site.ports -> site.posts 2011-01-23 02:29:27 +11:00
Jeff Hodges
b3634b522a adding date to wordpress migrator 2011-01-12 19:37:38 -08:00
Matt Hall
84c1a72443 Updating CLI for importing 2010-12-19 17:38:14 +00:00
Matt Hall
c1f0e070c9 Adding Posterous Importer 2010-12-19 16:27:22 +00:00
Tom Preston-Werner
13df722073 Release 0.10.0 2010-12-16 16:29:48 -08:00
Tom Preston-Werner
86397cbf00 Add --no-server option. 2010-12-16 16:27:41 -08:00
Tom Preston-Werner
a8a837cc8e Release 0.9.0 2010-12-15 15:36:15 -08:00
Higor Eurípedes
9e0eb75170 updated/fixed wordpress.com migration script 2010-12-15 15:44:01 -03:00
Tom Preston-Werner
36b1f8f9b1 Add Marley migrator. Closes #28. 2010-12-14 15:12:12 -08:00
Tom Preston-Werner
c1ed790534 Merge remote branch 'sos4nt/remove-orphaned-files' 2010-12-13 21:18:21 -08:00
Tom Preston-Werner
9bd48752e6 Merge remote branch 'MattHall/master' 2010-12-13 21:12:21 -08:00
Tom Preston-Werner
5db040802f Merge remote branch 'mattdipasquale/master' 2010-12-13 21:09:33 -08:00
Tom Preston-Werner
65622cb1e0 Use OptionParser's [no-] functionality for better boolean parsing. 2010-12-13 21:07:35 -08:00
MattHall
226c7cc121 Rescue exception when parsing invalid yaml. Prevents silent fail in auto and server mode 2010-12-11 14:30:44 +00:00
MattHall
0a58d78338 Catch Liquid template exceptions, and write out their details. Prevents silent fail of template parsing 2010-12-11 14:23:12 +00:00
Stefan Schüßler
5b680f8dd8 remove orphaned files in destination 2010-12-01 18:04:50 +01:00
Matt Di Pasquale
e8fd7ebbc3 Add Drupal migrator 2010-11-30 17:11:23 -05:00
Tom Preston-Werner
31901ee15b Release 0.8.0 2010-11-22 23:08:56 -08:00
Tom Preston-Werner
3ab016870d Prevent _includes dir from being a symlink. 2010-11-22 21:45:35 -08:00
Tom Preston-Werner
61acd47ed2 Merge remote branch 'jasongraham/kramdown-support' 2010-11-22 19:26:58 -08:00
Jason Graham
dca30c3ad1 Add kramdown's support for coderay
- no test added so that coderay isn't added to list of developer
    dependencies
2010-11-20 17:46:16 -08:00
Jason Graham
f85e229a9e Add support for kramdown HTML converter options
http://kramdown.rubyforge.org/converter/html.html#options

  Example: In the _config.yaml,

  markdown: kramdown

  kramdown:
    auto_ids: true
2010-11-20 17:40:27 -08:00
Jason Graham
ac7a0cc95f Add Kramdown support and tests 2010-11-20 17:40:27 -08:00
Tom Preston-Werner
53b999418c Merge remote branch 'stmpjmpr/master' 2010-11-20 11:37:22 -06:00
Scott Hill
00146909f9 Merge remote branch 'remotes/mojombo/master' 2010-11-19 02:38:50 -08:00
Scott Hill
a556e4f29e Swapping a '-' for the word separator for imported entries since that's the MT style, and I don't want to break existing permalinks. 2010-11-19 02:36:56 -08:00
Tom Preston-Werner
e2d26ff8ed Merge remote branch 'tomash/master' 2010-11-18 16:06:01 -06:00
Tomasz Stachewicz
9396c9d04c migrators now open Sequel connection to mysql with utf8 encoding. Closes GH-220 2010-11-18 18:14:08 +01:00
Tom Preston-Werner
38ed81e0ce Update history for --base-url option. 2010-11-18 00:11:04 -06:00
Arnar Birgisson
4a8fc1fa6e Adding baseurl option. Fixes #51 2010-11-17 22:50:40 +01:00
Tom Preston-Werner
d53ea4a0dd Update history for uri_escape filter. 2010-11-17 15:32:03 -06:00
Tom Preston-Werner
f7ab019a39 Merge remote branch 'claco/uri-escape' 2010-11-17 15:30:34 -06:00
Tom Preston-Werner
4afee1bda1 Merge remote branch 'jlecour/master'
Conflicts:
	lib/jekyll/page.rb
2010-11-17 15:25:55 -06:00
Tom Preston-Werner
8cc537026d Update history for --limit-posts option. 2010-11-17 14:59:20 -06:00
Tom Preston-Werner
054b796b9f Merge remote branch 'cblunt/limit_posts' 2010-11-17 14:56:32 -06:00
Tom Preston-Werner
c1a7662311 Merge remote branch 'lpenz/master'
Conflicts:
	History.txt
2010-11-17 12:35:29 -06:00
Tom Preston-Werner
accdb2d39f Update history for wordpress.com importer. 2010-11-17 12:16:15 -06:00
Christopher H. Laco
4c08643c50 Added uri_escape for cases where cgi_escape isn't appropriate 2010-11-12 11:15:30 -05:00
cblunt
d97bcadd03 Merge branch 'limit_posts' of github.com:cblunt/jekyll into limit_posts
Conflicts:
	bin/jekyll
2010-09-13 00:33:32 +01:00
cblunt
f688c9df81 Added limit-posts option to site configuration.
* Added unit tests for limit-posts.
  * Added feature for limit-posts.
  * Added --limit_posts option to bin/jekyll options parser
2010-09-13 00:31:52 +01:00
cblunt
8ecb70d3e3 Added limit-posts option to site configuration.
* Added unit tests for limit-posts.
  * Added feature for limit-posts.
  * Added --limit-posts option to bin/jekyll options parser
2010-09-13 00:15:42 +01:00
Jeremy Lecour
e9cf7b4636 Treat dotfiles as files without extension
If the file starts with a dot, the whole filename is considered the basename
and there is not extension.
2010-09-09 09:40:47 +02:00
Jeremy Lecour
16c19ecd19 Add a failing test for rendering dotfiles
The test uses a simple ".htaccess" file that needs to be rendered
as any other page, like the sitemap.xml, …
2010-09-09 09:37:51 +02:00
Leandro Lisboa Penz
b1049c84cd Correctly generates file basename. Fixes #208.
The previous procedure generated invalid basenames when the filename had
more than one dot.
2010-09-05 18:11:09 -03:00
Matt Hall
b6678d4e43 Added Wordpress.com migrator 2010-09-02 13:36:31 +01:00
Tom Preston-Werner
3fa9af17fa Release 0.7.0 2010-08-24 15:35:18 -07:00
Tom Preston-Werner
9b423a96fd Update history for ctrochalakis/rdiscount_extensions. 2010-08-24 15:21:47 -07:00
Tom Preston-Werner
391d1a9677 Merge remote branch 'ctrochalakis/rdiscount_extensions' 2010-08-24 15:19:47 -07:00
Postmodern
f4fb833d34 The site configuration may not always provide a 'time' setting. Closes #184.
* This fixes a bug on Ruby 1.9.1 and 1.9.2 where Time.parse was being
  passed an emptry String, if the 'time' setting was not defined.
2010-08-24 15:19:22 -07:00
Tom Preston-Werner
d9bc00c804 Highlight should not be able to render local files. 2010-08-24 15:05:28 -07:00
Scott Hill
b3cec39843 Now adding a "date" to the YAML front-matter of a post, based on the original date the post was authored according to MT. 2010-08-06 10:33:59 -07:00
Scott Hill
f6acbb869e Changed the date used by Jekyll to be the date the post was authored on instead of the date it was created. If the latter is used on an imported post, it gets the import date instead of the date the post was originally written. 2010-08-06 01:26:32 -07:00
Scott Hill
adf9ca5a05 Added code to change the extension of a post based on the format used to write the post in MT. 2010-08-05 15:36:14 -07:00
Tom Preston-Werner
5e997cae21 Release 0.6.2 2010-06-25 15:56:57 -07:00
Tom Preston-Werner
f35d287c66 Fix page.url to include full relative path. Fixes #181. 2010-06-25 15:12:39 -07:00
Tom Preston-Werner
1c3fedbb31 Expand source, destination, and plugin paths. Fixes #180. 2010-06-25 14:40:27 -07:00
Christos Trochalakis
a56eeb8289 Add support for rdiscount extensions
Specify extensions at your _config.yml file:

    ...
    rdiscount:
        extensions: [smart, autolink]

Available extensions can be found here:
http://rdoc.info/projects/rtomayko/rdiscount

closes #173
2010-06-25 16:38:45 +03:00
Tom Preston-Werner
908526455c Ensure that RedCloth is loaded when textilize filter is used. Fixes #183. 2010-06-24 18:14:59 -07:00
Tom Preston-Werner
ce5a2a04e3 Fix Rakefile release task (tag pushing was missing origin) 2010-06-23 15:58:09 -07:00
Tom Preston-Werner
44015665b9 Release 0.6.1 2010-06-23 15:52:56 -07:00
Tom Preston-Werner
6a605753c1 Need double quotes for newline character. Fixes #178. 2010-06-23 15:50:22 -07:00
Tom Preston-Werner
99ee0c4803 Release 0.6.0 2010-06-22 17:56:16 -07:00
Tom Preston-Werner
de3ee99d30 Use Dir.pwd for other default paths as well (reverts fix in #101) 2010-06-22 16:22:58 -07:00
Tom Preston-Werner
36411dd10f update history for #75 2010-06-22 16:15:31 -07:00
Tom Preston-Werner
f8484570b7 Merge remote branch 'christianhellsten/master' into next 2010-06-22 16:01:48 -07:00
Tom Preston-Werner
9bb2066cf1 update history for #147 2010-06-22 16:01:28 -07:00
Tom Preston-Werner
0ce13c943d Merge remote branch 'darwin/site_url_from_cmdline' 2010-06-22 15:33:06 -07:00
Tom Preston-Werner
de8bd48154 Maruku is now the only processor dependency installed by default. Closes #57.
Other processors will be lazy-loaded when necessary (and prompt the
user to install them when necessary).
2010-06-22 15:17:39 -07:00
Christian Hellsten
68c69fb3ef removed duplicate .js mime-type 2010-06-22 15:53:26 +03:00
Christian Hellsten
46a95bc036 git merge mojombo/master 2010-06-22 15:42:51 +03:00
Antonin Hildebrand
23d26c5525 allow setting --url <custom_site_url> from commandline (issue #15, closes #143)
Sometimes you may be forced to use absolute urls. For example I had problem with FeedBurner's blog post preview page. Image links specified as relative urls were not resolved correctly. I can imagine some poor RSS readers may behave similar way.

I wanted site.url to be configurable, because I didn't want to hard-code final url there. I still want to be able to have working link when doing local web site development and testing. I have small bash script which runs jekyll -serve --auto with this parameter set for local development. My setup is more complicated, because I use several jekylls behind reverse proxy to simulate setup on http://binaryage.com which uses gh-pages from many repos together with layouts linked as git modules.
2010-06-22 09:11:42 +02:00
Tom Preston-Werner
6932a40d17 update history for #31 2010-06-21 19:32:50 -07:00
Tom Preston-Werner
aa9993a6c1 Merge remote branch 'koraktor/pygments-options' into next 2010-06-21 19:31:22 -07:00
Tom Preston-Werner
8a417e86c0 update history for #142 2010-06-21 17:57:48 -07:00
Antonin Hildebrand
f91954be76 optimization: write static file to the destination only if source file timestamp differs
Also make sure static files get regenerated when they are missing in destination.

This is useful in --server --auto mode when it reduces disk/cpu load and also plays nice with xrefresh-server (which was my main motivation) -> soft CSS refresh works again!
2010-06-20 08:02:16 +02:00
Tom Preston-Werner
ace9911001 Merge remote branch 'sharms/master' 2010-06-19 11:03:42 -07:00
Tom Preston-Werner
cb77a5287b load plugins under safe mode 2010-06-18 17:55:17 -07:00
Tom Preston-Werner
31c65c56f4 Extension -> Plugin 2010-06-18 15:47:01 -07:00
Tom Preston-Werner
5335debfb2 Merge remote branch 'technoweenie/no-leading-zeroes'
Conflicts:
	lib/jekyll/post.rb
2010-06-18 15:34:56 -07:00
Steven Harms
1fba2ef516 Added yaml to requires 2010-06-09 10:13:43 -04:00
Tom Preston-Werner
f6ef6f21ae whitespace 2010-06-03 16:09:33 -07:00
rick
e8d119ef0a add :i_day and :i_month permalink values so you can get urls like /2010/6/1/title 2010-05-31 23:28:39 -07:00
Gaute Hope
2c542a652d converters/wordpress.rb missing require 'yaml' for to_yaml function. fixes #151. 2010-04-21 14:47:46 -07:00
Jan Berkel
fa90573176 Ruby 1.9 compat fix in features. Fixes #141. 2010-04-21 14:41:01 -07:00
Tom Preston-Werner
a8efc3a0a2 tomdoc and normalize new extension and converter classes 2010-04-21 14:40:29 -07:00
Tom Preston-Werner
0ba1f6c83e better formatting for History 2010-04-21 14:01:47 -07:00
Tom Preston-Werner
03cb12aeb3 convert to use rakegem 2010-04-21 13:55:01 -07:00
Tom Preston-Werner
3efe008544 better docs for jekyll.rb 2010-04-21 13:32:46 -07:00
Tom Preston-Werner
08bc63289d clean up globbed requires 2010-04-21 13:27:39 -07:00
Jon
81971c3342 teach Albino to run on both Windows and *nix 2010-04-21 13:19:38 -07:00
Christian Hellsten
8405d30764 Fixes bug that removes all highlight tags 2010-04-18 01:51:53 +03:00
Kris Brown
18545ddf71 pagination is now a generator extension 2010-02-28 11:17:03 +00:00
Kris Brown
fc86c9dd85 extended concept to extensions in general, providing both converters and generators 2010-02-28 10:10:10 +00:00
Kris Brown
84b26a31da removed use of content_type strings in the highlighting tag 2010-02-28 00:11:43 +00:00
Kris Brown
315f4c9222 allow converters to be registered through subclassing much like railties in rails 2010-02-27 23:31:54 +00:00
Kris Brown
cedda3afa3 move converters to classes 2010-02-27 22:14:27 +00:00
Kris Brown
ff3ca307b9 converters moved to migrators as they should be called this 2010-02-27 20:08:51 +00:00
Kris Brown
1261840769 generate phase added to site#process and pagination is now a generator 2010-02-27 15:31:59 +00:00
Kris Brown
bae52e0aba updated history 2010-02-27 14:31:37 +00:00
Kris Brown
ad4a80a653 Merge branch 'enh_pages_in_payload' 2010-02-27 14:11:28 +00:00
Kris Brown
80b13a81fa added usage of site.html_pages to test source sitemap.xml 2010-02-27 14:11:06 +00:00
Kris Brown
ef2fabb189 also provide html_pages. this is better for sitemaps should you wish to auto-populate page entries 2010-02-27 14:09:07 +00:00
Kris Brown
e8971b2999 Merge branch 'issue_64_broken' into enh_pages_in_payload 2010-02-27 09:38:05 +00:00
Kris Brown
bfdf7fb13a Merge branch 'enh_pages_in_payload' 2010-02-27 09:30:24 +00:00
Kris Brown
f73dac1582 fixes problem in issue 64 fix where pages like about.md would be output as about.md/index.html. provides the output extension as a method rather than replacing the ext attribute as part of transform 2010-02-27 09:27:36 +00:00
Kris Brown
5a807aa12e pages now present in the site payload and can be used through the site.pages variable 2010-02-27 08:09:13 +00:00
Kris Brown
cd946a587b removed tabs and made into a better example for sitemap times 2010-02-26 22:07:26 +00:00
Kris Brown
4fd2b54a7d updated history 2010-02-26 21:40:37 +00:00
Kris Brown
4dde9d9668 Merge branch 'issue_119' of github.com:krisb/jekyll into issue_119 2010-02-26 21:36:26 +00:00
Kris Brown
355b20265e removed whitespace from lazyeye's commit 2010-02-26 21:33:56 +00:00
lazyeye
cfd6ebc747 pass time object to liquid when time is specified in front matter 2010-02-26 21:31:01 +00:00
Kris Brown
e4a2319bf3 added tests to show how date and tags can end up having the wrong value when rendered 2010-02-26 21:24:32 +00:00
Kris Brown
657b2e4be3 updated history for change 2010-02-26 21:00:04 +00:00
Kris Brown
98fa570c86 added support for consistent site.time in payload, generating the site at a specific time and limiting future posts
squish
2010-02-26 20:52:41 +00:00
Sebastian Staudt
ef6aa6b5c4 Added passing of all options to Pygments, not just "linenos" 2010-02-03 14:38:22 +01:00
Kris Brown
58354e269e added tests to show how date and tags can end up having the wrong value when rendered 2010-01-16 14:48:21 +00:00
Tom Preston-Werner
a4f3f5c583 Merge commit '0a1e3cd2508c797d7b8d1038636a6e7111e5cd3d'. Fixes #33.
Conflicts:
	features/post_data.feature
2010-01-14 20:00:19 -08:00
Tom Preston-Werner
5fec20dfa8 update history for #64 fix 2010-01-13 22:46:58 -08:00
Tom Preston-Werner
a2e0d76d4e Merge commit 'a49326719132242c05e744f59d3c8b4afc1435e2' 2010-01-13 22:41:06 -08:00
Tom Preston-Werner
ba77a024d6 fix highlighting on ruby 1.9. fixes #65 2010-01-13 22:33:38 -08:00
Tom Preston-Werner
0756d1f765 add cuke feature for nested includes 2010-01-13 22:17:46 -08:00
Tom Preston-Werner
d88354e2df cuke feature for subdir include 2010-01-13 22:02:24 -08:00
Tom Preston-Werner
dd5fb69c2f Merge commit 'b1a055f10dc921fd8ec03db703d2fb0608179f4d' 2010-01-13 21:49:22 -08:00
Tom Preston-Werner
2b2e027b34 Render highlighted code for non markdown/textile pages. Fixes #116 2010-01-13 21:30:45 -08:00
Tom Preston-Werner
fff313a62d Regenerated gemspec for version 0.5.7 2010-01-12 15:09:16 -08:00
Tom Preston-Werner
6dcfe1283a Version bump to 0.5.7 2010-01-12 15:00:56 -08:00
Tom Preston-Werner
b68149c7bc fix pagination to adhere to read/render/write paradigm 2010-01-12 14:43:28 -08:00
Tom Preston-Werner
a076ce0702 add markdown feature test 2010-01-11 23:42:16 -08:00
Kris Brown
58b4ffd935 updated history 2010-01-10 22:00:18 +00:00
Kris Brown
a0aa3fa6dc Merge branch 'enh_post_date_in_front_matter_issue_62' 2010-01-10 21:58:34 +00:00
Kris Brown
a1550b3378 allow date to be specified in the front matter and override the value from the file name, fixes #62 and #38 2010-01-10 21:55:54 +00:00
Kris Brown
2aac9f3716 updated history 2010-01-10 21:54:42 +00:00
Kris Brown
db03bcac8f Merge branch 'fix_tags_and_categories_issues_73_and_84' into updates_20100110 2010-01-10 21:54:01 +00:00
Kris Brown
21c92d3eb2 updated history 2010-01-10 21:51:48 +00:00
Kris Brown
ce228ac1c4 removed accessor method and fixed tests 2010-01-10 16:24:56 +00:00
Kris Brown
93c029d62e fixed #73 and #84 2010-01-10 16:14:25 +00:00
Kris Brown
2292e4268c added tests for handling of tags and catergories, see #73 and #84 2010-01-10 16:12:41 +00:00
Kris Brown
e0e4a47af1 added pluralized_array method to Hash and tests 2010-01-10 16:09:24 +00:00
Kris Brown
45bf0e8a33 removed usages of site.ports.first in some features where a better alternative is available 2010-01-10 10:30:18 +00:00
Kris Brown
6b74454a07 resetting to upstream 2010-01-10 10:11:44 +00:00
Kris Brown
2a7b1cbd98 merged 'mojombo/master' at 'v0.5.6' 2010-01-09 09:03:59 +00:00
Tom Preston-Werner
c92eb564d2 Regenerated gemspec for version 0.5.6 2010-01-08 19:23:35 -08:00
Tom Preston-Werner
98f3767af3 Version bump to 0.5.6 2010-01-08 19:23:10 -08:00
Tom Preston-Werner
602a252364 add javascript mime type for webrick. fixes #98 2010-01-08 18:59:35 -08:00
Tom Preston-Werner
add546f61e update history 2010-01-08 18:27:05 -08:00
Tom Preston-Werner
8d4b96084a Merge commit 'e3bd1c88e9ad6c9d6c89a543ca72c82a289b6bd7' 2010-01-08 18:19:36 -08:00
Tom Preston-Werner
60fed241cd better deps in readme. fixes #87. fixes #88 2010-01-08 18:14:31 -08:00
Tom Preston-Werner
d020d4f2bf update history 2010-01-08 18:09:36 -08:00
Tom Preston-Werner
473f3ffc11 Merge commit '597c7a7904198d92aa5eacad356019165685c311' 2010-01-08 18:08:17 -08:00
Tom Preston-Werner
4c1021d597 don't prematurely terminate front matter on mid-line triple dashes. fixes #93 2010-01-08 18:04:36 -08:00
Tom Preston-Werner
c89d8dd0f3 allow .mkd as a markdown extension 2010-01-08 17:26:48 -08:00
Tom Preston-Werner
52b82af6e2 update history 2010-01-08 17:21:26 -08:00
Tom Preston-Werner
1adf9a7c64 Merge commit 'krisb/fix_for_test_redcloth_version' 2010-01-08 17:19:41 -08:00
Tom Preston-Werner
59ee8a6869 Regenerated gemspec for version 0.5.5 2010-01-08 16:12:44 -08:00
Tom Preston-Werner
c569f5e641 Version bump to 0.5.5 2010-01-08 16:12:09 -08:00
Tom Preston-Werner
5a37e0d96e update history 2010-01-08 16:11:47 -08:00
Kris Brown
7806a0d6bb separated up the attrs required by convertible and made tags and categories always non-nil as empty front matter entries could cause them to be nil 2010-01-06 15:19:39 +00:00
Kris Brown
5c17d6266d removed usages of site.posts.first in some features where a better alternative is available 2010-01-06 13:01:19 +00:00
Kris Brown
d25f419159 updated History.txt with recent changes 2010-01-06 13:01:12 +00:00
Kris Brown
b8c04dfb6d Merge branch 'jamie/master' 2010-01-05 22:59:43 +00:00
Kris Brown
d80c643681 Merge branch 'fix_for_render_order_issue71' 2010-01-05 22:21:58 +00:00
Kris Brown
0d69e9346b Merge branch 'fix_for_test_redcloth_version' 2010-01-05 22:21:22 +00:00
Kris Brown
45e13cf46f updated gemspec for my clone 2010-01-05 22:10:55 +00:00
Kris Brown
0cb1ebcda1 split process handling into phases to allow pages to have access to full and complete site payload and added some test improvements 2010-01-05 17:05:44 +00:00
Kris Brown
b5916caf4b added scenario to test correct site generation for a site with layouts, pages, posts and files 2010-01-05 17:05:36 +00:00
Kris Brown
5ea06f3ad9 fixes issue #78, including comprehensive scenarios and tests 2010-01-04 09:39:54 +00:00
Kris Brown
39a487cdf0 redcloth set to >= 4.2.1 2010-01-02 13:17:58 +00:00
Alex Young
b1a055f10d Call File.expand_path on source so liquid can see _includes in subdirectories 2009-11-30 17:27:57 +00:00
Jamie Macey
fab5a715c5 safely allow loading jekyll customizations from inside a site 2009-11-29 13:25:00 -05:00
Gregor Schmidt
597c7a7904 changes to stdout and -err - tests and behaviour
By using $stdin adn $stderr instead of STDIN and 
STDERR it is possible to capture or redirect them 
using in process ruby code without the need
to manage pipes and external processes
2009-11-24 21:42:22 +01:00
Christian Hellsten
b299a7bad3 Fixed WEBrick JavaScript mimetype. Fixes Firebug script pane 2009-11-08 17:38:34 +02:00
Christian Hellsten
52342fe6e1 Fixed bug where including includes from an include threw an exception. 2009-10-28 02:12:47 +02:00
Patrick Crowley
e3bd1c88e9 refactored render_pygments to remove duplicate code 2009-10-23 08:03:25 -07:00
Patrick Crowley
4cc0873172 updated pygments output to wrap code blocks with <code> tags 2009-10-22 21:14:05 -07:00
Tom Preston-Werner
2f2e45bedf Regenerated gemspec for version 0.5.4 2009-08-24 00:11:45 -07:00
Tom Preston-Werner
dc5520484b Version bump to 0.5.4 2009-08-24 00:10:33 -07:00
Tom Preston-Werner
86ac1eee9c update history for 0.5.4 release 2009-08-24 00:10:33 -07:00
Tom Preston-Werner
0dfb486c37 disallow symlinks 2009-08-24 00:10:09 -07:00
Nick Quaranto
e8e8f6449a Releasing 0.5.3 with a small bugfix for permalinks 2009-07-14 19:31:37 -04:00
Jeffry Degrande
176c047ff1 bugfix for permalinks
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-07-14 19:17:44 -04:00
Jeffry Degrande
a493267191 bugfix for permalinks 2009-06-29 08:40:31 -03:00
Nick Quaranto
f1c8e388e4 Updating history and bumping version to 0.5.2 2009-06-24 17:51:09 -04:00
Nick Quaranto
8b678a8f01 Merge commit 'bahuvrihi/master' 2009-06-24 17:33:57 -04:00
Nick Quaranto
ec637a13e9 Adding a scenario for config values available in the site payload. Closes #15 2009-06-24 08:33:32 -04:00
Martin Vilcans
05e8deae8d Make configuration accessible from page.
For example, if you have the following in _config.yml:

  url: http://www.librador.com

...you can have the following in an HTML page:

  <a href="{{site.url}}">Home!</a>

This is a reapply of change 7b449239f0908e34f0290c213970e4b14ba2c2df on latest HEAD.

Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-06-24 08:26:25 -04:00
Nick Quaranto
3bc4f590ea Updating readme with links to the mailing list 2009-06-24 07:56:17 -04:00
Nick Quaranto
237df13778 Upgrading RedCloth to 4.2.1, which fixed <notextile> tags 2009-06-24 07:53:13 -04:00
Nick Quaranto
74b17ff777 Attempting to fix the broken readme formatting 2009-06-24 07:44:00 -04:00
Simon Chiang
ca98cd0152 updated convertible to allow for posts with no, or empty YAML 2009-06-23 20:55:13 -06:00
Simon Chiang
b616a4ceca fixed test for CRLF (extra newline was being picked up) 2009-06-23 20:54:26 -06:00
Nick Quaranto
09946386b1 Adding Date#xmlschema from ActiveSupport for Ruby < 1.9. Closes #47 2009-06-23 18:22:27 -04:00
Nick Quaranto
150ff1e5e4 Fixed small bug in test_generated_site and updating history with latest fixes 2009-06-23 08:10:42 -04:00
Stefan Saasen
e39810c984 Fix exception that causes jekyll to fail when using CRLF (0d0a) linebreaks in YAML front matter.
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-06-23 08:10:38 -04:00
Gaius Novus
5468548948 creating a Site with an invalid Markdown processor fails sooner and gives a better error message
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-06-23 08:10:33 -04:00
eugenebolshakov
e0ceee2e89 Added trailing slash to pretty url template
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-06-23 08:10:27 -04:00
Nick Quaranto
52fbd940c3 Merging in eugenebolshakov/permalinks_for_pages 2009-06-22 18:32:18 -04:00
Nick Quaranto
750b5f5cb8 Keeping the history up to date with Chrononaut and ujh's fixes 2009-06-22 18:11:15 -04:00
Nick Quaranto
606269b33c Merge commit 'ujh/master' 2009-06-22 18:06:40 -04:00
Bjørn Arild Mæland
414dfbe26e Ruby 1.9 issue, must explicitly run to_s on the err object. Closes #14.
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-06-22 17:41:51 -04:00
Thomas Jack
0a1e3cd250 stop sorting post categories so they show up in order in the url 2009-06-08 19:26:29 -05:00
Thomas Jack
535d78de7d change features and tests to make sure categories in urls follow the order specified by directory layout or in yaml 2009-06-08 19:26:03 -05:00
Urban Hafner
8379958d95 Order posts by slug name if the date is the same 2009-06-03 08:48:16 +03:00
Urban Hafner
d8d7ae3f0e Feature that should test ordering of titles on the same day 2009-06-02 20:36:11 +03:00
Urban Hafner
5bbdf2239d Feature for the pagination templating 2009-06-02 11:11:04 +03:00
Urban Hafner
937efcf8b8 Feature for the last fix 2009-06-02 10:58:53 +03:00
Urban Hafner
a116eaf0ee As we are couting the pages from 1 we have to continue until pages+1 2009-06-02 10:44:34 +03:00
Urban Hafner
d79d94277b Correct pagination 2009-06-01 13:12:52 +03:00
Nick Quaranto
486ae25fc1 Validating the configuration loads properly and is a hash, based on jrk's implementation. Closes #22. 2009-05-31 21:33:27 -04:00
Nick Quaranto
86b1450234 Adding tags to the site payload. Derived mostly from Henrik's implementation in 072d9e7 2009-05-18 18:28:56 -04:00
Nick Quaranto
99098dd8c7 Removing the extremely brittle generated_site test and moving the tags check into post.rb so pages don't break 2009-05-18 18:28:56 -04:00
Nick Quaranto
102f6be6a2 Added tags to posts. Based off Henrik's implementation in 072d9e7. 2009-05-18 18:28:56 -04:00
Nick Quaranto
921aee23d3 Removing topics for good 2009-05-18 18:28:56 -04:00
Nick Quaranto
285f0aa327 Removing TODO. Use GitHub issues instead for this kind of stuff. 2009-05-18 18:28:56 -04:00
eugenebolshakov
49c39f43a1 the index page should always have index.html permalink no matter what 2009-05-10 15:29:05 +04:00
eugenebolshakov
ee0167d706 Made pages respect permalinks style and permalinks in yml front matter 2009-05-10 14:53:00 +04:00
Nick Quaranto
605adf88d5 Shoulda-izing the pager test and correcting some formatting issues 2009-05-09 11:45:36 -04:00
Nick Quaranto
e1dbda47ed Merging in calavera's pagination branch 2009-05-09 11:44:34 -04:00
Tom Ward
8a11c0e92a Ensure Regexp for today's time is escaped, as time formats can contain pluses and other Regexp unfriendly characters, causing the Scenario 'Use site.time variable' to fail.
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-05-09 10:47:53 -04:00
Nick Quaranto
6f90939221 Fixing readme formatting issues 2009-05-08 05:39:17 -07:00
Nick Quaranto
8a926d4f29 Bumping gemspec for 0.5.1 2009-05-06 12:41:16 -07:00
Nick Quaranto
a42690dd38 Freezing to RedCloth 4.1.0 just for the tests 2009-05-06 12:41:16 -07:00
Nick Quaranto
d948e0da91 Removing RedCloth gem lock and adding notes in for deps 2009-05-06 12:41:16 -07:00
Nick Quaranto
35a467117e Using CGI.escapeHTML instead of manually replacing a few characters for xml_escape 2009-05-03 08:40:13 -04:00
Martin Vilcans
6968346703 Added cgi_escape filter 2009-05-02 00:44:33 +02:00
Nick Quaranto
445347e259 Updating history with latest additions 2009-05-01 08:31:52 -04:00
Nick Quaranto
53368cc3e1 Making sure excludes can work with a YAML array 2009-05-01 08:28:00 -04:00
Nick Quaranto
252ca94b81 Merging in duritong's exclude branch 2009-05-01 07:59:40 -04:00
Nick Quaranto
80a229aef2 Joining the license together. 2009-04-30 08:27:23 -04:00
Nick Quaranto
5a1d736242 Updating README with links to the wiki 2009-04-30 08:23:30 -04:00
Nick Quaranto
26f9ad3d98 Testing for RedCloth notextile issue and locking to 4.1.0, which parses the tag correctly 2009-04-29 09:07:29 -04:00
Bjørn Arild Mæland
4bcece18ae Issue 7: CGI escape post titles
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-04-28 08:09:42 -04:00
Nick Quaranto
a5d236eb53 Updating history so far from 0.5.0 2009-04-27 09:06:22 -04:00
Nick Quaranto
db75c8f588 Removing print statement for RDiscount. 2009-04-27 08:33:37 -04:00
Henrik N
3c39612d84 Work around RDiscount bug where Markdown after Pygments-highlighted code would not be parsed as Markdown.
See http://gist.github.com/97682 for a runnable example of the bug.

Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-04-27 08:29:54 -04:00
Nick Quaranto
e0477e32cc Adding failing test for RDiscount parsing issue with highlight tags. 2009-04-27 08:29:54 -04:00
Henrik N
bad2d172ec Make syntax highlighting (Albino, Pygmentize) not break on UTF-8 in code.
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-04-25 23:29:50 -04:00
Nick Quaranto
6342a3842c Adding failing test for UTF-8 pygments issue GH-8 2009-04-25 23:27:46 -04:00
Nick Quaranto
ccbd2c39a1 Merge commit 'qrush/permalinks' 2009-04-25 21:54:10 -04:00
Tom Preston-Werner
13245354b2 update readme for new workflow 2009-04-25 17:22:01 -07:00
Nick Quaranto
080108b0f0 Making sure permalinks were set right, and only generating the url once 2009-04-25 01:07:05 -04:00
Nick Quaranto
9da140fcb2 Getting there, prefixes work great 2009-04-25 00:58:28 -04:00
Nick Quaranto
288d5045d2 Changing to the template permalink system, only test_post passing so far 2009-04-25 00:17:10 -04:00
Nick Quaranto
73fa7dcad4 Actually testing existing permalink_style and its effect on posts 2009-04-24 23:19:13 -04:00
Nick Quaranto
f3fd105b40 Starting feature for permalinks 2009-04-24 22:21:55 -04:00
David Calavera
6eb29a4808 basename deleted 2009-04-25 00:03:26 +02:00
duritong
1f6940feb2 Added cucumber feature for the exclude option
this should cover the basic idea behind the exclude
feature.
2009-04-24 10:06:26 +02:00
duritong
9a0485e812 Fix exclude to be an empty array
if no exclude is defined in the config file, the exclude should
simply be an empty array.
2009-04-24 10:04:27 +02:00
Nick Quaranto
563933f114 Update the help message and comments to use config.yml 2009-04-23 18:24:52 -04:00
duritong
5b540cf744 introduce an exclude config option
This is a YAML array for files in the root directory,
which should be excluded to be processed into '_site'.
This can be useful for README, Rakefiles etc.
2009-04-24 00:13:08 +02:00
Thomas Jack
dd268fae95 sort posts before rendering so next and previous posts work
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-04-22 22:36:06 -04:00
Nick Quaranto
45b46722bf Making the generated site test happy when doing a glob on Ubuntu 2009-04-22 22:35:53 -04:00
Juan Lupion
2e187864cf Next and previous posts
Signed-off-by: Nick Quaranto <nick@quaran.to>
2009-04-22 19:51:41 -04:00
Tom Preston-Werner
3c9ed56129 Regenerated gemspec for version 0.5.0 2009-04-07 17:10:09 -07:00
Tom Preston-Werner
56176a3799 Version bump to 0.5.0 2009-04-07 17:08:11 -07:00
Tom Preston-Werner
8443676eeb update history with 0.5.0 release 2009-04-07 17:08:03 -07:00
Tom Preston-Werner
5247f4ff92 exit from rakefile if wrong version of jeweler is detected 2009-04-07 17:07:42 -07:00
Josh Nichols
93e7240731 Updated to use jeweler 0.11.0, which lets you exclude files. 2009-04-05 02:41:59 -04:00
David Calavera
2e00c5957b pagination executable option 2009-04-04 14:46:44 +02:00
David Calavera
f099d00cb0 posts' pagination 2009-04-04 12:45:40 +02:00
David Calavera
808d6c6a62 posts' pagination 2009-04-04 12:43:46 +02:00
Nick Quaranto
07c2451c06 Removing test/dest and generating gemspec. Jeweler needs some ignore options 2009-04-03 17:40:46 -04:00
David Calavera
556131793f all features pass 2009-04-03 23:06:30 +02:00
Nick Quaranto
8d0e3dd0e2 Reset posts, layouts, and categories before processing to prevent duplication when regenerating 2009-04-03 08:39:40 -04:00
Nick Quaranto
3d77c20578 Regenerating gemspec so rake build is happy 2009-04-03 08:20:53 -04:00
Tom Preston-Werner
b85eb4a373 update history 2009-04-01 20:26:43 -07:00
Nick Quaranto
f2ea61ba2a Appeasing maruku with a newline 2009-04-01 22:17:42 -04:00
Nick Quaranto
d590f2ac06 Green all around, finally. 2009-04-01 20:38:59 -04:00
Nick Quaranto
c52484a257 Going to figure out how to test background processes later 2009-04-01 20:19:33 -04:00
Nick Quaranto
4e302c0445 Started on site config feature 2009-04-01 18:43:06 -04:00
Nick Quaranto
3c0bc3b2de Added features to default rake task, and post data feature all green 2009-04-01 16:40:30 -04:00
Nick Quaranto
03f511be61 Following post step is getting confusing, but it works 2009-04-01 07:52:01 -04:00
Nick Quaranto
829530be36 Adding the categories back into the post payload 2009-04-01 07:36:56 -04:00
Nick Quaranto
aff6c9c23a Filter feature passing, definitely room for refactoring 2009-03-31 23:09:57 -04:00
Nick Quaranto
0d78cb7063 All green for create sites feature 2009-03-31 20:13:30 -04:00
Nick Quaranto
c22cd84153 Starting on implementing the step defs 2009-03-31 17:26:04 -04:00
Nick Quaranto
6c41f93493 12 step program to awesome integration tests 2009-03-31 07:37:38 -04:00
Nick Quaranto
778894dc6b Adding rake task for features, removing pipe for filters and starting on step definitions 2009-03-31 07:28:47 -04:00
Nick Quaranto
937dad66a7 Changing to FIT tables for posts, way better. 2009-03-27 08:39:11 -04:00
Nick Quaranto
3ebe81bf06 Need to cut down on repeating story steps a bit 2009-03-26 18:09:08 -04:00
Nick Quaranto
ea2175b0ed Getting there with the stories...slowly but surely 2009-03-26 09:15:07 -04:00
Nick Quaranto
9d4e1697ef Filling out configuration story 2009-03-25 18:32:26 -04:00
Nick Quaranto
e8a25964c5 Started on more of the stories 2009-03-25 08:37:56 -04:00
Nick Quaranto
8b5eb0395f Adding plenty of features with just basic scenarios 2009-03-25 08:26:29 -04:00
Nick Quaranto
15eaebe981 First crack at creating some user stories 2009-03-24 18:39:37 -04:00
Nick Quaranto
cce2b8f32c Bringing back the pygments test. All unit tests are back onboard now 2009-03-19 08:12:35 -04:00
Nick Quaranto
ae4e7725bf Bringing back the test_site tests 2009-03-18 08:37:03 -04:00
Nick Quaranto
a4082378f7 Supposedly the include tag was already fixed, merging that in 2009-03-17 23:58:22 -04:00
Nick Quaranto
479d8c7572 Allowing the dest_dir and source_dir helpers to take arguments so tests aren't littered with File.joins 2009-03-17 23:23:47 -04:00
Nick Quaranto
c60be9c571 Stubbing out the configuration makes for much less warnings. 2009-03-17 23:17:51 -04:00
Nick Quaranto
ab262a2ab5 Stubbing out configuration with RR and making sure include tags get rendered 2009-03-17 23:07:18 -04:00
Nick Quaranto
1423ea91a0 Removing lambdas from test_post since that was just stupid 2009-03-17 22:41:23 -04:00
Josh Nichols and Nick Quaranto
a5155c8e00 Fixed tests (... or commented them out). We rule. 2009-03-17 21:13:08 -04:00
Josh Nichols and Nick Quaranto
d602600394 Fixed test_generated_site. 2009-03-17 20:44:25 -04:00
Josh Nichols and Nick Quaranto
18b512a531 Merge branch 'qrush/shoulda' into can_has_good_tests
Conflicts:
	test/test_generated_site.rb
	test/test_post.rb
	test/test_site.rb
	test/test_tags.rb
2009-03-17 20:31:10 -04:00
Tom Preston-Werner
4c81c4a6b6 fix include tag to use register 2009-03-12 21:20:31 -07:00
Tom Preston-Werner
73d42b24ad Huge refactor to move all config into Jekyll::Site
This commit makes Jekyll threadsafe (or at least makes it possible to be so).
It also makes it a ton easier to use Jekyll as a library for scripted site
transformation. I did, however, break all the tests. =(
2009-03-12 19:05:43 -07:00
mreid
cb13ea3000 Rebased with mojombo. All tests pass. Some conflicts with Liquid and Maruku 2009-03-12 21:25:34 +11:00
mreid
4b39c44664 configure now sets the source and dest fields so the Liquid include filter works again 2009-03-12 20:51:12 +11:00
mreid
9f3244e884 Fixed bug which meant config file did not override default source and destination 2009-03-12 20:51:12 +11:00
Mark
6edfae8c26 Refactored configuration and command-line option code 2009-03-12 20:51:11 +11:00
Mark
6fec047631 Added ability to set Jekyll parameters via _config.yaml file 2009-03-12 20:46:33 +11:00
mreid
e72cde12fa Added option to not put file date in permalink URL 2009-03-12 20:46:33 +11:00
Mark Reid
6a3680c60b Added wordpress converter 2009-03-12 20:44:02 +11:00
Tom Preston-Werner
3e42982201 update history 2009-03-10 17:24:53 -07:00
Tom Preston-Werner
872a221862 Merge commit '992c4a8e6f71334f6c1a422c3547fdc535e7c8c2' 2009-03-10 17:23:30 -07:00
Tom Preston-Werner
be56a0f685 update history 2009-03-10 16:59:05 -07:00
Tom Preston-Werner
fa53f5f7fe Merge commit 'fb4902799746b08424eb7c483f8219e26e20d3e3' 2009-03-10 16:58:22 -07:00
Tom Preston-Werner
06cc318b6f update history 2009-03-10 16:56:27 -07:00
Tom Preston-Werner
a67cea2637 four foo category posts now 2009-03-10 16:53:43 -07:00
Tom Preston-Werner
54d713b26a Merge commit 'fab8442432f473ba647c682608bc8ff9ced6cca2' 2009-03-10 16:51:26 -07:00
Tom Preston-Werner
5e725eb4c4 update history 2009-03-10 16:39:54 -07:00
Tom Preston-Werner
86e72a8b25 a few style changes and readme for pretty permalink 2009-03-10 16:39:44 -07:00
Tom Preston-Werner
fa1043ca69 Merge commit '7655c745c46559d7598b5558fc9bf6fa8b215e28' 2009-03-10 16:15:32 -07:00
Tom Preston-Werner
2b925baf01 update history 2009-03-10 15:36:19 -07:00
Nick Quaranto
0e132bf2cb Upgrading the rest of the tests to shoulda 2009-03-05 21:54:52 -05:00
Nick Quaranto
0d05f27fe4 Post conversion complete 2009-03-05 21:54:52 -05:00
Nick Quaranto
8807c7660b Starting conversion to shoulda 2009-03-05 21:54:52 -05:00
Brandon Dimcheff
992c4a8e6f prevented _posts from being copied to the destination directory 2009-03-04 01:24:52 -05:00
Tim Dysinger
7655c745c4 small patch to support wordpress style pretty blog urls 2009-02-26 09:13:45 -10:00
Ariejan de Vroom
fb49027997 Only query required fields from the WP Database. 2009-02-26 10:29:01 +01:00
Bjørn Arild Mæland
fab8442432 Factored the filtering code into a method 2009-02-25 21:44:07 +01:00
Ryan Tomayko
c180bc47bf close open4 streams to prevent zombies
The popen4 that execs pygmetize leaves a bunch of zombie processes
around unless these streams are closed for some reason. It's not too
bad when running jekyll in one-shot mode but when running with
--server --auto --pygmentize, I eventually get "fork: resource not
available" errors :/ Closing the streams let's the processes die
while the parent stays running.
2009-02-23 22:48:23 -08:00
Bjørn Arild Mæland
25d4951f0b Also ignore Emacs autosave files 2009-02-22 22:58:47 +01:00
Bjørn Arild Mæland
0ec9a1330a Made it possible to enter categories from YAML as an array. 2009-02-22 19:09:16 +01:00
Tom Preston-Werner
2569e9fb5e update history 2009-02-19 12:28:50 -08:00
Elijah Miller
2135a53897 Using block syntax of popen4 to ensure that subprocesses are properly disposed of.
This fixes resource unavailable errors when jekyll is run with '--auto --pygments':
  Liquid error: Resource temporarily unavailable – fork(2)
  fork: Resource temporarily unavailable
2009-02-19 11:12:26 -08:00
Tom Preston-Werner
82d96448b5 update history 2009-02-19 00:17:37 -08:00
Tom Preston-Werner
e9ccc5d600 Merge commit 'ee65dadc9a5ae5fc8f19848754f7175ebd630375' 2009-02-19 00:16:43 -08:00
Tom Preston-Werner
2960687ab9 update history 2009-02-18 23:35:50 -08:00
Kevin Marsh
ee65dadc9a Add textilize filter for transforming input into HTML via RedCloth, so you can have Textile-formatted attributes other than the page's content (for example, an excerpt) 2009-02-12 18:21:40 -05:00
Tom Preston-Werner
0168581a82 Merge commit '60709da7067fbe1d106fbdfadb3a84b35d07d721' into qrush 2009-02-12 11:49:50 -08:00
Tom Preston-Werner
9a81255729 Regenerated gemspec for version 0.4.1 2009-02-10 20:37:09 -08:00
Tom Preston-Werner
023b1d50bd Version bump to 0.4.1 2009-02-10 20:37:03 -08:00
Tom Preston-Werner
8147c317d7 gemspec tweak 2009-02-10 20:36:52 -08:00
Nick Quaranto
60709da706 Removing some bad formatting in the README 2009-02-10 01:38:09 -05:00
Nick Quaranto
45b33f7b96 Adding explanations for new YAML front matter options 2009-02-10 01:27:13 -05:00
Nick Quaranto
efdd5ef395 Making sure that posts flagged as published: false don't get rendered or copied. 2009-02-10 01:13:36 -05:00
Nick Quaranto
ad617da4e0 Added publish flag to posts, not preventing it from being in the destination directory yet. 2009-02-10 01:13:31 -05:00
Nick Quaranto
1211f23b53 Adding support for setting post categories through YAML if not specified by directory structure 2009-02-10 01:12:20 -05:00
Nick Quaranto
4bcfaeae69 Starting on yaml categories 2009-02-10 01:12:17 -05:00
Nick Quaranto
2303115235 Making rake test happy on 1.8.7 2009-02-10 01:11:13 -05:00
Tom Preston-Werner
d0f46c2120 update history 2009-02-09 19:16:59 -08:00
Tim Dysinger
a3c18fb095 changed date format on wordpress converter (zeropadding) 2009-02-08 18:37:59 -10:00
Tim Dysinger
36183cbcfb added jekyll to exec list - otherwise it wont show up in PATH 2009-02-08 16:07:59 -10:00
Tom Preston-Werner
bb4d1ee119 add --version 2009-02-03 18:43:53 -08:00
Tom Preston-Werner
c489c1c2b2 fix rake console task 2009-02-03 14:49:22 -08:00
96 changed files with 4757 additions and 1286 deletions

7
.gitignore vendored
View File

@@ -1,3 +1,8 @@
test/dest/
Gemfile.lock
test/dest
*.gem
pkg/
*.swp
*~
_site/
.bundle/

2
Gemfile Normal file
View File

@@ -0,0 +1,2 @@
source :rubygems
gemspec

View File

@@ -1,3 +1,197 @@
== HEAD
* Major Enhancements
* Add command line importer functionality (#253)
* Minor Enhancements
* Switch to Albino gem
* Bundler support
* Use English library to avoid hoops (#292)
* Add Posterous importer (#254)
* Fixes for Wordpress importer (#274, #252, #271)
* Better error message for invalid post date (#291)
* Print formatted fatal exceptions to stdout on build failure
* Bug Fixes
* Secure additional path exploits
== 0.10.0 / 2010-12-16
* Bug Fixes
* Add --no-server option.
== 0.9.0 / 2010-12-15
* Minor Enhancements
* Use OptionParser's [no-] functionality for better boolean parsing.
* Add Drupal migrator (#245)
* Complain about YAML and Liquid errors (#249)
* Remove orphaned files during regeneration (#247)
* Add Marley migrator (#28)
== 0.8.0 / 2010-11-22
* Minor Enhancements
* Add wordpress.com importer (#207)
* Add --limit-posts cli option (#212)
* Add uri_escape filter (#234)
* Add --base-url cli option (#235)
* Improve MT migrator (#238)
* Add kramdown support (#239)
* Bug Fixes
* Fixed filename basename generation (#208)
* Set mode to UTF8 on Sequel connections (#237)
* Prevent _includes dir from being a symlink
== 0.7.0 / 2010-08-24
* Minor Enhancements
* Add support for rdiscount extensions (#173)
* Bug Fixes
* Highlight should not be able to render local files
* The site configuration may not always provide a 'time' setting (#184)
== 0.6.2 / 2010-06-25
* Bug Fixes
* Fix Rakefile 'release' task (tag pushing was missing origin)
* Ensure that RedCloth is loaded when textilize filter is used (#183)
* Expand source, destination, and plugin paths (#180)
* Fix page.url to include full relative path (#181)
== 0.6.1 / 2010-06-24
* Bug Fixes
* Fix Markdown Pygments prefix and suffix (#178)
== 0.6.0 / 2010-06-23
* Major Enhancements
* Proper plugin system (#19, #100)
* Add safe mode so unsafe converters/generators can be added
* Maruku is now the only processor dependency installed by default.
Other processors will be lazy-loaded when necessary (and prompt the
user to install them when necessary) (#57)
* Minor Enhancements
* Inclusion/exclusion of future dated posts (#59)
* Generation for a specific time (#59)
* Allocate site.time on render not per site_payload invocation (#59)
* Pages now present in the site payload and can be used through the
site.pages and site.html_pages variables
* Generate phase added to site#process and pagination is now a generator
* Switch to RakeGem for build/test process
* Only regenerate static files when they have changed (#142)
* Allow arbitrary options to Pygments (#31)
* Allow URL to be set via command line option (#147)
* Bug Fixes
* Render highlighted code for non markdown/textile pages (#116)
* Fix highlighting on Ruby 1.9 (#65)
* Fix extension munging when pretty permalinks are enabled (#64)
* Stop sorting categories (#33)
* Preserve generated attributes over front matter (#119)
* Fix source directory binding using Dir.pwd (#75)
== 0.5.7 / 2010-01-12
* Minor Enhancements
* Allow overriding of post date in the front matter (#62, #38)
* Bug Fixes
* Categories isn't always an array (#73)
* Empty tags causes error in read_posts (#84)
* Fix pagination to adhere to read/render/write paradigm
* Test Enhancement
* cucumber features no longer use site.posts.first where a better
alternative is available
== 0.5.6 / 2010-01-08
* Bug Fixes
* Require redcloth >= 4.2.1 in tests (#92)
* Don't break on triple dashes in yaml frontmatter (#93)
* Minor Enhancements
* Allow .mkd as markdown extension
* Use $stdout/err instead of constants (#99)
* Properly wrap code blocks (#91)
* Add javascript mime type for webrick (#98)
== 0.5.5 / 2010-01-08
* Bug Fixes
* Fix pagination % 0 bug (#78)
* Ensure all posts are processed first (#71)
== NOTE
* After this point I will no longer be giving credit in the history;
that is what the commit log is for.
== 0.5.4 / 2009-08-23
* Bug Fixes
* Do not allow symlinks (security vulnerability)
== 0.5.3 / 2009-07-14
* Bug Fixes
* Solving the permalink bug where non-html files wouldn't work
[github.com/jeffrydegrande]
== 0.5.2 / 2009-06-24
* Enhancements
* Added --paginate option to the executable along with a paginator object
for the payload [github.com/calavera]
* Upgraded RedCloth to 4.2.1, which makes <notextile> tags work once
again.
* Configuration options set in config.yml are now available through the
site payload [github.com/vilcans]
* Posts can now have an empty YAML front matter or none at all
[github.com/bahuvrihi]
* Bug Fixes
* Fixing Ruby 1.9 issue that requires to_s on the err object
[github.com/Chrononaut]
* Fixes for pagination and ordering posts on the same day [github.com/ujh]
* Made pages respect permalinks style and permalinks in yml front matter
[github.com/eugenebolshakov]
* Index.html file should always have index.html permalink
[github.com/eugenebolshakov]
* Added trailing slash to pretty permalink style so Apache is happy
[github.com/eugenebolshakov]
* Bad markdown processor in config fails sooner and with better message
[github.com/gcnovus]
* Allow CRLFs in yaml frontmatter [github.com/juretta]
* Added Date#xmlschema for Ruby versions < 1.9
== 0.5.1 / 2009-05-06
* Major Enhancements
* Next/previous posts in site payload [github.com/pantulis,
github.com/tomo]
* Permalink templating system
* Moved most of the README out to the GitHub wiki
* Exclude option in configuration so specified files won't be brought over
with generated site [github.com/duritong]
* Bug Fixes
* Making sure config.yaml references are all gone, using only config.yml
* Fixed syntax highlighting breaking for UTF-8 code [github.com/henrik]
* Worked around RDiscount bug that prevents Markdown from getting parsed
after highlight [github.com/henrik]
* CGI escaped post titles [github.com/Chrononaut]
== 0.5.0 / 2009-04-07
* Minor Enhancements
* Ability to set post categories via YAML [github.com/qrush]
* Ability to set prevent a post from publishing via YAML
[github.com/qrush]
* Add textilize filter [github.com/willcodeforfoo]
* Add 'pretty' permalink style for wordpress-like urls
[github.com/dysinger]
* Made it possible to enter categories from YAML as an array
[github.com/Chrononaut]
* Ignore Emacs autosave files [github.com/Chrononaut]
* Bug Fixes
* Use block syntax of popen4 to ensure that subprocesses are properly
disposed [github.com/jqr]
* Close open4 streams to prevent zombies [github.com/rtomayko]
* Only query required fields from the WP Database [github.com/ariejan]
* Prevent _posts from being copied to the destination directory
[github.com/bdimcheff]
* Refactors
* Factored the filtering code into a method [github.com/Chrononaut]
* Fix tests and convert to Shoulda [github.com/qrush,
github.com/technicalpickles]
* Add Cucumber acceptance test suite [github.com/qrush,
github.com/technicalpickles]
== 0.4.1
* Minor Enhancements
* Changed date format on wordpress converter (zeropadding)
[github.com/dysinger]
* Bug Fixes
* Add jekyll binary as executable to gemspec [github.com/dysinger]
== 0.4.0 / 2009-02-03
* Major Enhancements
* Switch to Jeweler for packaging tasks
@@ -7,28 +201,35 @@
* Add array_to_sentence_string filter [github.com/mchung]
* Add a converter for textpattern [github.com/PerfectlyNormal]
* Add a working Mephisto / MySQL converter [github.com/ivey]
* Allowing .htaccess files to be copied over into the generated site [github.com/briandoll]
* Allowing .htaccess files to be copied over into the generated site
[github.com/briandoll]
* Add option to not put file date in permalink URL [github.com/mreid]
* Add line number capabilities to highlight blocks [github.com/jcon]
* Bug Fixes
* Fix permalink behavior [github.com/cavalle]
* Fixed an issue with pygments, markdown, and newlines [github.com/zpinter]
* Fixed an issue with pygments, markdown, and newlines
[github.com/zpinter]
* Ampersands need to be escaped [github.com/pufuwozu, github.com/ap]
* Test and fix the site.categories hash [github.com/zzot]
* Fix site payload available to files [github.com/matrix9180]
== 0.3.0 / 2008-12-24
* Major Enhancements
* Added --server option to start a simple WEBrick server on destination directory [github.com/johnreilly and github.com/mchung]
* Added --server option to start a simple WEBrick server on destination
directory [github.com/johnreilly and github.com/mchung]
* Minor Enhancements
* Added post categories based on directories containing _posts [github.com/mreid]
* Added post categories based on directories containing _posts
[github.com/mreid]
* Added post topics based on directories underneath _posts
* Added new date filter that shows the full month name [github.com/mreid]
* Merge Post's YAML front matter into its to_liquid payload [github.com/remi]
* Merge Post's YAML front matter into its to_liquid payload
[github.com/remi]
* Restrict includes to regular files underneath _includes
* Bug Fixes
* Change YAML delimiter matcher so as to not chew up 2nd level markdown headers [github.com/mreid]
* Fix bug that meant page data (such as the date) was not available in templates [github.com/mreid]
* Change YAML delimiter matcher so as to not chew up 2nd level markdown
headers [github.com/mreid]
* Fix bug that meant page data (such as the date) was not available in
templates [github.com/mreid]
* Properly reject directories in _layouts
== 0.2.1 / 2008-12-15
@@ -51,9 +252,11 @@
* Code highlighting with Pygments if --pygments is specified
* Disable true LSI by default, enable with --lsi
* Minor Enhancements
* Output informative message if RDiscount is not available [github.com/JackDanger]
* Output informative message if RDiscount is not available
[github.com/JackDanger]
* Bug Fixes
* Prevent Jekyll from picking up the output directory as a source [github.com/JackDanger]
* Prevent Jekyll from picking up the output directory as a source
[github.com/JackDanger]
* Skip related_posts when there is only one post [github.com/JackDanger]
== 0.1.4 / 2008-12-08

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
(The MIT License)
Copyright (c) 2008 Tom Preston-Werner
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

View File

@@ -1,475 +1,40 @@
h1. Jekyll
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. Visit
"http://tom.preston-werner.com":http://tom.preston-werner.com to see an
example of a Jekyll generated blog.
By Tom Preston-Werner, Nick Quaranto, and many awesome contributors!
To understand how this all works, open up my
"TPW":http://github.com/mojombo/tpw repo in a new browser window. I'll be
referencing the code there.
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.
Take a look at
"index.html":http://github.com/mojombo/tpw/tree/master/index.html. This file
represents the homepage of the site. At the top of the file is a chunk of YAML
that contains metadata about the file. This data tells Jekyll what layout to
give the file, what the page's title should be, etc. In this case, I specify
that the "default" template should be used. You can find the layout files in
the "_layouts":http://github.com/mojombo/tpw/tree/master/_layouts directory.
If you open
"default.html":http://github.com/mojombo/tpw/tree/master/_layouts/default.html
you can see that the homepage is constructed by wrapping index.html with this
layout.
h2. Getting Started
You'll also notice Liquid templating code in these files.
"Liquid":http://www.liquidmarkup.org/ is a simple, extensible templating
language that makes it easy to embed data in your templates. For my homepage I
wanted to have a list of all my blog posts. Jekyll hands me a Hash containing
various data about my site. A reverse chronological list of all my blog posts
can be found in <code>site.posts</code>. Each post, in turn, contains various
fields such as <code>title</code> and <code>date</code>.
* "Install":http://wiki.github.com/mojombo/jekyll/install the gem
* Read up about its "Usage":http://wiki.github.com/mojombo/jekyll/usage and "Configuration":http://wiki.github.com/mojombo/jekyll/configuration
* Take a gander at some existing "Sites":http://wiki.github.com/mojombo/jekyll/sites
* Fork and "Contribute":http://wiki.github.com/mojombo/jekyll/contribute your own modifications
* Have questions? Post them on the "Mailing List":http://groups.google.com/group/jekyll-rb
Jekyll gets the list of blog posts by parsing the files in any
"_posts":http://github.com/mojombo/tpw/tree/master/_posts directory found in
subdirectories below the root.
Each post's filename contains (by default) the publishing date and slug (what shows up in the
URL) that the final HTML file should have. Open up the file corresponding to a
blog post:
"2008-11-17-blogging-like-a-hacker.textile":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile.
GitHub renders textile files by default, so to better understand the file,
click on the
"raw":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile?raw=true
view to see the original file. Here I've specified the <code>post</code>
layout. If you look at that file you'll see an example of a nested layout.
Layouts can contain other layouts allowing you a great deal of flexibility in
how pages are assembled. In my case I use a nested layout in order to show
related posts for each blog entry. The YAML also specifies the post's title
which is then embedded in the post's body via Liquid.
h2. Diving In
Posts are handled in a special way by Jekyll. The date you specify in the
filename is used to construct the URL in the generated site. The example post,
for instance, ends up at
<code>http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html</code>.
* "Migrate":http://wiki.github.com/mojombo/jekyll/blog-migrations from your previous system
* Learn how the "YAML Front Matter":http://wiki.github.com/mojombo/jekyll/yaml-front-matter works
* Put information on your site with "Template Data":http://wiki.github.com/mojombo/jekyll/template-data
* Customize the "Permalinks":http://wiki.github.com/mojombo/jekyll/permalinks your posts are generated with
* Use the built-in "Liquid Extensions":http://wiki.github.com/mojombo/jekyll/liquid-extensions to make your life easier
Categories for posts are derived from the directory structure the posts were
found within. A post that appears in the directory foo/bar/_posts is placed in
the categories 'foo' and 'bar'. By selecting posts from particular categories
in your Liquid templates, you will be able to host multiple blogs within a
site.
h2. Runtime Dependencies
Files that do not reside in directories prefixed with an underscore are
mirrored into a corresponding directory structure in the generated site. If a
file does not have a YAML preface, it is not run through the Liquid
interpreter. Binary files are copied over unmodified.
* RedCloth: Textile support (Ruby)
* Liquid: Templating system (Ruby)
* Classifier: Generating related posts (Ruby)
* Maruku: Default markdown engine (Ruby)
* Directory Watcher: Auto-regeneration of sites (Ruby)
* Pygments: Syntax highlighting (Python)
Jekyll is still a very young project. I've only developed the exact
functionality that I've needed. As time goes on I'd like to see the project
mature and support additional features. If you end up using Jekyll for your
own blog, drop me a line and let me know what you'd like to see in future
versions. Better yet, fork the project over at GitHub and hack in the features
yourself!
h2. Developer Dependencies
h2. Example Proto-Site
My own personal site/blog is generated with Jekyll.
The proto-site repo
("http://github.com/mojombo/tpw":http://github.com/mojombo/tpw) is converted
into the actual site
("http://tom.preston-werner.com/":http://tom.preston-werner.com)
h2. Install
The best way to install Jekyll is via RubyGems:
$ sudo gem install mojombo-jekyll -s http://gems.github.com/
Jekyll requires the gems `directory_watcher`, `liquid`, `open4`,
and `maruku` (for markdown support). These are automatically
installed by the gem install command.
Maruku comes with optional support for LaTeX to PNG rendering via
"blahtex":http://gva.noekeon.org/blahtexml/ (Version 0.6) which must be in
your $PATH along with `dvips`.
(NOTE: the version of maruku I am using is `remi-maruku` on GitHub as it
does not assume a fixed location for `dvips`.)
h2. Run
$ cd /path/to/proto/site
$ jekyll
This will generate the site and place it in /path/to/proto/site/_site. If
you'd like the generated site placed somewhere else:
$ jekyll /path/to/place/generated/site
And if you don't want to be in the proto site root to run Jekyll:
$ jekyll /path/to/proto/site /path/to/place/generated/site
h2. Run Options
There is an autobuild feature that will regenerate your site if any of the
files change. The autobuild feature can be used on any of the invocations:
$ jekyll --auto
By default, the "related posts" functionality will produce crappy results.
In order to get high quality results with a true LSI algorithm, you must
enable it (it may take some time to run if you have many posts):
$ jekyll --lsi
For static code highlighting, you can install Pygments (see below) and then
use that to make your code blocks look pretty. To activate Pygments support
during the conversion:
$ jekyll --pygments
By default, Jekyll uses "Maruku":http://maruku.rubyforge.org (pure Ruby) for
Markdown support. If you'd like to use RDiscount (faster, but requires
compilation), you must install it (gem install rdiscount) and then you can
have it used instead:
$ jekyll --rdiscount
When previewing complex sites locally, simply opening the site in a web
browser (using file://) can cause problems with links that are relative to
the site root (e.g., "/stylesheets/style.css"). To get around this, Jekyll
can launch a simple WEBrick server (works well in conjunction with --auto).
Default port is 4000:
$ jekyll --server [PORT]
By default, the permalink for each post begins with its date in 'YYYY/MM/DD'
format. If you do not wish to have the date appear in the URL of each post,
you can change the permalink style to 'none' so that only the 'slug' part of
the filename is used. For example, with the permalink style set to 'none' the
file '2009-01-01-happy-new-year.markdown' will have a permalink like
'http://yoursite.com/happy-new-year.html'. The date of the post will still be
read from the filename (and is required!) to be used elsewhere in Jekyll.
Example usage:
$ jekyll --permalink none
h2. Data
Jekyll traverses your site looking for files to process. Any files with YAML
front matter (see below) are subject to processing. For each of these files,
Jekyll makes a variety of data available to the pages via the Liquid
templating system. The following is a reference of the available data.
h3. Global
site
Sitewide information.
page
For Posts, this is the union of the data in the YAML front matter and the
computed data (such as URL and date). For regular pages, this is just the
YAML front matter.
content
In layout files, this contains the content of the subview(s). In Posts or
Pages, this is undefined.
h3. Site
site.time
The current Time (when you run the jekyll command).
site.posts
A reverse chronological list of all Posts.
site.related_posts
If the page being processed is a Post, this contains a list of up to ten
related Posts. By default, these are low quality but fast to compute. For
high quality but slow to compute results, run the jekyll command with the
--lsi (latent semantic indexing) option.
site.categories.CATEGORY
The list of all Posts in category CATEGORY.
h3. Post
post.title
The title of the Post.
post.url
The URL of the Post without the domain.
e.g. /2008/12/14/my-post.html
post.date
The Date assigned to the Post.
post.id
An identifier unique to the Post (useful in RSS feeds).
e.g. /2008/12/14/my-post
post.categories
The list of categories to which this post belongs. Categories are
derived from the directory structure above the _posts directory. For
example, a post at /work/code/_posts/2008-12-24-closures.textile
would have this field set to ['work', 'code'].
post.topics
The list of topics for this Post. Topics are derived from the directory
structure beneath the _posts directory. For example, a post at
/_posts/music/metal/2008-12-24-metalocalypse.textile would have this field
set to ['music', 'metal'].
post.content
The content of the Post.
h2. YAML Front Matter
Any files that contain a YAML front matter block will be processed by Jekyll
as special files. The front matter must be the first thing in the file and
takes the form of:
<pre>
---
layout: post
title: Blogging Like a Hacker
---
</pre>
Between the triple-dashed lines, you can set predefined variables (see below
for a reference) or custom data of your own.
h3. Predefined Global Variables
layout
If set, this specifies the layout file to use. Use the layout file
name without file extension. Layout files must be placed in the
<code>_layouts</code> directory.
h3. Predefined Post Variables
permalink
If you need your processed URLs to be something other than the default
/year/month/day/title.html then you can set this variable and it will
be used as the final URL.
h3. Custom Variables
Any variables in the front matter that are not predefined are mixed into the
data that is sent to the Liquid templating engine during the conversion. For
instance, if you set a <code>title</code>, you can use that in your layout to
set the page title:
<pre>
<title>{{ page.title }}</title>
</pre>
h2. Filters, Tags, and Blocks
In addition to the built-in Liquid filters, tags, and blocks, Jekyll provides
some additional items that you can use in your site.
h3. Date to XML Schema (Filter)
Convert a Time into XML Schema format.
{{ site.time | date_to_xmlschema }}
becomes
2008-11-17T13:07:54-08:00
h3. XML Escape (Filter)
Escape some text for use in XML.
{{ post.content | xml_escape }}
h3. Number of Words (Filter)
Count the number of words in some text.
{{ post.content | number_of_words }}
becomes
1337
h3. Array to Sentence String
Convert an array into a sentence.
{{ page.tags | array_to_sentence_string }}
becomes
foo, bar, and baz
h3. Include (Tag)
If you have small page fragments that you wish to include in multiple places
on your site, you can use the <code>include</code> tag.
<pre>{% include sig.textile %}</pre>
Jekyll expects all include files to be placed in an <code>_includes</code>
directory at the root of your source dir. So this will embed the contents of
<code>/path/to/proto/site/_includes/sig.textile</code> into the calling file.
h3. Code Highlighting (Block)
Jekyll has built in support for syntax highlighting of over "100
languages":http://pygments.org/languages/ via "Pygments":http://pygments.org/.
In order to take advantage of this you'll need to have Pygments installed, and
the pygmentize binary must be in your path. When you run Jekyll, make sure you
run it with Pygments support:
$ jekyll --pygments
To denote a code block that should be highlighted:
<pre>
{% highlight ruby %}
def foo
puts 'foo'
end
{% endhighlight %}
</pre>
The argument to <code>highlight</code> is the language identifier. To find the
appropriate identifier to use for your favorite language, look for the "short
name" on the "Lexers":http://pygments.org/docs/lexers/ page.
There is a second argument to <code>highlight</code> called
<code>linenos</code> that is optional. Including the <code>linenos</code>
argument will force the highlighted code to include line numbers. For
instance, the following code block would include line numbers next to each
line:
<pre>
{% highlight ruby linenos %}
def foo
puts 'foo'
end
{% endhighlight %}
</pre>
In order for the highlighting to show up, you'll need to include a
highlighting stylesheet. For an example stylesheet you can look at
"syntax.css":http://github.com/mojombo/tpw/tree/master/css/syntax.css. These
are the same styles as used by GitHub and you are free to use them for your
own site. If you use linenos, you might want to include an additional CSS
class definition for <code>lineno</code> in syntax.css to distinguish the line
numbers from the highlighted code.
h2. Categories
Posts are placed into categories based on the directory structure they are
found within (see above for an example). The categories can be accessed from
within a Liquid template as follows:
<pre>
{% for post in site.categories.foo %}
<li><span>{{ post.date | date_to_string }}</span> - {{ post.title }}</li>
{% endfor %}
</pre>
This would list all the posts in the category 'foo' by date and title.
The posts within each category are sorted in reverse chronological order.
h2. Blog migrations
h3. Movable Type
To migrate your MT blog into Jekyll, you'll need read access to the database.
The lib/jekyll/converters/mt.rb module provides a simple convert to create
.markdown files in a _posts directory based on the entries contained therein.
$ export DB=my_mtdb
$ export USER=dbuser
$ export PASS=dbpass
$ ruby -r './lib/jekyll/converters/mt' -e 'Jekyll::MT.process( \
"#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")'
You may need to adjust the SQL query used to retrieve MT entries. Left alone,
it will attempt to pull all entries across all blogs regardless of status.
Please check the results and verify the posts before publishing.
h3. Typo 4+
To migrate your Typo blog into Jekyll, you'll need read access to the MySQL
database. The lib/jekyll/converters/typo.rb module provides a simple convert
to create .html, .textile, or .markdown files in a _posts directory based on
the entries contained therein.
$ export DB=my_typo_db
$ export USER=dbuser
$ export PASS=dbpass
$ ruby -r './lib/jekyll/converters/typo' -e 'Jekyll::Typo.process( \
"#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")'
You may need to adjust the code used to filter Typo entries. Left alone,
it will attempt to pull all entries across all blogs that were published.
This code also has only been tested with Typo version 4+. Previous versions
of Typo may not convert correctly. Please check the results and verify the
posts before publishing.
h3. TextPattern 4
To migrate your TextPattern blog into Jekyll, you'll need read access to the MySQL
database. The lib/jekyll/converters/textpattern.rb module provides a simple convert to create .textile files in a _posts directory based on
the entries contained therein.
$ ruby -r './lib/jekyll/converters/textpattern' -e 'Jekyll::TextPattern.process( \
"database_name", "username", "password", "hostname")'
The hostname defaults to _localhost_, all other variables are needed
You may need to adjust the code used to filter entries. Left alone,
it will attempt to pull all entries that are live or sticky.
h2. Contribute
If you'd like to hack on Jekyll, start by forking my repo on GitHub:
http://github.com/mojombo/jekyll
To get all of the dependencies, install the gem first. The best way to get
your changes merged back into core is as follows:
# Clone down your fork
# Create a topic branch to contain your change
# Hack away
# Add tests and make sure everything still passes by running `rake`
# If you are adding new functionality, document it in README.textile
# Do not change the version number, I will do that on my end
# If necessary, rebase your commits into logical chunks, without errors
# Push the branch up to GitHub
# Send me (mojombo) a pull request for your branch
* Shoulda: Test framework (Ruby)
* RR: Mocking (Ruby)
* RedGreen: Nicer test output (Ruby)
h2. License
(The MIT License)
Copyright (c) 2008 Tom Preston-Werner
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:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
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.
See LICENSE.

185
Rakefile
View File

@@ -1,74 +1,159 @@
require 'rubygems'
require 'rake'
require 'date'
#############################################################################
#
# Helper functions
#
#############################################################################
def name
@name ||= Dir['*.gemspec'].first.split('.').first
end
def version
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
end
def date
Date.today.to_s
end
def rubyforge_project
name
end
def gemspec_file
"#{name}.gemspec"
end
def gem_file
"#{name}-#{version}.gem"
end
def replace_header(head, header_name)
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
end
#############################################################################
#
# Standard tasks
#
#############################################################################
task :default => [:test, :features]
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/test_*.rb'
test.verbose = true
end
desc "Generate RCov test coverage and open in your browser"
task :coverage do
require 'rcov'
sh "rm -fr coverage"
sh "rcov test/test_*.rb"
sh "open coverage/index.html"
end
require 'rake/rdoctask'
begin
require 'jeweler'
Jeweler::Tasks.new do |s|
s.name = "jekyll"
s.summary = %Q{Jekyll is a simple, blog aware, static site generator.}
s.email = "tom@mojombo.com"
s.homepage = "http://github.com/mojombo/jekyll"
s.description = "Jekyll is a simple, blog aware, static site generator."
s.authors = ["Tom Preston-Werner"]
s.rubyforge_project = "jekyll"
s.add_dependency('RedCloth', '>= 4.0.4')
s.add_dependency('liquid', '>= 1.9.0')
s.add_dependency('classifier', '>= 1.3.1')
s.add_dependency('maruku', '>= 0.5.9')
s.add_dependency('directory_watcher', '>= 1.1.1')
s.add_dependency('open4', '>= 0.9.6')
end
rescue LoadError
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
end
Rake::TestTask.new do |t|
t.libs << 'lib'
t.pattern = 'test/**/test_*.rb'
t.verbose = false
end
Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'jekyll'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.title = "#{name} #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |t|
t.libs << 'test'
t.test_files = FileList['test/**/test_*.rb']
t.verbose = true
end
rescue LoadError
end
task :default => :test
# console
desc "Open an irb session preloaded with this library"
task :console do
sh "irb -rubygems -r ./lib/jekyll.rb"
sh "irb -rubygems -r ./lib/#{name}.rb"
end
# converters
#############################################################################
#
# Custom tasks (add your own tasks here)
#
#############################################################################
namespace :convert do
namespace :migrate do
desc "Migrate from mephisto in the current directory"
task :mephisto do
sh %q(ruby -r './lib/jekyll/converters/mephisto' -e 'Jekyll::Mephisto.postgres(:database => "#{ENV["DB"]}")')
sh %q(ruby -r './lib/jekyll/migrators/mephisto' -e 'Jekyll::Mephisto.postgres(:database => "#{ENV["DB"]}")')
end
desc "Migrate from Movable Type in the current directory"
task :mt do
sh %q(ruby -r './lib/jekyll/converters/mt' -e 'Jekyll::MT.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")')
sh %q(ruby -r './lib/jekyll/migrators/mt' -e 'Jekyll::MT.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")')
end
desc "Migrate from Typo in the current directory"
task :typo do
sh %q(ruby -r './lib/jekyll/converters/typo' -e 'Jekyll::Typo.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")')
sh %q(ruby -r './lib/jekyll/migrators/typo' -e 'Jekyll::Typo.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")')
end
end
begin
require 'cucumber/rake/task'
Cucumber::Rake::Task.new(:features) do |t|
t.cucumber_opts = "--format progress"
end
rescue LoadError
desc 'Cucumber rake task not available'
task :features do
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
end
end
#############################################################################
#
# Packaging tasks
#
#############################################################################
task :release => :build do
unless `git branch` =~ /^\* master$/
puts "You must be on the master branch to release!"
exit!
end
sh "git commit --allow-empty -a -m 'Release #{version}'"
sh "git tag v#{version}"
sh "git push origin master"
sh "git push origin v#{version}"
sh "gem push pkg/#{name}-#{version}.gem"
end
task :build => :gemspec do
sh "mkdir -p pkg"
sh "gem build #{gemspec_file}"
sh "mv #{gem_file} pkg"
end
task :gemspec do
# read spec file and split out manifest section
spec = File.read(gemspec_file)
head, manifest, tail = spec.split(" # = MANIFEST =\n")
# replace name version and date
replace_header(head, :name)
replace_header(head, :version)
replace_header(head, :date)
#comment this out if your rubyforge_project has a different name
replace_header(head, :rubyforge_project)
# determine file list from git ls-files
files = `git ls-files`.
split("\n").
sort.
reject { |file| file =~ /^\./ }.
reject { |file| file =~ /^(rdoc|pkg|coverage)/ }.
map { |file| " #{file}" }.
join("\n")
# piece file back together and write
manifest = " s.files = %w[\n#{files}\n ]\n"
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
File.open(gemspec_file, 'w') { |io| io.write(spec) }
puts "Updated #{gemspec_file}"
end

3
TODO
View File

@@ -1,3 +0,0 @@
[ ] Easier configuration of Maruka and blahtex directories [mdreid]
[ ] Accurate "related posts" calculator
[ ] Autobuild

View File

@@ -1,4 +0,0 @@
---
:minor: 4
:patch: 0
:major: 0

View File

@@ -9,58 +9,202 @@ Basic Command Line Usage:
jekyll # . -> ./_site
jekyll <path to write generated site> # . -> <path>
jekyll <path to source> <path to write generated site> # <path> -> <path>
Options:
jekyll import <importer name> <options> # imports posts using named import script
Configuration is read from '<source>/_config.yml' but can be overriden
using the following options:
HELP
require 'optparse'
require 'jekyll'
options = {}
exec = {}
options = {}
opts = OptionParser.new do |opts|
opts.banner = help
opts.on("--auto", "Auto-regenerate") do
options[:auto] = true
opts.on("--file [PATH]", "File to import from") do |import_file|
options['file'] = import_file
end
opts.on("--dbname [TEXT]", "DB to import from") do |import_dbname|
options['dbname'] = import_dbname
end
opts.on("--user [TEXT]", "Username to use when importing") do |import_user|
options['user'] = import_user
end
opts.on("--pass [TEXT]", "Password to use when importing") do |import_pass|
options['pass'] = import_pass
end
opts.on("--host [HOST ADDRESS]", "Host to import from") do |import_host|
options['host'] = import_host
end
opts.on("--site [SITE NAME]", "Site to import from") do |import_site|
options['site'] = import_site
end
opts.on("--[no-]safe", "Safe mode (default unsafe)") do |safe|
options['safe'] = safe
end
opts.on("--[no-]auto", "Auto-regenerate") do |auto|
options['auto'] = auto
end
opts.on("--server [PORT]", "Start web server (default port 4000)") do |port|
options[:server] = true
options[:server_port] = port || 4000
options['server'] = true
options['server_port'] = port unless port.nil?
end
opts.on("--lsi", "Use LSI for better related posts") do
Jekyll.lsi = true
opts.on("--no-server", "Do not start a web server") do |part|
options['server'] = false
end
opts.on("--pygments", "Use pygments to highlight code") do
Jekyll.pygments = true
opts.on("--base-url [BASE_URL]", "Serve website from a given base URL (default '/'") do |baseurl|
options['baseurl'] = baseurl
end
opts.on("--[no-]lsi", "Use LSI for better related posts") do |lsi|
options['lsi'] = lsi
end
opts.on("--[no-]pygments", "Use pygments to highlight code") do |pygments|
options['pygments'] = pygments
end
opts.on("--rdiscount", "Use rdiscount gem for Markdown") do
options['markdown'] = 'rdiscount'
end
opts.on("--kramdown", "Use kramdown gem for Markdown") do
options['markdown'] = 'kramdown'
end
opts.on("--time [TIME]", "Time to generate the site for") do |time|
options['time'] = Time.parse(time)
end
opts.on("--[no-]future", "Render future dated posts") do |future|
options['future'] = future
end
opts.on("--permalink [TYPE]", "Use 'date' (default) for YYYY/MM/DD") do |style|
options['permalink'] = style unless style.nil?
end
opts.on("--paginate [POSTS_PER_PAGE]", "Paginate a blog's posts") do |per_page|
begin
require 'rdiscount'
Jekyll.markdown_proc = Proc.new { |x| RDiscount.new(x).to_html }
puts 'Using rdiscount for Markdown'
rescue LoadError
puts 'You must have the rdiscount gem installed first'
options['paginate'] = per_page.to_i
raise ArgumentError if options['paginate'] == 0
rescue
puts 'you must specify a number of posts by page bigger than 0'
exit 0
end
end
opts.on("--permalink [TYPE]", "Use 'date' (default) for YYYY/MM/DD") do |style|
Jekyll.permalink_style = (style || 'date').to_sym
opts.on("--limit_posts [MAX_POSTS]", "Limit the number of posts to publish") do |limit_posts|
begin
options['limit_posts'] = limit_posts.to_i
raise ArgumentError if options['limit_posts'] < 1
rescue
puts 'you must specify a number of posts by page bigger than 0'
exit 0
end
end
opts.on("--url [URL]", "Set custom site.url") do |url|
options['url'] = url
end
opts.on("--version", "Display current version") do
puts "Jekyll " + Jekyll::VERSION
exit 0
end
end
# Read command line options into `options` hash
opts.parse!
def clean(dest)
FileUtils.rm_rf(dest)
FileUtils.mkdir_p(dest)
# Check for import stuff
if ARGV.size > 0
if ARGV[0] == 'import'
migrator = ARGV[1]
if migrator.nil?
puts "Invalid options. Run `jekyll --help` for assistance."
exit(1)
else
migrator = migrator.downcase
end
cmd_options = []
['file', 'dbname', 'user', 'pass', 'host', 'site'].each do |p|
cmd_options << "\"#{options[p]}\"" unless options[p].nil?
end
# It's import time
puts "Importing..."
# Ideally, this shouldn't be necessary. Maybe parse the actual
# src files for the migrator name?
migrators = {
:posterous => 'Posterous',
:wordpressdotcom => 'WordpressDotCom',
:wordpress => 'Wordpress',
:csv => 'CSV',
:drupal => 'Drupal',
:mephisto => 'Mephisto',
:mt => 'MT',
:textpattern => 'TextPattern',
:typo => 'Typo'
}
app_root = File.join(File.dirname(__FILE__), '..')
require "#{app_root}/lib/jekyll/migrators/#{migrator}"
if Jekyll.const_defined?(migrators[migrator.to_sym])
migrator_class = Jekyll.const_get(migrators[migrator.to_sym])
migrator_class.process(*cmd_options)
else
puts "Invalid migrator. Run `jekyll --help` for assistance."
exit(1)
end
exit(0)
end
end
# Get source and destintation from command line
case ARGV.size
when 0
when 1
options['destination'] = ARGV[0]
when 2
options['source'] = ARGV[0]
options['destination'] = ARGV[1]
else
puts "Invalid options. Run `jekyll --help` for assistance."
exit(1)
end
options = Jekyll.configuration(options)
# Get source and destination directories (possibly set by config file)
source = options['source']
destination = options['destination']
# Files to watch
def globs(source)
Dir.chdir(source) do
dirs = Dir['*'].select { |x| File.directory?(x) }
@@ -70,63 +214,63 @@ def globs(source)
end
end
source = nil
destination = nil
# Create the Site
site = Jekyll::Site.new(options)
case ARGV.size
when 0
source = '.'
destination = File.join('.', '_site')
when 1
source = '.'
destination = ARGV[0]
when 2
source = ARGV[0]
destination = ARGV[1]
else
puts "Invalid options. Run `jekyll --help` for assistance."
exit(1)
end
if options[:auto]
# Run the directory watcher for auto-generation, if required
if options['auto']
require 'directory_watcher'
puts "Auto-regenerating enabled: #{source} -> #{destination}"
dw = DirectoryWatcher.new(source)
dw.interval = 1
dw.glob = globs(source)
dw.add_observer do |*args|
t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
puts "[#{t}] regeneration: #{args.size} files changed"
Jekyll.process(source, destination)
site.process
end
dw.start
unless options[:server]
unless options['server']
loop { sleep 1000 }
end
else
Jekyll.process(source, destination)
puts "Successfully generated site in #{destination}"
puts "Building site: #{source} -> #{destination}"
begin
site.process
rescue Jekyll::FatalException => e
puts
puts "ERROR: YOUR SITE COULD NOT BE BUILT:"
puts "------------------------------------"
puts e.message
exit(1)
end
puts "Successfully generated site: #{source} -> #{destination}"
end
if options[:server]
# Run the server on the specified port, if required
if options['server']
require 'webrick'
include WEBrick
FileUtils.mkdir_p(destination)
mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
mime_types.store 'js', 'application/javascript'
s = HTTPServer.new(
:Port => options[:server_port],
:DocumentRoot => destination
:Port => options['server_port'],
:MimeTypes => mime_types
)
s.mount(options['baseurl'], HTTPServlet::FileHandler, destination)
t = Thread.new {
s.start
}
trap("INT") { s.shutdown }
t.join()
end
end

1
cucumber.yml Normal file
View File

@@ -0,0 +1 @@
default: --format progress

1
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
output

7
doc/.gitscribe Normal file
View File

@@ -0,0 +1,7 @@
---
publish: true
edition: 0.1
language: en
version: 1.0
author: Your Name
cover: image/cover.jpg

9
doc/README.asciidoc Normal file
View File

@@ -0,0 +1,9 @@
This Book
=========
This book is written using using the git-scribe toolchain, which can be found at:
http://github.com/schacon/git-scribe
Instructions on how to install the tool and use it for things like editing this book,
submitting errata and providing translations can be found at that site.

10
doc/book/book.asc Normal file
View File

@@ -0,0 +1,10 @@
Jekyll
======
:Author: Tom Preston-Werner
:Email: <tom@mojombo.com>
include::ch00-preface.asc[]
include::ch01-quick-start.asc[]
include::ch02-directory-layout.asc[]

41
doc/book/ch00-preface.asc Normal file
View File

@@ -0,0 +1,41 @@
== Preface
Jekyll was born out the desire to create a blog engine that would make it
possible to write posts in my local text editor, version those posts with Git,
and keep up with my desire to tweak the styles and layout of my site.
In other words, I wanted something that fit into my existing software
development workflow and toolchain. Jekyll handles not only this case, but a
wide variety of other situations that call for static site generation based on
converted content and layout templates.
At its core, Jekyll is a text transformation engine. The concept behind the
system is this: you give it text written in your favorite markup language, be
that Markdown, Textile, or just plain HTML, and it churns that through a
layout or series of layout files. Throughout that process you can tweak how
you want the site URLs to look, what data gets displayed on the layout and
much more.
If you're looking for a simple, yet powerful solution to your blogging or
static site needs, Jekyll may be just what you've been looking for.
=== What this book covers
_Chapter 1, Quick Start_ covers installation, introduces the Jekyll command
line interface, and runs through a quick example demonstrating the site
generator, post generator and how to convert your Jekyll site into a static
site.
_Chapter 2, Directory Layout_ covers the various files and directories that
comprise a Jekyll site.
_Chapter 3, Tags and Filters_
_Chapter X, Deploying your Jekyll Site_
_Chapter X, Customizing Jekyll with Plugins_
_Chapter X, Migrating to Jekyll from your Existing Blog_
_Chapter X, Configuration Reference_

View File

@@ -0,0 +1,153 @@
== Chapter 1: Quick Start
This chapter is designed to get you up and running with Jekyll as quickly as
possible.
=== Installation
The best way to install Jekyll is via RubyGems:
----
gem install jekyll
----
This is all you need in order to get started with a basic Jekyll site. Some
options require additional packages to be installed.
If you encounter errors during gem installation, you may need to install the
header files for compiling extension modules for ruby 1.8:
.Debian
----
sudo apt-get install ruby1.8-dev
----
.Red Hat / CentOS / Fedora systems
----
sudo yum install ruby-devel
----
.NearlyFreeSpeech
----
RB_USER_INSTALL=true gem install jekyll
----
If you encounter errors like +Failed to build gem native extension+ on Windows
you may need to install http://wiki.github.com/oneclick/rubyinstaller/development-kit[RubyInstaller
DevKit].
==== LaTeX to PNG
Maruku comes with optional support for LaTeX to PNG rendering via blahtex
(Version 0.6) which must be in your $PATH along with @dvips@.
(NOTE: "remi's fork of Maruku":http://github.com/remi/maruku/tree/master does
not assume a fixed location for @dvips@ if you need that fixed)
==== RDiscount
If you prefer to use
http://github.com/rtomayko/rdiscount/tree/master[RDiscount] instead of
http://maruku.rubyforge.org/[Maruku] for markdown, just make sure it's
installed:
----
sudo gem install rdiscount
----
And run Jekyll with the following option:
----
jekyll --rdiscount
----
Or, in your @_config.yml@ file put the following so you don't have to specify the flag:
----
markdown: rdiscount
----
==== Pygments
If you want syntax highlighting via the @{% highlight %}@ tag in your posts,
you'll need to install http://pygments.org/[Pygments].
.On OSX with Homebrew
----
brew install pip && pip install pygments
----
.On OSX with MacPorts
----
sudo port install python25 py25-pygments
----
.Bare OS X Leopard
----
sudo easy_install Pygments
----
.Archlinux
----
sudo pacman -S python-pygments
----
.Archlinux python2 for Pygments
----
$ sudo pacman -S python2-pygments
----
NOTE: python2 pygments version creates a `pygmentize2` executable, while
Jekyll tries to find `pygmentize`. Either create a symlink `# ln -s
/usr/bin/pygmentize2 /usr/bin/pygmentize` or use the python3 version.
.Ubuntu and Debian
----
sudo apt-get install python-pygments
----
.Gentoo
----
$ sudo emerge -av dev-python/pygments
----
=== Creating your First Site
Jekyll comes with a handy generator that will create a barebones skeleton site
to help you get up and running in no time. Simply create an empty directory to
contain your site, navigate to it, and run the generator command:
----
$ mkdir mysite
$ cd mysite
$ jekyll gen
----
Make sure the directory is empty or Jekyll will refuse to run. If everything
was successful, you'll be left with a complete, valid Jekyll site that's ready
to be converted into a static site.
To perform the conversion, make sure you're in the root of your Jekyll site
directory and run:
----
$ jekyll --server
----
If all goes well, you should get a few lines with information about config
file detection, source and destination paths, and a success message.
The `--server` command line option fires up a simple web server that will
serve the static site we just generated so that we can easily preview what it
will look like once we deploy it to a production environment.
Open up your favorite web browser and navigate to:
----
http://localhost:4000
----
Congratulations! You have now successfully created and converted your first
Jekyll site!

View File

@@ -0,0 +1,90 @@
== Chapter 2: Directory Layout
If you followed the Quick Start in the last chapter, you have a Jekyll site on
your local machine. Let's take a closer look at it and see what makes it tick.
The file layout should look something like this:
----
.
|-- _config.yml
|-- _layouts
| |-- default.html
| `-- post.html
|-- _posts
| |-- 2007-10-29-why-every-programmer-should-play-nethack.textile
| `-- 2009-04-26-barcamp-boston-4-roundup.textile
|-- _site
|-- images
| `-- logo.png
`-- index.html
----
Notice that some of the files and directories begin with an underscore. These
have special meaning to Jekyll. The underscore ensures that they will not
interfere with the rest of your site's normal content. It also means that if
any of your normal files start with an underscore, they will cause problems,
so try to avoid this.
=== _config.yml
This file stores configuration data. A majority of these options can be
specified from the command line executable but it's easier to throw them in
here so you don't have to type them out every time. Detailed explanations of
configuration directives can be found in Chapter X.
=== _layouts
Files in this directory represent templates that can be used to wrap converted
pages. Layouts are defined on a page-by-page basis in the YAML front matter.
The liquid tag +{{ content }}+ specifies where the content will be placed
during the conversion process.
=== _posts
If you're using Jekyll as a blog engine, this is where you'll place your blog
posts. A post's filename contains several pieces of data, so you must be very
careful about how these files are named. The filename format is:
+YEAR-MONTH-DATE-SLUG.MARKUP+. The YEAR must be four numbers and the MONTH and
DATE must be two numbers each. The SLUG is what will appear in the URL. The
MARKUP tells Jekyll the format of the post. The date and slug will be used
along with any permalink options you specify (See Chapter X) to construct the
final URL of the post.
=== _site
This is where the generated site will be placed (by default) once Jekyll is
done transforming it. If you're using version control, you'll want to add this
directory to the list of files to be ignored.
=== Normal Files with YAML Front Matter
All files outside of the special underscore directories and that do not
themselves begin with an underscore will be scanned by Jekyll and subjected to
conversion if they contain any YAML front matter.
=== Everything Else
Any files and directories that do not fall into one of the above categories
will be copied to the static site as-is without modification. In this example,
+images/logo.png+ will be copied to the same location in the generated site.
h2. Running Jekyll
Usually this is done through the @jekyll@ executable, which is installed with
the gem. In order to get a server up and running with your Jekyll site, run:
@jekyll --server@
and then browse to http://0.0.0.0:4000. There's plenty of [[configuration
options|Configuration]] available to you as well.
On Debian or Ubuntu, you may need to add @/var/lib/gems/1.8/bin/@ to your path.
h2. Deployment
Since Jekyll simply generates a folder filled with HTML files, it can be
served using practically any available web server out there. Please check the
[[Deployment]] page for more information regarding specific scenarios.

View File

@@ -0,0 +1,94 @@
Feature: Create sites
As a hacker who likes to blog
I want to be able to make a static site
In order to share my awesome ideas with the interwebs
Scenario: Basic site
Given I have an "index.html" file that contains "Basic Site"
When I run jekyll
Then the _site directory should exist
And I should see "Basic Site" in "_site/index.html"
Scenario: Basic site with a post
Given I have a _posts directory
And I have the following post:
| title | date | content |
| Hackers | 3/27/2009 | My First Exploit |
When I run jekyll
Then the _site directory should exist
And I should see "My First Exploit" in "_site/2009/03/27/hackers.html"
Scenario: Basic site with layout and a page
Given I have a _layouts directory
And I have an "index.html" page with layout "default" that contains "Basic Site with Layout"
And I have a default layout that contains "Page Layout: {{ content }}"
When I run jekyll
Then the _site directory should exist
And I should see "Page Layout: Basic Site with Layout" in "_site/index.html"
Scenario: Basic site with layout and a post
Given I have a _layouts directory
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| Wargames | 3/27/2009 | default | The only winning move is not to play. |
And I have a default layout that contains "Post Layout: {{ content }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
Scenario: Basic site with layouts, pages, posts and files
Given I have a _layouts directory
And I have a page layout that contains "Page {{ page.title }}: {{ content }}"
And I have a post layout that contains "Post {{ page.title }}: {{ content }}"
And I have an "index.html" page with layout "page" that contains "Site contains {{ site.pages.size }} pages and {{ site.posts.size }} posts"
And I have a blog directory
And I have a "blog/index.html" page with layout "page" that contains "blog category index page"
And I have an "about.html" file that contains "No replacement {{ site.posts.size }}"
And I have an "another_file" file that contains ""
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| entry1 | 3/27/2009 | post | content for entry1. |
| entry2 | 4/27/2009 | post | content for entry2. |
And I have a category/_posts directory
And I have the following posts in "category":
| title | date | layout | content |
| entry3 | 5/27/2009 | post | content for entry3. |
| entry4 | 6/27/2009 | post | content for entry4. |
When I run jekyll
Then the _site directory should exist
And I should see "Page : Site contains 2 pages and 4 posts" in "_site/index.html"
And I should see "No replacement \{\{ site.posts.size \}\}" in "_site/about.html"
And I should see "" in "_site/another_file"
And I should see "Page : blog category index page" in "_site/blog/index.html"
And I should see "Post entry1: <p>content for entry1.</p>" in "_site/2009/03/27/entry1.html"
And I should see "Post entry2: <p>content for entry2.</p>" in "_site/2009/04/27/entry2.html"
And I should see "Post entry3: <p>content for entry3.</p>" in "_site/category/2009/05/27/entry3.html"
And I should see "Post entry4: <p>content for entry4.</p>" in "_site/category/2009/06/27/entry4.html"
Scenario: Basic site with include tag
Given I have a _includes directory
And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
And I have an "_includes/about.textile" file that contains "Generated by Jekyll"
When I run jekyll
Then the _site directory should exist
And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"
Scenario: Basic site with subdir include tag
Given I have a _includes directory
And I have an "_includes/about.textile" file that contains "Generated by Jekyll"
And I have an info directory
And I have an "info/index.html" page that contains "Basic Site with subdir include tag: {% include about.textile %}"
When I run jekyll
Then the _site directory should exist
And I should see "Basic Site with subdir include tag: Generated by Jekyll" in "_site/info/index.html"
Scenario: Basic site with nested include tag
Given I have a _includes directory
And I have an "_includes/about.textile" file that contains "Generated by {% include jekyll.textile %}"
And I have an "_includes/jekyll.textile" file that contains "Jekyll"
And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
When I debug jekyll
Then the _site directory should exist
And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"

View File

@@ -0,0 +1,60 @@
Feature: Embed filters
As a hacker who likes to blog
I want to be able to transform text inside a post or page
In order to perform cool stuff in my posts
Scenario: Convert date to XML schema
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | default | These aren't the droids you're looking for. |
And I have a default layout that contains "{{ site.time | date_to_xmlschema }}"
When I run jekyll
Then the _site directory should exist
And I should see today's date in "_site/2009/03/27/star-wars.html"
Scenario: Escape text for XML
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star & Wars | 3/27/2009 | default | These aren't the droids you're looking for. |
And I have a default layout that contains "{{ page.title | xml_escape }}"
When I run jekyll
Then the _site directory should exist
And I should see "Star &amp; Wars" in "_site/2009/03/27/star-wars.html"
Scenario: Calculate number of words
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | default | These aren't the droids you're looking for. |
And I have a default layout that contains "{{ content | xml_escape }}"
When I run jekyll
Then the _site directory should exist
And I should see "7" in "_site/2009/03/27/star-wars.html"
Scenario: Convert an array into a sentence
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | tags | content |
| Star Wars | 3/27/2009 | default | [scifi, movies, force] | These aren't the droids you're looking for. |
And I have a default layout that contains "{{ page.tags | array_to_sentence_string }}"
When I run jekyll
Then the _site directory should exist
And I should see "scifi, movies, and force" in "_site/2009/03/27/star-wars.html"
Scenario: Textilize a given string
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | default | These aren't the droids you're looking for. |
And I have a default layout that contains "By {{ '_Obi-wan_' | textilize }}"
When I run jekyll
Then the _site directory should exist
And I should see "By <p><em>Obi-wan</em></p>" in "_site/2009/03/27/star-wars.html"

30
features/markdown.feature Normal file
View File

@@ -0,0 +1,30 @@
Feature: Markdown
As a hacker who likes to blog
I want to be able to make a static site
In order to share my awesome ideas with the interwebs
Scenario: Markdown in list on index
Given I have a configuration file with "paginate" set to "5"
And I have an "index.html" page that contains "Index - {% for post in site.posts %} {{ post.content }} {% endfor %}"
And I have a _posts directory
And I have the following post:
| title | date | content | type |
| Hackers | 3/27/2009 | # My Title | markdown |
When I run jekyll
Then the _site directory should exist
And I should see "Index" in "_site/index.html"
And I should see "<h1 id='my_title'>My Title</h1>" in "_site/2009/03/27/hackers.html"
And I should see "<h1 id='my_title'>My Title</h1>" in "_site/index.html"
Scenario: Markdown in pagination on index
Given I have a configuration file with "paginate" set to "5"
And I have an "index.html" page that contains "Index - {% for post in paginator.posts %} {{ post.content }} {% endfor %}"
And I have a _posts directory
And I have the following post:
| title | date | content | type |
| Hackers | 3/27/2009 | # My Title | markdown |
When I run jekyll
Then the _site directory should exist
And I should see "Index" in "_site/index.html"
And I should see "<h1 id='my_title'>My Title</h1>" in "_site/index.html"

View File

@@ -0,0 +1,27 @@
Feature: Site pagination
In order to paginate my blog
As a blog's user
I want divide the posts in several pages
Scenario Outline: Paginate with N posts per page
Given I have a configuration file with "paginate" set to "<num>"
And I have a _layouts directory
And I have an "index.html" page that contains "{{ paginator.posts.size }}"
And I have a _posts directory
And I have the following post:
| title | date | layout | content |
| Wargames | 3/27/2009 | default | The only winning move is not to play. |
| Wargames2 | 4/27/2009 | default | The only winning move is not to play2. |
| Wargames3 | 5/27/2009 | default | The only winning move is not to play3. |
| Wargames4 | 6/27/2009 | default | The only winning move is not to play4. |
When I run jekyll
Then the _site/page<exist> directory should exist
And the "_site/page<exist>/index.html" file should exist
And I should see "<posts>" in "_site/page<exist>/index.html"
And the "_site/page<not_exist>/index.html" file should not exist
Examples:
| num | exist | posts | not_exist |
| 1 | 4 | 1 | 5 |
| 2 | 2 | 2 | 3 |
| 3 | 2 | 1 | 3 |

View File

@@ -0,0 +1,65 @@
Feature: Fancy permalinks
As a hacker who likes to blog
I want to be able to set permalinks
In order to make my blog URLs awesome
Scenario: Use none permalink schema
Given I have a _posts directory
And I have the following post:
| title | date | content |
| None Permalink Schema | 3/27/2009 | Totally nothing. |
And I have a configuration file with "permalink" set to "none"
When I run jekyll
Then the _site directory should exist
And I should see "Totally nothing." in "_site/none-permalink-schema.html"
Scenario: Use pretty permalink schema
Given I have a _posts directory
And I have the following post:
| title | date | content |
| Pretty Permalink Schema | 3/27/2009 | Totally wordpress. |
And I have a configuration file with "permalink" set to "pretty"
When I run jekyll
Then the _site directory should exist
And I should see "Totally wordpress." in "_site/2009/03/27/pretty-permalink-schema/index.html"
Scenario: Use pretty permalink schema for pages
Given I have an "index.html" page that contains "Totally index"
And I have an "awesome.html" page that contains "Totally awesome"
And I have an "sitemap.xml" page that contains "Totally uhm, sitemap"
And I have a configuration file with "permalink" set to "pretty"
When I run jekyll
Then the _site directory should exist
And I should see "Totally index" in "_site/index.html"
And I should see "Totally awesome" in "_site/awesome/index.html"
And I should see "Totally uhm, sitemap" in "_site/sitemap.xml"
Scenario: Use custom permalink schema with prefix
Given I have a _posts directory
And I have the following post:
| title | category | date | content |
| Custom Permalink Schema | stuff | 3/27/2009 | Totally custom. |
And I have a configuration file with "permalink" set to "/blog/:year/:month/:day/:title"
When I run jekyll
Then the _site directory should exist
And I should see "Totally custom." in "_site/blog/2009/03/27/custom-permalink-schema/index.html"
Scenario: Use custom permalink schema with category
Given I have a _posts directory
And I have the following post:
| title | category | date | content |
| Custom Permalink Schema | stuff | 3/27/2009 | Totally custom. |
And I have a configuration file with "permalink" set to "/:categories/:title.html"
When I run jekyll
Then the _site directory should exist
And I should see "Totally custom." in "_site/stuff/custom-permalink-schema.html"
Scenario: Use custom permalink schema with squished date
Given I have a _posts directory
And I have the following post:
| title | category | date | content |
| Custom Permalink Schema | stuff | 3/27/2009 | Totally custom. |
And I have a configuration file with "permalink" set to "/:month-:day-:year/:title.html"
When I run jekyll
Then the _site directory should exist
And I should see "Totally custom." in "_site/03-27-2009/custom-permalink-schema.html"

153
features/post_data.feature Normal file
View File

@@ -0,0 +1,153 @@
Feature: Post data
As a hacker who likes to blog
I want to be able to embed data into my posts
In order to make the posts slightly dynamic
Scenario: Use post.title variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post title: {{ page.title }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post title: Star Wars" in "_site/2009/03/27/star-wars.html"
Scenario: Use post.url variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post url: {{ page.url }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post url: /2009/03/27/star-wars.html" in "_site/2009/03/27/star-wars.html"
Scenario: Use post.date variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post date: {{ page.date }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post date: Fri Mar 27" in "_site/2009/03/27/star-wars.html"
Scenario: Use post.id variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post id: {{ page.id }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post id: /2009/03/27/star-wars" in "_site/2009/03/27/star-wars.html"
Scenario: Use post.content variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post content: {{ content }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post content: <p>Luke, I am your father.</p>" in "_site/2009/03/27/star-wars.html"
Scenario: Use post.categories variable when category is in a folder
Given I have a movies directory
And I have a movies/_posts directory
And I have a _layouts directory
And I have the following post in "movies":
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post category: {{ page.categories }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
Scenario: Use post.tags variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | tag | content |
| Star Wars | 5/18/2009 | simple | twist | Luke, I am your father. |
And I have a simple layout that contains "Post tags: {{ page.tags }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post tags: twist" in "_site/2009/05/18/star-wars.html"
Scenario: Use post.categories variable when categories are in folders
Given I have a scifi directory
And I have a scifi/movies directory
And I have a scifi/movies/_posts directory
And I have a _layouts directory
And I have the following post in "scifi/movies":
| title | date | layout | content |
| Star Wars | 3/27/2009 | simple | Luke, I am your father. |
And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post categories: scifi and movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
Scenario: Use post.categories variable when category is in YAML
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | category | content |
| Star Wars | 3/27/2009 | simple | movies | Luke, I am your father. |
And I have a simple layout that contains "Post category: {{ page.categories }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
Scenario: Use post.categories variable when categories are in YAML
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | categories | content |
| Star Wars | 3/27/2009 | simple | ['scifi', 'movies'] | Luke, I am your father. |
And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post categories: scifi and movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
Scenario: Disable a post from being published
Given I have a _posts directory
And I have an "index.html" file that contains "Published!"
And I have the following post:
| title | date | layout | published | content |
| Star Wars | 3/27/2009 | simple | false | Luke, I am your father. |
When I run jekyll
Then the _site directory should exist
And the "_site/2009/03/27/star-wars.html" file should not exist
And I should see "Published!" in "_site/index.html"
Scenario: Use a custom variable
Given I have a _posts directory
And I have a _layouts directory
And I have the following post:
| title | date | layout | author | content |
| Star Wars | 3/27/2009 | simple | Darth Vader | Luke, I am your father. |
And I have a simple layout that contains "Post author: {{ page.author }}"
When I run jekyll
Then the _site directory should exist
And I should see "Post author: Darth Vader" in "_site/2009/03/27/star-wars.html"
Scenario: Previous and next posts title
Given I have a _posts directory
And I have a _layouts directory
And I have the following posts:
| title | date | layout | author | content |
| Star Wars | 3/27/2009 | ordered | Darth Vader | Luke, I am your father. |
| Some like it hot | 4/27/2009 | ordered | Osgood | Nobody is perfect. |
| Terminator | 5/27/2009 | ordered | Arnold | Sayonara, baby |
And I have a ordered layout that contains "Previous post: {{ page.previous.title }} and next post: {{ page.next.title }}"
When I run jekyll
Then the _site directory should exist
And I should see "next post: Some like it hot" in "_site/2009/03/27/star-wars.html"
And I should see "Previous post: Some like it hot" in "_site/2009/05/27/terminator.html"

View File

@@ -0,0 +1,126 @@
Feature: Site configuration
As a hacker who likes to blog
I want to be able to configure jekyll
In order to make setting up a site easier
Scenario: Change destination directory
Given I have a blank site in "_sourcedir"
And I have an "_sourcedir/index.html" file that contains "Changing source directory"
And I have a configuration file with "source" set to "_sourcedir"
When I run jekyll
Then the _site directory should exist
And I should see "Changing source directory" in "_site/index.html"
Scenario: Change destination directory
Given I have an "index.html" file that contains "Changing destination directory"
And I have a configuration file with "destination" set to "_mysite"
When I run jekyll
Then the _mysite directory should exist
And I should see "Changing destination directory" in "_mysite/index.html"
Scenario: Exclude files inline
Given I have an "Rakefile" file that contains "I want to be excluded"
And I have an "README" file that contains "I want to be excluded"
And I have an "index.html" file that contains "I want to be included"
And I have a configuration file with "exclude" set to "Rakefile", "README"
When I run jekyll
Then I should see "I want to be included" in "_site/index.html"
And the "_site/Rakefile" file should not exist
And the "_site/README" file should not exist
Scenario: Exclude files with YAML array
Given I have an "Rakefile" file that contains "I want to be excluded"
And I have an "README" file that contains "I want to be excluded"
And I have an "index.html" file that contains "I want to be included"
And I have a configuration file with "exclude" set to:
| value |
| README |
| Rakefile |
When I run jekyll
Then I should see "I want to be included" in "_site/index.html"
And the "_site/Rakefile" file should not exist
And the "_site/README" file should not exist
Scenario: Use RDiscount for markup
Given I have an "index.markdown" page that contains "[Google](http://google.com)"
And I have a configuration file with "markdown" set to "rdiscount"
When I run jekyll
Then the _site directory should exist
And I should see "<a href="http://google.com">Google</a>" in "_site/index.html"
Scenario: Use Kramdown for markup
Given I have an "index.markdown" page that contains "[Google](http://google.com)"
And I have a configuration file with "markdown" set to "kramdown"
When I run jekyll
Then the _site directory should exist
And I should see "<a href="http://google.com">Google</a>" in "_site/index.html"
Scenario: Use Maruku for markup
Given I have an "index.markdown" page that contains "[Google](http://google.com)"
And I have a configuration file with "markdown" set to "maruku"
When I run jekyll
Then the _site directory should exist
And I should see "<a href='http://google.com'>Google</a>" in "_site/index.html"
Scenario: Highlight code with pygments
Given I have an "index.html" file that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}"
And I have a configuration file with "pygments" set to "true"
When I run jekyll
Then the _site directory should exist
And I should see "puts 'Hello world!'" in "_site/index.html"
Scenario: Set time and no future dated posts
Given I have a _layouts directory
And I have a page layout that contains "Page Layout: {{ site.posts.size }} on {{ site.time | date: "%Y-%m-%d" }}"
And I have a post layout that contains "Post Layout: {{ content }}"
And I have an "index.html" page with layout "page" that contains "site index page"
And I have a configuration file with:
| key | value |
| time | 2010-01-01 |
| future | false |
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| entry1 | 12/31/2007 | post | content for entry1. |
| entry2 | 01/31/2020 | post | content for entry2. |
When I run jekyll
Then the _site directory should exist
And I should see "Page Layout: 1 on 2010-01-01" in "_site/index.html"
And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
And the "_site/2020/01/31/entry2.html" file should not exist
Scenario: Set time and future dated posts allowed
Given I have a _layouts directory
And I have a page layout that contains "Page Layout: {{ site.posts.size }} on {{ site.time | date: "%Y-%m-%d" }}"
And I have a post layout that contains "Post Layout: {{ content }}"
And I have an "index.html" page with layout "page" that contains "site index page"
And I have a configuration file with:
| key | value |
| time | 2010-01-01 |
| future | true |
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| entry1 | 12/31/2007 | post | content for entry1. |
| entry2 | 01/31/2020 | post | content for entry2. |
When I run jekyll
Then the _site directory should exist
And I should see "Page Layout: 2 on 2010-01-01" in "_site/index.html"
And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"
Scenario: Limit the number of posts generated by most recent date
Given I have a _posts directory
And I have a configuration file with:
| key | value |
| limit_posts | 2 |
And I have the following posts:
| title | date | content |
| Apples | 3/27/2009 | An article about apples |
| Oranges | 4/1/2009 | An article about oranges |
| Bananas | 4/5/2009 | An article about bananas |
When I run jekyll
Then the _site directory should exist
And the "_site/2009/04/05/bananas.html" file should exist
And the "_site/2009/04/01/oranges.html" file should exist
And the "_site/2009/03/27/apples.html" file should not exist

View File

@@ -0,0 +1,82 @@
Feature: Site data
As a hacker who likes to blog
I want to be able to embed data into my site
In order to make the site slightly dynamic
Scenario: Use page variable in a page
Given I have an "contact.html" page with title "Contact" that contains "{{ page.title }}: email@me.com"
When I run jekyll
Then the _site directory should exist
And I should see "Contact: email@me.com" in "_site/contact.html"
Scenario: Use site.time variable
Given I have an "index.html" page that contains "{{ site.time }}"
When I run jekyll
Then the _site directory should exist
And I should see today's time in "_site/index.html"
Scenario: Use site.posts variable for latest post
Given I have a _posts directory
And I have an "index.html" page that contains "{{ site.posts.first.title }}: {{ site.posts.first.url }}"
And I have the following posts:
| title | date | content |
| First Post | 3/25/2009 | My First Post |
| Second Post | 3/26/2009 | My Second Post |
| Third Post | 3/27/2009 | My Third Post |
When I run jekyll
Then the _site directory should exist
And I should see "Third Post: /2009/03/27/third-post.html" in "_site/index.html"
Scenario: Use site.posts variable in a loop
Given I have a _posts directory
And I have an "index.html" page that contains "{% for post in site.posts %} {{ post.title }} {% endfor %}"
And I have the following posts:
| title | date | content |
| First Post | 3/25/2009 | My First Post |
| Second Post | 3/26/2009 | My Second Post |
| Third Post | 3/27/2009 | My Third Post |
When I run jekyll
Then the _site directory should exist
And I should see "Third Post Second Post First Post" in "_site/index.html"
Scenario: Use site.categories.code variable
Given I have a _posts directory
And I have an "index.html" page that contains "{% for post in site.categories.code %} {{ post.title }} {% endfor %}"
And I have the following posts:
| title | date | category | content |
| Awesome Hack | 3/26/2009 | code | puts 'Hello World' |
| Delicious Beer | 3/26/2009 | food | 1) Yuengling |
When I run jekyll
Then the _site directory should exist
And I should see "Awesome Hack" in "_site/index.html"
Scenario: Use site.tags variable
Given I have a _posts directory
And I have an "index.html" page that contains "{% for post in site.tags.beer %} {{ post.content }} {% endfor %}"
And I have the following posts:
| title | date | tag | content |
| Delicious Beer | 3/26/2009 | beer | 1) Yuengling |
When I run jekyll
Then the _site directory should exist
And I should see "Yuengling" in "_site/index.html"
Scenario: Order Posts by name when on the same date
Given I have a _posts directory
And I have an "index.html" page that contains "{% for post in site.posts %}{{ post.title }}:{{ post.previous.title}},{{ post.next.title}} {% endfor %}"
And I have the following posts:
| title | date | content |
| first | 2/26/2009 | first |
| A | 3/26/2009 | A |
| B | 3/26/2009 | B |
| C | 3/26/2009 | C |
| last | 4/26/2009 | last |
When I run jekyll
Then the _site directory should exist
And I should see "last:C, C:B,last B:A,C A:first,B first:,A" in "_site/index.html"
Scenario: Use configuration date in site payload
Given I have an "index.html" page that contains "{{ site.url }}"
And I have a configuration file with "url" set to "http://mysite.com"
When I run jekyll
Then the _site directory should exist
And I should see "http://mysite.com" in "_site/index.html"

View File

@@ -0,0 +1,145 @@
Before do
FileUtils.mkdir(TEST_DIR)
Dir.chdir(TEST_DIR)
end
After do
Dir.chdir(TEST_DIR)
FileUtils.rm_rf(TEST_DIR)
end
Given /^I have a blank site in "(.*)"$/ do |path|
FileUtils.mkdir(path)
end
# Like "I have a foo file" but gives a yaml front matter so jekyll actually processes it
Given /^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$/ do |file, key, value, text|
File.open(file, 'w') do |f|
f.write <<EOF
---
#{key || 'layout'}: #{value || 'nil'}
---
#{text}
EOF
f.close
end
end
Given /^I have an? "(.*)" file that contains "(.*)"$/ do |file, text|
File.open(file, 'w') do |f|
f.write(text)
f.close
end
end
Given /^I have a (.*) layout that contains "(.*)"$/ do |layout, text|
File.open(File.join('_layouts', layout + '.html'), 'w') do |f|
f.write(text)
f.close
end
end
Given /^I have an? (.*) directory$/ do |dir|
FileUtils.mkdir_p(dir)
end
Given /^I have the following posts?(?: (.*) "(.*)")?:$/ do |direction, folder, table|
table.hashes.each do |post|
date = Date.strptime(post['date'], '%m/%d/%Y').strftime('%Y-%m-%d')
title = post['title'].downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
if direction && direction == "in"
before = folder || '.'
elsif direction && direction == "under"
after = folder || '.'
end
path = File.join(before || '.', '_posts', after || '.', "#{date}-#{title}.#{post['type'] || 'textile'}")
matter_hash = {}
%w(title layout tag tags category categories published author).each do |key|
matter_hash[key] = post[key] if post[key]
end
matter = matter_hash.map { |k, v| "#{k}: #{v}\n" }.join.chomp
content = post['content']
if post['input'] && post['filter']
content = "{{ #{post['input']} | #{post['filter']} }}"
end
File.open(path, 'w') do |f|
f.write <<EOF
---
#{matter}
---
#{content}
EOF
f.close
end
end
end
Given /^I have a configuration file with "(.*)" set to "(.*)"$/ do |key, value|
File.open('_config.yml', 'w') do |f|
f.write("#{key}: #{value}\n")
f.close
end
end
Given /^I have a configuration file with:$/ do |table|
File.open('_config.yml', 'w') do |f|
table.hashes.each do |row|
f.write("#{row["key"]}: #{row["value"]}\n")
end
f.close
end
end
Given /^I have a configuration file with "([^\"]*)" set to:$/ do |key, table|
File.open('_config.yml', 'w') do |f|
f.write("#{key}:\n")
table.hashes.each do |row|
f.write("- #{row["value"]}\n")
end
f.close
end
end
When /^I run jekyll$/ do
run_jekyll
end
When /^I debug jekyll$/ do
run_jekyll(:debug => true)
end
When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
File.open(file, 'a') do |f|
f.write(text)
end
end
Then /^the (.*) directory should exist$/ do |dir|
assert File.directory?(dir)
end
Then /^I should see "(.*)" in "(.*)"$/ do |text, file|
assert_match Regexp.new(text), File.open(file).readlines.join
end
Then /^the "(.*)" file should exist$/ do |file|
assert File.file?(file)
end
Then /^the "(.*)" file should not exist$/ do |file|
assert !File.exists?(file)
end
Then /^I should see today's time in "(.*)"$/ do |file|
assert_match Regexp.new(Regexp.escape(Time.now.to_s)), File.open(file).readlines.join
end
Then /^I should see today's date in "(.*)"$/ do |file|
assert_match Regexp.new(Date.today.to_s), File.open(file).readlines.join
end

19
features/support/env.rb Normal file
View File

@@ -0,0 +1,19 @@
require 'fileutils'
require 'rr'
require 'test/unit'
World do
include Test::Unit::Assertions
end
TEST_DIR = File.join('/', 'tmp', 'jekyll')
JEKYLL_PATH = File.join(ENV['PWD'], 'bin', 'jekyll')
def run_jekyll(opts = {})
command = JEKYLL_PATH
command << " >> /dev/null 2>&1" if opts[:debug].nil?
system command
end
# work around "invalid option: --format" cucumber bug (see #296)
Test::Unit.run = true

View File

@@ -1,48 +1,142 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{jekyll}
s.version = "0.4.0"
s.specification_version = 2 if s.respond_to? :specification_version=
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Tom Preston-Werner"]
s.date = %q{2009-02-03}
s.description = %q{Jekyll is a simple, blog aware, static site generator.}
s.email = %q{tom@mojombo.com}
s.files = ["History.txt", "README.textile", "VERSION.yml", "bin/jekyll", "lib/jekyll", "lib/jekyll/albino.rb", "lib/jekyll/converters", "lib/jekyll/converters/csv.rb", "lib/jekyll/converters/mephisto.rb", "lib/jekyll/converters/mt.rb", "lib/jekyll/converters/textpattern.rb", "lib/jekyll/converters/typo.rb", "lib/jekyll/converters/wordpress.rb", "lib/jekyll/convertible.rb", "lib/jekyll/core_ext.rb", "lib/jekyll/filters.rb", "lib/jekyll/layout.rb", "lib/jekyll/page.rb", "lib/jekyll/post.rb", "lib/jekyll/site.rb", "lib/jekyll/tags", "lib/jekyll/tags/highlight.rb", "lib/jekyll/tags/include.rb", "lib/jekyll.rb", "test/dest", "test/dest/2008", "test/dest/2008/10", "test/dest/2008/10/18", "test/dest/2008/10/18/foo-bar.html", "test/dest/2008/11", "test/dest/2008/11/21", "test/dest/2008/11/21/complex.html", "test/dest/2008/12", "test/dest/2008/12/13", "test/dest/2008/12/13/include.html", "test/dest/_posts", "test/dest/_posts/2008-10-18-foo-bar.html", "test/dest/_posts/2008-11-21-complex.html", "test/dest/_posts/2008-12-03-permalinked-post.html", "test/dest/_posts/2008-12-13-include.html", "test/dest/category", "test/dest/category/2008", "test/dest/category/2008/09", "test/dest/category/2008/09/23", "test/dest/category/2008/09/23/categories.html", "test/dest/category/_posts", "test/dest/category/_posts/2008-9-23-categories.html", "test/dest/css", "test/dest/css/screen.css", "test/dest/foo", "test/dest/foo/2008", "test/dest/foo/2008/12", "test/dest/foo/2008/12/12", "test/dest/foo/2008/12/12/topical-post.html", "test/dest/foo/_posts", "test/dest/foo/_posts/bar", "test/dest/foo/_posts/bar/2008-12-12-topical-post.html", "test/dest/index.html", "test/dest/my_category", "test/dest/my_category/permalinked-post", "test/dest/z_category", "test/dest/z_category/2008", "test/dest/z_category/2008/09", "test/dest/z_category/2008/09/23", "test/dest/z_category/2008/09/23/categories.html", "test/dest/z_category/_posts", "test/dest/z_category/_posts/2008-9-23-categories.html", "test/helper.rb", "test/source", "test/source/_includes", "test/source/_includes/sig.markdown", "test/source/_layouts", "test/source/_layouts/default.html", "test/source/_layouts/simple.html", "test/source/_posts", "test/source/_posts/2008-10-18-foo-bar.textile", "test/source/_posts/2008-11-21-complex.textile", "test/source/_posts/2008-12-03-permalinked-post.textile", "test/source/_posts/2008-12-13-include.markdown", "test/source/category", "test/source/category/_posts", "test/source/category/_posts/2008-9-23-categories.textile", "test/source/css", "test/source/css/screen.css", "test/source/foo", "test/source/foo/_posts", "test/source/foo/_posts/bar", "test/source/foo/_posts/bar/2008-12-12-topical-post.textile", "test/source/index.html", "test/source/z_category", "test/source/z_category/_posts", "test/source/z_category/_posts/2008-9-23-categories.textile", "test/suite.rb", "test/test_filters.rb", "test/test_generated_site.rb", "test/test_jekyll.rb", "test/test_post.rb", "test/test_site.rb", "test/test_tags.rb"]
s.has_rdoc = true
s.homepage = %q{http://github.com/mojombo/jekyll}
s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{jekyll}
s.rubygems_version = %q{1.3.0}
s.summary = %q{Jekyll is a simple, blog aware, static site generator.}
s.rubygems_version = '1.3.5'
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 2
s.name = 'jekyll'
s.version = '0.10.0'
s.date = '2010-12-16'
s.rubyforge_project = 'jekyll'
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<RedCloth>, [">= 4.0.4"])
s.add_runtime_dependency(%q<liquid>, [">= 1.9.0"])
s.add_runtime_dependency(%q<classifier>, [">= 1.3.1"])
s.add_runtime_dependency(%q<maruku>, [">= 0.5.9"])
s.add_runtime_dependency(%q<directory_watcher>, [">= 1.1.1"])
s.add_runtime_dependency(%q<open4>, [">= 0.9.6"])
else
s.add_dependency(%q<RedCloth>, [">= 4.0.4"])
s.add_dependency(%q<liquid>, [">= 1.9.0"])
s.add_dependency(%q<classifier>, [">= 1.3.1"])
s.add_dependency(%q<maruku>, [">= 0.5.9"])
s.add_dependency(%q<directory_watcher>, [">= 1.1.1"])
s.add_dependency(%q<open4>, [">= 0.9.6"])
end
else
s.add_dependency(%q<RedCloth>, [">= 4.0.4"])
s.add_dependency(%q<liquid>, [">= 1.9.0"])
s.add_dependency(%q<classifier>, [">= 1.3.1"])
s.add_dependency(%q<maruku>, [">= 0.5.9"])
s.add_dependency(%q<directory_watcher>, [">= 1.1.1"])
s.add_dependency(%q<open4>, [">= 0.9.6"])
end
s.summary = "A simple, blog aware, static site generator."
s.description = "Jekyll is a simple, blog aware, static site generator."
s.authors = ["Tom Preston-Werner"]
s.email = 'tom@mojombo.com'
s.homepage = 'http://github.com/mojombo/jekyll'
s.require_paths = %w[lib]
s.executables = ["jekyll"]
s.default_executable = 'jekyll'
s.rdoc_options = ["--charset=UTF-8"]
s.extra_rdoc_files = %w[README.textile LICENSE]
s.add_runtime_dependency('liquid', ">= 1.9.0")
s.add_runtime_dependency('classifier', ">= 1.3.1")
s.add_runtime_dependency('directory_watcher', ">= 1.1.1")
s.add_runtime_dependency('maruku', ">= 0.5.9")
s.add_runtime_dependency('kramdown', ">= 0.13.2")
s.add_runtime_dependency('albino', ">= 1.3.2")
s.add_development_dependency('redgreen', ">= 1.2.2")
s.add_development_dependency('shoulda', ">= 2.11.3")
s.add_development_dependency('rr', ">= 1.0.2")
s.add_development_dependency('cucumber', ">= 0.10.0")
s.add_development_dependency('RedCloth', ">= 4.2.1")
s.add_development_dependency('rdiscount', ">= 1.6.5")
# = MANIFEST =
s.files = %w[
History.txt
LICENSE
README.textile
Rakefile
bin/jekyll
cucumber.yml
features/create_sites.feature
features/embed_filters.feature
features/markdown.feature
features/pagination.feature
features/permalinks.feature
features/post_data.feature
features/site_configuration.feature
features/site_data.feature
features/step_definitions/jekyll_steps.rb
features/support/env.rb
jekyll.gemspec
lib/jekyll.rb
lib/jekyll/albino.rb
lib/jekyll/converter.rb
lib/jekyll/converters/identity.rb
lib/jekyll/converters/markdown.rb
lib/jekyll/converters/textile.rb
lib/jekyll/convertible.rb
lib/jekyll/core_ext.rb
lib/jekyll/errors.rb
lib/jekyll/filters.rb
lib/jekyll/generator.rb
lib/jekyll/generators/pagination.rb
lib/jekyll/layout.rb
lib/jekyll/migrators/csv.rb
lib/jekyll/migrators/drupal.rb
lib/jekyll/migrators/marley.rb
lib/jekyll/migrators/mephisto.rb
lib/jekyll/migrators/mt.rb
lib/jekyll/migrators/textpattern.rb
lib/jekyll/migrators/typo.rb
lib/jekyll/migrators/wordpress.com.rb
lib/jekyll/migrators/wordpress.rb
lib/jekyll/page.rb
lib/jekyll/plugin.rb
lib/jekyll/post.rb
lib/jekyll/site.rb
lib/jekyll/static_file.rb
lib/jekyll/tags/highlight.rb
lib/jekyll/tags/include.rb
test/helper.rb
test/source/.htaccess
test/source/_includes/sig.markdown
test/source/_layouts/default.html
test/source/_layouts/simple.html
test/source/_posts/2008-02-02-not-published.textile
test/source/_posts/2008-02-02-published.textile
test/source/_posts/2008-10-18-foo-bar.textile
test/source/_posts/2008-11-21-complex.textile
test/source/_posts/2008-12-03-permalinked-post.textile
test/source/_posts/2008-12-13-include.markdown
test/source/_posts/2009-01-27-array-categories.textile
test/source/_posts/2009-01-27-categories.textile
test/source/_posts/2009-01-27-category.textile
test/source/_posts/2009-01-27-empty-categories.textile
test/source/_posts/2009-01-27-empty-category.textile
test/source/_posts/2009-03-12-hash-#1.markdown
test/source/_posts/2009-05-18-empty-tag.textile
test/source/_posts/2009-05-18-empty-tags.textile
test/source/_posts/2009-05-18-tag.textile
test/source/_posts/2009-05-18-tags.textile
test/source/_posts/2009-06-22-empty-yaml.textile
test/source/_posts/2009-06-22-no-yaml.textile
test/source/_posts/2010-01-08-triple-dash.markdown
test/source/_posts/2010-01-09-date-override.textile
test/source/_posts/2010-01-09-time-override.textile
test/source/_posts/2010-01-09-timezone-override.textile
test/source/_posts/2010-01-16-override-data.textile
test/source/about.html
test/source/category/_posts/2008-9-23-categories.textile
test/source/contacts.html
test/source/css/screen.css
test/source/deal.with.dots.html
test/source/foo/_posts/bar/2008-12-12-topical-post.textile
test/source/index.html
test/source/sitemap.xml
test/source/win/_posts/2009-05-24-yaml-linebreak.markdown
test/source/z_category/_posts/2008-9-23-categories.textile
test/suite.rb
test/test_configuration.rb
test/test_core_ext.rb
test/test_filters.rb
test/test_generated_site.rb
test/test_kramdown.rb
test/test_page.rb
test/test_pager.rb
test/test_post.rb
test/test_rdiscount.rb
test/test_site.rb
test/test_tags.rb
]
# = MANIFEST =
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
end

View File

@@ -1,34 +1,30 @@
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
# Require all of the Ruby files in the given directory.
#
# path - The String relative path from here to the directory.
#
# Returns nothing.
def require_all(path)
glob = File.join(File.dirname(__FILE__), path, '*.rb')
Dir[glob].each do |f|
require f
end
end
# rubygems
require 'rubygems'
# core
# stdlib
require 'fileutils'
require 'time'
require 'yaml'
# stdlib
require 'English'
# 3rd party
require 'liquid'
require 'redcloth'
begin
require 'maruku'
require 'maruku/ext/math'
# Switch off MathML output
MaRuKu::Globals[:html_math_output_mathml] = false
MaRuKu::Globals[:html_math_engine] = 'none'
# Turn on math to PNG support with blahtex
# Resulting PNGs stored in `images/latex`
MaRuKu::Globals[:html_math_output_png] = true
MaRuKu::Globals[:html_png_engine] = 'blahtex'
MaRuKu::Globals[:html_png_dir] = 'images/latex'
MaRuKu::Globals[:html_png_url] = '/images/latex/'
rescue LoadError
puts "The maruku gem is required for markdown support!"
end
require 'maruku'
require 'albino'
# internal requires
require 'jekyll/core_ext'
@@ -38,27 +34,93 @@ require 'jekyll/layout'
require 'jekyll/page'
require 'jekyll/post'
require 'jekyll/filters'
require 'jekyll/tags/highlight'
require 'jekyll/tags/include'
require 'jekyll/albino'
require 'jekyll/static_file'
require 'jekyll/errors'
# extensions
require 'jekyll/plugin'
require 'jekyll/converter'
require 'jekyll/generator'
require_all 'jekyll/converters'
require_all 'jekyll/generators'
require_all 'jekyll/tags'
module Jekyll
VERSION = '0.3.0'
class << self
attr_accessor :source, :dest, :lsi, :pygments, :markdown_proc, :content_type, :permalink_style
end
Jekyll.lsi = false
Jekyll.pygments = false
Jekyll.markdown_proc = Proc.new { |x| Maruku.new(x).to_html }
Jekyll.permalink_style = :date
def self.process(source, dest)
require 'classifier' if Jekyll.lsi
Jekyll.source = source
Jekyll.dest = dest
Jekyll::Site.new(source, dest).process
VERSION = '0.10.0'
# Default options. Overriden by values in _config.yml or command-line opts.
# (Strings rather symbols used for compatability with YAML).
DEFAULTS = {
'safe' => false,
'auto' => false,
'server' => false,
'server_port' => 4000,
'source' => Dir.pwd,
'destination' => File.join(Dir.pwd, '_site'),
'plugins' => File.join(Dir.pwd, '_plugins'),
'future' => true,
'lsi' => false,
'pygments' => false,
'markdown' => 'maruku',
'permalink' => 'date',
'maruku' => {
'use_tex' => false,
'use_divs' => false,
'png_engine' => 'blahtex',
'png_dir' => 'images/latex',
'png_url' => '/images/latex'
},
'rdiscount' => {
'extensions' => []
},
'kramdown' => {
'auto_ids' => true,
'footnote_nr' => 1,
'entity_output' => 'as_char',
'toc_levels' => '1..6',
'use_coderay' => false,
'coderay' => {
'coderay_wrap' => 'div',
'coderay_line_numbers' => 'inline',
'coderay_line_number_start' => 1,
'coderay_tab_width' => 4,
'coderay_bold_every' => 10,
'coderay_css' => 'style'
}
}
}
# Generate a Jekyll configuration Hash by merging the default options
# with anything in _config.yml, and adding the given options on top.
#
# override - A Hash of config directives that override any options in both
# the defaults and the config file. See Jekyll::DEFAULTS for a
# list of option names and their defaults.
#
# Returns the final configuration Hash.
def self.configuration(override)
# _config.yml may override default source location, but until
# then, we need to know where to look for _config.yml
source = override['source'] || Jekyll::DEFAULTS['source']
# Get configuration from <source>/_config.yml
config_file = File.join(source, '_config.yml')
begin
config = YAML.load_file(config_file)
raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
$stdout.puts "Configuration from #{config_file}"
rescue => err
$stderr.puts "WARNING: Could not read configuration. " +
"Using defaults (and options)."
$stderr.puts "\t" + err.to_s
config = {}
end
# Merge DEFAULTS < _config.yml < override
Jekyll::DEFAULTS.deep_merge(config).deep_merge(override)
end
end

View File

@@ -1,116 +0,0 @@
##
# Wrapper for the Pygments command line tool, pygmentize.
#
# Pygments: http://pygments.org/
#
# Assumes pygmentize is in the path. If not, set its location
# with Albino.bin = '/path/to/pygmentize'
#
# Use like so:
#
# @syntaxer = Albino.new('/some/file.rb', :ruby)
# puts @syntaxer.colorize
#
# This'll print out an HTMLized, Ruby-highlighted version
# of '/some/file.rb'.
#
# To use another formatter, pass it as the third argument:
#
# @syntaxer = Albino.new('/some/file.rb', :ruby, :bbcode)
# puts @syntaxer.colorize
#
# You can also use the #colorize class method:
#
# puts Albino.colorize('/some/file.rb', :ruby)
#
# Another also: you get a #to_s, for somewhat nicer use in Rails views.
#
# ... helper file ...
# def highlight(text)
# Albino.new(text, :ruby)
# end
#
# ... view file ...
# <%= highlight text %>
#
# The default lexer is 'text'. You need to specify a lexer yourself;
# because we are using STDIN there is no auto-detect.
#
# To see all lexers and formatters available, run `pygmentize -L`.
#
# Chris Wanstrath // chris@ozmm.org
# GitHub // http://github.com
#
require 'open4'
class Albino
@@bin = Rails.development? ? 'pygmentize' : '/usr/bin/pygmentize' rescue 'pygmentize'
def self.bin=(path)
@@bin = path
end
def self.colorize(*args)
new(*args).colorize
end
def initialize(target, lexer = :text, format = :html)
@target = File.exists?(target) ? File.read(target) : target rescue target
@options = { :l => lexer, :f => format }
end
def execute(command)
pid, stdin, stdout, stderr = Open4.popen4(command)
stdin.puts @target
stdin.close
stdout.read.strip
end
def colorize(options = {})
execute @@bin + convert_options(options)
end
alias_method :to_s, :colorize
def convert_options(options = {})
@options.merge(options).inject('') do |string, (flag, value)|
string + " -#{flag} #{value}"
end
end
end
if $0 == __FILE__
require 'rubygems'
require 'test/spec'
require 'mocha'
begin require 'redgreen'; rescue LoadError; end
context "Albino" do
setup do
@syntaxer = Albino.new(__FILE__, :ruby)
end
specify "defaults to text" do
syntaxer = Albino.new(__FILE__)
syntaxer.expects(:execute).with('pygmentize -f html -l text').returns(true)
syntaxer.colorize
end
specify "accepts options" do
@syntaxer.expects(:execute).with('pygmentize -f html -l ruby').returns(true)
@syntaxer.colorize
end
specify "works with strings" do
syntaxer = Albino.new('class New; end', :ruby)
assert_match %r(highlight), syntaxer.colorize
end
specify "aliases to_s" do
assert_equal @syntaxer.colorize, @syntaxer.to_s
end
specify "class method colorize" do
assert_equal @syntaxer.colorize, Albino.colorize(__FILE__, :ruby)
end
end
end

50
lib/jekyll/converter.rb Normal file
View File

@@ -0,0 +1,50 @@
module Jekyll
class Converter < Plugin
# Public: Get or set the pygments prefix. When an argument is specified,
# the prefix will be set. If no argument is specified, the current prefix
# will be returned.
#
# pygments_prefix - The String prefix (default: nil).
#
# Returns the String prefix.
def self.pygments_prefix(pygments_prefix = nil)
@pygments_prefix = pygments_prefix if pygments_prefix
@pygments_prefix
end
# Public: Get or set the pygments suffix. When an argument is specified,
# the suffix will be set. If no argument is specified, the current suffix
# will be returned.
#
# pygments_suffix - The String suffix (default: nil).
#
# Returns the String suffix.
def self.pygments_suffix(pygments_suffix = nil)
@pygments_suffix = pygments_suffix if pygments_suffix
@pygments_suffix
end
# Initialize the converter.
#
# Returns an initialized Converter.
def initialize(config = {})
@config = config
end
# Get the pygments prefix.
#
# Returns the String prefix.
def pygments_prefix
self.class.pygments_prefix
end
# Get the pygments suffix.
#
# Returns the String suffix.
def pygments_suffix
self.class.pygments_suffix
end
end
end

View File

@@ -0,0 +1,22 @@
module Jekyll
class IdentityConverter < Converter
safe true
priority :lowest
def matches(ext)
true
end
def output_ext(ext)
ext
end
def convert(content)
content
end
end
end

View File

@@ -0,0 +1,113 @@
module Jekyll
class MarkdownConverter < Converter
safe true
pygments_prefix "\n"
pygments_suffix "\n"
def setup
return if @setup
# Set the Markdown interpreter (and Maruku self.config, if necessary)
case @config['markdown']
when 'kramdown'
begin
require 'kramdown'
rescue LoadError
STDERR.puts 'You are missing a library required for Markdown. Please run:'
STDERR.puts ' $ [sudo] gem install kramdown'
raise FatalException.new("Missing dependency: kramdown")
end
when 'rdiscount'
begin
require 'rdiscount'
# Load rdiscount extensions
@rdiscount_extensions = @config['rdiscount']['extensions'].map { |e| e.to_sym }
rescue LoadError
STDERR.puts 'You are missing a library required for Markdown. Please run:'
STDERR.puts ' $ [sudo] gem install rdiscount'
raise FatalException.new("Missing dependency: rdiscount")
end
when 'maruku'
begin
require 'maruku'
if @config['maruku']['use_divs']
require 'maruku/ext/div'
STDERR.puts 'Maruku: Using extended syntax for div elements.'
end
if @config['maruku']['use_tex']
require 'maruku/ext/math'
STDERR.puts "Maruku: Using LaTeX extension. Images in `#{@config['maruku']['png_dir']}`."
# Switch off MathML output
MaRuKu::Globals[:html_math_output_mathml] = false
MaRuKu::Globals[:html_math_engine] = 'none'
# Turn on math to PNG support with blahtex
# Resulting PNGs stored in `images/latex`
MaRuKu::Globals[:html_math_output_png] = true
MaRuKu::Globals[:html_png_engine] = @config['maruku']['png_engine']
MaRuKu::Globals[:html_png_dir] = @config['maruku']['png_dir']
MaRuKu::Globals[:html_png_url] = @config['maruku']['png_url']
end
rescue LoadError
STDERR.puts 'You are missing a library required for Markdown. Please run:'
STDERR.puts ' $ [sudo] gem install maruku'
raise FatalException.new("Missing dependency: maruku")
end
else
STDERR.puts "Invalid Markdown processor: #{@config['markdown']}"
STDERR.puts " Valid options are [ maruku | rdiscount | kramdown ]"
raise FatalException.new("Invalid Markdown process: #{@config['markdown']}")
end
@setup = true
end
def matches(ext)
ext =~ /(markdown|mkdn?|md)/i
end
def output_ext(ext)
".html"
end
def convert(content)
setup
case @config['markdown']
when 'kramdown'
# Check for use of coderay
if @config['kramdown']['use_coderay']
Kramdown::Document.new(content, {
:auto_ids => @config['kramdown']['auto_ids'],
:footnote_nr => @config['kramdown']['footnote_nr'],
:entity_output => @config['kramdown']['entity_output'],
:toc_levels => @config['kramdown']['toc_levels'],
:coderay_wrap => @config['kramdown']['coderay']['coderay_wrap'],
:coderay_line_numbers => @config['kramdown']['coderay']['coderay_line_numbers'],
:coderay_line_number_start => @config['kramdown']['coderay']['coderay_line_number_start'],
:coderay_tab_width => @config['kramdown']['coderay']['coderay_tab_width'],
:coderay_bold_every => @config['kramdown']['coderay']['coderay_bold_every'],
:coderay_css => @config['kramdown']['coderay']['coderay_css']
}).to_html
else
# not using coderay
Kramdown::Document.new(content, {
:auto_ids => @config['kramdown']['auto_ids'],
:footnote_nr => @config['kramdown']['footnote_nr'],
:entity_output => @config['kramdown']['entity_output'],
:toc_levels => @config['kramdown']['toc_levels']
}).to_html
end
when 'rdiscount'
RDiscount.new(content, *@rdiscount_extensions).to_html
when 'maruku'
Maruku.new(content).to_html
end
end
end
end

View File

@@ -0,0 +1,33 @@
module Jekyll
class TextileConverter < Converter
safe true
pygments_prefix '<notextile>'
pygments_suffix '</notextile>'
def setup
return if @setup
require 'redcloth'
@setup = true
rescue LoadError
STDERR.puts 'You are missing a library required for Textile. Please run:'
STDERR.puts ' $ [sudo] gem install RedCloth'
raise FatalException.new("Missing dependency: RedCloth")
end
def matches(ext)
ext =~ /textile/i
end
def output_ext(ext)
".html"
end
def convert(content)
setup
RedCloth.new(content).to_html
end
end
end

View File

@@ -1,69 +1,100 @@
# Convertible provides methods for converting a pagelike item
# from a certain type of markup into actual content
#
# Requires
# self.site -> Jekyll::Site
# self.content
# self.content=
# self.data=
# self.ext=
# self.output=
module Jekyll
module Convertible
# Return the contents as a string
# Returns the contents as a String.
def to_s
self.content || ''
end
# Read the YAML frontmatter
# +base+ is the String path to the dir containing the file
# +name+ is the String filename of the file
# Read the YAML frontmatter.
#
# Returns nothing
# base - The String path to the dir containing the file.
# name - The String filename of the file.
#
# Returns nothing.
def read_yaml(base, name)
self.content = File.read(File.join(base, name))
if self.content =~ /^(---\s*\n.*?)\n---\s*\n/m
self.content = self.content[($1.size + 5)..-1]
self.data = YAML.load($1)
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
self.content = $POSTMATCH
begin
self.data = YAML.load($1)
rescue => e
puts "YAML Exception: #{e.message}"
end
end
self.data ||= {}
end
# Transform the contents based on the file extension.
# Transform the contents based on the content type.
#
# Returns nothing
# Returns nothing.
def transform
case Jekyll.content_type
when :textile
self.ext = ".html"
self.content = RedCloth.new(self.content).to_html
when :markdown
self.ext = ".html"
self.content = Jekyll.markdown_proc.call(self.content)
end
self.content = converter.convert(self.content)
end
def determine_content_type
case self.ext[1..-1]
when /textile/i
return :textile
when /markdown/i, /mkdn/i, /md/i
return :markdown
end
return :unknown
end
# Add any necessary layouts to this convertible document
# +layouts+ is a Hash of {"name" => "layout"}
# +site_payload+ is the site payload hash
# Determine the extension depending on content_type.
#
# Returns nothing
# Returns the String extension for the output file.
# e.g. ".html" for an HTML output file.
def output_ext
converter.output_ext(self.ext)
end
# Determine which converter to use based on this convertible's
# extension.
#
# Returns the Converter instance.
def converter
@converter ||= self.site.converters.find { |c| c.matches(self.ext) }
end
# Add any necessary layouts to this convertible document.
#
# payload - The site payload Hash.
# layouts - A Hash of {"name" => "layout"}.
#
# Returns nothing.
def do_layout(payload, layouts)
info = { :filters => [Jekyll::Filters], :registers => { :site => self.site } }
# render and transform content (this becomes the final content of the object)
Jekyll.content_type = self.determine_content_type
self.content = Liquid::Template.parse(self.content).render(payload, [Jekyll::Filters])
payload["pygments_prefix"] = converter.pygments_prefix
payload["pygments_suffix"] = converter.pygments_suffix
begin
self.content = Liquid::Template.parse(self.content).render(payload, info)
rescue => e
puts "Liquid Exception: #{e.message} in #{self.data["layout"]}"
end
self.transform
# output keeps track of what will finally be written
self.output = self.content
# recursively render layouts
layout = layouts[self.data["layout"]]
while layout
payload = payload.deep_merge({"content" => self.output, "page" => layout.data})
self.output = Liquid::Template.parse(layout.content).render(payload, [Jekyll::Filters])
begin
self.output = Liquid::Template.parse(layout.content).render(payload, info)
rescue => e
puts "Liquid Exception: #{e.message} in #{self.data["layout"]}"
end
layout = layouts[layout.data["layout"]]
end
end

View File

@@ -1,22 +1,52 @@
class Hash
# Merges self with another hash, recursively.
#
#
# This code was lovingly stolen from some random gem:
# http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
#
#
# Thanks to whoever made it.
def deep_merge(hash)
target = dup
hash.keys.each do |key|
if hash[key].is_a? Hash and self[key].is_a? Hash
target[key] = target[key].deep_merge(hash[key])
next
end
target[key] = hash[key]
end
target
end
end
# Read array from the supplied hash favouring the singular key
# and then the plural key, and handling any nil entries.
# +hash+ the hash to read from
# +singular_key+ the singular key
# +plural_key+ the singular key
#
# Returns an array
def pluralized_array(singular_key, plural_key)
hash = self
if hash.has_key?(singular_key)
array = [hash[singular_key]] if hash[singular_key]
elsif hash.has_key?(plural_key)
case hash[plural_key]
when String
array = hash[plural_key].split
when Array
array = hash[plural_key].compact
end
end
array || []
end
end
# Thanks, ActiveSupport!
class Date
# Converts datetime to an appropriate format for use in XML
def xmlschema
strftime("%Y-%m-%dT%H:%M:%S%Z")
end if RUBY_VERSION < '1.9'
end

6
lib/jekyll/errors.rb Normal file
View File

@@ -0,0 +1,6 @@
module Jekyll
class FatalException < StandardError
end
end

View File

@@ -1,6 +1,12 @@
require 'uri'
module Jekyll
module Filters
def textilize(input)
TextileConverter.new.convert(input)
end
def date_to_string(date)
date.strftime("%d %b %Y")
end
@@ -8,19 +14,27 @@ module Jekyll
def date_to_long_string(date)
date.strftime("%d %B %Y")
end
def date_to_xmlschema(date)
date.xmlschema
end
def xml_escape(input)
input.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
CGI.escapeHTML(input)
end
def cgi_escape(input)
CGI::escape(input)
end
def uri_escape(input)
URI.escape(input)
end
def number_of_words(input)
input.split.length
end
def array_to_sentence_string(array)
connector = "and"
case array.length
@@ -35,5 +49,5 @@ module Jekyll
end
end
end
end
end

7
lib/jekyll/generator.rb Normal file
View File

@@ -0,0 +1,7 @@
module Jekyll
class Generator < Plugin
end
end

View File

@@ -0,0 +1,87 @@
module Jekyll
class Pagination < Generator
safe true
def generate(site)
site.pages.dup.each do |page|
paginate(site, page) if Pager.pagination_enabled?(site.config, page.name)
end
end
# Paginates the blog's posts. Renders the index.html file into paginated
# directories, ie: page2/index.html, page3/index.html, etc and adds more
# site-wide data.
# +page+ is the index.html Page that requires pagination
#
# {"paginator" => { "page" => <Number>,
# "per_page" => <Number>,
# "posts" => [<Post>],
# "total_posts" => <Number>,
# "total_pages" => <Number>,
# "previous_page" => <Number>,
# "next_page" => <Number> }}
def paginate(site, page)
all_posts = site.site_payload['site']['posts']
pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i)
(1..pages).each do |num_page|
pager = Pager.new(site.config, num_page, all_posts, pages)
if num_page > 1
newpage = Page.new(site, site.source, page.dir, page.name)
newpage.pager = pager
newpage.dir = File.join(page.dir, "page#{num_page}")
site.pages << newpage
else
page.pager = pager
end
end
end
end
class Pager
attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page
def self.calculate_pages(all_posts, per_page)
num_pages = all_posts.size / per_page.to_i
num_pages = num_pages + 1 if all_posts.size % per_page.to_i != 0
num_pages
end
def self.pagination_enabled?(config, file)
file == 'index.html' && !config['paginate'].nil?
end
def initialize(config, page, all_posts, num_pages = nil)
@page = page
@per_page = config['paginate'].to_i
@total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page)
if @page > @total_pages
raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
end
init = (@page - 1) * @per_page
offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1)
@total_posts = all_posts.size
@posts = all_posts[init..offset]
@previous_page = @page != 1 ? @page - 1 : nil
@next_page = @page != @total_pages ? @page + 1 : nil
end
def to_liquid
{
'page' => page,
'per_page' => per_page,
'posts' => posts,
'total_posts' => total_posts,
'total_pages' => total_pages,
'previous_page' => previous_page,
'next_page' => next_page
}
end
end
end

View File

@@ -2,25 +2,28 @@ module Jekyll
class Layout
include Convertible
attr_accessor :site
attr_accessor :ext
attr_accessor :data, :content
# Initialize a new Layout.
# +site+ is the Site
# +base+ is the String path to the <source>
# +name+ is the String filename of the post file
#
# Returns <Page>
def initialize(base, name)
def initialize(site, base, name)
@site = site
@base = base
@name = name
self.data = {}
self.process(name)
self.read_yaml(base, name)
end
# Extract information from the layout filename
# +name+ is the String filename of the layout file
#

View File

@@ -0,0 +1,86 @@
require 'rubygems'
require 'sequel'
require 'fileutils'
require 'yaml'
# NOTE: This converter requires Sequel and the MySQL gems.
# The MySQL gem can be difficult to install on OS X. Once you have MySQL
# installed, running the following commands should work:
# $ sudo gem install sequel
# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
module Jekyll
module Drupal
# Reads a MySQL database via Sequel and creates a post file for each
# post in wp_posts that has post_status = 'publish'.
# This restriction is made because 'draft' posts are not guaranteed to
# have valid dates.
QUERY = "SELECT node.nid, node.title, node_revisions.body, node.created, node.status FROM node, node_revisions WHERE (node.type = 'blog' OR node.type = 'story') AND node.vid = node_revisions.vid"
def self.process(dbname, user, pass, host = 'localhost')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
FileUtils.mkdir_p "_posts"
FileUtils.mkdir_p "_drafts"
# Create the refresh layout
# Change the refresh url if you customized your permalink config
File.open("_layouts/refresh.html", "w") do |f|
f.puts <<EOF
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="0;url={{ page.refresh_to_post_id }}.html" />
</head>
</html>
EOF
end
db[QUERY].each do |post|
# Get required fields and construct Jekyll compatible name
node_id = post[:nid]
title = post[:title]
content = post[:body]
created = post[:created]
time = Time.at(created)
is_published = post[:status] == 1
dir = is_published ? "_posts" : "_drafts"
slug = title.strip.downcase.gsub(/(&|&amp;)/, ' and ').gsub(/[\s\.\/\\]/, '-').gsub(/[^\w-]/, '').gsub(/[-_]{2,}/, '-').gsub(/^[-_]/, '').gsub(/[-_]$/, '')
name = time.strftime("%Y-%m-%d-") + slug + '.md'
# Get the relevant fields as a hash, delete empty fields and convert
# to YAML for the header
data = {
'layout' => 'post',
'title' => title.to_s,
'created' => created,
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
# Write out the data and content to file
File.open("#{dir}/#{name}", "w") do |f|
f.puts data
f.puts "---"
f.puts content
end
# Make a file to redirect from the old Drupal URL
if is_published
FileUtils.mkdir_p "node/#{node_id}"
File.open("node/#{node_id}/index.md", "w") do |f|
f.puts "---"
f.puts "layout: refresh"
f.puts "refresh_to_post_id: /#{time.strftime("%Y/%m/%d/") + slug}"
f.puts "---"
end
end
end
# TODO: Make dirs & files for nodes of type 'page'
# Make refresh pages for these as well
# TODO: Make refresh dirs & files according to entries in url_alias table
end
end
end

View File

@@ -0,0 +1,53 @@
require 'yaml'
require 'fileutils'
module Jekyll
module Marley
def self.regexp
{ :id => /^\d{0,4}-{0,1}(.*)$/,
:title => /^#\s*(.*)\s+$/,
:title_with_date => /^#\s*(.*)\s+\(([0-9\/]+)\)$/,
:published_on => /.*\s+\(([0-9\/]+)\)$/,
:perex => /^([^\#\n]+\n)$/,
:meta => /^\{\{\n(.*)\}\}\n$/mi # Multiline Regexp
}
end
def self.process(marley_data_dir)
raise ArgumentError, "marley dir #{marley_data_dir} not found" unless File.directory?(marley_data_dir)
FileUtils.mkdir_p "_posts"
posts = 0
Dir["#{marley_data_dir}/**/*.txt"].each do |f|
next unless File.exists?(f)
#copied over from marley's app/lib/post.rb
file_content = File.read(f)
meta_content = file_content.slice!( self.regexp[:meta] )
body = file_content.sub( self.regexp[:title], '').sub( self.regexp[:perex], '').strip
title = file_content.scan( self.regexp[:title] ).first.to_s.strip
prerex = file_content.scan( self.regexp[:perex] ).first.to_s.strip
published_on = DateTime.parse( post[:published_on] ) rescue File.mtime( File.dirname(f) )
meta = ( meta_content ) ? YAML::load( meta_content.scan( self.regexp[:meta]).to_s ) : {}
meta['title'] = title
meta['layout'] = 'post'
formatted_date = published_on.strftime('%Y-%m-%d')
post_name = File.dirname(f).split(%r{/}).last.gsub(/\A\d+-/, '')
name = "#{formatted_date}-#{post_name}"
File.open("_posts/#{name}.markdown", "w") do |f|
f.puts meta.to_yaml
f.puts "---\n"
f.puts "\n#{prerex}\n\n" if prerex
f.puts body
end
posts += 1
end
"Created #{posts} posts!"
end
end
end

View File

@@ -13,7 +13,7 @@ require File.join(File.dirname(__FILE__),"csv.rb")
# installed, running the following commands should work:
# $ sudo gem install sequel
# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
module Jekyll
module Mephisto
#Accepts a hash with database config variables, exports mephisto posts into a csv
@@ -38,24 +38,24 @@ module Jekyll
# through the created posts to make sure nothing is accidently published.
QUERY = "SELECT id, permalink, body, published_at, title FROM contents WHERE user_id = 1 AND type = 'Article' AND published_at IS NOT NULL ORDER BY published_at"
def self.process(dbname, user, pass, host = 'localhost')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host)
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
FileUtils.mkdir_p "_posts"
db[QUERY].each do |post|
title = post[:title]
slug = post[:permalink]
date = post[:published_at]
content = post[:body]
# more_content = ''
# Be sure to include the body and extended body.
# if more_content != nil
# content = content + " \n" + more_content
# end
# Ideally, this script would determine the post format (markdown, html
# , etc) and create files with proper extensions. At this point it
# just assumes that markdown will be acceptable.
@@ -66,14 +66,14 @@ module Jekyll
'title' => title.to_s,
'mt_id' => post[:entry_id],
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
File.open("_posts/#{name}", "w") do |f|
f.puts data
f.puts "---"
f.puts content
end
end
end
end
end

View File

@@ -5,55 +5,73 @@
require 'rubygems'
require 'sequel'
require 'fileutils'
require 'yaml'
# NOTE: This converter requires Sequel and the MySQL gems.
# The MySQL gem can be difficult to install on OS X. Once you have MySQL
# installed, running the following commands should work:
# $ sudo gem install sequel
# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
module Jekyll
module MT
# This query will pull blog posts from all entries across all blogs. If
# you've got unpublished, deleted or otherwise hidden posts please sift
# through the created posts to make sure nothing is accidently published.
QUERY = "SELECT entry_id, entry_basename, entry_text, entry_text_more, entry_created_on, entry_title FROM mt_entry"
QUERY = "SELECT entry_id, entry_basename, entry_text, entry_text_more, entry_authored_on, entry_title, entry_convert_breaks FROM mt_entry"
def self.process(dbname, user, pass, host = 'localhost')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host)
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
FileUtils.mkdir_p "_posts"
db[QUERY].each do |post|
title = post[:entry_title]
slug = post[:entry_basename]
date = post[:entry_created_on]
slug = post[:entry_basename].gsub(/_/, '-')
date = post[:entry_authored_on]
content = post[:entry_text]
more_content = post[:entry_text_more]
entry_convert_breaks = post[:entry_convert_breaks]
# Be sure to include the body and extended body.
if more_content != nil
content = content + " \n" + more_content
end
# Ideally, this script would determine the post format (markdown, html
# , etc) and create files with proper extensions. At this point it
# just assumes that markdown will be acceptable.
name = [date.year, date.month, date.day, slug].join('-') + ".markdown"
name = [date.year, date.month, date.day, slug].join('-') + '.' + self.suffix(entry_convert_breaks)
data = {
'layout' => 'post',
'title' => title.to_s,
'mt_id' => post[:entry_id],
'date' => date
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
File.open("_posts/#{name}", "w") do |f|
f.puts data
f.puts "---"
f.puts content
end
end
end
def self.suffix(entry_type)
if entry_type.nil? || entry_type.include?("markdown")
# The markdown plugin I have saves this as "markdown_with_smarty_pants", so I just look for "markdown".
"markdown"
elsif entry_type.include?("textile")
# This is saved as "textile_2" on my installation of MT 5.1.
"textile"
elsif entry_type == "0" || entry_type.include?("richtext")
# richtext looks to me like it's saved as HTML, so I include it here.
"html"
else
# Other values might need custom work.
entry_type
end
end
end
end

View File

@@ -0,0 +1,73 @@
require 'rubygems'
require 'jekyll'
require 'fileutils'
require 'net/http'
require 'uri'
require "json"
# ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, blog)'
module Jekyll
module Posterous
def self.fetch(uri_str, limit = 10)
# You should choose better exception.
raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0
response = nil
Net::HTTP.start('posterous.com') {|http|
req = Net::HTTP::Get.new(uri_str)
req.basic_auth @email, @pass
response = http.request(req)
}
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else response.error!
end
end
def self.process(email, pass, blog = 'primary')
@email, @pass = email, pass
@api_token = JSON.parse(self.fetch("/api/2/auth/token").body)['api_token']
FileUtils.mkdir_p "_posts"
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}").body)
page = 1
while posts.any?
posts.each do |post|
title = post["title"]
slug = title.gsub(/[^[:alnum:]]+/, '-').downcase
date = Date.parse(post["display_date"])
content = post["body_html"]
published = !post["is_private"]
name = "%02d-%02d-%02d-%s.html" % [date.year, date.month, date.day, slug]
# Get the relevant fields as a hash, delete empty fields and convert
# to YAML for the header
data = {
'layout' => 'post',
'title' => title.to_s,
'published' => published
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
# Write out the data and content to file
File.open("_posts/#{name}", "w") do |f|
f.puts data
f.puts "---"
f.puts content
end
end
page += 1
posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body)
end
end
end
end

View File

@@ -17,21 +17,21 @@ module Jekyll
QUERY = "select Title, url_title, Posted, Body, Keywords from textpattern where Status = '4' or Status = '5'"
def self.process(dbname, user, pass, host = 'localhost')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host)
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
FileUtils.mkdir_p "_posts"
db[QUERY].each do |post|
# Get required fields and construct Jekyll compatible name
title = post[:Title]
slug = post[:url_title]
date = post[:Posted]
content = post[:Body]
name = [date.strftime("%Y-%m-%d"), slug].join('-') + ".textile"
# Get the relevant fields as a hash, delete empty fields and convert
# to YAML for the header
# to YAML for the header
data = {
'layout' => 'post',
'title' => title.to_s,

View File

@@ -2,27 +2,27 @@
require 'fileutils'
require 'rubygems'
require 'sequel'
module Jekyll
module Typo
# this SQL *should* work for both MySQL and PostgreSQL, but I haven't
# this SQL *should* work for both MySQL and PostgreSQL, but I haven't
# tested PostgreSQL yet (as of 2008-12-16)
SQL = <<-EOS
SELECT c.id id,
c.title title,
c.permalink slug,
c.title title,
c.permalink slug,
c.body body,
c.published_at date,
c.published_at date,
c.state state,
COALESCE(tf.name, 'html') filter
FROM contents c
FROM contents c
LEFT OUTER JOIN text_filters tf
ON c.text_filter_id = tf.id
ON c.text_filter_id = tf.id
EOS
def self.process dbname, user, pass, host='localhost'
FileUtils.mkdir_p '_posts'
db = Sequel.mysql dbname, :user => user, :password => pass, :host => host
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
db[SQL].each do |post|
next unless post[:state] =~ /Published/
@@ -30,7 +30,7 @@ module Jekyll
sprintf("%.02d", post[:date].month),
sprintf("%.02d", post[:date].day),
post[:slug].strip ].join('-')
# Can have more than one text filter in this field, but we just want
# Can have more than one text filter in this field, but we just want
# the first one for this
name += '.' + post[:filter].split(' ')[0]

View File

@@ -1,6 +1,7 @@
require 'rubygems'
require 'sequel'
require 'fileutils'
require 'yaml'
# NOTE: This converter requires Sequel and the MySQL gems.
# The MySQL gem can be difficult to install on OS X. Once you have MySQL
@@ -10,35 +11,36 @@ require 'fileutils'
module Jekyll
module WordPress
# Reads a MySQL database via Sequel and creates a post file for each
# post in wp_posts that has post_status = 'publish'.
# This restriction is made because 'draft' posts are not guaranteed to
# have valid dates.
QUERY = "select * from wp_posts where post_status = 'publish' and post_type = 'post'"
def self.process(dbname, user, pass, host = 'localhost')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host)
def self.process(dbname, user, pass, host = 'localhost', table_prefix = 'wp_')
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
FileUtils.mkdir_p "_posts"
db[QUERY].each do |post|
# Reads a MySQL database via Sequel and creates a post file for each
# post in wp_posts that has post_status = 'publish'.
# This restriction is made because 'draft' posts are not guaranteed to
# have valid dates.
query = "select post_title, post_name, post_date, post_content, post_excerpt, ID, guid from #{table_prefix}posts where post_status = 'publish' and post_type = 'post'"
db[query].each do |post|
# Get required fields and construct Jekyll compatible name
title = post[:post_title]
slug = post[:post_name]
date = post[:post_date]
content = post[:post_content]
name = [date.year, date.month, date.day, slug].join('-') + ".markdown"
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
slug]
# Get the relevant fields as a hash, delete empty fields and convert
# to YAML for the header
# to YAML for the header
data = {
'layout' => 'post',
'title' => title.to_s,
'excerpt' => post[:post_excerpt].to_s,
'wordpress_id' => post[:ID],
'wordpress_url' => post[:guid]
'wordpress_url' => post[:guid],
'date' => date
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
# Write out the data and content to file
@@ -51,4 +53,4 @@ module Jekyll
end
end
end
end

View File

@@ -0,0 +1,45 @@
# coding: utf-8
require 'rubygems'
require 'hpricot'
require 'fileutils'
require 'yaml'
module Jekyll
# This importer takes a wordpress.xml file,
# which can be exported from your
# wordpress.com blog (/wp-admin/export.php)
module WordpressDotCom
def self.process(filename = "wordpress.xml")
FileUtils.mkdir_p "_posts"
posts = 0
doc = Hpricot::XML(File.read(filename))
(doc/:channel/:item).each do |item|
title = item.at(:title).inner_text.strip
permalink_title = item.at('wp:post_name').inner_text
date = Time.parse(item.at(:pubDate).inner_text)
tags = (item/:category).map{|c| c.inner_text}.reject{|c| c == 'Uncategorized'}.uniq
name = "#{date.strftime('%Y-%m-%d')}-#{permalink_title}.html"
header = {
'layout' => 'post',
'title' => title,
'tags' => tags
}
File.open("_posts/#{name}", "w") do |f|
f.puts header.to_yaml
f.puts '---'
f.puts item.at('content:encoded').inner_text
end
posts += 1
end
puts "Imported #{posts} posts"
end
end
end

View File

@@ -2,63 +2,142 @@ module Jekyll
class Page
include Convertible
attr_accessor :ext
attr_accessor :site, :pager
attr_accessor :name, :ext, :basename, :dir
attr_accessor :data, :content, :output
# Initialize a new Page.
# +site+ is the Site
# +base+ is the String path to the <source>
# +dir+ is the String path between <source> and the file
# +name+ is the String filename of the file
#
# Returns <Page>
def initialize(base, dir, name)
def initialize(site, base, dir, name)
@site = site
@base = base
@dir = dir
@dir = dir
@name = name
self.data = {}
self.process(name)
self.read_yaml(File.join(base, dir), name)
#self.transform
end
# The generated directory into which the page will be placed
# upon generation. This is derived from the permalink or, if
# permalink is absent, set to '/'
#
# Returns <String>
def dir
url[-1, 1] == '/' ? url : File.dirname(url)
end
# The full path and filename of the post.
# Defined in the YAML of the post body
# (Optional)
#
# Returns <String>
def permalink
self.data && self.data['permalink']
end
def template
if self.site.permalink_style == :pretty && !index? && html?
"/:basename/"
else
"/:basename:output_ext"
end
end
# The generated relative url of this page
# e.g. /about.html
#
# Returns <String>
def url
return @url if @url
url = if permalink
permalink
else
{
"basename" => self.basename,
"output_ext" => self.output_ext,
}.inject(template) { |result, token|
result.gsub(/:#{token.first}/, token.last)
}.gsub(/\/\//, "/")
end
# sanitize url
@url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
@url += "/" if url =~ /\/$/
@url
end
# Extract information from the page filename
# +name+ is the String filename of the page file
#
# Returns nothing
def process(name)
self.ext = File.extname(name)
self.basename = name[0 .. -self.ext.length-1]
end
# Add any necessary layouts to this post
# +layouts+ is a Hash of {"name" => "layout"}
# +site_payload+ is the site payload hash
#
# Returns nothing
def render(layouts, site_payload)
payload = {"page" => self.data}.deep_merge(site_payload)
payload = {
"page" => self.to_liquid,
'paginator' => pager.to_liquid
}.deep_merge(site_payload)
do_layout(payload, layouts)
end
def to_liquid
self.data.deep_merge({
"url" => File.join(@dir, self.url),
"content" => self.content })
end
# Obtain destination path.
# +dest+ is the String path to the destination dir
#
# Returns destination file path.
def destination(dest)
# The url needs to be unescaped in order to preserve the correct filename
path = File.join(dest, @dir, CGI.unescape(self.url))
path = File.join(path, "index.html") if self.url =~ /\/$/
path
end
# Write the generated page file to the destination directory.
# +dest+ is the String path to the destination dir
#
# Returns nothing
def write(dest)
FileUtils.mkdir_p(File.join(dest, @dir))
name = @name
if self.ext != ""
name = @name.split(".")[0..-2].join('.') + self.ext
end
path = File.join(dest, @dir, name)
path = destination(dest)
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(self.output)
end
end
def inspect
"#<Jekyll:Page @name=#{self.name.inspect}>"
end
def html?
output_ext == '.html'
end
def index?
basename == 'index'
end
end
end
end

76
lib/jekyll/plugin.rb Normal file
View File

@@ -0,0 +1,76 @@
module Jekyll
class Plugin
PRIORITIES = { :lowest => -100,
:low => -10,
:normal => 0,
:high => 10,
:highest => 100 }
# Install a hook so that subclasses are recorded. This method is only
# ever called by Ruby itself.
#
# base - The Class subclass.
#
# Returns nothing.
def self.inherited(base)
subclasses << base
subclasses.sort!
end
# The list of Classes that have been subclassed.
#
# Returns an Array of Class objects.
def self.subclasses
@subclasses ||= []
end
# Get or set the priority of this plugin. When called without an
# argument it returns the priority. When an argument is given, it will
# set the priority.
#
# priority - The Symbol priority (default: nil). Valid options are:
# :lowest, :low, :normal, :high, :highest
#
# Returns the Symbol priority.
def self.priority(priority = nil)
if priority && PRIORITIES.has_key?(priority)
@priority = priority
end
@priority || :normal
end
# Get or set the safety of this plugin. When called without an argument
# it returns the safety. When an argument is given, it will set the
# safety.
#
# safe - The Boolean safety (default: nil).
#
# Returns the safety Boolean.
def self.safe(safe = nil)
if safe
@safe = safe
end
@safe || false
end
# Spaceship is priority [higher -> lower]
#
# other - The class to be compared.
#
# Returns -1, 0, 1.
def self.<=>(other)
PRIORITIES[other.priority] <=> PRIORITIES[self.priority]
end
# Initialize a new plugin. This should be overridden by the subclass.
#
# config - The Hash of configuration options.
#
# Returns a new instance.
def initialize(config = {})
# no-op for default
end
end
end

View File

@@ -3,13 +3,13 @@ module Jekyll
class Post
include Comparable
include Convertible
class << self
attr_accessor :lsi
end
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
# Post name validator. Post filenames must be like:
# 2008-11-05-my-awesome-post.textile
#
@@ -17,36 +17,58 @@ module Jekyll
def self.valid?(name)
name =~ MATCHER
end
attr_accessor :date, :slug, :ext, :categories, :topics
attr_accessor :data, :content, :output
attr_accessor :site
attr_accessor :data, :content, :output, :ext
attr_accessor :date, :slug, :published, :tags, :categories
# Initialize this Post instance.
# +site+ is the Site
# +base+ is the String path to the dir containing the post file
# +name+ is the String filename of the post file
# +categories+ is an Array of Strings for the categories for this post
#
# Returns <Post>
def initialize(source, dir, name)
def initialize(site, source, dir, name)
@site = site
@base = File.join(source, dir, '_posts')
@name = name
self.categories = dir.split('/').reject { |x| x.empty? }
parts = name.split('/')
self.topics = parts.size > 1 ? parts[0..-2] : []
self.process(name)
self.read_yaml(@base, name)
#If we've added a date and time to the yaml, use that instead of the filename date
#Means we'll sort correctly.
if self.data.has_key?('date')
# ensure Time via to_s and reparse
self.date = Time.parse(self.data["date"].to_s)
end
if self.data.has_key?('published') && self.data['published'] == false
self.published = false
else
self.published = true
end
self.tags = self.data.pluralized_array("tag", "tags")
if self.categories.empty?
self.categories = self.data.pluralized_array('category', 'categories')
end
end
# Spaceship is based on Post#date
# Spaceship is based on Post#date, slug
#
# Returns -1, 0, 1
def <=>(other)
self.date <=> other.date
cmp = self.date <=> other.date
if 0 == cmp
cmp = self.slug <=> other.slug
end
return cmp
end
# Extract information from the post filename
# +name+ is the String filename of the post file
#
@@ -56,8 +78,10 @@ module Jekyll
self.date = Time.parse(date)
self.slug = slug
self.ext = ext
rescue ArgumentError
raise FatalException.new("Post #{name} does not have a valid date.")
end
# The generated directory into which the post will be placed
# upon generation. This is derived from the permalink or, if
# permalink is absent, set to the default date
@@ -65,18 +89,9 @@ module Jekyll
#
# Returns <String>
def dir
if permalink
permalink.to_s.split("/")[0..-2].join("/") + '/'
else
prefix = self.categories.empty? ? '' : '/' + self.categories.join('/')
if Jekyll.permalink_style == :date
prefix + date.strftime("/%Y/%m/%d/")
else
prefix + '/'
end
end
File.dirname(url)
end
# The full path and filename of the post.
# Defined in the YAML of the post body
# (Optional)
@@ -85,30 +100,65 @@ module Jekyll
def permalink
self.data && self.data['permalink']
end
def template
case self.site.permalink_style
when :pretty
"/:categories/:year/:month/:day/:title/"
when :none
"/:categories/:title.html"
when :date
"/:categories/:year/:month/:day/:title.html"
else
self.site.permalink_style.to_s
end
end
# The generated relative url of this post
# e.g. /2008/11/05/my-awesome-post.html
#
# Returns <String>
def url
permalink || self.dir + self.slug + ".html"
return @url if @url
url = if permalink
permalink
else
{
"year" => date.strftime("%Y"),
"month" => date.strftime("%m"),
"day" => date.strftime("%d"),
"title" => CGI.escape(slug),
"i_day" => date.strftime("%d").to_i.to_s,
"i_month" => date.strftime("%m").to_i.to_s,
"categories" => categories.join('/'),
"output_ext" => self.output_ext
}.inject(template) { |result, token|
result.gsub(/:#{Regexp.escape token.first}/, token.last)
}.gsub(/\/\//, "/")
end
# sanitize url
@url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
@url += "/" if url =~ /\/$/
@url
end
# The UID for this post (useful in feeds)
# e.g. /2008/11/05/my-awesome-post
#
# Returns <String>
def id
self.dir + self.slug
File.join(self.dir, self.slug)
end
# Calculate related posts.
#
# Returns [<Post>]
def related_posts(posts)
return [] unless posts.size > 1
if Jekyll.lsi
if self.site.lsi
self.class.lsi ||= begin
puts "Running the classifier... this could take a while."
lsi = Classifier::LSI.new
@@ -123,7 +173,7 @@ module Jekyll
(posts - [self])[0..9]
end
end
# Add any necessary layouts to this post
# +layouts+ is a Hash of {"name" => "layout"}
# +site_payload+ is the site payload hash
@@ -131,44 +181,75 @@ module Jekyll
# Returns nothing
def render(layouts, site_payload)
# construct payload
payload =
{
payload = {
"site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) },
"page" => self.to_liquid
}
payload = payload.deep_merge(site_payload)
}.deep_merge(site_payload)
do_layout(payload, layouts)
end
# Obtain destination path.
# +dest+ is the String path to the destination dir
#
# Returns destination file path.
def destination(dest)
# The url needs to be unescaped in order to preserve the correct filename
path = File.join(dest, CGI.unescape(self.url))
path = File.join(path, "index.html") if template[/\.html$/].nil?
path
end
# Write the generated post file to the destination directory.
# +dest+ is the String path to the destination dir
#
# Returns nothing
def write(dest)
FileUtils.mkdir_p(File.join(dest, dir))
path = File.join(dest, self.url)
path = destination(dest)
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(self.output)
end
end
# Convert this post into a Hash for use in Liquid templates.
#
# Returns <Hash>
def to_liquid
{ "title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
"id" => self.id,
"topics" => self.topics,
"content" => self.content }.deep_merge(self.data)
self.data.deep_merge({
"title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
"url" => self.url,
"date" => self.date,
"id" => self.id,
"categories" => self.categories,
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content })
end
def inspect
"<Post: #{self.id}>"
end
def next
pos = self.site.posts.index(self)
if pos && pos < self.site.posts.length-1
self.site.posts[pos+1]
else
nil
end
end
def previous
pos = self.site.posts.index(self)
if pos && pos > 0
self.site.posts[pos-1]
else
nil
end
end
end
end

View File

@@ -1,136 +1,233 @@
require 'set'
module Jekyll
class Site
attr_accessor :source, :dest
attr_accessor :layouts, :posts, :categories
attr_accessor :config, :layouts, :posts, :pages, :static_files,
:categories, :exclude, :source, :dest, :lsi, :pygments,
:permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts
attr_accessor :converters, :generators
# Initialize the site
# +source+ is String path to the source directory containing
# the proto-site
# +dest+ is the String path to the directory where the generated
# site should be written
# +config+ is a Hash containing site configurations details
#
# Returns <Site>
def initialize(source, dest)
self.source = source
self.dest = dest
self.layouts = {}
self.posts = []
self.categories = Hash.new { |hash, key| hash[key] = Array.new }
def initialize(config)
self.config = config.clone
self.safe = config['safe']
self.source = File.expand_path(config['source'])
self.dest = File.expand_path(config['destination'])
self.plugins = File.expand_path(config['plugins'])
self.lsi = config['lsi']
self.pygments = config['pygments']
self.permalink_style = config['permalink'].to_sym
self.exclude = config['exclude'] || []
self.future = config['future']
self.limit_posts = config['limit_posts'] || nil
self.reset
self.setup
end
def reset
self.time = if self.config['time']
Time.parse(self.config['time'].to_s)
else
Time.now
end
self.layouts = {}
self.posts = []
self.pages = []
self.static_files = []
self.categories = Hash.new { |hash, key| hash[key] = [] }
self.tags = Hash.new { |hash, key| hash[key] = [] }
raise ArgumentError, "Limit posts must be nil or >= 1" if !self.limit_posts.nil? && self.limit_posts < 1
end
def setup
require 'classifier' if self.lsi
# If safe mode is off, load in any ruby files under the plugins
# directory.
unless self.safe
Dir[File.join(self.plugins, "**/*.rb")].each do |f|
require f
end
end
self.converters = Jekyll::Converter.subclasses.select do |c|
!self.safe || c.safe
end.map do |c|
c.new(self.config)
end
self.generators = Jekyll::Generator.subclasses.select do |c|
!self.safe || c.safe
end.map do |c|
c.new(self.config)
end
end
# Do the actual work of processing the site and generating the
# real deal.
# real deal. 5 phases; reset, read, generate, render, write. This allows
# rendering to have full site payload available.
#
# Returns nothing
def process
self.read_layouts
self.transform_pages
self.write_posts
self.reset
self.read
self.generate
self.render
self.cleanup
self.write
end
# Read all the files in <source>/_layouts except backup files
# (end with "~") into memory for later use.
def read
self.read_layouts # existing implementation did this at top level only so preserved that
self.read_directories
end
# Read all the files in <source>/<dir>/_layouts and create a new Layout
# object with each one.
#
# Returns nothing
def read_layouts
base = File.join(self.source, "_layouts")
entries = Dir.entries(base)
entries = entries.reject { |e| e[-1..-1] == '~' }
entries = entries.reject { |e| File.directory?(File.join(base, e)) }
def read_layouts(dir = '')
base = File.join(self.source, dir, "_layouts")
return unless File.exists?(base)
entries = []
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
entries.each do |f|
name = f.split(".")[0..-2].join(".")
self.layouts[name] = Layout.new(base, f)
self.layouts[name] = Layout.new(self, base, f)
end
rescue Errno::ENOENT => e
# ignore missing layout dir
end
# Read all the files in <base>/_posts except backup files (end with "~")
# and create a new Post object with each one.
# Read all the files in <source>/<dir>/_posts and create a new Post
# object with each one.
#
# Returns nothing
def read_posts(dir)
base = File.join(self.source, dir, '_posts')
entries = []
Dir.chdir(base) { entries = Dir['**/*'] }
entries = entries.reject { |e| e[-1..-1] == '~' }
entries = entries.reject { |e| File.directory?(File.join(base, e)) }
return unless File.exists?(base)
entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
# first pass processes, but does not yet render post content
entries.each do |f|
if Post.valid?(f)
post = Post.new(self.source, dir, f)
self.posts << post
post.categories.each { |c| self.categories[c] << post }
post = Post.new(self, self.source, dir, f)
if post.published && (self.future || post.date <= self.time)
self.posts << post
post.categories.each { |c| self.categories[c] << post }
post.tags.each { |c| self.tags[c] << post }
end
end
end
# second pass renders each post now that full site payload is available
self.posts.sort!
# limit the posts if :limit_posts option is set
self.posts = self.posts[-limit_posts, limit_posts] if limit_posts
end
def generate
self.generators.each do |generator|
generator.generate(self)
end
end
def render
self.posts.each do |post|
post.render(self.layouts, site_payload)
end
self.posts.sort!
self.categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
self.pages.each do |page|
page.render(self.layouts, site_payload)
end
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
rescue Errno::ENOENT => e
# ignore missing layout dir
end
# Write each post to <dest>/<year>/<month>/<day>/<slug>
# Remove orphaned files and empty directories in destination
#
# Returns nothing
def write_posts
def cleanup
# all files and directories in destination, including hidden ones
dest_files = Set.new
Dir.glob(File.join(self.dest, "**", "*"), File::FNM_DOTMATCH) do |file|
dest_files << file unless file =~ /\/\.{1,2}$/
end
# files to be written
files = Set.new
self.posts.each do |post|
files << post.destination(self.dest)
end
self.pages.each do |page|
files << page.destination(self.dest)
end
self.static_files.each do |sf|
files << sf.destination(self.dest)
end
# adding files' parent directories
dirs = Set.new
files.each { |file| dirs << File.dirname(file) }
files.merge(dirs)
obsolete_files = dest_files - files
FileUtils.rm_rf(obsolete_files.to_a)
end
# Write static files, pages and posts
#
# Returns nothing
def write
self.posts.each do |post|
post.write(self.dest)
end
self.pages.each do |page|
page.write(self.dest)
end
self.static_files.each do |sf|
sf.write(self.dest)
end
end
# Copy all regular files from <source> to <dest>/ ignoring
# any files/directories that are hidden or backup files (start
# with "." or end with "~") or contain site content (start with "_")
# unless they are "_posts" directories or web server files such as
# '.htaccess'
# Reads the directories and finds posts, pages and static files that will
# become part of the valid site according to the rules in +filter_entries+.
# The +dir+ String is a relative path used to call this method
# recursively as it descends through directories
#
# Returns nothing
def transform_pages(dir = '')
def read_directories(dir = '')
base = File.join(self.source, dir)
entries = Dir.entries(base)
entries = entries.reject { |e| e[-1..-1] == '~' }
entries = entries.reject do |e|
(e != '_posts') and ['.', '_'].include?(e[0..0]) unless ['.htaccess'].include?(e)
end
directories = entries.select { |e| File.directory?(File.join(base, e)) }
files = entries.reject { |e| File.directory?(File.join(base, e)) }
entries = Dir.chdir(base){ filter_entries(Dir['*']) }
# we need to make sure to process _posts *first* otherwise they
# might not be available yet to other templates as {{ site.posts }}
if entries.include?('_posts')
entries.delete('_posts')
read_posts(dir)
end
[directories, files].each do |entries|
entries.each do |f|
if File.directory?(File.join(base, f))
next if self.dest.sub(/\/$/, '') == File.join(base, f)
transform_pages(File.join(dir, f))
self.read_posts(dir)
entries.each do |f|
f_abs = File.join(base, f)
f_rel = File.join(dir, f)
if File.directory?(f_abs)
next if self.dest.sub(/\/$/, '') == f_abs
read_directories(f_rel)
elsif !File.symlink?(f_abs)
first3 = File.open(f_abs) { |fd| fd.read(3) }
if first3 == "---"
# file appears to have a YAML header so process it as a page
pages << Page.new(self, self.source, dir, f)
else
first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) }
if first3 == "---"
# file appears to have a YAML header so process it as a page
page = Page.new(self.source, dir, f)
page.render(self.layouts, site_payload)
page.write(self.dest)
else
# otherwise copy the file without transforming it
FileUtils.mkdir_p(File.join(self.dest, dir))
FileUtils.cp(File.join(self.source, dir, f), File.join(self.dest, dir, f))
end
# otherwise treat it as a static file
static_files << StaticFile.new(self, self.source, dir, f)
end
end
end
@@ -152,16 +249,32 @@ module Jekyll
#
# Returns {"site" => {"time" => <Time>,
# "posts" => [<Post>],
# "categories" => [<Post>],
# "topics" => [<Post>] }}
# "pages" => [<Page>],
# "categories" => [<Post>]}
def site_payload
{"site" => {
"time" => Time.now,
"posts" => self.posts.sort { |a,b| b <=> a },
"categories" => post_attr_hash('categories'),
"topics" => post_attr_hash('topics')
}}
{"site" => self.config.merge({
"time" => self.time,
"posts" => self.posts.sort { |a,b| b <=> a },
"pages" => self.pages,
"html_pages" => self.pages.reject { |page| !page.html? },
"categories" => post_attr_hash('categories'),
"tags" => post_attr_hash('tags')})}
end
end
# Filter out any files/directories that are hidden or backup files (start
# with "." or "#" or end with "~"), or contain site content (start with "_"),
# or are excluded in the site configuration, unless they are web server
# files such as '.htaccess'
def filter_entries(entries)
entries = entries.reject do |e|
unless ['.htaccess'].include?(e)
['.', '_', '#'].include?(e[0..0]) ||
e[-1..-1] == '~' ||
self.exclude.include?(e) ||
File.symlink?(e)
end
end
end
end
end

75
lib/jekyll/static_file.rb Normal file
View File

@@ -0,0 +1,75 @@
module Jekyll
class StaticFile
@@mtimes = Hash.new # the cache of last modification times [path] -> mtime
# Initialize a new StaticFile.
# +site+ is the Site
# +base+ is the String path to the <source>
# +dir+ is the String path between <source> and the file
# +name+ is the String filename of the file
#
# Returns <StaticFile>
def initialize(site, base, dir, name)
@site = site
@base = base
@dir = dir
@name = name
end
# Obtains source file path.
#
# Returns source file path.
def path
File.join(@base, @dir, @name)
end
# Obtain destination path.
# +dest+ is the String path to the destination dir
#
# Returns destination file path.
def destination(dest)
File.join(dest, @dir, @name)
end
# Obtain mtime of the source path.
#
# Returns last modifiaction time for this file.
def mtime
File.stat(path).mtime.to_i
end
# Is source path modified?
#
# Returns true if modified since last write.
def modified?
@@mtimes[path] != mtime
end
# Write the static file to the destination directory (if modified).
# +dest+ is the String path to the destination dir
#
# Returns false if the file was not modified since last time (no-op).
def write(dest)
dest_path = destination(dest)
return false if File.exist? dest_path and !modified?
@@mtimes[path] = mtime
FileUtils.mkdir_p(File.dirname(dest_path))
FileUtils.cp(path, dest_path)
true
end
# Reset the mtimes cache (for testing purposes).
#
# Returns nothing.
def self.reset_cache
@@mtimes = Hash.new
nil
end
end
end

View File

@@ -1,17 +1,31 @@
module Jekyll
class HighlightBlock < Liquid::Block
include Liquid::StandardFilters
# we need a language, but the linenos argument is optional.
SYNTAX = /(\w+)\s?(:?linenos)?\s?/
SYNTAX = /(\w+)\s?([\w\s=]+)*/
def initialize(tag_name, markup, tokens)
super
if markup =~ SYNTAX
@lang = $1
if defined? $2
tmp_options = {}
$2.split.each do |opt|
key, value = opt.split('=')
if value.nil?
if key == 'linenos'
value = 'inline'
else
value = true
end
end
tmp_options[key] = value
end
tmp_options = tmp_options.to_a.collect { |opt| opt.join('=') }
# additional options to pass to Albino.
@options = { 'O' => 'linenos=inline' }
@options = { 'O' => tmp_options.join(',') }
else
@options = {}
end
@@ -19,23 +33,22 @@ module Jekyll
raise SyntaxError.new("Syntax Error in 'highlight' - Valid syntax: highlight <lang> [linenos]")
end
end
def render(context)
if Jekyll.pygments
render_pygments(context, super.to_s)
if context.registers[:site].pygments
render_pygments(context, super.join)
else
render_codehighlighter(context, super.to_s)
render_codehighlighter(context, super.join)
end
end
def render_pygments(context, code)
if Jekyll.content_type == :markdown
return "\n" + Albino.new(code, @lang).to_s(@options) + "\n"
else
"<notextile>" + Albino.new(code, @lang).to_s(@options) + "</notextile>"
end
output = add_code_tags(Albino.new(code, @lang).to_s(@options), @lang)
output = context["pygments_prefix"] + output if context["pygments_prefix"]
output = output + context["pygments_suffix"] if context["pygments_suffix"]
output
end
def render_codehighlighter(context, code)
#The div is required because RDiscount blows ass
<<-HTML
@@ -46,8 +59,15 @@ module Jekyll
</div>
HTML
end
def add_code_tags(code, lang)
# Add nested <code> tags to code blocks
code = code.sub(/<pre>/,'<pre><code class="' + lang + '">')
code = code.sub(/<\/pre>/,"</code></pre>")
end
end
end
Liquid::Template.register_tag('highlight', Jekyll::HighlightBlock)

View File

@@ -1,17 +1,23 @@
module Jekyll
class IncludeTag < Liquid::Tag
def initialize(tag_name, file, tokens)
super
@file = file.strip
end
def render(context)
includes_dir = File.join(context.registers[:site].source, '_includes')
if File.symlink?(includes_dir)
return "Includes directory '#{includes_dir}' cannot be a symlink"
end
if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
return "Include file '#{@file}' contains invalid characters or sequences"
end
Dir.chdir(File.join(Jekyll.source, '_includes')) do
Dir.chdir(includes_dir) do
choices = Dir['**/*'].reject { |x| File.symlink?(x) }
if choices.include?(@file)
source = File.read(@file)
@@ -25,7 +31,7 @@ module Jekyll
end
end
end
end
Liquid::Template.register_tag('include', Jekyll::IncludeTag)

View File

@@ -1,13 +1,34 @@
require 'rubygems'
gem 'RedCloth', '>= 4.2.1'
require File.join(File.dirname(__FILE__), *%w[.. lib jekyll])
require 'RedCloth'
require 'rdiscount'
require 'kramdown'
require 'test/unit'
require 'redgreen'
require 'shoulda'
require 'rr'
include Jekyll
def dest_dir
File.join(File.dirname(__FILE__), *%w[dest])
end
# Send STDERR into the void to suppress program output messages
STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:')
def clear_dest
FileUtils.rm_rf(dest_dir)
end
class Test::Unit::TestCase
include RR::Adapters::TestUnit
def dest_dir(*subdirs)
File.join(File.dirname(__FILE__), 'dest', *subdirs)
end
def source_dir(*subdirs)
File.join(File.dirname(__FILE__), 'source', *subdirs)
end
def clear_dest
FileUtils.rm_rf(dest_dir)
end
end

8
test/source/.htaccess Normal file
View File

@@ -0,0 +1,8 @@
---
layout: nil
---
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
{% for post in site.posts %}
# {{ post.url }}
{% endfor %}

View File

@@ -0,0 +1,8 @@
---
layout: default
title: Not published!
published: false
category: publish_test
---
This should *not* be published!

View File

@@ -0,0 +1,8 @@
---
layout: default
title: Publish
category: publish_test
---
This should be published.

View File

@@ -0,0 +1,10 @@
---
layout: default
title: Array categories in YAML
categories:
- foo
- bar
- baz
---
Best *post* ever

View File

@@ -0,0 +1,7 @@
---
layout: default
title: Categories in YAML
categories: foo bar baz
---
Best *post* ever

View File

@@ -0,0 +1,7 @@
---
layout: default
title: Category in YAML
category: foo
---
Best *post* ever

View File

@@ -0,0 +1,7 @@
---
layout: default
title: Category in YAML
categories:
---
Best *post* ever

View File

@@ -0,0 +1,7 @@
---
layout: default
title: Category in YAML
category:
---
Best *post* ever

View File

@@ -0,0 +1,6 @@
---
layout: default
title: Hash #1
---
Hashes are nice

View File

@@ -0,0 +1,6 @@
---
title: A Tag
tag:
---
Whoa.

View File

@@ -0,0 +1,6 @@
---
title: Some Tags
tags:
---
Awesome!

View File

@@ -0,0 +1,6 @@
---
title: A Tag
tag: code
---
Whoa.

View File

@@ -0,0 +1,9 @@
---
title: Some Tags
tags:
- food
- cooking
- pizza
---
Awesome!

View File

@@ -0,0 +1,3 @@
---
---
Empty YAML.

View File

@@ -0,0 +1 @@
No YAML.

View File

@@ -0,0 +1,5 @@
---
title: Foo --- Bar
---
Triple the fun!

View File

@@ -0,0 +1,7 @@
---
date: 2010-01-10
---
Post with a front matter date
{{ page.date | date_to_string }}

View File

@@ -0,0 +1,7 @@
---
date: 2010-01-10 13:07:09
---
Post with a front matter time
{{ page.date | date_to_string }}

View File

@@ -0,0 +1,7 @@
---
date: 2010-01-10 13:07:09 +00:00
---
Post with a front matter time with timezone
{{ page.date | date_to_string }}

View File

@@ -0,0 +1,4 @@
---
date: 2010-01-10 13:07:09
tags: A string
---

6
test/source/about.html Normal file
View File

@@ -0,0 +1,6 @@
---
title: About
permalink: /about/
---
About the site

View File

@@ -0,0 +1,5 @@
---
title: Contact Information
---
Contact Information

View File

@@ -0,0 +1,7 @@
---
title: Deal with dots
permalink: /deal.with.dots/
---
Let's test if jekyll deals properly with dots.

32
test/source/sitemap.xml Normal file
View File

@@ -0,0 +1,32 @@
---
layout: nil
---
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://example.com</loc>
<lastmod>{{ site.time | date: "%Y-%m-%d" }}</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
{% for post in site.posts %}
<url>
<loc>http://example.com{{ post.url }}/</loc>
<lastmod>{{ post.date | date: "%Y-%m-%d" }}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.2</priority>
</url>
{% endfor %}
{% for page in site.html_pages %}
<url>
<loc>http://example.com{{ page.url }}</loc>
<lastmod>{{ site.time | date: "%Y-%m-%d" }}</lastmod>
{% if page.changefreq %}<changefreq>{{ page.changefreq }}</changefreq>{% endif %}
{% if page.priority %}<priority>{{ page.priority }}</priority>{% endif %}
</url>
{% endfor %}
</urlset>

View File

@@ -0,0 +1,7 @@
---
layout: post
title: "Test title"
tag: "Ruby"
---
This is the content

View File

@@ -0,0 +1,29 @@
require File.dirname(__FILE__) + '/helper'
class TestConfiguration < Test::Unit::TestCase
context "loading configuration" do
setup do
@path = File.join(Dir.pwd, '_config.yml')
end
should "fire warning with no _config.yml" do
mock(YAML).load_file(@path) { raise "No such file or directory - #{@path}" }
mock($stderr).puts("WARNING: Could not read configuration. Using defaults (and options).")
mock($stderr).puts("\tNo such file or directory - #{@path}")
assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
end
should "load configuration as hash" do
mock(YAML).load_file(@path) { Hash.new }
mock($stdout).puts("Configuration from #{@path}")
assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
end
should "fire warning with bad config" do
mock(YAML).load_file(@path) { Array.new }
mock($stderr).puts("WARNING: Could not read configuration. Using defaults (and options).")
mock($stderr).puts("\tInvalid configuration - #{@path}")
assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
end
end
end

66
test/test_core_ext.rb Normal file
View File

@@ -0,0 +1,66 @@
require File.dirname(__FILE__) + '/helper'
class TestCoreExt < Test::Unit::TestCase
context "hash" do
context "pluralized_array" do
should "return empty array with no values" do
data = {}
assert_equal [], data.pluralized_array('tag', 'tags')
end
should "return empty array with no matching values" do
data = { 'foo' => 'bar' }
assert_equal [], data.pluralized_array('tag', 'tags')
end
should "return empty array with matching nil singular" do
data = { 'foo' => 'bar', 'tag' => nil, 'tags' => ['dog', 'cat'] }
assert_equal [], data.pluralized_array('tag', 'tags')
end
should "return single value array with matching singular" do
data = { 'foo' => 'bar', 'tag' => 'dog', 'tags' => ['dog', 'cat'] }
assert_equal ['dog'], data.pluralized_array('tag', 'tags')
end
should "return single value array with matching singular with spaces" do
data = { 'foo' => 'bar', 'tag' => 'dog cat', 'tags' => ['dog', 'cat'] }
assert_equal ['dog cat'], data.pluralized_array('tag', 'tags')
end
should "return empty array with matching nil plural" do
data = { 'foo' => 'bar', 'tags' => nil }
assert_equal [], data.pluralized_array('tag', 'tags')
end
should "return empty array with matching empty array" do
data = { 'foo' => 'bar', 'tags' => [] }
assert_equal [], data.pluralized_array('tag', 'tags')
end
should "return single value array with matching plural with single string value" do
data = { 'foo' => 'bar', 'tags' => 'dog' }
assert_equal ['dog'], data.pluralized_array('tag', 'tags')
end
should "return multiple value array with matching plural with single string value with spaces" do
data = { 'foo' => 'bar', 'tags' => 'dog cat' }
assert_equal ['dog', 'cat'], data.pluralized_array('tag', 'tags')
end
should "return single value array with matching plural with single value array" do
data = { 'foo' => 'bar', 'tags' => ['dog'] }
assert_equal ['dog'], data.pluralized_array('tag', 'tags')
end
should "return multiple value array with matching plural with multiple value array" do
data = { 'foo' => 'bar', 'tags' => ['dog', 'cat'] }
assert_equal ['dog', 'cat'], data.pluralized_array('tag', 'tags')
end
end
end
end

View File

@@ -1,37 +1,53 @@
require File.dirname(__FILE__) + '/helper'
class TestFilters < Test::Unit::TestCase
class JekyllFilter
include Jekyll::Filters
end
def setup
@filter = JekyllFilter.new
end
def test_array_to_sentence_string_with_no_args
assert_equal "", @filter.array_to_sentence_string([])
end
context "filters" do
setup do
@filter = JekyllFilter.new
end
def test_array_to_sentence_string_with_one_arg
assert_equal "1", @filter.array_to_sentence_string([1])
assert_equal "chunky", @filter.array_to_sentence_string(["chunky"])
should "textilize with simple string" do
assert_equal "<p>something <strong>really</strong> simple</p>", @filter.textilize("something *really* simple")
end
should "convert array to sentence string with no args" do
assert_equal "", @filter.array_to_sentence_string([])
end
should "convert array to sentence string with one arg" do
assert_equal "1", @filter.array_to_sentence_string([1])
assert_equal "chunky", @filter.array_to_sentence_string(["chunky"])
end
should "convert array to sentence string with two args" do
assert_equal "1 and 2", @filter.array_to_sentence_string([1, 2])
assert_equal "chunky and bacon", @filter.array_to_sentence_string(["chunky", "bacon"])
end
should "convert array to sentence string with multiple args" do
assert_equal "1, 2, 3, and 4", @filter.array_to_sentence_string([1, 2, 3, 4])
assert_equal "chunky, bacon, bits, and pieces", @filter.array_to_sentence_string(["chunky", "bacon", "bits", "pieces"])
end
should "escape xml with ampersands" do
assert_equal "AT&amp;T", @filter.xml_escape("AT&T")
assert_equal "&lt;code&gt;command &amp;lt;filename&amp;gt;&lt;/code&gt;", @filter.xml_escape("<code>command &lt;filename&gt;</code>")
end
should "escape space as plus" do
assert_equal "my+things", @filter.cgi_escape("my things")
end
should "escape special characters" do
assert_equal "hey%21", @filter.cgi_escape("hey!")
end
should "escape space as %20" do
assert_equal "my%20things", @filter.uri_escape("my things")
end
end
def test_array_to_sentence_string_with_two_args
assert_equal "1 and 2", @filter.array_to_sentence_string([1, 2])
assert_equal "chunky and bacon", @filter.array_to_sentence_string(["chunky", "bacon"])
end
def test_array_to_sentence_string_with_multiple_args
assert_equal "1, 2, 3, and 4", @filter.array_to_sentence_string([1, 2, 3, 4])
assert_equal "chunky, bacon, bits, and pieces", @filter.array_to_sentence_string(["chunky", "bacon", "bits", "pieces"])
end
def test_xml_escape_with_ampersands
assert_equal "AT&amp;T", @filter.xml_escape("AT&T")
assert_equal "&lt;code&gt;command &amp;lt;filename&amp;gt;&lt;/code&gt;", @filter.xml_escape("<code>command &lt;filename&gt;</code>")
end
end

View File

@@ -1,22 +1,72 @@
require File.dirname(__FILE__) + '/helper'
class TestGeneratedSite < Test::Unit::TestCase
def setup
clear_dest
source = File.join(File.dirname(__FILE__), *%w[source])
@s = Site.new(source, dest_dir)
@s.process
@index = File.read(File.join(dest_dir, 'index.html'))
end
def test_site_posts_in_index
# confirm that {{ site.posts }} is working
puts @s.posts.size
assert @index.include?("#{@s.posts.size} Posts")
context "generated sites" do
setup do
clear_dest
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
end
@site = Site.new(Jekyll.configuration)
@site.process
@index = File.read(dest_dir('index.html'))
end
should "ensure post count is as expected" do
assert_equal 26, @site.posts.size
end
should "insert site.posts into the index" do
assert @index.include?("#{@site.posts.size} Posts")
end
should "render latest post's content" do
assert @index.include?(@site.posts.last.content)
end
should "hide unpublished posts" do
published = Dir[dest_dir('publish_test/2008/02/02/*.html')].map {|f| File.basename(f)}
assert_equal 1, published.size
assert_equal "published.html", published.first
end
should "not copy _posts directory" do
assert !File.exist?(dest_dir('_posts'))
end
should "process other static files and generate correct permalinks" do
assert File.exists?(dest_dir('/about/index.html'))
assert File.exists?(dest_dir('/contacts.html'))
end
end
def test_post_content_in_index
# confirm that the {{ post.content }} is rendered OK
assert @index.include?('<p>This <em>is</em> cool</p>')
context "generating limited posts" do
setup do
clear_dest
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 5})
end
@site = Site.new(Jekyll.configuration)
@site.process
@index = File.read(dest_dir('index.html'))
end
should "generate only the specified number of posts" do
assert_equal 5, @site.posts.size
end
should "ensure limit posts is 1 or more" do
assert_raise ArgumentError do
clear_dest
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 0})
end
@site = Site.new(Jekyll.configuration)
end
end
end
end

View File

23
test/test_kramdown.rb Normal file
View File

@@ -0,0 +1,23 @@
require File.dirname(__FILE__) + '/helper'
class TestKramdown < Test::Unit::TestCase
context "kramdown" do
setup do
config = {
'markdown' => 'kramdown',
'kramdown' => {
'auto_ids' => false,
'footnote_nr' => 1,
'entity_output' => 'as_char',
'toc_levels' => '1..6'
}
}
@markdown = MarkdownConverter.new config
end
# http://kramdown.rubyforge.org/converter/html.html#options
should "pass kramdown options" do
assert_equal "<h1>Some Header</h1>", @markdown.convert('# Some Header #').strip
end
end
end

117
test/test_page.rb Normal file
View File

@@ -0,0 +1,117 @@
require File.dirname(__FILE__) + '/helper'
class TestPage < Test::Unit::TestCase
def setup_page(file)
@page = Page.new(@site, source_dir, '', file)
end
def do_render(page)
layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")}
page.render(layouts, {"site" => {"posts" => []}})
end
context "A Page" do
setup do
clear_dest
stub(Jekyll).configuration { Jekyll::DEFAULTS }
@site = Site.new(Jekyll.configuration)
end
context "processing pages" do
should "create url based on filename" do
@page = setup_page('contacts.html')
assert_equal "/contacts.html", @page.url
end
should "deal properly with extensions" do
@page = setup_page('deal.with.dots.html')
assert_equal ".html", @page.ext
end
should "deal properly with dots" do
@page = setup_page('deal.with.dots.html')
assert_equal "deal.with.dots", @page.basename
end
context "with pretty url style" do
setup do
@site.permalink_style = :pretty
end
should "return dir correctly" do
@page = setup_page('contacts.html')
assert_equal '/contacts/', @page.dir
end
should "return dir correctly for index page" do
@page = setup_page('index.html')
assert_equal '/', @page.dir
end
end
context "with any other url style" do
should "return dir correctly" do
@site.permalink_style = nil
@page = setup_page('contacts.html')
assert_equal '/', @page.dir
end
end
should "respect permalink in yaml front matter" do
file = "about.html"
@page = setup_page(file)
assert_equal "/about/", @page.permalink
assert_equal @page.permalink, @page.url
assert_equal "/about/", @page.dir
end
end
context "rendering" do
setup do
clear_dest
end
should "write properly" do
page = setup_page('contacts.html')
do_render(page)
page.write(dest_dir)
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir, 'contacts.html'))
end
should "write properly without html extension" do
page = setup_page('contacts.html')
page.site.permalink_style = :pretty
do_render(page)
page.write(dest_dir)
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir, 'contacts', 'index.html'))
end
should "write properly with extension different from html" do
page = setup_page("sitemap.xml")
page.site.permalink_style = :pretty
do_render(page)
page.write(dest_dir)
assert_equal("/sitemap.xml", page.url)
assert_nil(page.url[/\.html$/])
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir,'sitemap.xml'))
end
should "write dotfiles properly" do
page = setup_page('.htaccess')
do_render(page)
page.write(dest_dir)
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir, '.htaccess'))
end
end
end
end

113
test/test_pager.rb Normal file
View File

@@ -0,0 +1,113 @@
require File.dirname(__FILE__) + '/helper'
class TestPager < Test::Unit::TestCase
should "calculate number of pages" do
assert_equal(0, Pager.calculate_pages([], '2'))
assert_equal(1, Pager.calculate_pages([1], '2'))
assert_equal(1, Pager.calculate_pages([1,2], '2'))
assert_equal(2, Pager.calculate_pages([1,2,3], '2'))
assert_equal(2, Pager.calculate_pages([1,2,3,4], '2'))
assert_equal(3, Pager.calculate_pages([1,2,3,4,5], '2'))
end
context "pagination disabled" do
setup do
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({
'source' => source_dir,
'destination' => dest_dir
})
end
@config = Jekyll.configuration
end
should "report that pagination is disabled" do
assert !Pager.pagination_enabled?(@config, 'index.html')
end
end
context "pagination enabled for 2" do
setup do
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({
'source' => source_dir,
'destination' => dest_dir,
'paginate' => 2
})
end
@config = Jekyll.configuration
@site = Site.new(@config)
@site.process
@posts = @site.posts
end
should "report that pagination is enabled" do
assert Pager.pagination_enabled?(@config, 'index.html')
end
context "with 4 posts" do
setup do
@posts = @site.posts[1..4] # limit to 4
end
should "create first pager" do
pager = Pager.new(@config, 1, @posts)
assert_equal(2, pager.posts.size)
assert_equal(2, pager.total_pages)
assert_nil(pager.previous_page)
assert_equal(2, pager.next_page)
end
should "create second pager" do
pager = Pager.new(@config, 2, @posts)
assert_equal(2, pager.posts.size)
assert_equal(2, pager.total_pages)
assert_equal(1, pager.previous_page)
assert_nil(pager.next_page)
end
should "not create third pager" do
assert_raise(RuntimeError) { Pager.new(@config, 3, @posts) }
end
end
context "with 5 posts" do
setup do
@posts = @site.posts[1..5] # limit to 5
end
should "create first pager" do
pager = Pager.new(@config, 1, @posts)
assert_equal(2, pager.posts.size)
assert_equal(3, pager.total_pages)
assert_nil(pager.previous_page)
assert_equal(2, pager.next_page)
end
should "create second pager" do
pager = Pager.new(@config, 2, @posts)
assert_equal(2, pager.posts.size)
assert_equal(3, pager.total_pages)
assert_equal(1, pager.previous_page)
assert_equal(3, pager.next_page)
end
should "create third pager" do
pager = Pager.new(@config, 3, @posts)
assert_equal(1, pager.posts.size)
assert_equal(3, pager.total_pages)
assert_equal(2, pager.previous_page)
assert_nil(pager.next_page)
end
should "not create fourth pager" do
assert_raise(RuntimeError) { Pager.new(@config, 4, @posts) }
end
end
end
end

View File

@@ -1,113 +1,402 @@
require File.dirname(__FILE__) + '/helper'
class TestPost < Test::Unit::TestCase
def setup
end
def test_valid
assert Post.valid?("2008-10-19-foo-bar.textile")
assert Post.valid?("foo/bar/2008-10-19-foo-bar.textile")
assert !Post.valid?("lol2008-10-19-foo-bar.textile")
assert !Post.valid?("blah")
end
def test_process
p = Post.allocate
p.process("2008-10-19-foo-bar.textile")
assert_equal Time.parse("2008-10-19"), p.date
assert_equal "foo-bar", p.slug
assert_equal ".textile", p.ext
end
def test_url
p = Post.allocate
p.categories = []
p.process("2008-10-19-foo-bar.textile")
assert_equal "/2008/10/19/foo-bar.html", p.url
end
def test_permalink
p = Post.allocate
p.process("2008-12-03-permalinked-post.textile")
p.read_yaml(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-12-03-permalinked-post.textile")
assert_equal "my_category/permalinked-post", p.permalink
def setup_post(file)
Post.new(@site, source_dir, '', file)
end
def test_dir_respects_permalink
p = Post.allocate
p.process("2008-12-03-permalinked-post.textile")
p.read_yaml(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-12-03-permalinked-post.textile")
assert_equal "my_category/", p.dir
end
def test_url_respects_permalink
p = Post.allocate
p.process("2008-12-03-permalinked-post.textile")
p.read_yaml(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-12-03-permalinked-post.textile")
assert_equal "my_category/permalinked-post", p.url
def do_render(post)
layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")}
post.render(layouts, {"site" => {"posts" => []}})
end
def test_read_yaml
p = Post.allocate
p.read_yaml(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-10-18-foo-bar.textile")
assert_equal({"title" => "Foo Bar", "layout" => "default"}, p.data)
assert_equal "\nh1. {{ page.title }}\n\nBest *post* ever", p.content
context "A Post" do
setup do
clear_dest
stub(Jekyll).configuration { Jekyll::DEFAULTS }
@site = Site.new(Jekyll.configuration)
end
should "ensure valid posts are valid" do
assert Post.valid?("2008-09-09-foo-bar.textile")
assert Post.valid?("foo/bar/2008-09-09-foo-bar.textile")
assert !Post.valid?("lol2008-09-09-foo-bar.textile")
assert !Post.valid?("blah")
end
context "processing posts" do
setup do
@post = Post.allocate
@post.site = @site
@real_file = "2008-10-18-foo-bar.textile"
@fake_file = "2008-09-09-foo-bar.textile"
@source = source_dir('_posts')
end
should "keep date, title, and markup type" do
@post.categories = []
@post.process(@fake_file)
assert_equal Time.parse("2008-09-09"), @post.date
assert_equal "foo-bar", @post.slug
assert_equal ".textile", @post.ext
assert_equal "/2008/09/09", @post.dir
assert_equal "/2008/09/09/foo-bar", @post.id
end
should "create url based on date and title" do
@post.categories = []
@post.process(@fake_file)
assert_equal "/2008/09/09/foo-bar.html", @post.url
end
should "raise a good error on invalid post date" do
assert_raise Jekyll::FatalException do
@post.process("2009-27-03-foo-bar.textile")
end
end
should "CGI escape urls" do
@post.categories = []
@post.process("2009-03-12-hash-#1.markdown")
assert_equal "/2009/03/12/hash-%231.html", @post.url
assert_equal "/2009/03/12/hash-#1", @post.id
end
should "respect permalink in yaml front matter" do
file = "2008-12-03-permalinked-post.textile"
@post.process(file)
@post.read_yaml(@source, file)
assert_equal "my_category/permalinked-post", @post.permalink
assert_equal "my_category", @post.dir
assert_equal "my_category/permalinked-post", @post.url
end
context "with CRLF linebreaks" do
setup do
@real_file = "2009-05-24-yaml-linebreak.markdown"
@source = source_dir('win/_posts')
end
should "read yaml front-matter" do
@post.read_yaml(@source, @real_file)
assert_equal({"title" => "Test title", "layout" => "post", "tag" => "Ruby"}, @post.data)
assert_equal "This is the content", @post.content
end
end
context "with embedded triple dash" do
setup do
@real_file = "2010-01-08-triple-dash.markdown"
end
should "consume the embedded dashes" do
@post.read_yaml(@source, @real_file)
assert_equal({"title" => "Foo --- Bar"}, @post.data)
assert_equal "Triple the fun!", @post.content
end
end
context "with site wide permalink" do
setup do
@post.categories = []
end
context "with unspecified (date) style" do
setup do
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/2008/09/09/foo-bar.html", @post.url
end
end
context "with unspecified (date) style and a category" do
setup do
@post.categories << "beer"
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/beer/2008/09/09/foo-bar.html", @post.url
end
end
context "with unspecified (date) style and categories" do
setup do
@post.categories << "food"
@post.categories << "beer"
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/food/beer/2008/09/09/foo-bar.html", @post.url
end
end
context "with none style" do
setup do
@post.site.permalink_style = :none
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/:categories/:title.html", @post.template
assert_equal "/foo-bar.html", @post.url
end
end
context "with pretty style" do
setup do
@post.site.permalink_style = :pretty
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title/", @post.template
assert_equal "/2008/09/09/foo-bar/", @post.url
end
end
context "with custom date permalink" do
setup do
@post.site.permalink_style = '/:categories/:year/:i_month/:i_day/:title/'
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/2008/9/9/foo-bar/", @post.url
end
end
context "with prefix style and no extension" do
setup do
@post.site.permalink_style = "/prefix/:title"
@post.process(@fake_file)
end
should "process the url correctly" do
assert_equal "/prefix/:title", @post.template
assert_equal "/prefix/foo-bar", @post.url
end
end
end
should "read yaml front-matter" do
@post.read_yaml(@source, @real_file)
assert_equal({"title" => "Foo Bar", "layout" => "default"}, @post.data)
assert_equal "h1. {{ page.title }}\n\nBest *post* ever", @post.content
end
should "transform textile" do
@post.process(@real_file)
@post.read_yaml(@source, @real_file)
@post.transform
assert_equal "<h1>{{ page.title }}</h1>\n<p>Best <strong>post</strong> ever</p>", @post.content
end
end
context "when in a site" do
setup do
clear_dest
stub(Jekyll).configuration { Jekyll::DEFAULTS }
@site = Site.new(Jekyll.configuration)
@site.posts = [setup_post('2008-02-02-published.textile'),
setup_post('2009-01-27-categories.textile')]
end
should "have next post" do
assert_equal(@site.posts.last, @site.posts.first.next)
end
should "have previous post" do
assert_equal(@site.posts.first, @site.posts.last.previous)
end
should "not have previous post if first" do
assert_equal(nil, @site.posts.first.previous)
end
should "not have next post if last" do
assert_equal(nil, @site.posts.last.next)
end
end
context "initializing posts" do
should "publish when published yaml is no specified" do
post = setup_post("2008-02-02-published.textile")
assert_equal true, post.published
end
should "not published when published yaml is false" do
post = setup_post("2008-02-02-not-published.textile")
assert_equal false, post.published
end
should "recognize date in yaml" do
post = setup_post("2010-01-09-date-override.textile")
do_render(post)
assert_equal Time, post.date.class
assert_equal Time, post.to_liquid["date"].class
assert_equal "/2010/01/10/date-override.html", post.url
assert_equal "<p>Post with a front matter date</p>\n<p>10 Jan 2010</p>", post.output
end
should "recognize time in yaml" do
post = setup_post("2010-01-09-time-override.textile")
do_render(post)
assert_equal Time, post.date.class
assert_equal Time, post.to_liquid["date"].class
assert_equal "/2010/01/10/time-override.html", post.url
assert_equal "<p>Post with a front matter time</p>\n<p>10 Jan 2010</p>", post.output
end
should "recognize time with timezone in yaml" do
post = setup_post("2010-01-09-timezone-override.textile")
do_render(post)
assert_equal Time, post.date.class
assert_equal Time, post.to_liquid["date"].class
assert_equal "/2010/01/10/timezone-override.html", post.url
assert_equal "<p>Post with a front matter time with timezone</p>\n<p>10 Jan 2010</p>", post.output
end
should "to_liquid prioritizes post attributes over data" do
post = setup_post("2010-01-16-override-data.textile")
assert_equal Array, post.tags.class
assert_equal Array, post.to_liquid["tags"].class
assert_equal Time, post.date.class
assert_equal Time, post.to_liquid["date"].class
end
should "recognize category in yaml" do
post = setup_post("2009-01-27-category.textile")
assert post.categories.include?('foo')
end
should "recognize several categories in yaml" do
post = setup_post("2009-01-27-categories.textile")
assert post.categories.include?('foo')
assert post.categories.include?('bar')
assert post.categories.include?('baz')
end
should "recognize empty category in yaml" do
post = setup_post("2009-01-27-empty-category.textile")
assert_equal [], post.categories
end
should "recognize empty categories in yaml" do
post = setup_post("2009-01-27-empty-categories.textile")
assert_equal [], post.categories
end
should "recognize tag in yaml" do
post = setup_post("2009-05-18-tag.textile")
assert post.tags.include?('code')
end
should "recognize tags in yaml" do
post = setup_post("2009-05-18-tags.textile")
assert post.tags.include?('food')
assert post.tags.include?('cooking')
assert post.tags.include?('pizza')
end
should "recognize empty tag in yaml" do
post = setup_post("2009-05-18-empty-tag.textile")
assert_equal [], post.tags
end
should "recognize empty tags in yaml" do
post = setup_post("2009-05-18-empty-tags.textile")
assert_equal [], post.tags
end
should "allow no yaml" do
post = setup_post("2009-06-22-no-yaml.textile")
assert_equal "No YAML.", post.content
end
should "allow empty yaml" do
post = setup_post("2009-06-22-empty-yaml.textile")
assert_equal "Empty YAML.", post.content
end
context "rendering" do
setup do
clear_dest
end
should "render properly" do
post = setup_post("2008-10-18-foo-bar.textile")
do_render(post)
assert_equal "<<< <h1>Foo Bar</h1>\n<p>Best <strong>post</strong> ever</p> >>>", post.output
end
should "write properly" do
post = setup_post("2008-10-18-foo-bar.textile")
do_render(post)
post.write(dest_dir)
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir, '2008', '10', '18', 'foo-bar.html'))
end
should "write properly without html extension" do
post = setup_post("2008-10-18-foo-bar.textile")
post.site.permalink_style = ":title"
do_render(post)
post.write(dest_dir)
assert File.directory?(dest_dir)
assert File.exists?(File.join(dest_dir, 'foo-bar', 'index.html'))
end
should "insert data" do
post = setup_post("2008-11-21-complex.textile")
do_render(post)
assert_equal "<<< <p>url: /2008/11/21/complex.html<br />\ndate: #{Time.parse("2008-11-21")}<br />\nid: /2008/11/21/complex</p> >>>", post.output
end
should "include templates" do
post = setup_post("2008-12-13-include.markdown")
post.site.source = File.join(File.dirname(__FILE__), 'source')
do_render(post)
assert_equal "<<< <hr />\n<p>Tom Preston-Werner github.com/mojombo</p>\n\n<p>This <em>is</em> cool</p> >>>", post.output
end
should "render date specified in front matter properly" do
post = setup_post("2010-01-09-date-override.textile")
do_render(post)
assert_equal "<p>Post with a front matter date</p>\n<p>10 Jan 2010</p>", post.output
end
should "render time specified in front matter properly" do
post = setup_post("2010-01-09-time-override.textile")
do_render(post)
assert_equal "<p>Post with a front matter time</p>\n<p>10 Jan 2010</p>", post.output
end
end
end
should "generate categories and topics" do
post = Post.new(@site, File.join(File.dirname(__FILE__), *%w[source]), 'foo', 'bar/2008-12-12-topical-post.textile')
assert_equal ['foo'], post.categories
end
end
def test_transform
p = Post.allocate
p.process("2008-10-18-foo-bar.textile")
p.read_yaml(File.join(File.dirname(__FILE__), *%w[source _posts]), "2008-10-18-foo-bar.textile")
p.transform
assert_equal "<h1>{{ page.title }}</h1>\n<p>Best <strong>post</strong> ever</p>", p.content
end
def test_render
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-10-18-foo-bar.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
assert_equal "<<< <h1>Foo Bar</h1>\n<p>Best <strong>post</strong> ever</p> >>>", p.output
end
def test_write
clear_dest
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-10-18-foo-bar.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
p.write(dest_dir)
end
def test_data
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-11-21-complex.textile")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
assert_equal "<<< <p>url: /2008/11/21/complex.html<br />\ndate: #{Time.parse("2008-11-21")}<br />\nid: /2008/11/21/complex</p> >>>", p.output
end
def test_categories_and_topics
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), 'foo', 'bar/2008-12-12-topical-post.textile')
assert_equal ['foo'], p.categories
assert_equal ['bar'], p.topics
end
def test_include
Jekyll.source = File.join(File.dirname(__FILE__), *%w[source])
p = Post.new(File.join(File.dirname(__FILE__), *%w[source]), '', "2008-12-13-include.markdown")
layouts = {"default" => Layout.new(File.join(File.dirname(__FILE__), *%w[source _layouts]), "simple.html")}
p.render(layouts, {"site" => {"posts" => []}})
assert_equal "<<< <hr />\n<p>Tom Preston-Werner github.com/mojombo</p>\n\n<p>This <em>is</em> cool</p> >>>", p.output
end
end
end

18
test/test_rdiscount.rb Normal file
View File

@@ -0,0 +1,18 @@
require File.dirname(__FILE__) + '/helper'
class TestRdiscount < Test::Unit::TestCase
context "rdiscount" do
setup do
config = {
'rdiscount' => { 'extensions' => ['smart'] },
'markdown' => 'rdiscount'
}
@markdown = MarkdownConverter.new config
end
should "pass rdiscount extensions" do
assert_equal "<p>&ldquo;smart&rdquo;</p>", @markdown.convert('"smart"').strip
end
end
end

View File

@@ -1,33 +1,186 @@
require File.dirname(__FILE__) + '/helper'
class TestSite < Test::Unit::TestCase
def setup
source = File.join(File.dirname(__FILE__), *%w[source])
@s = Site.new(source, dest_dir)
end
def test_site_init
context "creating sites" do
setup do
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
end
@site = Site.new(Jekyll.configuration)
end
should "have an empty tag hash by default" do
assert_equal Hash.new, @site.tags
end
should "reset data before processing" do
clear_dest
@site.process
before_posts = @site.posts.length
before_layouts = @site.layouts.length
before_categories = @site.categories.length
before_tags = @site.tags.length
before_pages = @site.pages.length
before_static_files = @site.static_files.length
before_time = @site.time
@site.process
assert_equal before_posts, @site.posts.length
assert_equal before_layouts, @site.layouts.length
assert_equal before_categories, @site.categories.length
assert_equal before_tags, @site.tags.length
assert_equal before_pages, @site.pages.length
assert_equal before_static_files, @site.static_files.length
assert before_time <= @site.time
end
should "write only modified static files" do
clear_dest
StaticFile.reset_cache
@site.process
some_static_file = @site.static_files[0].path
dest = File.expand_path(@site.static_files[0].destination(@site.dest))
mtime1 = File.stat(dest).mtime.to_i # first run must generate dest file
# need to sleep because filesystem timestamps have best resolution in seconds
sleep 1
@site.process
mtime2 = File.stat(dest).mtime.to_i
assert_equal mtime1, mtime2
# simulate file modification by user
FileUtils.touch some_static_file
sleep 1
@site.process
mtime3 = File.stat(dest).mtime.to_i
assert_not_equal mtime2, mtime3 # must be regenerated!
sleep 1
@site.process
mtime4 = File.stat(dest).mtime.to_i
assert_equal mtime3, mtime4 # no modifications, so must be the same
end
should "write static files if not modified but missing in destination" do
clear_dest
StaticFile.reset_cache
@site.process
some_static_file = @site.static_files[0].path
dest = File.expand_path(@site.static_files[0].destination(@site.dest))
mtime1 = File.stat(dest).mtime.to_i # first run must generate dest file
# need to sleep because filesystem timestamps have best resolution in seconds
sleep 1
@site.process
mtime2 = File.stat(dest).mtime.to_i
assert_equal mtime1, mtime2
# simulate destination file deletion
File.unlink dest
sleep 1
@site.process
mtime3 = File.stat(dest).mtime.to_i
assert_not_equal mtime2, mtime3 # must be regenerated and differ!
sleep 1
@site.process
mtime4 = File.stat(dest).mtime.to_i
assert_equal mtime3, mtime4 # no modifications, so must be the same
end
should "read layouts" do
@site.read_layouts
assert_equal ["default", "simple"].sort, @site.layouts.keys.sort
end
should "read posts" do
@site.read_posts('')
posts = Dir[source_dir('_posts', '*')]
assert_equal posts.size - 1, @site.posts.size
end
should "deploy payload" do
clear_dest
@site.process
posts = Dir[source_dir("**", "_posts", "*")]
categories = %w(bar baz category foo z_category publish_test win).sort
assert_equal posts.size - 1, @site.posts.size
assert_equal categories, @site.categories.keys.sort
assert_equal 4, @site.categories['foo'].size
end
should "filter entries" do
ent1 = %w[foo.markdown bar.markdown baz.markdown #baz.markdown#
.baz.markdow foo.markdown~]
ent2 = %w[.htaccess _posts _pages bla.bla]
assert_equal %w[foo.markdown bar.markdown baz.markdown], @site.filter_entries(ent1)
assert_equal %w[.htaccess bla.bla], @site.filter_entries(ent2)
end
should "filter entries with exclude" do
excludes = %w[README TODO]
includes = %w[index.html site.css]
@site.exclude = excludes
assert_equal includes, @site.filter_entries(excludes + includes)
end
end
def test_read_layouts
@s.read_layouts
context 'with orphaned files in destination' do
setup do
clear_dest
@site.process
# generate some orphaned files:
# hidden file
File.open(dest_dir('.htpasswd'), 'w')
# single file
File.open(dest_dir('obsolete.html'), 'w')
# single file in sub directory
FileUtils.mkdir(dest_dir('qux'))
File.open(dest_dir('qux/obsolete.html'), 'w')
# empty directory
FileUtils.mkdir(dest_dir('quux'))
end
teardown do
FileUtils.rm_f(dest_dir('.htpasswd'))
FileUtils.rm_f(dest_dir('obsolete.html'))
FileUtils.rm_rf(dest_dir('qux'))
FileUtils.rm_f(dest_dir('quux'))
end
should 'remove orphaned files in destination' do
@site.process
assert !File.exist?(dest_dir('.htpasswd'))
assert !File.exist?(dest_dir('obsolete.html'))
assert !File.exist?(dest_dir('qux'))
assert !File.exist?(dest_dir('quux'))
end
end
assert_equal ["default", "simple"].sort, @s.layouts.keys.sort
end
def test_read_posts
@s.read_posts('')
context 'with an invalid markdown processor in the configuration' do
should 'not throw an error at initialization time' do
bad_processor = 'not a processor name'
assert_nothing_raised do
Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
end
end
should 'throw FatalException at process time' do
bad_processor = 'not a processor name'
s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
assert_raise Jekyll::FatalException do
s.process
end
end
end
assert_equal 4, @s.posts.size
end
def test_site_payload
clear_dest
@s.process
assert_equal 7, @s.posts.length
assert_equal ["category", "foo", "z_category"].sort, @s.categories.keys.sort
assert_equal 1, @s.categories['foo'].length
end
end

View File

@@ -1,31 +1,127 @@
require File.dirname(__FILE__) + '/helper'
class TestTags < Test::Unit::TestCase
def setup
@content = <<CONTENT
def create_post(content, override = {}, converter_class = Jekyll::MarkdownConverter)
stub(Jekyll).configuration do
Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override)
end
site = Site.new(Jekyll.configuration)
info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
@converter = site.converters.find { |c| c.class == converter_class }
payload = { "pygments_prefix" => @converter.pygments_prefix,
"pygments_suffix" => @converter.pygments_suffix }
@result = Liquid::Template.parse(content).render(payload, info)
@result = @converter.convert(@result)
end
def fill_post(code, override = {})
content = <<CONTENT
---
layout: post
title: This is a test
---
This document results in a markdown error with maruku
{% highlight ruby %}
puts "hi"
puts "bye"
This document results in a markdown error with maruku
{% highlight text %}#{code}{% endhighlight %}
CONTENT
create_post(content, override)
end
context "post content has highlight tag" do
setup do
fill_post("test")
end
should "not cause a markdown error" do
assert_no_match /markdown\-html\-error/, @result
end
should "render markdown with pygments line handling" do
assert_match %{<pre><code class='text'>test\n</code></pre>}, @result
end
end
context "post content has highlight with file reference" do
setup do
fill_post("./jekyll.gemspec")
end
should "not embed the file" do
assert_match %{<pre><code class='text'>./jekyll.gemspec\n</code></pre>}, @result
end
end
context "post content has highlight tag with UTF character" do
setup do
fill_post("Æ")
end
should "render markdown with pygments line handling" do
assert_match %{<pre><code class='text'>Æ\n</code></pre>}, @result
end
end
context "simple post with markdown and pre tags" do
setup do
@content = <<CONTENT
---
title: Maruku vs. RDiscount
---
_FIGHT!_
{% highlight ruby %}
puts "3..2..1.."
{% endhighlight %}
*FINISH HIM*
CONTENT
end
def test_markdown_with_pygments_line_handling
Jekyll.pygments = true
Jekyll.content_type = :markdown
result = Liquid::Template.parse(@content).render({}, [Jekyll::Filters])
result = Jekyll.markdown_proc.call(result)
assert_no_match(/markdown\-html\-error/,result)
end
context "using Textile" do
setup do
create_post(@content, {}, Jekyll::TextileConverter)
end
# Broken in RedCloth 4.1.9
should "not textilize highlight block" do
assert_no_match %r{3\.\.2\.\.1\.\.&quot;</span><br />}, @result
end
end
context "using Maruku" do
setup do
create_post(@content)
end
should "parse correctly" do
assert_match %r{<em>FIGHT!</em>}, @result
assert_match %r{<em>FINISH HIM</em>}, @result
end
end
context "using RDiscount" do
setup do
create_post(@content, 'markdown' => 'rdiscount')
end
should "parse correctly" do
assert_match %r{<em>FIGHT!</em>}, @result
assert_match %r{<em>FINISH HIM</em>}, @result
end
end
context "using Kramdown" do
setup do
create_post(@content, 'markdown' => 'kramdown')
end
should "parse correctly" do
assert_match %r{<em>FIGHT!</em>}, @result
assert_match %r{<em>FINISH HIM</em>}, @result
end
end
end
end