Compare commits

...

208 Commits
v0.5.4 ... 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
Jeffry Degrande
a493267191 bugfix for permalinks 2009-06-29 08:40:31 -03: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
79 changed files with 2952 additions and 871 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,8 @@
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,60 +1,194 @@
== 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* 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]
* Changed date format on wordpress converter (zeropadding)
[github.com/dysinger]
* Bug Fixes
* Add jekyll binary as executable to gemspec [github.com/dysinger]
@@ -67,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
@@ -111,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

@@ -20,23 +20,21 @@ h2. Diving In
* 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
h2. Dependencies
h2. Runtime Dependencies
* RedCloth: Textile support
* Liquid: Templating system
* Classifier: Generating related posts
* Maruku: Default markdown engine
* Directory Watcher: Auto-regeneration of sites
* Open4: Talking to pygments for syntax highlighting
* 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)
h2. Developer Dependencies
* 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.

178
Rakefile
View File

@@ -1,85 +1,101 @@
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
gem 'jeweler', '>= 0.11.0'
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.files.exclude 'test/dest'
s.test_files.exclude 'test/dest'
s.add_dependency('RedCloth', '>= 4.2.1')
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 jeweler --version '>= 0.11.0'"
exit(1)
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, :features]
# console
desc "Open an irb session preloaded with this library"
task :console do
sh "irb -rubygems -I lib -r 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
@@ -89,3 +105,55 @@ rescue LoadError
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

View File

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

View File

@@ -9,7 +9,8 @@ Basic Command Line Usage:
jekyll # . -> ./_site
jekyll <path to write generated site> # . -> <path>
jekyll <path to source> <path to write generated site> # <path> -> <path>
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:
@@ -18,17 +19,43 @@ HELP
require 'optparse'
require 'jekyll'
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", "No auto-regenerate") do
options['auto'] = false
opts.on("--[no-]auto", "Auto-regenerate") do |auto|
options['auto'] = auto
end
opts.on("--server [PORT]", "Start web server (default port 4000)") do |port|
@@ -36,18 +63,38 @@ opts = OptionParser.new do |opts|
options['server_port'] = port unless port.nil?
end
opts.on("--lsi", "Use LSI for better related posts") do
options['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
options['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
@@ -62,8 +109,22 @@ opts = OptionParser.new do |opts|
end
end
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
puts "Jekyll " + Jekyll::VERSION
exit 0
end
end
@@ -71,6 +132,59 @@ end
# Read command line options into `options` hash
opts.parse!
# 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
@@ -126,7 +240,15 @@ if options['auto']
end
else
puts "Building site: #{source} -> #{destination}"
site.process
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
@@ -137,10 +259,14 @@ if options['server']
FileUtils.mkdir_p(destination)
mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
mime_types.store 'js', 'application/javascript'
s = HTTPServer.new(
:Port => options['server_port'],
:DocumentRoot => destination
:MimeTypes => mime_types
)
s.mount(options['baseurl'], HTTPServlet::FileHandler, destination)
t = Thread.new {
s.start
}

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

@@ -29,7 +29,7 @@ Feature: Create sites
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 post:
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 }}"
@@ -37,6 +37,36 @@ Feature: Create sites
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 %}"
@@ -44,3 +74,21 @@ Feature: Create sites
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

@@ -20,7 +20,7 @@ Feature: Embed filters
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.posts.first.title | xml_escape }}"
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"
@@ -31,7 +31,7 @@ Feature: Embed filters
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.posts.first.content | xml_escape }}"
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"
@@ -42,7 +42,7 @@ Feature: Embed filters
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 "{{ site.posts.first.tags | array_to_sentence_string }}"
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"

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

@@ -6,35 +6,22 @@ Feature: Site pagination
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" file that contains "Basic Site"
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 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/page2 directory should exist
And the _site/page2/index.html file should exist
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 |
| 1 |
| 2 |
Scenario: Correct liquid paginator replacements
Given I have a configuration file with "paginate" set to "1"
And I have a _layouts directory
And I have an "index.html" file that contains "{{ paginator.page }}"
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. |
When I run jekyll
Then the _site/index.html file should exist
And I should see "1" in "_site/index.html"
Then the _site/page2 directory should exist
And the _site/page2/index.html file should exist
And I should see "2" in "_site/page2/index.html"
| num | exist | posts | not_exist |
| 1 | 4 | 1 | 5 |
| 2 | 2 | 2 | 3 |
| 3 | 2 | 1 | 3 |

View File

@@ -9,7 +9,7 @@ Feature: Post data
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: {{ site.posts.first.title }}"
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"
@@ -20,7 +20,7 @@ Feature: Post data
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: {{ site.posts.first.url }}"
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"
@@ -31,7 +31,7 @@ Feature: Post data
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: {{ site.posts.first.date }}"
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"
@@ -42,7 +42,7 @@ Feature: Post data
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: {{ site.posts.first.id }}"
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"
@@ -53,7 +53,7 @@ Feature: Post data
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: {{ site.posts.first.content }}"
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"
@@ -65,7 +65,7 @@ Feature: Post data
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: {{ site.posts.first.categories }}"
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"
@@ -76,23 +76,23 @@ Feature: Post data
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: {{ site.posts.first.tags }}"
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 movies directory
And I have a movies/scifi directory
And I have a movies/scifi/_posts directory
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 "movies/scifi":
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: {{ site.posts.first.categories | array_to_sentence_string }}"
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: movies and scifi" in "_site/movies/scifi/2009/03/27/star-wars.html"
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
@@ -100,7 +100,7 @@ Feature: Post data
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: {{ site.posts.first.categories }}"
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"
@@ -110,11 +110,11 @@ Feature: Post data
And I have a _layouts directory
And I have the following post:
| title | date | layout | categories | content |
| Star Wars | 3/27/2009 | simple | ['movies', 'scifi'] | Luke, I am your father. |
And I have a simple layout that contains "Post categories: {{ site.posts.first.categories | array_to_sentence_string }}"
| 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: movies and scifi" in "_site/movies/scifi/2009/03/27/star-wars.html"
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
@@ -133,7 +133,7 @@ Feature: Post data
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: {{ site.posts.first.author }}"
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"

View File

@@ -33,7 +33,7 @@ Feature: Site configuration
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 |
| value |
| README |
| Rakefile |
When I run jekyll
@@ -48,6 +48,13 @@ Feature: Site configuration
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"
@@ -61,3 +68,59 @@ Feature: Site configuration
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

@@ -13,7 +13,7 @@ Given /^I have a blank site in "(.*)"$/ do |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|
Given /^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$/ do |file, key, value, text|
File.open(file, 'w') do |f|
f.write <<EOF
---
@@ -25,7 +25,7 @@ EOF
end
end
Given /^I have an "(.*)" file that contains "(.*)"$/ do |file, text|
Given /^I have an? "(.*)" file that contains "(.*)"$/ do |file, text|
File.open(file, 'w') do |f|
f.write(text)
f.close
@@ -39,13 +39,13 @@ Given /^I have a (.*) layout that contains "(.*)"$/ do |layout, text|
end
end
Given /^I have a (.*) directory$/ do |dir|
FileUtils.mkdir(dir)
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.parse(post['date']).strftime('%Y-%m-%d')
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"
@@ -81,7 +81,16 @@ end
Given /^I have a configuration file with "(.*)" set to "(.*)"$/ do |key, value|
File.open('_config.yml', 'w') do |f|
f.write("#{key}: #{value}")
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
@@ -90,7 +99,7 @@ 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")
f.write("- #{row["value"]}\n")
end
f.close
end
@@ -115,14 +124,14 @@ Then /^the (.*) directory should exist$/ do |dir|
assert File.directory?(dir)
end
Then /^the (.*) file should exist$/ do |file|
assert File.file?(file)
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

View File

@@ -14,3 +14,6 @@ def run_jekyll(opts = {})
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,135 +1,142 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{jekyll}
s.version = "0.5.4"
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-08-24}
s.default_executable = %q{jekyll}
s.description = %q{Jekyll is a simple, blog aware, static site generator.}
s.email = %q{tom@mojombo.com}
s.rubygems_version = '1.3.5'
s.name = 'jekyll'
s.version = '0.10.0'
s.date = '2010-12-16'
s.rubyforge_project = 'jekyll'
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.extra_rdoc_files = [
"README.textile"
]
s.files = [
".gitignore",
"History.txt",
"README.textile",
"Rakefile",
"VERSION.yml",
"bin/jekyll",
"features/create_sites.feature",
"features/embed_filters.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/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/pager.rb",
"lib/jekyll/post.rb",
"lib/jekyll/site.rb",
"lib/jekyll/tags/highlight.rb",
"lib/jekyll/tags/include.rb",
"test/helper.rb",
"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-03-12-hash-#1.markdown",
"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/about.html",
"test/source/category/_posts/2008-9-23-categories.textile",
"test/source/contacts.html",
"test/source/css/screen.css",
"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_filters.rb",
"test/test_generated_site.rb",
"test/test_page.rb",
"test/test_pager.rb",
"test/test_post.rb",
"test/test_site.rb",
"test/test_tags.rb"
]
s.homepage = %q{http://github.com/mojombo/jekyll}
s.default_executable = 'jekyll'
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{jekyll}
s.rubygems_version = %q{1.3.5}
s.summary = %q{Jekyll is a simple, blog aware, static site generator.}
s.test_files = [
"test/helper.rb",
"test/suite.rb",
"test/test_configuration.rb",
"test/test_filters.rb",
"test/test_generated_site.rb",
"test/test_page.rb",
"test/test_pager.rb",
"test/test_post.rb",
"test/test_site.rb",
"test/test_tags.rb"
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 =
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<RedCloth>, [">= 4.2.1"])
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.2.1"])
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.2.1"])
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.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
end

View File

@@ -1,43 +1,66 @@
$:.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'
require 'maruku'
require 'albino'
# internal requires
require 'jekyll/core_ext'
require 'jekyll/pager'
require 'jekyll/site'
require 'jekyll/convertible'
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.10.0'
# Default options. Overriden by values in _config.yml or command-line opts.
# (Strings rather symbols used for compatability with YAML)
# (Strings rather symbols used for compatability with YAML).
DEFAULTS = {
'safe' => false,
'auto' => false,
'server' => false,
'server_port' => 4000,
'source' => '.',
'destination' => File.join('.', '_site'),
'source' => Dir.pwd,
'destination' => File.join(Dir.pwd, '_site'),
'plugins' => File.join(Dir.pwd, '_plugins'),
'future' => true,
'lsi' => false,
'pygments' => false,
'markdown' => 'maruku',
@@ -49,14 +72,36 @@ module Jekyll
'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+ is a Hash of config directives
# with anything in _config.yml, and adding the given options on top.
#
# Returns Hash
# 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
@@ -67,19 +112,15 @@ module Jekyll
begin
config = YAML.load_file(config_file)
raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
STDOUT.puts "Configuration from #{config_file}"
$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
$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
def self.version
yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
"#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
end
end

View File

@@ -1,122 +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, :O => 'encoding=utf-8' }
end
def execute(command)
output = ''
Open4.popen4(command) do |pid, stdin, stdout, stderr|
stdin.puts @target
stdin.close
output = stdout.read.strip
[stdout, stderr].each { |io| io.close }
end
output
end
def colorize(options = {})
html = execute(@@bin + convert_options(options))
# Work around an RDiscount bug: http://gist.github.com/97682
html.to_s.sub(%r{</pre></div>\Z}, "</pre>\n</div>")
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

@@ -3,69 +3,82 @@
#
# 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?)(---.*?\n)/m
self.content = self.content[($1.size + $2.size)..-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 self.content_type
when 'textile'
self.ext = ".html"
self.content = self.site.textile(self.content)
when 'markdown'
self.ext = ".html"
self.content = self.site.markdown(self.content)
end
self.content = converter.convert(self.content)
end
# Determine which formatting engine to use based on this convertible's
# extension
# Determine the extension depending on content_type.
#
# Returns one of :textile, :markdown or :unknown
def content_type
case self.ext[1..-1]
when /textile/i
return 'textile'
when /markdown/i, /mkdn/i, /md/i
return 'markdown'
end
return 'unknown'
# 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
# Add any necessary layouts to this convertible document
# +layouts+ is a Hash of {"name" => "layout"}
# +site_payload+ is the site payload hash
# Determine which converter to use based on this convertible's
# extension.
#
# Returns nothing
# 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)
payload["content_type"] = self.content_type
self.content = Liquid::Template.parse(self.content).render(payload, info)
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
@@ -75,7 +88,12 @@ module Jekyll
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, info)
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

View File

@@ -19,6 +19,28 @@ class Hash
target
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!

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

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

View File

@@ -1,8 +1,10 @@
require 'uri'
module Jekyll
module Filters
def textilize(input)
RedCloth.new(input).to_html
TextileConverter.new.convert(input)
end
def date_to_string(date)
@@ -25,6 +27,10 @@ module Jekyll
CGI::escape(input)
end
def uri_escape(input)
URI.escape(input)
end
def number_of_words(input)
input.split.length
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

@@ -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

@@ -40,7 +40,7 @@ module Jekyll
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"

View File

@@ -5,6 +5,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
@@ -17,19 +18,20 @@ module Jekyll
# 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
@@ -39,12 +41,13 @@ module Jekyll
# 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|
@@ -53,7 +56,22 @@ module Jekyll
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,7 +17,7 @@ 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"

View File

@@ -22,7 +22,7 @@ module Jekyll
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/

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
@@ -11,18 +12,18 @@ 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 post_title, post_name, post_date, post_content, post_excerpt, ID, guid 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"
# 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|
db[query].each do |post|
# Get required fields and construct Jekyll compatible name
title = post[:post_title]
slug = post[:post_name]
@@ -38,7 +39,8 @@ module Jekyll
'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

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

@@ -3,8 +3,8 @@ module Jekyll
class Page
include Convertible
attr_accessor :site
attr_accessor :name, :ext, :basename
attr_accessor :site, :pager
attr_accessor :name, :ext, :basename, :dir
attr_accessor :data, :content, :output
# Initialize a new Page.
@@ -43,10 +43,10 @@ module Jekyll
end
def template
if self.site.permalink_style == :pretty && !index?
"/:name/"
if self.site.permalink_style == :pretty && !index? && html?
"/:basename/"
else
"/:name.html"
"/:basename:output_ext"
end
end
@@ -55,9 +55,23 @@ module Jekyll
#
# Returns <String>
def url
return permalink if permalink
return @url if @url
@url ||= (ext == '.html') ? template.gsub(':name', basename) : "/#{name}"
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
@@ -66,7 +80,7 @@ module Jekyll
# Returns nothing
def process(name)
self.ext = File.extname(name)
self.basename = name.split('.')[0..-2].first
self.basename = name[0 .. -self.ext.length-1]
end
# Add any necessary layouts to this post
@@ -75,37 +89,54 @@ module Jekyll
#
# 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_prefix+ is the String path to the destination dir
# +dest_suffix+ is a suffix path to the destination dir
# +dest+ is the String path to the destination dir
#
# Returns nothing
def write(dest_prefix, dest_suffix = nil)
dest = File.join(dest_prefix, @dir)
dest = File.join(dest, dest_suffix) if dest_suffix
FileUtils.mkdir_p(dest)
# The url needs to be unescaped in order to preserve the correct filename
path = File.join(dest, CGI.unescape(self.url))
if self.ext == '.html' && self.url[/\.html$/].nil?
FileUtils.mkdir_p(path)
path = File.join(path, "index.html")
end
def write(dest)
path = destination(dest)
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(self.output)
end
end
private
def inspect
"#<Jekyll:Page @name=#{self.name.inspect}>"
end
def index?
basename == 'index'
end
def html?
output_ext == '.html'
end
def index?
basename == 'index'
end
end

View File

@@ -1,45 +0,0 @@
module Jekyll
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.abs + 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_hash
{
'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

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

@@ -18,12 +18,9 @@ module Jekyll
name =~ MATCHER
end
attr_accessor :site, :date, :slug, :ext, :published, :data, :content, :output, :tags
attr_writer :categories
def categories
@categories ||= []
end
attr_accessor :site
attr_accessor :data, :content, :output, :ext
attr_accessor :date, :slug, :published, :tags, :categories
# Initialize this Post instance.
# +site+ is the Site
@@ -41,32 +38,23 @@ module Jekyll
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
if self.data.has_key?("tag")
self.tags = [self.data["tag"]]
elsif self.data.has_key?("tags")
self.tags = self.data['tags']
else
self.tags = []
end
self.tags = self.data.pluralized_array("tag", "tags")
if self.categories.empty?
if self.data.has_key?('category')
self.categories << self.data['category']
elsif self.data.has_key?('categories')
# Look for categories in the YAML-header, either specified as
# an array or a string.
if self.data['categories'].kind_of? String
self.categories = self.data['categories'].split
else
self.categories = self.data['categories']
end
end
self.categories = self.data.pluralized_array('category', 'categories')
end
end
@@ -90,6 +78,8 @@ 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
@@ -129,17 +119,29 @@ module Jekyll
#
# Returns <String>
def url
return permalink if permalink
return @url if @url
@url ||= {
"year" => date.strftime("%Y"),
"month" => date.strftime("%m"),
"day" => date.strftime("%d"),
"title" => CGI.escape(slug),
"categories" => categories.sort.join('/')
}.inject(template) { |result, token|
result.gsub(/:#{token.first}/, token.last)
}.gsub(/\/\//, "/")
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)
@@ -179,31 +181,32 @@ 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))
# The url needs to be unescaped in order to preserve the correct filename
path = File.join(dest, CGI.unescape(self.url))
if template[/\.html$/].nil?
FileUtils.mkdir_p(path)
path = File.join(path, "index.html")
end
path = destination(dest)
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(self.output)
end
@@ -213,7 +216,8 @@ module Jekyll
#
# Returns <Hash>
def to_liquid
{ "title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
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,
@@ -221,7 +225,7 @@ module Jekyll
"next" => self.next,
"previous" => self.previous,
"tags" => self.tags,
"content" => self.content }.deep_merge(self.data)
"content" => self.content })
end
def inspect

View File

@@ -1,8 +1,13 @@
require 'set'
module Jekyll
class Site
attr_accessor :config, :layouts, :posts, :categories, :exclude,
:source, :dest, :lsi, :pygments, :permalink_style, :tags
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
# +config+ is a Hash containing site configurations details
@@ -11,97 +16,87 @@ module Jekyll
def initialize(config)
self.config = config.clone
self.source = config['source']
self.dest = config['destination']
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
# Check to see if LSI is enabled.
require 'classifier' if self.lsi
# Set the Markdown interpreter (and Maruku self.config, if necessary)
case self.config['markdown']
when 'rdiscount'
begin
require 'rdiscount'
# 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
def markdown(content)
RDiscount.new(content).to_html
end
self.converters = Jekyll::Converter.subclasses.select do |c|
!self.safe || c.safe
end.map do |c|
c.new(self.config)
end
rescue LoadError
puts 'You must have the rdiscount gem installed first'
end
when 'maruku'
begin
require 'maruku'
def markdown(content)
Maruku.new(content).to_html
end
if self.config['maruku']['use_divs']
require 'maruku/ext/div'
puts 'Maruku: Using extended syntax for div elements.'
end
if self.config['maruku']['use_tex']
require 'maruku/ext/math'
puts "Maruku: Using LaTeX extension. Images in `#{self.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] = self.config['maruku']['png_engine']
MaRuKu::Globals[:html_png_dir] = self.config['maruku']['png_dir']
MaRuKu::Globals[:html_png_url] = self.config['maruku']['png_url']
end
rescue LoadError
puts "The maruku gem is required for markdown support!"
end
else
raise "Invalid Markdown processor: '#{self.config['markdown']}' -- did you mean 'maruku' or 'rdiscount'?"
self.generators = Jekyll::Generator.subclasses.select do |c|
!self.safe || c.safe
end.map do |c|
c.new(self.config)
end
end
def textile(content)
RedCloth.new(content).to_html
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.reset
self.read_layouts
self.transform_pages
self.write_posts
self.read
self.generate
self.render
self.cleanup
self.write
end
# Read all the files in <source>/_layouts 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")
def read_layouts(dir = '')
base = File.join(self.source, dir, "_layouts")
return unless File.exists?(base)
entries = []
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
@@ -109,24 +104,23 @@ module Jekyll
name = f.split(".")[0..-2].join(".")
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 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 = filter_entries(Dir['**/*']) }
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, self.source, dir, f)
if post.published
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 }
@@ -136,67 +130,104 @@ module Jekyll
self.posts.sort!
# second pass renders each post now that full site payload is available
# 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.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 "#" 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 = filter_entries(Dir.entries(base))
directories = entries.select { |e| File.directory?(File.join(base, e)) }
files = entries.reject { |e| File.directory?(File.join(base, e)) || File.symlink?(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 directories.include?('_posts')
directories.delete('_posts')
read_posts(dir)
end
self.read_posts(dir)
[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))
elsif Pager.pagination_enabled?(self.config, f)
paginate_posts(f, 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, 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
@@ -218,48 +249,32 @@ module Jekyll
#
# Returns {"site" => {"time" => <Time>,
# "posts" => [<Post>],
# "pages" => [<Page>],
# "categories" => [<Post>]}
def site_payload
{"site" => self.config.merge({
"time" => Time.now,
"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
# Filter out any files/directories that are hidden or backup files (start
# with "." or "#" or end with "~") or contain site content (start with "_")
# unless they are "_posts" directories or web server files such as
# '.htaccess'
# 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 ['_posts', '.htaccess'].include?(e)
['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
unless ['.htaccess'].include?(e)
['.', '_', '#'].include?(e[0..0]) ||
e[-1..-1] == '~' ||
self.exclude.include?(e) ||
File.symlink?(e)
end
end
end
# Paginates the blog's posts. Renders the index.html file into paginated directories, ie: page2, page3...
# and adds more wite-wide data
#
# {"paginator" => { "page" => <Number>,
# "per_page" => <Number>,
# "posts" => [<Post>],
# "total_posts" => <Number>,
# "total_pages" => <Number>,
# "previous_page" => <Number>,
# "next_page" => <Number> }}
def paginate_posts(file, dir)
all_posts = self.posts.sort { |a,b| b <=> a }
pages = Pager.calculate_pages(all_posts, self.config['paginate'].to_i)
pages += 1
(1..pages).each do |num_page|
pager = Pager.new(self.config, num_page, all_posts, pages)
page = Page.new(self, self.source, dir, file)
page.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
suffix = "page#{num_page}" if num_page > 1
page.write(self.dest, suffix)
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

@@ -4,15 +4,28 @@ module Jekyll
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
@@ -23,20 +36,17 @@ module Jekyll
def render(context)
if context.registers[:site].pygments
render_pygments(context, super.to_s)
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 context["content_type"] == "markdown"
return "\n" + Albino.new(code, @lang).to_s(@options) + "\n"
elsif context["content_type"] == "textile"
return "<notextile>" + Albino.new(code, @lang).to_s(@options) + "</notextile>"
else
return Albino.new(code, @lang).to_s(@options)
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)
@@ -49,6 +59,13 @@ 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

View File

@@ -7,11 +7,17 @@ module Jekyll
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(context.registers[:site].source, '_includes')) do
Dir.chdir(includes_dir) do
choices = Dir['**/*'].reject { |x| File.symlink?(x) }
if choices.include?(@file)
source = File.read(@file)

View File

@@ -1,8 +1,12 @@
require 'rubygems'
gem 'RedCloth', '= 4.2.1'
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'
@@ -10,6 +14,9 @@ require 'rr'
include Jekyll
# Send STDERR into the void to suppress program output messages
STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:')
class Test::Unit::TestCase
include RR::Adapters::TestUnit

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,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 @@
---
title: A Tag
tag:
---
Whoa.

View File

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

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
---

View File

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

View File

@@ -2,22 +2,31 @@
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">
<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_to_xmlschema }}</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
{% for post in site.posts %}
<url>
<loc>http://example.com/{{ post.url }}/</loc>
<lastmod>{{ site.time }}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.2</priority>
</url>
{% endfor %}
</urlset>
<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

@@ -3,26 +3,26 @@ require File.dirname(__FILE__) + '/helper'
class TestConfiguration < Test::Unit::TestCase
context "loading configuration" do
setup do
@path = './_config.yml'
@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}")
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}")
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}")
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

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

@@ -45,5 +45,9 @@ class TestFilters < Test::Unit::TestCase
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
end

View File

@@ -13,6 +13,10 @@ class TestGeneratedSite < Test::Unit::TestCase
@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
@@ -37,4 +41,32 @@ class TestGeneratedSite < Test::Unit::TestCase
assert File.exists?(dest_dir('/contacts.html'))
end
end
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

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

View File

@@ -16,13 +16,23 @@ class TestPage < Test::Unit::TestCase
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
@@ -61,7 +71,7 @@ class TestPage < Test::Unit::TestCase
setup do
clear_dest
end
should "write properly" do
page = setup_page('contacts.html')
do_render(page)
@@ -73,14 +83,14 @@ class TestPage < Test::Unit::TestCase
should "write properly without html extension" do
page = setup_page('contacts.html')
page.site.permalink_style = :pretty
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
@@ -92,7 +102,16 @@ class TestPage < Test::Unit::TestCase
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
end

View File

@@ -1,11 +1,38 @@
require File.dirname(__FILE__) + '/helper'
class TestPager < Test::Unit::TestCase
context "pagination enabled" do
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,
'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
})
@@ -13,35 +40,74 @@ class TestPager < Test::Unit::TestCase
@config = Jekyll.configuration
@site = Site.new(@config)
@posts = @site.read_posts('')
@site.process
@posts = @site.posts
end
should "calculate number of pages" do
assert_equal(2, Pager.calculate_pages(@posts, @config['paginate']))
end
should "create first pager" do
pager = Pager.new(@config, 1, @posts)
assert_equal(@config['paginate'].to_i, 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(@posts.size - @config['paginate'].to_i, 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
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

@@ -18,10 +18,10 @@ class TestPost < Test::Unit::TestCase
end
should "ensure valid posts are valid" do
assert Post.valid?("2008-10-19-foo-bar.textile")
assert Post.valid?("foo/bar/2008-10-19-foo-bar.textile")
assert Post.valid?("2008-09-09-foo-bar.textile")
assert Post.valid?("foo/bar/2008-09-09-foo-bar.textile")
assert !Post.valid?("lol2008-10-19-foo-bar.textile")
assert !Post.valid?("lol2008-09-09-foo-bar.textile")
assert !Post.valid?("blah")
end
@@ -31,24 +31,31 @@ class TestPost < Test::Unit::TestCase
@post.site = @site
@real_file = "2008-10-18-foo-bar.textile"
@fake_file = "2008-10-19-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-10-19"), @post.date
assert_equal Time.parse("2008-09-09"), @post.date
assert_equal "foo-bar", @post.slug
assert_equal ".textile", @post.ext
assert_equal "/2008/10/19", @post.dir
assert_equal "/2008/10/19/foo-bar", @post.id
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/10/19/foo-bar.html", @post.url
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
@@ -77,7 +84,19 @@ class TestPost < Test::Unit::TestCase
@post.read_yaml(@source, @real_file)
assert_equal({"title" => "Test title", "layout" => "post", "tag" => "Ruby"}, @post.data)
assert_equal "\r\nThis is the content", @post.content
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
@@ -93,7 +112,7 @@ class TestPost < Test::Unit::TestCase
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/2008/10/19/foo-bar.html", @post.url
assert_equal "/2008/09/09/foo-bar.html", @post.url
end
end
@@ -105,7 +124,7 @@ class TestPost < Test::Unit::TestCase
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/beer/2008/10/19/foo-bar.html", @post.url
assert_equal "/beer/2008/09/09/foo-bar.html", @post.url
end
end
@@ -118,7 +137,7 @@ class TestPost < Test::Unit::TestCase
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
assert_equal "/beer/food/2008/10/19/foo-bar.html", @post.url
assert_equal "/food/beer/2008/09/09/foo-bar.html", @post.url
end
end
@@ -142,7 +161,18 @@ class TestPost < Test::Unit::TestCase
should "process the url correctly" do
assert_equal "/:categories/:year/:month/:day/:title/", @post.template
assert_equal "/2008/10/19/foo-bar/", @post.url
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
@@ -163,7 +193,7 @@ class TestPost < Test::Unit::TestCase
@post.read_yaml(@source, @real_file)
assert_equal({"title" => "Foo Bar", "layout" => "default"}, @post.data)
assert_equal "\nh1. {{ page.title }}\n\nBest *post* ever", @post.content
assert_equal "h1. {{ page.title }}\n\nBest *post* ever", @post.content
end
should "transform textile" do
@@ -212,6 +242,41 @@ class TestPost < Test::Unit::TestCase
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')
@@ -224,6 +289,16 @@ class TestPost < Test::Unit::TestCase
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')
@@ -236,6 +311,16 @@ class TestPost < Test::Unit::TestCase
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
@@ -290,6 +375,21 @@ class TestPost < Test::Unit::TestCase
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

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

@@ -19,11 +19,77 @@ class TestSite < Test::Unit::TestCase
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
@@ -52,10 +118,10 @@ class TestSite < Test::Unit::TestCase
should "filter entries" do
ent1 = %w[foo.markdown bar.markdown baz.markdown #baz.markdown#
.baz.markdow foo.markdown~]
ent2 = %w[.htaccess _posts bla.bla]
ent2 = %w[.htaccess _posts _pages bla.bla]
assert_equal %w[foo.markdown bar.markdown baz.markdown], @site.filter_entries(ent1)
assert_equal ent2, @site.filter_entries(ent2)
assert_equal %w[.htaccess bla.bla], @site.filter_entries(ent2)
end
should "filter entries with exclude" do
@@ -66,19 +132,54 @@ class TestSite < Test::Unit::TestCase
assert_equal includes, @site.filter_entries(excludes + includes)
end
context 'with an invalid markdown processor in the configuration' do
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
should 'give a meaningful error message' do
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
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'
begin
assert_nothing_raised do
Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor }))
flunk 'Invalid markdown processors should cause a failure on site creation'
rescue RuntimeError => e
assert e.to_s =~ /invalid|bad/i
assert e.to_s =~ %r{#{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
end

View File

@@ -2,26 +2,18 @@ require File.dirname(__FILE__) + '/helper'
class TestTags < Test::Unit::TestCase
def create_post(content, override = {}, markdown = true)
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 } }
if markdown
payload = {"content_type" => "markdown"}
else
payload = {"content_type" => "textile"}
end
@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)
if markdown
@result = site.markdown(@result)
else
@result = site.textile(@result)
end
@result = @converter.convert(@result)
end
def fill_post(code, override = {})
@@ -32,9 +24,7 @@ title: This is a test
This document results in a markdown error with maruku
{% highlight text %}
#{code}
{% endhighlight %}
{% highlight text %}#{code}{% endhighlight %}
CONTENT
create_post(content, override)
end
@@ -49,7 +39,17 @@ CONTENT
end
should "render markdown with pygments line handling" do
assert_match %{<pre>test\n</pre>}, @result
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
@@ -59,7 +59,7 @@ CONTENT
end
should "render markdown with pygments line handling" do
assert_match %{<pre>Æ\n</pre>}, @result
assert_match %{<pre><code class='text'>Æ\n</code></pre>}, @result
end
end
@@ -82,7 +82,7 @@ CONTENT
context "using Textile" do
setup do
create_post(@content, {}, false)
create_post(@content, {}, Jekyll::TextileConverter)
end
# Broken in RedCloth 4.1.9
@@ -112,5 +112,16 @@ CONTENT
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