Building a Website with Webby
Written by Magnus Holm.
My previous blog was generated by Webby, a neat micro-CMS built by Tim Pease. It’s a lovely piece of Ruby which was a perfect fit for my blog:
-
I wanted to write my blog posts in TextMate, right on my desktop. This makes it really easy to copy text around, and it takes no time to save my work (no need to worry about closing the wrong tab or window).
-
The blog should handle large traffic very well. I’m so tired of meeting 503’s all the time. 99% of the time a blog will show the exact same content, so it shouldn’t be hard to “scale”.
-
It should be hackable. Every blog has different needs and you shouldn’t need to change the source code directly. Some sort of plugin system or monkey patching would be appreciated.
Editing
With Webby you decide how you would write your site. Since everything is just plain text files, you can use Vim, Emacs, TextMate or even Notepad. At the top of each page you can define some metadata:
---
title: Building a Website with Webby
created_at: 2008-02-25 22:45:43.134435 +01:00
filter:
- fn
- uv
- textile
---
The title and created_at is only used by me, while Webby uses the filters to format the content. The Textile-filter is bundled with Webby, while the uv and fn filters are written by me.
Speed of Light
Since Webby simply generates static files, they will be served directly by Apache by the speed of light! After a simple webby deploy, the blog is getting rebuilt and deployed to the server (using rsync). Simple and efficient.
Hacks!
However, the best thing about Webby is probably that it’s dead simple to extend. You can easily create new filters and thanks to Ruby, you can also easily monkey patch anything. Webby automatically includes all the files in the lib-folder, so there’s no need to edit the source directly.
For instance, I wasn’t satisfied with the way Textile showed the footnotes, so I added my own footnote-filter like this:
Webby::Filters.register :fn do |input|
# If you add `fn` to filters, Webby will run this piece of code where
# `input` contains the content and the return value is what it will
# be replaced with.
input.gsub!(/fn(\d+)\. ([^\n]+)/) do |s|
"<li id=\"fn#{$1}\"><sup>#{$1}</sup> #{$2}</li>"
end
li = '<li id="fn\d+.*?</li>'
input.sub(/#{li}([\n\040]+#{li})*/, '<ul class="footnotes">\0</ul>')
end
I also wanted to use Ultraviolet for syntax highlighting:
Webby::Filters.register :uv do |input|
input.gsub(%r{<syntax( lang="(\w+)")?>(.*?)</syntax>}m) do |s|
if $2
"<notextile>" + Uv.parse($3, "xhtml", $2, false, "sunburst") + "</notextile>"
else
"<pre>#{$3}</pre>"
end
end
end
index.txt
After you’ve mastered the editing, and maybe even created some nifty filters, you want to create an index page. Webby makes this very easy: the variable @pages returns an instance of Webby::PagesDB and @pages.find makes it dead simple to find the pages you want:
---
filter:
- erb
---
<% pages = @pages.find(:limit => :all,
:in_directory => 'posts',
:sort_by => 'created_at').reverse
# I want to show the first page differently:
first = pages.shift %>
<h2 id="first"><a href="<%= first.url %>"><%= first.title %></a></h2>
<%= first.render %>
<% pages.each do |page| %>
<h2><a href="<%= page.url %>"><%= page.title %></a></h2>
<% end %>
Feedalicious
In these busy days you can’t run a blog without providing a feed. Since a feed is basically just a XML-file (just like your blog posts are just a HTML-file), we can use Webby’s ERB-filter to find the pages and just generate it just the way we generated the index page.
Have a look at my atom feed if you need something to build upon.
Conclusion
Webby is still my favourite blog engine; the reason I built Timeless was because I no longer wanted a traditional blog. That said, it should be mentioned that it’s been a while since the latest release of Webby, and maybe Nanoc is a better solution for you.