mirror of
https://github.com/jekyll/jekyll.git
synced 2026-04-28 03:01:03 -04:00
Compare commits
208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf71631c34 | ||
|
|
6c0e4b37b9 | ||
|
|
0f71bdb540 | ||
|
|
dce4ccc5a4 | ||
|
|
6c94db1486 | ||
|
|
68eaadd13a | ||
|
|
01a90904e2 | ||
|
|
d2814cf750 | ||
|
|
f58a821e20 | ||
|
|
38844cd3bc | ||
|
|
a31780a1ec | ||
|
|
5f4dfe388f | ||
|
|
f82c51df7a | ||
|
|
13cc44fb12 | ||
|
|
be8b7715d3 | ||
|
|
edef0251d3 | ||
|
|
9da714dbe1 | ||
|
|
8cc7f06b36 | ||
|
|
4b5a4e8713 | ||
|
|
08725eb234 | ||
|
|
16ea3262da | ||
|
|
a04c270f1b | ||
|
|
bd01e647a7 | ||
|
|
034b06431e | ||
|
|
c70dac3cee | ||
|
|
ca48ea91e6 | ||
|
|
f68bbcbe8d | ||
|
|
d61c1e930a | ||
|
|
bc3771aa22 | ||
|
|
e902bb9c30 | ||
|
|
42f63f919f | ||
|
|
033333f9bc | ||
|
|
b3634b522a | ||
|
|
84c1a72443 | ||
|
|
c1f0e070c9 | ||
|
|
13df722073 | ||
|
|
86397cbf00 | ||
|
|
a8a837cc8e | ||
|
|
9e0eb75170 | ||
|
|
36b1f8f9b1 | ||
|
|
c1ed790534 | ||
|
|
9bd48752e6 | ||
|
|
5db040802f | ||
|
|
65622cb1e0 | ||
|
|
226c7cc121 | ||
|
|
0a58d78338 | ||
|
|
5b680f8dd8 | ||
|
|
e8fd7ebbc3 | ||
|
|
31901ee15b | ||
|
|
3ab016870d | ||
|
|
61acd47ed2 | ||
|
|
dca30c3ad1 | ||
|
|
f85e229a9e | ||
|
|
ac7a0cc95f | ||
|
|
53b999418c | ||
|
|
00146909f9 | ||
|
|
a556e4f29e | ||
|
|
e2d26ff8ed | ||
|
|
9396c9d04c | ||
|
|
38ed81e0ce | ||
|
|
4a8fc1fa6e | ||
|
|
d53ea4a0dd | ||
|
|
f7ab019a39 | ||
|
|
4afee1bda1 | ||
|
|
8cc537026d | ||
|
|
054b796b9f | ||
|
|
c1a7662311 | ||
|
|
accdb2d39f | ||
|
|
4c08643c50 | ||
|
|
d97bcadd03 | ||
|
|
f688c9df81 | ||
|
|
8ecb70d3e3 | ||
|
|
e9cf7b4636 | ||
|
|
16c19ecd19 | ||
|
|
b1049c84cd | ||
|
|
b6678d4e43 | ||
|
|
3fa9af17fa | ||
|
|
9b423a96fd | ||
|
|
391d1a9677 | ||
|
|
f4fb833d34 | ||
|
|
d9bc00c804 | ||
|
|
b3cec39843 | ||
|
|
f6acbb869e | ||
|
|
adf9ca5a05 | ||
|
|
5e997cae21 | ||
|
|
f35d287c66 | ||
|
|
1c3fedbb31 | ||
|
|
a56eeb8289 | ||
|
|
908526455c | ||
|
|
ce5a2a04e3 | ||
|
|
44015665b9 | ||
|
|
6a605753c1 | ||
|
|
99ee0c4803 | ||
|
|
de3ee99d30 | ||
|
|
36411dd10f | ||
|
|
f8484570b7 | ||
|
|
9bb2066cf1 | ||
|
|
0ce13c943d | ||
|
|
de8bd48154 | ||
|
|
68c69fb3ef | ||
|
|
46a95bc036 | ||
|
|
23d26c5525 | ||
|
|
6932a40d17 | ||
|
|
aa9993a6c1 | ||
|
|
8a417e86c0 | ||
|
|
f91954be76 | ||
|
|
ace9911001 | ||
|
|
cb77a5287b | ||
|
|
31c65c56f4 | ||
|
|
5335debfb2 | ||
|
|
1fba2ef516 | ||
|
|
f6ef6f21ae | ||
|
|
e8d119ef0a | ||
|
|
2c542a652d | ||
|
|
fa90573176 | ||
|
|
a8efc3a0a2 | ||
|
|
0ba1f6c83e | ||
|
|
03cb12aeb3 | ||
|
|
3efe008544 | ||
|
|
08bc63289d | ||
|
|
81971c3342 | ||
|
|
8405d30764 | ||
|
|
18545ddf71 | ||
|
|
fc86c9dd85 | ||
|
|
84b26a31da | ||
|
|
315f4c9222 | ||
|
|
cedda3afa3 | ||
|
|
ff3ca307b9 | ||
|
|
1261840769 | ||
|
|
bae52e0aba | ||
|
|
ad4a80a653 | ||
|
|
80b13a81fa | ||
|
|
ef2fabb189 | ||
|
|
e8971b2999 | ||
|
|
bfdf7fb13a | ||
|
|
f73dac1582 | ||
|
|
5a807aa12e | ||
|
|
cd946a587b | ||
|
|
4fd2b54a7d | ||
|
|
4dde9d9668 | ||
|
|
355b20265e | ||
|
|
cfd6ebc747 | ||
|
|
e4a2319bf3 | ||
|
|
657b2e4be3 | ||
|
|
98fa570c86 | ||
|
|
ef6aa6b5c4 | ||
|
|
58354e269e | ||
|
|
a4f3f5c583 | ||
|
|
5fec20dfa8 | ||
|
|
a2e0d76d4e | ||
|
|
ba77a024d6 | ||
|
|
0756d1f765 | ||
|
|
d88354e2df | ||
|
|
dd5fb69c2f | ||
|
|
2b2e027b34 | ||
|
|
fff313a62d | ||
|
|
6dcfe1283a | ||
|
|
b68149c7bc | ||
|
|
a076ce0702 | ||
|
|
58b4ffd935 | ||
|
|
a0aa3fa6dc | ||
|
|
a1550b3378 | ||
|
|
2aac9f3716 | ||
|
|
db03bcac8f | ||
|
|
21c92d3eb2 | ||
|
|
ce228ac1c4 | ||
|
|
93c029d62e | ||
|
|
2292e4268c | ||
|
|
e0e4a47af1 | ||
|
|
45bf0e8a33 | ||
|
|
6b74454a07 | ||
|
|
2a7b1cbd98 | ||
|
|
c92eb564d2 | ||
|
|
98f3767af3 | ||
|
|
602a252364 | ||
|
|
add546f61e | ||
|
|
8d4b96084a | ||
|
|
60fed241cd | ||
|
|
d020d4f2bf | ||
|
|
473f3ffc11 | ||
|
|
4c1021d597 | ||
|
|
c89d8dd0f3 | ||
|
|
52b82af6e2 | ||
|
|
1adf9a7c64 | ||
|
|
59ee8a6869 | ||
|
|
c569f5e641 | ||
|
|
5a37e0d96e | ||
|
|
7806a0d6bb | ||
|
|
5c17d6266d | ||
|
|
d25f419159 | ||
|
|
b8c04dfb6d | ||
|
|
d80c643681 | ||
|
|
0d69e9346b | ||
|
|
45e13cf46f | ||
|
|
0cb1ebcda1 | ||
|
|
b5916caf4b | ||
|
|
5ea06f3ad9 | ||
|
|
39a487cdf0 | ||
|
|
b1a055f10d | ||
|
|
fab5a715c5 | ||
|
|
597c7a7904 | ||
|
|
b299a7bad3 | ||
|
|
52342fe6e1 | ||
|
|
e3bd1c88e9 | ||
|
|
4cc0873172 | ||
|
|
a493267191 | ||
|
|
0a1e3cd250 | ||
|
|
535d78de7d |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
Gemfile.lock
|
||||
test/dest
|
||||
*.gem
|
||||
pkg/
|
||||
*.swp
|
||||
*~
|
||||
_site/
|
||||
.bundle/
|
||||
|
||||
203
History.txt
203
History.txt
@@ -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
21
LICENSE
Normal 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.
|
||||
@@ -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
178
Rakefile
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
:patch: 4
|
||||
:major: 0
|
||||
:minor: 5
|
||||
150
bin/jekyll
150
bin/jekyll
@@ -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
1
cucumber.yml
Normal file
@@ -0,0 +1 @@
|
||||
default: --format progress
|
||||
1
doc/.gitignore
vendored
Normal file
1
doc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
output
|
||||
7
doc/.gitscribe
Normal file
7
doc/.gitscribe
Normal 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
9
doc/README.asciidoc
Normal 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
10
doc/book/book.asc
Normal 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
41
doc/book/ch00-preface.asc
Normal 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_
|
||||
153
doc/book/ch01-quick-start.asc
Normal file
153
doc/book/ch01-quick-start.asc
Normal 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!
|
||||
90
doc/book/ch02-directory-layout.asc
Normal file
90
doc/book/ch02-directory-layout.asc
Normal 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.
|
||||
@@ -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"
|
||||
|
||||
@@ -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 & 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
30
features/markdown.feature
Normal 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"
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
263
jekyll.gemspec
263
jekyll.gemspec
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
50
lib/jekyll/converter.rb
Normal 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
|
||||
22
lib/jekyll/converters/identity.rb
Normal file
22
lib/jekyll/converters/identity.rb
Normal 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
|
||||
113
lib/jekyll/converters/markdown.rb
Normal file
113
lib/jekyll/converters/markdown.rb
Normal 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
|
||||
33
lib/jekyll/converters/textile.rb
Normal file
33
lib/jekyll/converters/textile.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
6
lib/jekyll/errors.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module Jekyll
|
||||
|
||||
class FatalException < StandardError
|
||||
end
|
||||
|
||||
end
|
||||
@@ -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
7
lib/jekyll/generator.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
module Jekyll
|
||||
|
||||
class Generator < Plugin
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
87
lib/jekyll/generators/pagination.rb
Normal file
87
lib/jekyll/generators/pagination.rb
Normal 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
|
||||
86
lib/jekyll/migrators/drupal.rb
Normal file
86
lib/jekyll/migrators/drupal.rb
Normal 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(/(&|&)/, ' 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
|
||||
53
lib/jekyll/migrators/marley.rb
Normal file
53
lib/jekyll/migrators/marley.rb
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
73
lib/jekyll/migrators/posterous.rb
Normal file
73
lib/jekyll/migrators/posterous.rb
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
45
lib/jekyll/migrators/wordpressdotcom.rb
Normal file
45
lib/jekyll/migrators/wordpressdotcom.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
76
lib/jekyll/plugin.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
75
lib/jekyll/static_file.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
8
test/source/.htaccess
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
layout: nil
|
||||
---
|
||||
ErrorDocument 404 /404.html
|
||||
ErrorDocument 500 /500.html
|
||||
{% for post in site.posts %}
|
||||
# {{ post.url }}
|
||||
{% endfor %}
|
||||
7
test/source/_posts/2009-01-27-empty-categories.textile
Normal file
7
test/source/_posts/2009-01-27-empty-categories.textile
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
layout: default
|
||||
title: Category in YAML
|
||||
categories:
|
||||
---
|
||||
|
||||
Best *post* ever
|
||||
7
test/source/_posts/2009-01-27-empty-category.textile
Normal file
7
test/source/_posts/2009-01-27-empty-category.textile
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
layout: default
|
||||
title: Category in YAML
|
||||
category:
|
||||
---
|
||||
|
||||
Best *post* ever
|
||||
6
test/source/_posts/2009-05-18-empty-tag.textile
Normal file
6
test/source/_posts/2009-05-18-empty-tag.textile
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: A Tag
|
||||
tag:
|
||||
---
|
||||
|
||||
Whoa.
|
||||
6
test/source/_posts/2009-05-18-empty-tags.textile
Normal file
6
test/source/_posts/2009-05-18-empty-tags.textile
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Some Tags
|
||||
tags:
|
||||
---
|
||||
|
||||
Awesome!
|
||||
5
test/source/_posts/2010-01-08-triple-dash.markdown
Normal file
5
test/source/_posts/2010-01-08-triple-dash.markdown
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Foo --- Bar
|
||||
---
|
||||
|
||||
Triple the fun!
|
||||
7
test/source/_posts/2010-01-09-date-override.textile
Normal file
7
test/source/_posts/2010-01-09-date-override.textile
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
date: 2010-01-10
|
||||
---
|
||||
|
||||
Post with a front matter date
|
||||
|
||||
{{ page.date | date_to_string }}
|
||||
7
test/source/_posts/2010-01-09-time-override.textile
Normal file
7
test/source/_posts/2010-01-09-time-override.textile
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
date: 2010-01-10 13:07:09
|
||||
---
|
||||
|
||||
Post with a front matter time
|
||||
|
||||
{{ page.date | date_to_string }}
|
||||
7
test/source/_posts/2010-01-09-timezone-override.textile
Normal file
7
test/source/_posts/2010-01-09-timezone-override.textile
Normal 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 }}
|
||||
4
test/source/_posts/2010-01-16-override-data.textile
Normal file
4
test/source/_posts/2010-01-16-override-data.textile
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
date: 2010-01-10 13:07:09
|
||||
tags: A string
|
||||
---
|
||||
7
test/source/deal.with.dots.html
Normal file
7
test/source/deal.with.dots.html
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Deal with dots
|
||||
permalink: /deal.with.dots/
|
||||
---
|
||||
|
||||
Let's test if jekyll deals properly with dots.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
66
test/test_core_ext.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
23
test/test_kramdown.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
18
test/test_rdiscount.rb
Normal 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>“smart”</p>", @markdown.convert('"smart"').strip
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user