4 tips for how to customize a Toto blog site

During the week between Christmas and New Year’s I finally took the time to redesign and redeploy this site on Heroku using Toto, a very simple Rack blog engine. Sorry if I spammed your RSS inbox with duplicate articles.

What makes Toto fantastic is that it includes just enough code to run a very simple blog site… and nothing else. Alexis Sellier’s code is concise and elegant; you can see it all in a single Ruby file: toto.rb. It leaves you a clean, blank slate to add anything special or custom you might need. In fact, I chose to use Toto instead of Jekyll, Nesta or other blog engine alternatives only because it looked like it would be fun to understand how it works and customize it.

Here are 4 tips to keep in mind as you work with Toto, based on my experience building this site:

Use bundler instead of a Heroku .gems file

The best way to get started with Toto is to take a look at the GitHub readme page. Basically what you do is clone the example blog template called “Dorothy” like this:

$ git clone git://github.com/cloudhead/dorothy.git myblog
$ cd myblog

Now you have a super-simple Rack app called “myblog” that you could deploy to Heroku immediately if you wanted to. It comes with a rackup file (config.ru) and also a .gems file that tells Heroku which gems to install:

$ cat .gems
builder
rdiscount
toto

You can see your new blog site will use builder (to generate the RSS XML feed), rdiscount (to parse the markdown content) and the toto gem, which is the blog engine itself. However, before proceeding I would take a few minutes to add bundler to your app and replace the .gems file with a Gemfile. Besides feeling a bit more modern and similar to Rails 3, using Bundler will make it easy to use a customized Toto gem from your hard drive or your github repo. Here’s how to do it…

First, in the myblog folder edit config.ru and add the 2 lines at the top that I’ve highlighted:

require 'bundler' Bundler.setup
require 'toto' # Rack config use Rack::Static, :urls => ['/css', '/js', '/images', '/favicon.ico'], :root => 'public' use Rack::CommonLogger etc...

And now replace the .gems file

$ rm .gems

…with a Gemfile:

source "http://rubygems.org" 
 
gem "builder" 
gem "rdiscount" 
gem "toto", :path => '../customized_toto'

Here along with the builder and rdiscount gems, I’ve indicated to bundler that it should use a copy of Toto on my local hard drive in a folder called “customized_toto.” At this point you should fork the Toto repo on GitHub and clone it on your machine into the “customized_toto” folder for example:

$ cd ..
$ git clone git@github.com:yourname/toto.git customized_toto

And finally install the bundle for your blog app:

$ cd myblog
$ bundle install
Fetching source index for http://rubygems.org/
Using builder (3.0.0) 
Using rack (1.2.1) 
Using rdiscount (1.6.5) 
Using toto (0.4.9) from source at /Users/pat/apps/customized_toto 
Using bundler (1.0.0) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

When you’re ready to push your site to Heroku, you will just replace the “:path =>” location with your github repo URL, using the “:git” option. For example, here’s the Gemfile from this site’s Heroku app:

source "http://rubygems.org" 
 
gem "builder" 
gem "rdiscount" 
gem "toto", :git => 'https://github.com/patshaughnessy/toto.git'

Heroku now supports bundler, and will automatically run bundle install on the server after you push your blog site there. Without bundler, using different versions of the Toto gem would be much more of a hassle.

Run with Shotgun

Normally you would startup your Toto blog site like any other rack app, with the “rackup” command:

$ cd myblog
$ rackup

Rackup will look for config.ru in the current directory, and launch your application on port 9292. However, the problem with this is that the application code is cached between HTTP requests, similar to how a Rails application works in production. If you’re planning on modifying the Toto blog engine code and not just your blog’s content, then you would have to stop and restart the server each time you made a code change.

For development, it’s much more convenient to use Shotgun instead. This is a version of the rackup command that will create an entirely new process for every HTTP request. What this means while you’re working with the Toto code is that you can make any sort of code change you’d like and just refresh your browser to see it work. You don’t need to worry about anything being cached.

You just need to install it, and run “shotgun” instead of “rackup:”

$ gem install shotgun
$ cd myblog
$ shotgun

Now you’ll find your blog at http://locahost:9393 instead of port 9292.

Use Rack::Rewrite for supporting shortened or obsolete URLs

As Dmitry Fadeyev pointed out in his helpful post Getting Started With Toto, a Tiny WordPress Killer, if you’re migrating from a different blog engine the Rack-Rewrite gem by John Trupiano is a great way to redirect URL patterns from your old site into what Toto expects. You can also use it like me to shorten URLs for some posts. Rack-Rewrite is a helpful piece of rack middleware that applies Apache rewrite rules to HTTP requests coming through the Rack stack. This means it can be used to redirect or change URL patterns before they hit the Toto code, and avoid the need to change Toto at all for this purpose.

With bundler it’s very easy to add Rack-Rewrite… all you need to do is add a line to your Gemfile like this:

source "http://rubygems.org" 
 
gem "builder" 
gem "rdiscount" 
gem "rack-rewrite"
gem "toto", :git => 'https://github.com/yourname/toto.git'

… and then run bundle install again:

$ bundle install
Using builder (3.0.0) 
Using rack (1.2.1) 
Using rack-rewrite (1.0.2)
Using rdiscount (1.6.5) 
Using toto (0.4.9) from https://github.com/yourname/toto.git (at master) 
Using bundler (1.0.0) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

You use a simple Ruby DSL in config.ru to specify the rewrite/redirect rules to Rack-Rewrite; here’s an example from my site:

require 'rack/rewrite' 
use Rack::Rewrite do 
  r301 '/code_buddy', '/2010/12/13/codebuddy-see-your-ruby-stack-come-alive' 
end

This redirects requests for the “/code_buddy” page to the actual article’s full path. With rack-rewrite I’m able to do this without writing a single line of code.

Take the time to learn and use Toto’s Riot/RR test suite

As I mentioned above, Toto’s source code is very concise and elegant… an entire blog application in just 200 or 300 lines of code. Toto’s test suite is equally concise and elegant. Alexis Sellier chose to use Riot, an alternative to RSpec, and also RR for mocking and stubbing. The result is a super fast and effective test suite. To use it you’ll probably just need to install Riot, like this:

$ gem install riot
Fetching: rr-1.0.2.gem (100%)
Fetching: riot-0.12.1.gem (100%)
Successfully installed rr-1.0.2
Successfully installed riot-0.12.1
2 gems installed

Now from your Toto folder (e.g. “customized_toto”) you can run the test suite just by running “rake:”

$ rake
(in /Users/pat/apps/customized_toto)
All dependencies seem to be installed.
/Users/pat/.rvm/rubies/ruby-1.8.7-p302/bin/ruby -I"lib:lib:test" "/Users/pat/.rvm/gems/ruby-1.8.7-p302/gems...
Toto GET /
  + asserts returns a 200 is equal to 200
  + asserts body is not empty
 
etc...

However, I actually got this exception the first time I started working with the Toto Riot tests:

/test/../lib/toto.rb:174:in `to_xml': ./test/../lib/ext/ext.rb:43:in `utc': time out of range (ArgumentError)
    from ./test/../lib/ext/ext.rb:43:in `iso8601'
etc...

The problem here is that one of the test articles uses a date in the distant past (1900), which Ruby 1.8.7 chokes on… if you run Ruby 1.9 it will work fine. If you want to use Ruby 1.8.7, you just need to change the test article’s date to something more recent like 1990:

$ cd test/articles
$ git mv 1900-05-17-the-wonderful-wizard-of-oz.txt 1990-05-17-the-wonderful-wizard-of-oz.txt

… and also type the corresponding article date inside the test article file like this:

title: The Wonderful Wizard of Oz
date: 17/05/1990

_Once upon a time_...

… and you’ll need to update the corresponding test in test/toto_test.rb on line 58 to use the same date:

context "GET a single article" do 
  setup { @toto.get("/1990/05/17/the-wonderful-wizard-of-oz") }
  asserts("returns a 200")                { topic.status }.equals 200 
  asserts("content type is set properly") { topic.content_type }.equals "text/html" 
  should("contain the article")           { topic.body }.includes_html("p" => /<em>Once upon a time<em>/)
end

… and now the tests should pass. For me I was able to run all 61 tests in 0.15 seconds. But even better is that the slow Rails startup time I’m used to is gone; after typing “rake” the tests run and are finished almost immediately… another advantage to working with a simple Rack app vs. something more complex such as Rails.

What next?

Now that you’ve got Bundler setup with your version of Toto and the test suite working, you’re ready to add something something new to Toto. Next week, I’ll walk through how I added support for tagging/categories of articles, for example to get this page to work: http://patshaughnessy.net/tags/view-mapper