Merge branch 'alagu-posterous-importer-rebased' of git://github.com/simensen/jekyll
This commit is contained in:
commit
67f403a9d6
|
@ -6,3 +6,5 @@ pkg/
|
|||
*~
|
||||
_site/
|
||||
.bundle/
|
||||
.DS_Store
|
||||
bbin/
|
||||
|
|
20
History.txt
20
History.txt
|
@ -1,3 +1,23 @@
|
|||
== HEAD
|
||||
* Minor Enhancements
|
||||
* Add ability to explicitly specify included files (#261)
|
||||
* Add --default-mimetype option (#279)
|
||||
* Allow setting of RedCloth options (#284)
|
||||
* Add post_url Liquid tag for internal post linking (#369)
|
||||
* Bug Fixes
|
||||
* Allow some special characters in highlight names
|
||||
* URL escape category names in URL generation (#360)
|
||||
* Fix error with limit_posts (#442)
|
||||
|
||||
== 0.11.2 / 2011-12-27
|
||||
* Bug Fixes
|
||||
* Fix gemspec
|
||||
|
||||
== 0.11.1 / 2011-12-27
|
||||
* Bug Fixes
|
||||
* Fix extra blank line in highlight blocks (#409)
|
||||
* Update dependencies
|
||||
|
||||
== 0.11.0 / 2011-07-10
|
||||
* Major Enhancements
|
||||
* Add command line importer functionality (#253)
|
||||
|
|
9
Rakefile
9
Rakefile
|
@ -1,5 +1,6 @@
|
|||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rdoc'
|
||||
require 'date'
|
||||
|
||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w[lib]))
|
||||
|
@ -49,6 +50,10 @@ task :default => [:test, :features]
|
|||
|
||||
require 'rake/testtask'
|
||||
Rake::TestTask.new(:test) do |test|
|
||||
if `which pygmentize` == ''
|
||||
puts "You must have Pygments installed to run the tests."
|
||||
exit 1
|
||||
end
|
||||
test.libs << 'lib' << 'test'
|
||||
test.pattern = 'test/**/test_*.rb'
|
||||
test.verbose = true
|
||||
|
@ -62,7 +67,7 @@ task :coverage do
|
|||
sh "open coverage/index.html"
|
||||
end
|
||||
|
||||
require 'rake/rdoctask'
|
||||
require 'rdoc/task'
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = "#{name} #{version}"
|
||||
|
@ -119,7 +124,7 @@ task :release => :build do
|
|||
puts "You must be on the master branch to release!"
|
||||
exit!
|
||||
end
|
||||
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
||||
sh "git commit --allow-empty -m 'Release #{version}'"
|
||||
sh "git tag v#{version}"
|
||||
sh "git push origin master"
|
||||
sh "git push origin v#{version}"
|
||||
|
|
11
bin/jekyll
11
bin/jekyll
|
@ -71,6 +71,10 @@ opts = OptionParser.new do |opts|
|
|||
options['baseurl'] = baseurl
|
||||
end
|
||||
|
||||
opts.on("--default-mimetype [MT]", "Mimetype to use when no file extension (if --server)") do |mt|
|
||||
options['default-mimetype'] = mt
|
||||
end
|
||||
|
||||
opts.on("--[no-]lsi", "Use LSI for better related posts") do |lsi|
|
||||
options['lsi'] = lsi
|
||||
end
|
||||
|
@ -162,7 +166,7 @@ if ARGV.size > 0
|
|||
migrators = {
|
||||
:posterous => 'Posterous',
|
||||
:wordpressdotcom => 'WordpressDotCom',
|
||||
:wordpress => 'Wordpress',
|
||||
:wordpress => 'WordPress',
|
||||
:csv => 'CSV',
|
||||
:drupal => 'Drupal',
|
||||
:enki => 'Enki',
|
||||
|
@ -191,7 +195,7 @@ end
|
|||
|
||||
|
||||
|
||||
# Get source and destintation from command line
|
||||
# Get source and destination from command line
|
||||
case ARGV.size
|
||||
when 0
|
||||
when 1
|
||||
|
@ -267,6 +271,9 @@ if options['server']
|
|||
|
||||
mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
|
||||
mime_types.store 'js', 'application/javascript'
|
||||
if options['default-mimetype']
|
||||
mime_types.store(nil, options['default-mimetype'])
|
||||
end
|
||||
|
||||
s = HTTPServer.new(
|
||||
:Port => options['server_port'],
|
||||
|
|
|
@ -1,574 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="generator" content="AsciiDoc 8.5.3" />
|
||||
<title>Jekyll</title>
|
||||
<style type="text/css">
|
||||
/* ---------------------------------------------------------------------------
|
||||
Bare AsciiDoc styles
|
||||
Ryan Tomayko <r@tomayko.com>
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family:verdana,helvetica,arial,sans-serif;
|
||||
font-size:81.25%; /* 13px */
|
||||
line-height:1.538; /* 20px */
|
||||
margin:40px auto 50px auto;
|
||||
max-width:53.8461538462em; /* 790px */
|
||||
color:#333;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight:bold;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
tt {
|
||||
font-family:consolas, 'lucida console', 'bitstream vera sans mono',
|
||||
'courier new', monospace;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
p, ul, ol, dl {
|
||||
margin:10px 0
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left:40px
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family:'lucida grande',georgia,verdana,helvetica,arial,sans-serif;
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:40px;
|
||||
line-height:1.428;
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:30px;
|
||||
line-height:1.36363636; /* repeating, of course */
|
||||
margin:60px 0 20px 0;
|
||||
}
|
||||
|
||||
h2 + .sectionbody {}
|
||||
|
||||
h3 {
|
||||
font-size:24px;
|
||||
line-height:1.1;
|
||||
margin:30px 0 10px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:18px;
|
||||
line-height:1.1;
|
||||
margin:20px 0 5px 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size:13px;
|
||||
font-style:italic;
|
||||
line-height:1.1;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align:center;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
#header h1 { margin-bottom:0 }
|
||||
|
||||
.title, .sidebar-title {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
.admonitionblock .title {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.admonitionblock {
|
||||
margin:30px 0px;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
.admonitionblock td.icon {
|
||||
width:30px;
|
||||
padding-right:20px;
|
||||
padding-left:20px;
|
||||
text-transform:uppercase;
|
||||
font-weight:bold;
|
||||
color:#888;
|
||||
}
|
||||
|
||||
.listingblock {
|
||||
margin: 13px 0;
|
||||
}
|
||||
|
||||
.listingblock .content {
|
||||
border:1px solid silver;
|
||||
background:#eee;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.listingblock .content pre {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.literalblock .content {
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.verseblock .content {
|
||||
white-space:pre
|
||||
}
|
||||
|
||||
.sidebarblock .sidebar-content {
|
||||
border:1px solid silver;
|
||||
background:#FFFFEE;
|
||||
padding:0 10px;
|
||||
color:#222;
|
||||
font-size:smaller;
|
||||
line-height:1.5;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin:10px 0;
|
||||
font-weight:bold;
|
||||
color:#442;
|
||||
}
|
||||
|
||||
.quoteblock-content {
|
||||
font-style:italic;
|
||||
color:#444;
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.quoteblock-content .attribution {
|
||||
font-style:normal;
|
||||
text-align:right;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.exampleblock-content *:first-child { margin-top:0 }
|
||||
.exampleblock-content {
|
||||
border-left:2px solid silver;
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
font-size:11px;
|
||||
margin-top:40px;
|
||||
border-top:1px solid silver;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
#author {
|
||||
color:#000;
|
||||
text-transform:uppercase
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
/*<+'])');
|
||||
// Function that scans the DOM tree for header elements (the DOM2
|
||||
// nodeIterator API would be a better technique but not supported by all
|
||||
// browsers).
|
||||
var iterate = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
var mo = re.exec(i.tagName);
|
||||
if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
|
||||
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
|
||||
}
|
||||
iterate(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterate(el);
|
||||
return result;
|
||||
}
|
||||
|
||||
var toc = document.getElementById("toc");
|
||||
var entries = tocEntries(document.getElementById("content"), toclevels);
|
||||
for (var i = 0; i < entries.length; ++i) {
|
||||
var entry = entries[i];
|
||||
if (entry.element.id == "")
|
||||
entry.element.id = "_toc_" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + entry.element.id;
|
||||
a.appendChild(document.createTextNode(entry.text));
|
||||
var div = document.createElement("div");
|
||||
div.appendChild(a);
|
||||
div.className = "toclevel" + entry.toclevel;
|
||||
toc.appendChild(div);
|
||||
}
|
||||
if (entries.length == 0)
|
||||
toc.parentNode.removeChild(toc);
|
||||
},
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Footnotes generator
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Based on footnote generation code from:
|
||||
* http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
|
||||
*/
|
||||
|
||||
footnotes: function () {
|
||||
var cont = document.getElementById("content");
|
||||
var noteholder = document.getElementById("footnotes");
|
||||
var spans = cont.getElementsByTagName("span");
|
||||
var refs = {};
|
||||
var n = 0;
|
||||
for (i=0; i<spans.length; i++) {
|
||||
if (spans[i].className == "footnote") {
|
||||
n++;
|
||||
// Use [\s\S] in place of . so multi-line matches work.
|
||||
// Because JavaScript has no s (dotall) regex flag.
|
||||
note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
|
||||
noteholder.innerHTML +=
|
||||
"<div class='footnote' id='_footnote_" + n + "'>" +
|
||||
"<a href='#_footnoteref_" + n + "' title='Return to text'>" +
|
||||
n + "</a>. " + note + "</div>";
|
||||
spans[i].innerHTML =
|
||||
"[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
|
||||
"' title='View footnote' class='footnote'>" + n + "</a>]";
|
||||
var id =spans[i].getAttribute("id");
|
||||
if (id != null) refs["#"+id] = n;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
noteholder.parentNode.removeChild(noteholder);
|
||||
else {
|
||||
// Process footnoterefs.
|
||||
for (i=0; i<spans.length; i++) {
|
||||
if (spans[i].className == "footnoteref") {
|
||||
var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
|
||||
href = href.match(/#.*/)[0]; // Because IE return full URL.
|
||||
n = refs[href];
|
||||
spans[i].innerHTML =
|
||||
"[<a href='#_footnote_" + n +
|
||||
"' title='View footnote' class='footnote'>" + n + "</a>]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*]]>*/
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>Jekyll</h1>
|
||||
<span id="author">Tom Preston-Werner</span><br />
|
||||
<span id="email"><tt><<a href="mailto:<tom@mojombo.com>"><tom@mojombo.com></a>></tt></span><br />
|
||||
<div id="toc">
|
||||
<div id="toctitle">Table of Contents</div>
|
||||
<noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<h2 id="_preface">1. Preface</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<h3 id="_what_this_book_covers">1.1. What this book covers</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p><em>Chapter 1, Quick Start</em> 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.</p></div>
|
||||
<div class="paragraph"><p><em>Chapter 2, Directory Layout</em> covers the various files and directories that
|
||||
comprise a Jekyll site.</p></div>
|
||||
<div class="paragraph"><p><em>Chapter 3, Tags and Filters</em></p></div>
|
||||
<div class="paragraph"><p><em>Chapter X, Deploying your Jekyll Site</em></p></div>
|
||||
<div class="paragraph"><p><em>Chapter X, Customizing Jekyll with Plugins</em></p></div>
|
||||
<div class="paragraph"><p><em>Chapter X, Migrating to Jekyll from your Existing Blog</em></p></div>
|
||||
<div class="paragraph"><p><em>Chapter X, Configuration Reference</em></p></div>
|
||||
</div>
|
||||
<h2 id="_chapter_1_quick_start">2. Chapter 1: Quick Start</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph"><p>This chapter is designed to get you up and running with Jekyll as quickly as
|
||||
possible.</p></div>
|
||||
<h3 id="_installation">2.1. Installation</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>The best way to install Jekyll is via RubyGems:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>gem install jekyll</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>This is all you need in order to get started with a basic Jekyll site. Some
|
||||
options require additional packages to be installed.</p></div>
|
||||
<div class="paragraph"><p>If you encounter errors during gem installation, you may need to install the
|
||||
header files for compiling extension modules for ruby 1.8:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Debian</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo apt-get install ruby1.8-dev</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Red Hat / CentOS / Fedora systems</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo yum install ruby-devel</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">NearlyFreeSpeech</div>
|
||||
<div class="content">
|
||||
<pre><tt>RB_USER_INSTALL=true gem install jekyll</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>If you encounter errors like <tt>Failed to build gem native extension</tt> on Windows
|
||||
you may need to install <a href="http://wiki.github.com/oneclick/rubyinstaller/development-kit">RubyInstaller
|
||||
DevKit</a>.</p></div>
|
||||
<h4 id="_latex_to_png">2.1.1. LaTeX to PNG</h4>
|
||||
<div class="paragraph"><p>Maruku comes with optional support for LaTeX to PNG rendering via blahtex
|
||||
(Version 0.6) which must be in your $PATH along with @dvips@.</p></div>
|
||||
<div class="paragraph"><p>(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)</p></div>
|
||||
<h4 id="_rdiscount">2.1.2. RDiscount</h4>
|
||||
<div class="paragraph"><p>If you prefer to use
|
||||
<a href="http://github.com/rtomayko/rdiscount/tree/master">RDiscount</a> instead of
|
||||
<a href="http://maruku.rubyforge.org/">Maruku</a> for markdown, just make sure it’s
|
||||
installed:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>sudo gem install rdiscount</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>And run Jekyll with the following option:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>jekyll --rdiscount</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Or, in your @_config.yml@ file put the following so you don’t have to specify the flag:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>markdown: rdiscount</tt></pre>
|
||||
</div></div>
|
||||
<h4 id="_pygments">2.1.3. Pygments</h4>
|
||||
<div class="paragraph"><p>If you want syntax highlighting via the @{% highlight %}@ tag in your posts,
|
||||
you’ll need to install <a href="http://pygments.org/">Pygments</a>.</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">On OSX with Homebrew</div>
|
||||
<div class="content">
|
||||
<pre><tt>brew install pip && pip install pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">On OSX with MacPorts</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo port install python25 py25-pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Bare OS X Leopard</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo easy_install Pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Archlinux</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo pacman -S python-pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Archlinux python2 for Pygments</div>
|
||||
<div class="content">
|
||||
<pre><tt>$ sudo pacman -S python2-pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<div class="title">Note</div>
|
||||
</td>
|
||||
<td class="content">python2 pygments version creates a <tt>pygmentize2</tt> executable, while
|
||||
Jekyll tries to find <tt>pygmentize</tt>. Either create a symlink <tt># ln -s
|
||||
/usr/bin/pygmentize2 /usr/bin/pygmentize</tt> or use the python3 version.</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Ubuntu and Debian</div>
|
||||
<div class="content">
|
||||
<pre><tt>sudo apt-get install python-pygments</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Gentoo</div>
|
||||
<div class="content">
|
||||
<pre><tt>$ sudo emerge -av dev-python/pygments</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_creating_your_first_site">2.2. Creating your First Site</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ mkdir mysite
|
||||
$ cd mysite
|
||||
$ jekyll gen</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<div class="paragraph"><p>To perform the conversion, make sure you’re in the root of your Jekyll site
|
||||
directory and run:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>$ jekyll --server</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>If all goes well, you should get a few lines with information about config
|
||||
file detection, source and destination paths, and a success message.</p></div>
|
||||
<div class="paragraph"><p>The <tt>--server</tt> 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.</p></div>
|
||||
<div class="paragraph"><p>Open up your favorite web browser and navigate to:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>http://localhost:4000</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Congratulations! You have now successfully created and converted your first
|
||||
Jekyll site!</p></div>
|
||||
</div>
|
||||
<h2 id="_chapter_2_directory_layout">3. Chapter 2: Directory Layout</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph"><p>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:</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
<pre><tt>.
|
||||
|-- _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</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<h3 id="_config_yml">3.1. _config.yml</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<h3 id="_layouts">3.2. _layouts</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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 <tt>{{ content }}</tt> specifies where the content will be placed
|
||||
during the conversion process.</p></div>
|
||||
<h3 id="_posts">3.3. _posts</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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:
|
||||
<tt>YEAR-MONTH-DATE-SLUG.MARKUP</tt>. 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.</p></div>
|
||||
<h3 id="_site">3.4. _site</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<h3 id="_normal_files_with_yaml_front_matter">3.5. Normal Files with YAML Front Matter</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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.</p></div>
|
||||
<h3 id="_everything_else">3.6. Everything Else</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>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,
|
||||
<tt>images/logo.png</tt> will be copied to the same location in the generated site.</p></div>
|
||||
<div class="paragraph"><p>h2. Running Jekyll</p></div>
|
||||
<div class="paragraph"><p>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:</p></div>
|
||||
<div class="paragraph"><p>@jekyll --server@</p></div>
|
||||
<div class="paragraph"><p>and then browse to <a href="http://0.0.0.0:4000">http://0.0.0.0:4000</a>. There’s plenty of <a id="configuration options|Configuration"></a> available to you as well.</p></div>
|
||||
<div class="paragraph"><p>On Debian or Ubuntu, you may need to add @/var/lib/gems/1.8/bin/@ to your path.</p></div>
|
||||
<div class="paragraph"><p>h2. Deployment</p></div>
|
||||
<div class="paragraph"><p>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
|
||||
<a id="Deployment"></a> page for more information regarding specific scenarios.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footnotes"><hr /></div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2011-03-18 21:05:02 PDT
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||
== 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_
|
|
@ -1,153 +0,0 @@
|
|||
== 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!
|
|
@ -1,90 +0,0 @@
|
|||
== 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.
|
|
@ -1,231 +0,0 @@
|
|||
/* BEG */
|
||||
/* ---------------------------------------------------------------------------
|
||||
Bare AsciiDoc styles
|
||||
Ryan Tomayko <r@tomayko.com>
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family:verdana,helvetica,arial,sans-serif;
|
||||
font-size:81.25%; /* 13px */
|
||||
line-height:1.538; /* 20px */
|
||||
margin:40px 50px;
|
||||
max-width:53.8461538462em; /* 790px */
|
||||
color:#333;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight:bold;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
tt {
|
||||
font-family:consolas, 'lucida console', 'bitstream vera sans mono',
|
||||
'courier new', monospace;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
p, ul, ol, dl {
|
||||
margin:10px 0
|
||||
}
|
||||
|
||||
dl { }
|
||||
|
||||
dt {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family:'lucida grande',georgia,verdana,helvetica,arial,sans-serif;
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:30px;
|
||||
line-height:1.428;
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:23px;
|
||||
line-height:1.36363636; /* repeating, of course */
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
h2 + .sectionbody {}
|
||||
|
||||
h3 {
|
||||
font-size:18px;
|
||||
line-height:1.1;
|
||||
margin:30px 0 10px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:13px;
|
||||
font-weight:bold;
|
||||
line-height:1.538;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size:13px;
|
||||
font-style:italic;
|
||||
line-height:1.538;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size:larger;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align:center;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
#header h1 { margin-bottom:0 }
|
||||
|
||||
|
||||
.title, .sidebar-title {
|
||||
font-weight:normal;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
.admonitionblock .title {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.admonitionblock {
|
||||
margin:30px 0px;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
.admonitionblock td.icon {
|
||||
width:30px;
|
||||
padding-right:20px;
|
||||
padding-left:20px;
|
||||
text-transform:uppercase;
|
||||
font-weight:bold;
|
||||
color:#888;
|
||||
}
|
||||
|
||||
.listingblock .content {
|
||||
border:1px solid silver;
|
||||
background:#eee;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.listingblock .content pre {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.literalblock .content {
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.verseblock .content {
|
||||
white-space:pre
|
||||
}
|
||||
|
||||
.sidebarblock .sidebar-content {
|
||||
border:1px solid silver;
|
||||
background:#FFFFEE;
|
||||
padding:0 10px;
|
||||
color:#222;
|
||||
font-size:smaller;
|
||||
line-height:1.5;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin:10px 0;
|
||||
font-weight:bold;
|
||||
color:#442;
|
||||
}
|
||||
|
||||
.quoteblock-content {
|
||||
font-style:italic;
|
||||
color:#444;
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.quoteblock-content .attribution {
|
||||
font-style:normal;
|
||||
text-align:right;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.exampleblock-content *:first-child { margin-top:0 }
|
||||
.exampleblock-content {
|
||||
border-left:2px solid silver;
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
font-size:11px;
|
||||
margin-top:40px;
|
||||
border-top:1px solid silver;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
#author {
|
||||
color:#000;
|
||||
text-transform:uppercase
|
||||
}
|
||||
|
||||
/* vim: set ft=css ts=4 sw=4 noexpandtab: */
|
||||
|
||||
/* END @import url(bare.css); */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
FreeBSD AsciiDoc Theme
|
||||
Ryan Tomayko <r@tomayko.com>
|
||||
|
||||
Based on The FreeBSD Handbook and various other FreeBSD documenration.
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family:verdana,helvetica,arial,sans-serif;
|
||||
font-size:100%;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
tt { color:#007A00 }
|
||||
pre tt { color:#000 }
|
||||
|
||||
dt { color:#000 }
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family:'lucida grande',helvetica,verdana,sans-serif;
|
||||
color:#900;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align:left;
|
||||
}
|
||||
#header h1 { margin-bottom:40px }
|
||||
|
||||
h1 {
|
||||
font-size:36px;
|
||||
line-height:1;
|
||||
margin:40px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:28px;
|
||||
line-height:1;
|
||||
margin:30px 0 20px 0;
|
||||
}
|
||||
|
||||
.sectionbody {
|
||||
margin-left:30px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background:#EEE;
|
||||
}
|
||||
|
||||
/* vim: set ft=css ts=4 sw=4 noexpandtab: */
|
|
@ -1,177 +0,0 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Bare AsciiDoc styles
|
||||
Ryan Tomayko <r@tomayko.com>
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family:verdana,helvetica,arial,sans-serif;
|
||||
font-size:81.25%; /* 13px */
|
||||
line-height:1.538; /* 20px */
|
||||
margin:40px auto 50px auto;
|
||||
max-width:53.8461538462em; /* 790px */
|
||||
color:#333;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight:bold;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
tt {
|
||||
font-family:consolas, 'lucida console', 'bitstream vera sans mono',
|
||||
'courier new', monospace;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
p, ul, ol, dl {
|
||||
margin:10px 0
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left:40px
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family:'lucida grande',georgia,verdana,helvetica,arial,sans-serif;
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:40px;
|
||||
line-height:1.428;
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:30px;
|
||||
line-height:1.36363636; /* repeating, of course */
|
||||
margin:60px 0 20px 0;
|
||||
}
|
||||
|
||||
h2 + .sectionbody {}
|
||||
|
||||
h3 {
|
||||
font-size:24px;
|
||||
line-height:1.1;
|
||||
margin:30px 0 10px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:18px;
|
||||
line-height:1.1;
|
||||
margin:20px 0 5px 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size:13px;
|
||||
font-style:italic;
|
||||
line-height:1.1;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align:center;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
#header h1 { margin-bottom:0 }
|
||||
|
||||
.title, .sidebar-title {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
.admonitionblock .title {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.admonitionblock {
|
||||
margin:30px 0px;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
.admonitionblock td.icon {
|
||||
width:30px;
|
||||
padding-right:20px;
|
||||
padding-left:20px;
|
||||
text-transform:uppercase;
|
||||
font-weight:bold;
|
||||
color:#888;
|
||||
}
|
||||
|
||||
.listingblock {
|
||||
margin: 13px 0;
|
||||
}
|
||||
|
||||
.listingblock .content {
|
||||
border:1px solid silver;
|
||||
background:#eee;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.listingblock .content pre {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.literalblock .content {
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.verseblock .content {
|
||||
white-space:pre
|
||||
}
|
||||
|
||||
.sidebarblock .sidebar-content {
|
||||
border:1px solid silver;
|
||||
background:#FFFFEE;
|
||||
padding:0 10px;
|
||||
color:#222;
|
||||
font-size:smaller;
|
||||
line-height:1.5;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin:10px 0;
|
||||
font-weight:bold;
|
||||
color:#442;
|
||||
}
|
||||
|
||||
.quoteblock-content {
|
||||
font-style:italic;
|
||||
color:#444;
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.quoteblock-content .attribution {
|
||||
font-style:normal;
|
||||
text-align:right;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.exampleblock-content *:first-child { margin-top:0 }
|
||||
.exampleblock-content {
|
||||
border-left:2px solid silver;
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
font-size:11px;
|
||||
margin-top:40px;
|
||||
border-top:1px solid silver;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
#author {
|
||||
color:#000;
|
||||
text-transform:uppercase
|
||||
}
|
|
@ -92,3 +92,15 @@ Feature: Create sites
|
|||
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"
|
||||
|
||||
Scenario: Basic site with internal post linking
|
||||
Given I have an "index.html" page that contains "URL: {% post_url 2020-01-31-entry2 %}"
|
||||
And I have a configuration file with "permalink" set to "pretty"
|
||||
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 "URL: /2020/01/31/entry2/" in "_site/index.html"
|
||||
|
|
48
g.pl
48
g.pl
|
@ -1,48 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
#fetch Gravatars
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use LWP::Simple;
|
||||
use Digest::MD5 qw(md5_hex);
|
||||
|
||||
my $size = 90;
|
||||
my $output_dir = '.git/avatar';
|
||||
|
||||
die("no .git/ directory found in current path\n") unless -d '.git';
|
||||
|
||||
mkdir($output_dir) unless -d $output_dir;
|
||||
|
||||
open(GITLOG, q/git log --pretty=format:"%ae|%an" |/) or die("failed to read git-log: $!\n");
|
||||
|
||||
my %processed_authors;
|
||||
|
||||
while(<GITLOG>) {
|
||||
chomp;
|
||||
my($email, $author) = split(/\|/, $_);
|
||||
|
||||
next if $processed_authors{$author}++;
|
||||
|
||||
my $author_image_file = $output_dir . '/' . $author . '.png';
|
||||
|
||||
#skip images we have
|
||||
next if -e $author_image_file;
|
||||
|
||||
#try and fetch image
|
||||
|
||||
my $grav_url = "http://www.gravatar.com/avatar/".md5_hex(lc $email)."?d=404&size=".$size;
|
||||
|
||||
warn "fetching image for '$author' $email ($grav_url)...\n";
|
||||
|
||||
my $rc = getstore($grav_url, $author_image_file);
|
||||
|
||||
sleep(1);
|
||||
|
||||
if($rc != 200) {
|
||||
unlink($author_image_file);
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
close GITLOG;
|
|
@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|||
s.rubygems_version = '1.3.5'
|
||||
|
||||
s.name = 'jekyll'
|
||||
s.version = '0.11.0'
|
||||
s.date = '2011-07-10'
|
||||
s.version = '0.11.2'
|
||||
s.date = '2011-12-27'
|
||||
s.rubyforge_project = 'jekyll'
|
||||
|
||||
s.summary = "A simple, blog aware, static site generator."
|
||||
|
@ -22,20 +22,22 @@ Gem::Specification.new do |s|
|
|||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.extra_rdoc_files = %w[README.textile LICENSE]
|
||||
|
||||
s.add_runtime_dependency('liquid', ">= 1.9.0")
|
||||
s.add_runtime_dependency('classifier', ">= 1.3.1")
|
||||
s.add_runtime_dependency('directory_watcher', ">= 1.1.1")
|
||||
s.add_runtime_dependency('maruku', ">= 0.5.9")
|
||||
s.add_runtime_dependency('kramdown', ">= 0.13.2")
|
||||
s.add_runtime_dependency('albino', ">= 1.3.2")
|
||||
s.add_runtime_dependency('liquid', "~> 2.3")
|
||||
s.add_runtime_dependency('classifier', "~> 1.3")
|
||||
s.add_runtime_dependency('directory_watcher', "~> 1.1")
|
||||
s.add_runtime_dependency('maruku', "~> 0.5")
|
||||
s.add_runtime_dependency('kramdown', "~> 0.13")
|
||||
s.add_runtime_dependency('albino', "~> 1.3")
|
||||
|
||||
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.3")
|
||||
s.add_development_dependency('RedCloth', ">= 4.2.1")
|
||||
s.add_development_dependency('rdiscount', ">= 1.6.5")
|
||||
s.add_development_dependency('redcarpet', ">= 1.9.0")
|
||||
s.add_development_dependency('rake', "~> 0.9")
|
||||
s.add_development_dependency('rdoc', "~> 3.11")
|
||||
s.add_development_dependency('redgreen', "~> 1.2")
|
||||
s.add_development_dependency('shoulda', "~> 2.11")
|
||||
s.add_development_dependency('rr', "~> 1.0")
|
||||
s.add_development_dependency('cucumber', "1.1")
|
||||
s.add_development_dependency('RedCloth', "~> 4.2")
|
||||
s.add_development_dependency('rdiscount', "~> 1.6")
|
||||
s.add_development_dependency('redcarpet', "~> 1.9")
|
||||
|
||||
# = MANIFEST =
|
||||
s.files = %w[
|
||||
|
@ -46,14 +48,6 @@ Gem::Specification.new do |s|
|
|||
Rakefile
|
||||
bin/jekyll
|
||||
cucumber.yml
|
||||
doc/output/book.html
|
||||
doc/output/ch00-preface.asc
|
||||
doc/output/ch01-quick-start.asc
|
||||
doc/output/ch02-directory-layout.asc
|
||||
doc/output/stylesheets/handbookish-quirks.css
|
||||
doc/output/stylesheets/handbookish.css
|
||||
doc/output/stylesheets/scribe-quirks.css
|
||||
doc/output/stylesheets/scribe.css
|
||||
features/create_sites.feature
|
||||
features/embed_filters.feature
|
||||
features/markdown.feature
|
||||
|
@ -64,7 +58,6 @@ Gem::Specification.new do |s|
|
|||
features/site_data.feature
|
||||
features/step_definitions/jekyll_steps.rb
|
||||
features/support/env.rb
|
||||
g.pl
|
||||
jekyll.gemspec
|
||||
lib/jekyll.rb
|
||||
lib/jekyll/converter.rb
|
||||
|
@ -97,8 +90,6 @@ Gem::Specification.new do |s|
|
|||
lib/jekyll/static_file.rb
|
||||
lib/jekyll/tags/highlight.rb
|
||||
lib/jekyll/tags/include.rb
|
||||
output/stylesheets/scribe-quirks.css
|
||||
output/stylesheets/scribe.css
|
||||
test/helper.rb
|
||||
test/source/.htaccess
|
||||
test/source/_includes/sig.markdown
|
||||
|
@ -152,6 +143,7 @@ Gem::Specification.new do |s|
|
|||
test/test_redcarpet.rb
|
||||
test/test_site.rb
|
||||
test/test_tags.rb
|
||||
test/test_redcloth.rb
|
||||
]
|
||||
# = MANIFEST =
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ require_all 'jekyll/generators'
|
|||
require_all 'jekyll/tags'
|
||||
|
||||
module Jekyll
|
||||
VERSION = '0.11.0'
|
||||
VERSION = '0.11.2'
|
||||
|
||||
# Default options. Overriden by values in _config.yml or command-line opts.
|
||||
# (Strings rather symbols used for compatability with YAML).
|
||||
|
@ -65,7 +65,8 @@ module Jekyll
|
|||
'pygments' => false,
|
||||
'markdown' => 'maruku',
|
||||
'permalink' => 'date',
|
||||
|
||||
'include' => ['.htaccess'],
|
||||
|
||||
'markdown_ext' => 'markdown,mkd,mkdn,md',
|
||||
'textile_ext' => 'textile',
|
||||
|
||||
|
@ -97,6 +98,9 @@ module Jekyll
|
|||
'coderay_bold_every' => 10,
|
||||
'coderay_css' => 'style'
|
||||
}
|
||||
},
|
||||
'redcloth' => {
|
||||
'hard_breaks' => true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,23 @@ module Jekyll
|
|||
|
||||
def convert(content)
|
||||
setup
|
||||
RedCloth.new(content).to_html
|
||||
|
||||
# Shortcut if config doesn't contain RedCloth section
|
||||
return RedCloth.new(content).to_html if @config['redcloth'].nil?
|
||||
|
||||
# List of attributes defined on RedCloth
|
||||
# (from http://redcloth.rubyforge.org/classes/RedCloth/TextileDoc.html)
|
||||
attrs = ['filter_classes', 'filter_html', 'filter_ids', 'filter_styles',
|
||||
'hard_breaks', 'lite_mode', 'no_span_caps', 'sanitize_html']
|
||||
|
||||
r = RedCloth.new(content)
|
||||
|
||||
# Set attributes in r if they are NOT nil in the config
|
||||
attrs.each do |attr|
|
||||
r.instance_variable_set("@#{attr}".to_sym, @config['redcloth'][attr]) unless @config['redcloth'][attr].nil?
|
||||
end
|
||||
|
||||
r.to_html
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ require 'set'
|
|||
# self.data=
|
||||
# self.ext=
|
||||
# self.output=
|
||||
# self.name
|
||||
module Jekyll
|
||||
module Convertible
|
||||
# Returns the contents as a String.
|
||||
|
@ -26,14 +27,13 @@ module Jekyll
|
|||
def read_yaml(base, name)
|
||||
self.content = File.read(File.join(base, name))
|
||||
|
||||
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
||||
self.content = $POSTMATCH
|
||||
|
||||
begin
|
||||
begin
|
||||
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
||||
self.content = $POSTMATCH
|
||||
self.data = YAML.load($1)
|
||||
rescue => e
|
||||
puts "YAML Exception reading #{name}: #{e.message}"
|
||||
end
|
||||
rescue => e
|
||||
puts "YAML Exception reading #{name}: #{e.message}"
|
||||
end
|
||||
|
||||
self.data ||= {}
|
||||
|
|
|
@ -14,19 +14,24 @@ module Jekyll
|
|||
# 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"
|
||||
QUERY = "SELECT n.nid, \
|
||||
n.title, \
|
||||
nr.body, \
|
||||
n.created, \
|
||||
n.status \
|
||||
FROM node AS n, \
|
||||
node_revisions AS nr \
|
||||
WHERE (n.type = 'blog' OR n.type = 'story') \
|
||||
AND n.vid = nr.vid"
|
||||
|
||||
def self.process(dbname, user, pass, host = 'localhost')
|
||||
def self.process(dbname, user, pass, host = 'localhost', prefix = '')
|
||||
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
|
||||
|
||||
if prefix != ''
|
||||
QUERY[" node "] = " " + prefix + "node "
|
||||
QUERY[" node_revisions "] = " " + prefix + "node_revisions "
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p "_posts"
|
||||
FileUtils.mkdir_p "_drafts"
|
||||
|
||||
|
@ -73,12 +78,18 @@ EOF
|
|||
|
||||
# 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 "---"
|
||||
aliases = db["SELECT dst FROM #{prefix}url_alias WHERE src = ?", "node/#{node_id}"].all
|
||||
|
||||
aliases.push(:dst => "node/#{node_id}")
|
||||
|
||||
aliases.each do |url_alias|
|
||||
FileUtils.mkdir_p url_alias[:dst]
|
||||
File.open("#{url_alias[:dst]}/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
|
||||
end
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
require 'rubygems'
|
||||
require 'sequel'
|
||||
require 'fileutils'
|
||||
require 'yaml'
|
||||
|
||||
# NOTE: This migrator is made for Joomla 1.5 databases.
|
||||
# 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 Joomla
|
||||
def self.process(dbname, user, pass, host = 'localhost', table_prefix = 'jos_', section = '1')
|
||||
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 `title`, `alias`, CONCAT(`introtext`,`fulltext`) as content, `created`, `id` FROM #{table_prefix}content WHERE state = '0' OR state = '1' AND sectionid = '#{section}'"
|
||||
|
||||
db[query].each do |post|
|
||||
# Get required fields and construct Jekyll compatible name.
|
||||
title = post[:title]
|
||||
slug = post[:alias]
|
||||
date = post[:created]
|
||||
content = post[:content]
|
||||
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
|
||||
slug]
|
||||
|
||||
# Get the relevant fields as a hash, delete empty fields and convert
|
||||
# to YAML for the header.
|
||||
data = {
|
||||
'layout' => 'post',
|
||||
'title' => title.to_s,
|
||||
'joomla_id' => post[:id],
|
||||
'joomla_url' => post[:alias],
|
||||
'date' => date
|
||||
}.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
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,12 +29,17 @@ module Jekyll
|
|||
case response
|
||||
when Net::HTTPSuccess then response
|
||||
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
||||
when Net::HTTPForbidden then
|
||||
retry_after = response.to_hash['retry-after'][0]
|
||||
puts "We have been told to try again after #{retry_after} seconds"
|
||||
sleep(retry_after.to_i + 1)
|
||||
fetch(uri_str, limit - 1)
|
||||
else response.error!
|
||||
end
|
||||
end
|
||||
|
||||
def self.process(email, pass, api_token, blog = 'primary', tags_key = 'categories')
|
||||
@email, @pass , @api_token = email, pass, api_token
|
||||
@email, @pass, @api_token = email, pass, api_token
|
||||
FileUtils.mkdir_p "_posts"
|
||||
|
||||
posts = JSON.parse(self.fetch("/api/2/sites/#{blog}/posts?api_token=#{@api_token}").body)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
# Created by Kendall Buchanan (https://github.com/kendagriff) on 2011-12-22.
|
||||
# Use at your own risk. The end.
|
||||
#
|
||||
# Usage:
|
||||
# (URL)
|
||||
# ruby -r '_import/rss.rb' -e "Jekyll::MigrateRSS.process('http://yourdomain.com/your-favorite-feed.xml')"
|
||||
#
|
||||
# (Local file)
|
||||
# ruby -r '_import/rss.rb' -e "Jekyll::MigrateRSS.process('./somefile/on/your/computer.xml')"
|
||||
|
||||
require 'rubygems'
|
||||
require 'rss/1.0'
|
||||
require 'rss/2.0'
|
||||
require 'open-uri'
|
||||
require 'fileutils'
|
||||
require 'yaml'
|
||||
|
||||
module Jekyll
|
||||
module MigrateRSS
|
||||
|
||||
# The `source` argument may be a URL or a local file.
|
||||
def self.process(source)
|
||||
content = ""
|
||||
open(source) { |s| content = s.read }
|
||||
rss = RSS::Parser.parse(content, false)
|
||||
|
||||
raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless rss
|
||||
|
||||
rss.items.each do |item|
|
||||
formatted_date = item.date.strftime('%Y-%m-%d')
|
||||
post_name = item.title.split(%r{ |!|/|:|&|-|$|,}).map { |i| i.downcase if i != '' }.compact.join('-')
|
||||
name = "#{formatted_date}-#{post_name}"
|
||||
|
||||
header = {
|
||||
'layout' => 'post',
|
||||
'title' => item.title
|
||||
}
|
||||
|
||||
File.open("_posts/#{name}.html", "w") do |f|
|
||||
f.puts header.to_yaml
|
||||
f.puts "---\n"
|
||||
f.puts item.description
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
|
@ -1,119 +1,195 @@
|
|||
require 'rubygems'
|
||||
require 'nokogiri'
|
||||
require 'open-uri'
|
||||
require 'fileutils'
|
||||
require 'CGI'
|
||||
require 'iconv'
|
||||
require 'nokogiri'
|
||||
require 'date'
|
||||
require 'json'
|
||||
require 'uri'
|
||||
require 'jekyll'
|
||||
|
||||
module Jekyll
|
||||
module Tumblr
|
||||
def self.process(url, grab_images = false)
|
||||
current_page = 0
|
||||
|
||||
while true
|
||||
f = open(url + "/api/read?num=50&start=#{current_page * 50}")
|
||||
doc = Nokogiri::HTML(Iconv.conv("utf-8", f.charset, f.readlines.join("\n")))
|
||||
|
||||
puts "Page: #{current_page + 1} - Posts: #{(doc/:tumblr/:posts/:post).size}"
|
||||
|
||||
FileUtils.mkdir_p "_posts/tumblr"
|
||||
|
||||
(doc/:tumblr/:posts/:post).each do |post|
|
||||
title = ""
|
||||
content = nil
|
||||
name = nil
|
||||
|
||||
if post['type'] == "regular"
|
||||
title_element = post.at("regular-title")
|
||||
title = title_element.inner_text unless title_element == nil
|
||||
content = CGI::unescapeHTML post.at("regular-body").inner_html unless post.at("regular-body") == nil
|
||||
elsif post['type'] == "link"
|
||||
title = post.at("link-text").inner_html unless post.at("link-text") == nil
|
||||
|
||||
if post.at("link-text") != nil
|
||||
content = "<a href=\"#{post.at("link-url").inner_html}\">#{post.at("link-text").inner_html}</a>"
|
||||
else
|
||||
content = "<a href=\"#{post.at("link-url").inner_html}\">#{post.at("link-url").inner_html}</a>"
|
||||
end
|
||||
|
||||
content << "<br/>" + CGI::unescapeHTML(post.at("link-description").inner_html) unless post.at("link-description") == nil
|
||||
elsif post['type'] == "photo"
|
||||
content = ""
|
||||
|
||||
if post.at("photo-link-url") != nil
|
||||
content = "<a href=\"#{post.at("photo-link-url").inner_html}\"><img src=\"#{save_file((post/"photo-url")[1].inner_html, grab_images)}\"/></a>"
|
||||
else
|
||||
content = "<img src=\"#{save_file((post/"photo-url")[1].inner_html, grab_images)}\"/>"
|
||||
end
|
||||
|
||||
if post.at("photo-caption") != nil
|
||||
content << "<br/>" unless content == nil
|
||||
content << CGI::unescapeHTML(post.at("photo-caption").inner_html)
|
||||
end
|
||||
elsif post['type'] == "audio"
|
||||
content = CGI::unescapeHTML(post.at("audio-player").inner_html)
|
||||
content << CGI::unescapeHTML(post.at("audio-caption").inner_html) unless post.at("audio-caption") == nil
|
||||
elsif post['type'] == "quote"
|
||||
content = "<blockquote>" + CGI::unescapeHTML(post.at("quote-text").inner_html) + "</blockquote>"
|
||||
content << "—" + CGI::unescapeHTML(post.at("quote-source").inner_html) unless post.at("quote-source") == nil
|
||||
elsif post['type'] == "conversation"
|
||||
title = post.at("conversation-title").inner_html unless post.at("conversation-title") == nil
|
||||
content = "<section><dialog>"
|
||||
|
||||
(post/:conversation/:line).each do |line|
|
||||
content << "<dt>" + line['label'] + "</dt><dd>" + line.inner_html + "</dd>" unless line['label'] == nil || line == nil
|
||||
end
|
||||
|
||||
content << "</section></dialog>"
|
||||
elsif post['type'] == "video"
|
||||
title = post.at("video-title").inner_html unless post.at("video-title") == nil
|
||||
content = CGI::unescapeHTML(post.at("video-player").inner_html)
|
||||
content << CGI::unescapeHTML(post.at("video-caption").inner_html) unless post.at("video-caption") == nil
|
||||
end # End post types
|
||||
|
||||
name = "#{Date.parse(post['date']).to_s}-#{post['id'].downcase.gsub(/[^a-z0-9]/, '-')}.html"
|
||||
|
||||
if title != nil || content != nil && name != nil
|
||||
File.open("_posts/tumblr/#{name}", "w") do |f|
|
||||
|
||||
f.puts <<-HEADER
|
||||
---
|
||||
layout: post
|
||||
title: #{title}
|
||||
---
|
||||
|
||||
HEADER
|
||||
|
||||
f.puts content
|
||||
end # End file
|
||||
end
|
||||
|
||||
end # End post XML
|
||||
|
||||
if (doc/:tumblr/:posts/:post).size < 50
|
||||
break
|
||||
else
|
||||
current_page = current_page + 1
|
||||
def self.process(url, format = "html", grab_images = false,
|
||||
add_highlights = false, rewrite_urls = true)
|
||||
@grab_images = grab_images
|
||||
FileUtils.mkdir_p "_posts/tumblr"
|
||||
url += "/api/read/json/"
|
||||
per_page = 50
|
||||
posts = []
|
||||
# Two passes are required so that we can rewrite URLs.
|
||||
# First pass builds up an array of each post as a hash.
|
||||
begin
|
||||
current_page = (current_page || -1) + 1
|
||||
feed = open(url + "?num=#{per_page}&start=#{current_page * per_page}")
|
||||
json = feed.readlines.join("\n")[21...-2] # Strip Tumblr's JSONP chars.
|
||||
blog = JSON.parse(json)
|
||||
puts "Page: #{current_page + 1} - Posts: #{blog["posts"].size}"
|
||||
posts += blog["posts"].map { |post| post_to_hash(post, format) }
|
||||
end until blog["posts"].size < per_page
|
||||
# Rewrite URLs and create redirects.
|
||||
posts = rewrite_urls_and_redirects posts if rewrite_urls
|
||||
# Second pass for writing post files.
|
||||
posts.each do |post|
|
||||
if format == "md"
|
||||
post[:content] = html_to_markdown post[:content]
|
||||
post[:content] = add_syntax_highlights post[:content] if add_highlights
|
||||
end
|
||||
|
||||
end # End while loop
|
||||
end # End method
|
||||
File.open("_posts/tumblr/#{post[:name]}", "w") do |f|
|
||||
f.puts post[:header].to_yaml + "---\n" + post[:content]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.save_file(url, grab_image = false)
|
||||
unless grab_image == false
|
||||
FileUtils.mkdir_p "tumblr_files"
|
||||
|
||||
File.open("tumblr_files/#{url.split('/').last}", "w") do |f|
|
||||
f.write(open(url).read)
|
||||
end
|
||||
|
||||
return "/tumblr_files/#{url.split('/').last}"
|
||||
else
|
||||
return url
|
||||
# Converts each type of Tumblr post to a hash with all required
|
||||
# data for Jekyll.
|
||||
def self.post_to_hash(post, format)
|
||||
case post['type']
|
||||
when "regular"
|
||||
title = post["regular-title"]
|
||||
content = post["regular-body"]
|
||||
when "link"
|
||||
title = post["link-text"] || post["link-url"]
|
||||
content = "<a href=\"#{post["link-url"]}\">#{title}</a>"
|
||||
unless post["link-description"].nil?
|
||||
content << "<br/>" + post["link-description"]
|
||||
end
|
||||
when "photo"
|
||||
title = post["photo-caption"]
|
||||
max_size = post.keys.map{ |k| k.gsub("photo-url-", "").to_i }.max
|
||||
url = post["photo-url"] || post["photo-url-#{max_size}"]
|
||||
ext = "." + post[post.keys.select { |k|
|
||||
k =~ /^photo-url-/ && post[k].split("/").last =~ /\./
|
||||
}.first].split(".").last
|
||||
content = "<img src=\"#{save_file(url, ext)}\"/>"
|
||||
unless post["photo-link-url"].nil?
|
||||
content = "<a href=\"#{post["photo-link-url"]}\">#{content}</a>"
|
||||
end
|
||||
when "audio"
|
||||
if !post["id3-title"].nil?
|
||||
title = post["id3-title"]
|
||||
content = post.at["audio-player"] + "<br/>" + post["audio-caption"]
|
||||
else
|
||||
title = post["audio-caption"]
|
||||
content = post.at["audio-player"]
|
||||
end
|
||||
when "quote"
|
||||
title = post["quote-text"]
|
||||
content = "<blockquote>#{post["quote-text"]}</blockquote>"
|
||||
unless post["quote-source"].nil?
|
||||
content << "—" + post["quote-source"]
|
||||
end
|
||||
when "conversation"
|
||||
title = post["conversation-title"]
|
||||
content = "<section><dialog>"
|
||||
post["conversation"]["line"].each do |line|
|
||||
content << "<dt>#{line['label']}</dt><dd>#{line}</dd>"
|
||||
end
|
||||
content << "</section></dialog>"
|
||||
when "video"
|
||||
title = post["video-title"]
|
||||
content = post["video-player"]
|
||||
unless post["video-caption"].nil?
|
||||
content << "<br/>" + post["video-caption"]
|
||||
end
|
||||
end
|
||||
date = Date.parse(post['date']).to_s
|
||||
title = Nokogiri::HTML(title).text
|
||||
slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
|
||||
{
|
||||
:name => "#{date}-#{slug}.#{format}",
|
||||
:header => {
|
||||
"layout" => "post",
|
||||
"title" => title,
|
||||
"tags" => post["tags"],
|
||||
},
|
||||
:content => content,
|
||||
:url => post["url"],
|
||||
:slug => post["url-with-slug"],
|
||||
}
|
||||
end
|
||||
|
||||
# Create a Hash of old urls => new urls, for rewriting and
|
||||
# redirects, and replace urls in each post. Instantiate Jekyll
|
||||
# site/posts to get the correct permalink format.
|
||||
def self.rewrite_urls_and_redirects(posts)
|
||||
site = Jekyll::Site.new(Jekyll.configuration({}))
|
||||
dir = File.join(File.dirname(__FILE__), "..")
|
||||
urls = Hash[posts.map { |post|
|
||||
# Create an initial empty file for the post so that
|
||||
# we can instantiate a post object.
|
||||
File.open("_posts/tumblr/#{post[:name]}", "w")
|
||||
tumblr_url = URI.parse(post[:slug]).path
|
||||
jekyll_url = Jekyll::Post.new(site, dir, "", "tumblr/" + post[:name]).url
|
||||
redirect_dir = tumblr_url.sub(/\//, "") + "/"
|
||||
FileUtils.mkdir_p redirect_dir
|
||||
File.open(redirect_dir + "index.html", "w") do |f|
|
||||
f.puts "<html><head><meta http-equiv='Refresh' content='0; " +
|
||||
"url=#{jekyll_url}'></head><body></body></html>"
|
||||
end
|
||||
[tumblr_url, jekyll_url]
|
||||
}]
|
||||
posts.map { |post|
|
||||
urls.each do |tumblr_url, jekyll_url|
|
||||
post[:content].gsub!(/#{tumblr_url}/i, jekyll_url)
|
||||
end
|
||||
post
|
||||
}
|
||||
end
|
||||
|
||||
# Uses Python's html2text to convert a post's content to
|
||||
# markdown. Preserve HTML tables as per the markdown docs.
|
||||
def self.html_to_markdown(content)
|
||||
preserve = ["table", "tr", "th", "td"]
|
||||
preserve.each do |tag|
|
||||
content.gsub!(/<#{tag}/i, "$$" + tag)
|
||||
content.gsub!(/<\/#{tag}/i, "||" + tag)
|
||||
end
|
||||
content = %x[echo '#{content.gsub("'", "''")}' | html2text]
|
||||
preserve.each do |tag|
|
||||
content.gsub!("$$" + tag, "<" + tag)
|
||||
content.gsub!("||" + tag, "</" + tag)
|
||||
end
|
||||
content
|
||||
end
|
||||
|
||||
# Adds pygments highlight tags to code blocks in posts that use
|
||||
# markdown format. This doesn't guess the language of the code
|
||||
# block, so you should modify this to suit your own content.
|
||||
# For example, my code block only contain Python and JavaScript,
|
||||
# so I can assume the block is JavaScript if it contains a
|
||||
# semi-colon.
|
||||
def self.add_syntax_highlights(content)
|
||||
lines = content.split("\n")
|
||||
block, indent, lang, start = false, /^ /, nil, nil
|
||||
lines.each_with_index do |line, i|
|
||||
if !block && line =~ indent
|
||||
block = true
|
||||
lang = "python"
|
||||
start = i
|
||||
elsif block
|
||||
lang = "javascript" if line =~ /;$/
|
||||
block = line =~ indent && i < lines.size - 1 # Also handle EOF
|
||||
if !block
|
||||
lines[start] = "{% highlight #{lang} %}"
|
||||
lines[i - 1] = "{% endhighlight %}"
|
||||
end
|
||||
lines[i] = lines[i].sub(indent, "")
|
||||
end
|
||||
end
|
||||
lines.join("\n")
|
||||
end
|
||||
|
||||
def self.save_file(url, ext)
|
||||
if @grab_images
|
||||
path = "tumblr_files/#{url.split('/').last}"
|
||||
path += ext unless path =~ /#{ext}$/
|
||||
FileUtils.mkdir_p "tumblr_files"
|
||||
File.open(path, "w") { |f| f.write(open(url).read) }
|
||||
url = "/" + path
|
||||
end
|
||||
url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,52 +11,284 @@ require 'yaml'
|
|||
|
||||
module Jekyll
|
||||
module WordPress
|
||||
def self.process(dbname, user, pass, host = 'localhost', table_prefix = 'wp_')
|
||||
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
|
||||
|
||||
# Main migrator function. Call this to perform the migration.
|
||||
#
|
||||
# dbname:: The name of the database
|
||||
# user:: The database user name
|
||||
# pass:: The database user's password
|
||||
# host:: The address of the MySQL database host. Default: 'localhost'
|
||||
# options:: A hash table of configuration options.
|
||||
#
|
||||
# Supported options are:
|
||||
#
|
||||
# :table_prefix:: Prefix of database tables used by WordPress.
|
||||
# Default: 'wp_'
|
||||
# :clean_entities:: If true, convert non-ASCII characters to HTML
|
||||
# entities in the posts, comments, titles, and
|
||||
# names. Requires the 'htmlentities' gem to
|
||||
# work. Default: true.
|
||||
# :comments:: If true, migrate post comments too. Comments
|
||||
# are saved in the post's YAML front matter.
|
||||
# Default: true.
|
||||
# :categories:: If true, save the post's categories in its
|
||||
# YAML front matter.
|
||||
# :tags:: If true, save the post's tags in its
|
||||
# YAML front matter.
|
||||
# :more_excerpt:: If true, when a post has no excerpt but
|
||||
# does have a <!-- more --> tag, use the
|
||||
# preceding post content as the excerpt.
|
||||
# Default: true.
|
||||
# :more_anchor:: If true, convert a <!-- more --> tag into
|
||||
# two HTML anchors with ids "more" and
|
||||
# "more-NNN" (where NNN is the post number).
|
||||
# Default: true.
|
||||
# :status:: Array of allowed post statuses. Only
|
||||
# posts with matching status will be migrated.
|
||||
# Known statuses are :publish, :draft, :private,
|
||||
# and :revision. If this is nil or an empty
|
||||
# array, all posts are migrated regardless of
|
||||
# status. Default: [:publish].
|
||||
#
|
||||
def self.process(dbname, user, pass, host='localhost', options={})
|
||||
options = {
|
||||
:table_prefix => 'wp_',
|
||||
:clean_entities => true,
|
||||
:comments => true,
|
||||
:categories => true,
|
||||
:tags => true,
|
||||
:more_excerpt => true,
|
||||
:more_anchor => true,
|
||||
:status => [:publish] # :draft, :private, :revision
|
||||
}.merge(options)
|
||||
|
||||
if options[:clean_entities]
|
||||
begin
|
||||
require 'htmlentities'
|
||||
rescue LoadError
|
||||
STDERR.puts "Could not require 'htmlentities', so the " +
|
||||
":clean_entities option is now disabled."
|
||||
options[:clean_entities] = false
|
||||
end
|
||||
end
|
||||
|
||||
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 = Sequel.mysql(dbname, :user => user, :password => pass,
|
||||
:host => host, :encoding => 'utf8')
|
||||
|
||||
db[query].each do |post|
|
||||
# Get required fields and construct Jekyll compatible name.
|
||||
title = post[:post_title]
|
||||
slug = post[:post_name]
|
||||
date = post[:post_date]
|
||||
content = post[:post_content]
|
||||
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
|
||||
slug]
|
||||
px = options[:table_prefix]
|
||||
|
||||
# Get the relevant fields as a hash, delete empty fields and convert
|
||||
# to YAML for the header.
|
||||
data = {
|
||||
'layout' => 'post',
|
||||
'title' => title.to_s,
|
||||
'excerpt' => post[:post_excerpt].to_s,
|
||||
'wordpress_id' => post[:ID],
|
||||
'wordpress_url' => post[:guid],
|
||||
'date' => date
|
||||
}.delete_if { |k,v| v.nil? || v == '' }.to_yaml
|
||||
posts_query = "
|
||||
SELECT
|
||||
posts.ID AS `id`,
|
||||
posts.guid AS `guid`,
|
||||
posts.post_type AS `type`,
|
||||
posts.post_status AS `status`,
|
||||
posts.post_title AS `title`,
|
||||
posts.post_name AS `slug`,
|
||||
posts.post_date AS `date`,
|
||||
posts.post_content AS `content`,
|
||||
posts.post_excerpt AS `excerpt`,
|
||||
posts.comment_count AS `comment_count`,
|
||||
users.display_name AS `author`,
|
||||
users.user_login AS `author_login`,
|
||||
users.user_email AS `author_email`,
|
||||
users.user_url AS `author_url`
|
||||
FROM #{px}posts AS `posts`
|
||||
LEFT JOIN #{px}users AS `users`
|
||||
ON posts.post_author = users.ID"
|
||||
|
||||
# Write out the data and content to file
|
||||
File.open("_posts/#{name}", "w") do |f|
|
||||
f.puts data
|
||||
f.puts "---"
|
||||
f.puts content
|
||||
if options[:status] and not options[:status].empty?
|
||||
status = options[:status][0]
|
||||
posts_query << "
|
||||
WHERE posts.post_status = '#{status.to_s}'"
|
||||
options[:status][1..-1].each do |status|
|
||||
posts_query << " OR
|
||||
posts.post_status = '#{status.to_s}'"
|
||||
end
|
||||
end
|
||||
|
||||
db[posts_query].each do |post|
|
||||
process_post(post, db, options)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.process_post(post, db, options)
|
||||
px = options[:table_prefix]
|
||||
|
||||
title = post[:title]
|
||||
if options[:clean_entities]
|
||||
title = clean_entities(title)
|
||||
end
|
||||
|
||||
slug = post[:slug]
|
||||
if !slug or slug.empty?
|
||||
slug = sluggify(title)
|
||||
end
|
||||
|
||||
date = post[:date] || Time.now
|
||||
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month,
|
||||
date.day, slug]
|
||||
content = post[:content].to_s
|
||||
if options[:clean_entities]
|
||||
content = clean_entities(content)
|
||||
end
|
||||
|
||||
excerpt = post[:excerpt].to_s
|
||||
|
||||
more_index = content.index(/<!-- *more *-->/)
|
||||
more_anchor = nil
|
||||
if more_index
|
||||
if options[:more_excerpt] and
|
||||
(post[:excerpt].nil? or post[:excerpt].empty?)
|
||||
excerpt = content[0...more_index]
|
||||
end
|
||||
if options[:more_anchor]
|
||||
more_link = "more"
|
||||
content.sub!(/<!-- *more *-->/,
|
||||
"<a id=\"more\"></a>" +
|
||||
"<a id=\"more-#{post[:id]}\"></a>")
|
||||
end
|
||||
end
|
||||
|
||||
categories = []
|
||||
tags = []
|
||||
|
||||
if options[:categories] or options[:tags]
|
||||
|
||||
cquery =
|
||||
"SELECT
|
||||
terms.name AS `name`,
|
||||
ttax.taxonomy AS `type`
|
||||
FROM
|
||||
#{px}terms AS `terms`,
|
||||
#{px}term_relationships AS `trels`,
|
||||
#{px}term_taxonomy AS `ttax`
|
||||
WHERE
|
||||
trels.object_id = '#{post[:id]}' AND
|
||||
trels.term_taxonomy_id = ttax.term_taxonomy_id AND
|
||||
terms.term_id = ttax.term_id"
|
||||
|
||||
db[cquery].each do |term|
|
||||
if options[:categories] and term[:type] == "category"
|
||||
if options[:clean_entities]
|
||||
categories << clean_entities(term[:name])
|
||||
else
|
||||
categories << term[:name]
|
||||
end
|
||||
elsif options[:tags] and term[:type] == "post_tag"
|
||||
if options[:clean_entities]
|
||||
tags << clean_entities(term[:name])
|
||||
else
|
||||
tags << term[:name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
comments = []
|
||||
|
||||
if options[:comments] and post[:comment_count].to_i > 0
|
||||
cquery =
|
||||
"SELECT
|
||||
comment_ID AS `id`,
|
||||
comment_author AS `author`,
|
||||
comment_author_email AS `author_email`,
|
||||
comment_author_url AS `author_url`,
|
||||
comment_date AS `date`,
|
||||
comment_date_gmt AS `date_gmt`,
|
||||
comment_content AS `content`
|
||||
FROM #{px}comments
|
||||
WHERE
|
||||
comment_post_ID = '#{post[:id]}' AND
|
||||
comment_approved != 'spam'"
|
||||
|
||||
|
||||
db[cquery].each do |comment|
|
||||
|
||||
comcontent = comment[:content].to_s
|
||||
if comcontent.respond_to?(:force_encoding)
|
||||
comcontent.force_encoding("UTF-8")
|
||||
end
|
||||
if options[:clean_entities]
|
||||
comcontent = clean_entities(comcontent)
|
||||
end
|
||||
comauthor = comment[:author].to_s
|
||||
if options[:clean_entities]
|
||||
comauthor = clean_entities(comauthor)
|
||||
end
|
||||
|
||||
comments << {
|
||||
'id' => comment[:id].to_i,
|
||||
'author' => comauthor,
|
||||
'author_email' => comment[:author_email].to_s,
|
||||
'author_url' => comment[:author_url].to_s,
|
||||
'date' => comment[:date].to_s,
|
||||
'date_gmt' => comment[:date_gmt].to_s,
|
||||
'content' => comcontent,
|
||||
}
|
||||
end
|
||||
|
||||
comments.sort!{ |a,b| a['id'] <=> b['id'] }
|
||||
end
|
||||
|
||||
# Get the relevant fields as a hash, delete empty fields and
|
||||
# convert to YAML for the header.
|
||||
data = {
|
||||
'layout' => post[:type].to_s,
|
||||
'status' => post[:status].to_s,
|
||||
'published' => (post[:status].to_s == "publish"),
|
||||
'title' => title.to_s,
|
||||
'author' => post[:author].to_s,
|
||||
'author_login' => post[:author_login].to_s,
|
||||
'author_email' => post[:author_email].to_s,
|
||||
'author_url' => post[:author_url].to_s,
|
||||
'excerpt' => excerpt,
|
||||
'more_anchor' => more_anchor,
|
||||
'wordpress_id' => post[:id],
|
||||
'wordpress_url' => post[:guid].to_s,
|
||||
'date' => date,
|
||||
'categories' => options[:categories] ? categories : nil,
|
||||
'tags' => options[:tags] ? tags : nil,
|
||||
'comments' => options[:comments] ? comments : nil,
|
||||
}.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
|
||||
|
||||
|
||||
def self.clean_entities( text )
|
||||
if text.respond_to?(:force_encoding)
|
||||
text.force_encoding("UTF-8")
|
||||
end
|
||||
text = HTMLEntities.new.encode(text, :named)
|
||||
# We don't want to convert these, it would break all
|
||||
# HTML tags in the post and comments.
|
||||
text.gsub!("&", "&")
|
||||
text.gsub!("<", "<")
|
||||
text.gsub!(">", ">")
|
||||
text.gsub!(""", '"')
|
||||
text.gsub!("'", "'")
|
||||
text
|
||||
end
|
||||
|
||||
|
||||
def self.sluggify( title )
|
||||
begin
|
||||
require 'unidecode'
|
||||
title = title.to_ascii
|
||||
rescue LoadError
|
||||
STDERR.puts "Could not require 'unidecode'. If your post titles have non-ASCII characters, you could get nicer permalinks by installing unidecode."
|
||||
end
|
||||
title.downcase.gsub(/[^0-9A-Za-z]+/, " ").strip.gsub(" ", "-")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,6 +22,8 @@ module Jekyll
|
|||
attr_accessor :data, :content, :output, :ext
|
||||
attr_accessor :date, :slug, :published, :tags, :categories
|
||||
|
||||
attr_reader :name
|
||||
|
||||
# Initialize this Post instance.
|
||||
# +site+ is the Site
|
||||
# +base+ is the String path to the dir containing the post file
|
||||
|
@ -131,7 +133,7 @@ module Jekyll
|
|||
"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('/'),
|
||||
"categories" => categories.map { |c| URI.escape(c) }.join('/'),
|
||||
"output_ext" => self.output_ext
|
||||
}.inject(template) { |result, token|
|
||||
result.gsub(/:#{Regexp.escape token.first}/, token.last)
|
||||
|
|
|
@ -4,7 +4,7 @@ module Jekyll
|
|||
|
||||
class Site
|
||||
attr_accessor :config, :layouts, :posts, :pages, :static_files,
|
||||
:categories, :exclude, :source, :dest, :lsi, :pygments,
|
||||
:categories, :exclude, :include, :source, :dest, :lsi, :pygments,
|
||||
:permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts
|
||||
|
||||
attr_accessor :converters, :generators
|
||||
|
@ -23,6 +23,7 @@ module Jekyll
|
|||
self.pygments = config['pygments']
|
||||
self.permalink_style = config['permalink'].to_sym
|
||||
self.exclude = config['exclude'] || []
|
||||
self.include = config['include'] || []
|
||||
self.future = config['future']
|
||||
self.limit_posts = config['limit_posts'] || nil
|
||||
|
||||
|
@ -173,7 +174,10 @@ module Jekyll
|
|||
self.posts.sort!
|
||||
|
||||
# limit the posts if :limit_posts option is set
|
||||
self.posts = self.posts[-limit_posts, limit_posts] if limit_posts
|
||||
if limit_posts
|
||||
limit = self.posts.length < limit_posts ? self.posts.length : limit_posts
|
||||
self.posts = self.posts[-limit, limit]
|
||||
end
|
||||
end
|
||||
|
||||
# Run each of the Generators.
|
||||
|
@ -305,7 +309,7 @@ module Jekyll
|
|||
# Returns the Array of filtered entries.
|
||||
def filter_entries(entries)
|
||||
entries = entries.reject do |e|
|
||||
unless ['.htaccess'].include?(e)
|
||||
unless self.include.include?(e)
|
||||
['.', '_', '#'].include?(e[0..0]) ||
|
||||
e[-1..-1] == '~' ||
|
||||
self.exclude.include?(e) ||
|
||||
|
|
|
@ -3,14 +3,19 @@ module Jekyll
|
|||
class HighlightBlock < Liquid::Block
|
||||
include Liquid::StandardFilters
|
||||
|
||||
# We need a language, but the linenos argument is optional.
|
||||
SYNTAX = /(\w+)\s?([\w\s=]+)*/
|
||||
# The regular expression syntax checker. Start with the language specifier.
|
||||
# Follow that by zero or more space separated options that take one of two
|
||||
# forms:
|
||||
#
|
||||
# 1. name
|
||||
# 2. name=value
|
||||
SYNTAX = /^([a-zA-Z0-9.+#-]+)((\s+\w+(=\w+)?)*)$/
|
||||
|
||||
def initialize(tag_name, markup, tokens)
|
||||
super
|
||||
if markup =~ SYNTAX
|
||||
if markup.strip =~ SYNTAX
|
||||
@lang = $1
|
||||
if defined? $2
|
||||
if defined?($2) && $2 != ''
|
||||
tmp_options = {}
|
||||
$2.split.each do |opt|
|
||||
key, value = opt.split('=')
|
||||
|
@ -23,7 +28,7 @@ module Jekyll
|
|||
end
|
||||
tmp_options[key] = value
|
||||
end
|
||||
tmp_options = tmp_options.to_a.collect { |opt| opt.join('=') }
|
||||
tmp_options = tmp_options.to_a.sort.collect { |opt| opt.join('=') }
|
||||
# additional options to pass to Albino
|
||||
@options = { 'O' => tmp_options.join(',') }
|
||||
else
|
||||
|
@ -36,9 +41,9 @@ module Jekyll
|
|||
|
||||
def render(context)
|
||||
if context.registers[:site].pygments
|
||||
render_pygments(context, super.join)
|
||||
render_pygments(context, super)
|
||||
else
|
||||
render_codehighlighter(context, super.join)
|
||||
render_codehighlighter(context, super)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -53,9 +58,7 @@ module Jekyll
|
|||
#The div is required because RDiscount blows ass
|
||||
<<-HTML
|
||||
<div>
|
||||
<pre>
|
||||
<code class='#{@lang}'>#{h(code).strip}</code>
|
||||
</pre>
|
||||
<pre><code class='#{@lang}'>#{h(code).strip}</code></pre>
|
||||
</div>
|
||||
HTML
|
||||
end
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
module Jekyll
|
||||
|
||||
class PostComparer
|
||||
MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)$/
|
||||
|
||||
attr_accessor :date, :slug
|
||||
|
||||
def initialize(name)
|
||||
who, cares, date, slug = *name.match(MATCHER)
|
||||
@slug = slug
|
||||
@date = Time.parse(date)
|
||||
end
|
||||
end
|
||||
|
||||
class PostUrl < Liquid::Tag
|
||||
def initialize(tag_name, post, tokens)
|
||||
super
|
||||
@orig_post = post.strip
|
||||
@post = PostComparer.new(@orig_post)
|
||||
end
|
||||
|
||||
def render(context)
|
||||
site = context.registers[:site]
|
||||
|
||||
site.posts.each do |p|
|
||||
if p == @post
|
||||
return p.url
|
||||
end
|
||||
end
|
||||
|
||||
puts "ERROR: post_url: \"#{@orig_post}\" could not be found"
|
||||
|
||||
return "#"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Liquid::Template.register_tag('post_url', Jekyll::PostUrl)
|
|
@ -1,177 +0,0 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Bare AsciiDoc styles
|
||||
Ryan Tomayko <r@tomayko.com>
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family:verdana,helvetica,arial,sans-serif;
|
||||
font-size:81.25%; /* 13px */
|
||||
line-height:1.538; /* 20px */
|
||||
margin:40px auto 50px auto;
|
||||
max-width:53.8461538462em; /* 790px */
|
||||
color:#333;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight:bold;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
tt {
|
||||
font-family:consolas, 'lucida console', 'bitstream vera sans mono',
|
||||
'courier new', monospace;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
p, ul, ol, dl {
|
||||
margin:10px 0
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-left:40px
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family:'lucida grande',georgia,verdana,helvetica,arial,sans-serif;
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:40px;
|
||||
line-height:1.428;
|
||||
margin:20px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:30px;
|
||||
line-height:1.36363636; /* repeating, of course */
|
||||
margin:60px 0 20px 0;
|
||||
}
|
||||
|
||||
h2 + .sectionbody {}
|
||||
|
||||
h3 {
|
||||
font-size:24px;
|
||||
line-height:1.1;
|
||||
margin:30px 0 10px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:18px;
|
||||
line-height:1.1;
|
||||
margin:20px 0 5px 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size:13px;
|
||||
font-style:italic;
|
||||
line-height:1.1;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align:center;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
#header h1 { margin-bottom:0 }
|
||||
|
||||
.title, .sidebar-title {
|
||||
font-weight:normal;
|
||||
color:#000;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
.admonitionblock .title {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.admonitionblock {
|
||||
margin:30px 0px;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
.admonitionblock td.icon {
|
||||
width:30px;
|
||||
padding-right:20px;
|
||||
padding-left:20px;
|
||||
text-transform:uppercase;
|
||||
font-weight:bold;
|
||||
color:#888;
|
||||
}
|
||||
|
||||
.listingblock {
|
||||
margin: 13px 0;
|
||||
}
|
||||
|
||||
.listingblock .content {
|
||||
border:1px solid silver;
|
||||
background:#eee;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.listingblock .content pre {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.literalblock .content {
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.verseblock .content {
|
||||
white-space:pre
|
||||
}
|
||||
|
||||
.sidebarblock .sidebar-content {
|
||||
border:1px solid silver;
|
||||
background:#FFFFEE;
|
||||
padding:0 10px;
|
||||
color:#222;
|
||||
font-size:smaller;
|
||||
line-height:1.5;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin:10px 0;
|
||||
font-weight:bold;
|
||||
color:#442;
|
||||
}
|
||||
|
||||
.quoteblock-content {
|
||||
font-style:italic;
|
||||
color:#444;
|
||||
margin-left:40px;
|
||||
}
|
||||
|
||||
.quoteblock-content .attribution {
|
||||
font-style:normal;
|
||||
text-align:right;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.exampleblock-content *:first-child { margin-top:0 }
|
||||
.exampleblock-content {
|
||||
border-left:2px solid silver;
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
font-size:11px;
|
||||
margin-top:40px;
|
||||
border-top:1px solid silver;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
#author {
|
||||
color:#000;
|
||||
text-transform:uppercase
|
||||
}
|
|
@ -141,6 +141,19 @@ class TestPost < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
context "with space (categories)" do
|
||||
setup do
|
||||
@post.categories << "French cuisine"
|
||||
@post.categories << "Belgian beer"
|
||||
@post.process(@fake_file)
|
||||
end
|
||||
|
||||
should "process the url correctly" do
|
||||
assert_equal "/:categories/:year/:month/:day/:title.html", @post.template
|
||||
assert_equal "/French%20cuisine/Belgian%20beer/2008/09/09/foo-bar.html", @post.url
|
||||
end
|
||||
end
|
||||
|
||||
context "with none style" do
|
||||
setup do
|
||||
@post.site.permalink_style = :none
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
require File.dirname(__FILE__) + '/helper'
|
||||
|
||||
class TestRedCloth < Test::Unit::TestCase
|
||||
|
||||
context "RedCloth default (no explicit config) hard_breaks enabled" do
|
||||
setup do
|
||||
@textile = TextileConverter.new
|
||||
end
|
||||
|
||||
should "preserve single line breaks in HTML output" do
|
||||
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
||||
end
|
||||
end
|
||||
|
||||
context "Default hard_breaks enabled w/ redcloth section, no hard_breaks value" do
|
||||
setup do
|
||||
config = {
|
||||
'redcloth' => {}
|
||||
}
|
||||
@textile = TextileConverter.new config
|
||||
end
|
||||
|
||||
should "preserve single line breaks in HTML output" do
|
||||
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
||||
end
|
||||
end
|
||||
|
||||
context "RedCloth with hard_breaks enabled" do
|
||||
setup do
|
||||
config = {
|
||||
'redcloth' => {
|
||||
'hard_breaks' => true # default
|
||||
}
|
||||
}
|
||||
@textile = TextileConverter.new config
|
||||
end
|
||||
|
||||
should "preserve single line breaks in HTML output" do
|
||||
assert_equal "<p>line1<br />\nline2</p>", @textile.convert("p. line1\nline2").strip
|
||||
end
|
||||
end
|
||||
|
||||
context "RedCloth with hard_breaks disabled" do
|
||||
setup do
|
||||
config = {
|
||||
'redcloth' => {
|
||||
'hard_breaks' => false
|
||||
}
|
||||
}
|
||||
@textile = TextileConverter.new config
|
||||
end
|
||||
|
||||
should "not generate break tags in HTML output" do
|
||||
assert_equal "<p>line1\nline2</p>", @textile.convert("p. line1\nline2").strip
|
||||
end
|
||||
end
|
||||
|
||||
context "RedCloth w/no_span_caps set to false" do
|
||||
setup do
|
||||
config = {
|
||||
'redcloth' => {
|
||||
'no_span_caps' => false
|
||||
}
|
||||
}
|
||||
@textile = TextileConverter.new config
|
||||
end
|
||||
should "generate span tags around capitalized words" do
|
||||
assert_equal "<p><span class=\"caps\">NSC</span></p>", @textile.convert("NSC").strip
|
||||
end
|
||||
end
|
||||
|
||||
context "RedCloth w/no_span_caps set to true" do
|
||||
setup do
|
||||
config = {
|
||||
'redcloth' => {
|
||||
'no_span_caps' => true
|
||||
}
|
||||
}
|
||||
@textile = TextileConverter.new config
|
||||
end
|
||||
|
||||
should "not generate span tags around capitalized words" do
|
||||
assert_equal "<p>NSC</p>", @textile.convert("NSC").strip
|
||||
end
|
||||
end
|
||||
end
|
|
@ -126,12 +126,20 @@ class TestSite < Test::Unit::TestCase
|
|||
|
||||
should "filter entries with exclude" do
|
||||
excludes = %w[README TODO]
|
||||
includes = %w[index.html site.css]
|
||||
files = %w[index.html site.css .htaccess]
|
||||
|
||||
@site.exclude = excludes
|
||||
assert_equal includes, @site.filter_entries(excludes + includes)
|
||||
assert_equal files, @site.filter_entries(excludes + files)
|
||||
end
|
||||
|
||||
should "not filter entries within include" do
|
||||
includes = %w[_index.html .htaccess]
|
||||
files = %w[index.html _index.html .htaccess]
|
||||
|
||||
@site.include = includes
|
||||
assert_equal files, @site.filter_entries(files)
|
||||
end
|
||||
|
||||
context 'with orphaned files in destination' do
|
||||
setup do
|
||||
clear_dest
|
||||
|
|
|
@ -9,6 +9,11 @@ class TestTags < Test::Unit::TestCase
|
|||
Jekyll::DEFAULTS.merge({'pygments' => true}).merge(override)
|
||||
end
|
||||
site = Site.new(Jekyll.configuration)
|
||||
|
||||
if override['read_posts']
|
||||
site.read_posts('')
|
||||
end
|
||||
|
||||
info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
|
||||
@converter = site.converters.find { |c| c.class == converter_class }
|
||||
payload = { "pygments_prefix" => @converter.pygments_prefix,
|
||||
|
@ -31,6 +36,41 @@ CONTENT
|
|||
create_post(content, override)
|
||||
end
|
||||
|
||||
context "language name" do
|
||||
should "match only the required set of chars" do
|
||||
r = Jekyll::HighlightBlock::SYNTAX
|
||||
assert_match r, "ruby"
|
||||
assert_match r, "c#"
|
||||
assert_match r, "xml+cheetah"
|
||||
assert_match r, "x.y"
|
||||
assert_match r, "coffee-script"
|
||||
|
||||
assert_no_match r, "blah^"
|
||||
|
||||
assert_match r, "ruby key=val"
|
||||
assert_match r, "ruby a=b c=d"
|
||||
end
|
||||
end
|
||||
|
||||
context "initialized tag" do
|
||||
should "work" do
|
||||
tag = Jekyll::HighlightBlock.new('highlight', 'ruby ', ["test", "{% endhighlight %}", "\n"])
|
||||
assert_equal({}, tag.instance_variable_get(:@options))
|
||||
|
||||
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos ', ["test", "{% endhighlight %}", "\n"])
|
||||
assert_equal({'O' => "linenos=inline"}, tag.instance_variable_get(:@options))
|
||||
|
||||
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table ', ["test", "{% endhighlight %}", "\n"])
|
||||
assert_equal({'O' => "linenos=table"}, tag.instance_variable_get(:@options))
|
||||
|
||||
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table nowrap', ["test", "{% endhighlight %}", "\n"])
|
||||
assert_equal({'O' => "linenos=table,nowrap=true"}, tag.instance_variable_get(:@options))
|
||||
|
||||
tag = Jekyll::HighlightBlock.new('highlight', 'ruby linenos=table cssclass=hl', ["test", "{% endhighlight %}", "\n"])
|
||||
assert_equal({'O' => "cssclass=hl,linenos=table"}, tag.instance_variable_get(:@options))
|
||||
end
|
||||
end
|
||||
|
||||
context "post content has highlight tag" do
|
||||
setup do
|
||||
fill_post("test")
|
||||
|
@ -137,4 +177,25 @@ CONTENT
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "simple page with post linking" do
|
||||
setup do
|
||||
content = <<CONTENT
|
||||
---
|
||||
title: Post linking
|
||||
---
|
||||
|
||||
{% post_url 2008-11-21-complex %}
|
||||
CONTENT
|
||||
create_post(content, {'permalink' => 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true})
|
||||
end
|
||||
|
||||
should "not cause an error" do
|
||||
assert_no_match /markdown\-html\-error/, @result
|
||||
end
|
||||
|
||||
should "have the url to the \"complex\" post from 2008-11-21" do
|
||||
assert_match %r{/2008/11/21/complex/}, @result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue