Blogging with Toto
I got tired of bad Wordpress performance at Dreamhost so I started looking around for new options. I found one with Toto. Toto is a micro-blogging framework written in Ruby. It appealed to me on several fronts – it’s Ruby and I like Ruby, it’s extremely lightweight and I can easily understand and extend it.
Toto is a single Ruby file ‘toto.rb’ that sits on top of the Rack infrastructure. I played around with it and liked what I saw. From the outside it looks very similar to a Wordpress installation. URLs still look like ‘/2009/03’ and ‘/2010/04/18/my-article’. That was important to me since I wanted to seamlessly migrate from my existing Wordpress blog.
You can’t get much more lightweight then Toto. It doesn’t use a database. Comments are handled by Disqus. And each article is a single file consisting of a YAML header followed by the article text. You can read much more about it in an excellent overview article written by Dmitry Fadeyev.
Since I was converting an existing Wordpress blog I needed to extract the existing posts. I wrote a short Ruby program to do that for me:
#!/usr/bin/ruby require 'rubygems' require 'fastercsv' require 'xmlrpc/client' USERID = '<wordpress userid>' PASSWORD = '<wordpress password>' def getPages(blog) blog.call("wp.getPages", 0, USERID, PASSWORD, 1000) end def getPosts(blog) blog.call("metaWeblog.getRecentPosts", 0, USERID, PASSWORD, 1000) end def slugify(title) title.downcase.gsub(/[ \._]/, '-') end blog = XMLRPC::Client.new3(:host => "<blog domain>", :path => "/xmlrpc.php") begin puts "Logging into blog and getting the list of posts..." posts = getPosts(blog) puts " response received, found #{posts.size} posts" `mkdir articles` posts.each do |post| permaLink = post['permaLink'] dateAndName = permaLink.gsub(/http:\/\/<blog name>\.com\//, '').split('/') postFilename = 'articles/' + dateAndName.join('-') + '.txt' postDate = dateAndName[0] + '/' + dateAndName[1] + '/' + dateAndName[2] escapedTitle = post['title'].gsub(/"/, '\\"') File.open(postFilename, "w") do |postFile| postFile.puts("title: \"#{escapedTitle}\"") postFile.puts("author: <your name>") postFile.puts("date: #{postDate}") postFile.puts("slug: #{dateAndName[3]}") puts "#{post['title']} - #{postDate}" postFile.puts("categories: #{post['categories']}") postFile.puts("keywords: #{post['mt_keywords']}") postFile.puts postFile.puts post['description'] end end rescue XMLRPC::FaultException => e puts "ERROR: Code: #{e.faultCode}" puts "ERROR: Msg.: #{e.faultString}" end
That program pulls out all of the posts and generates Toto article files for each of them. It dumps them into a directory called ‘articles’.
I created some of the pages by hand and updated a script I used to generate Wordpress pages to generate Toto pages instead. Pages are simply ERB (rhtml) files.
Toto didn’t mesh exactly with what I wanted to do so I copied it into my blog directory and started modifying it. That included supporting the ‘/page/n’ Wordpress URLs and other features. I also added YAML files to specify all of the categories and tags.
The most annoying problem I ran into was dealing with Disqus. I had already switched my Wordpress blog to use it so my comments were already imported. I ended up embedding this code into my layout:
<script type="text/javascript"> var disqus_domain = 'disqus.com'; var disqus_shortname = '<%= @config[:disqus] %>'; var disqus_url = '<%= @config[:base_url] + "/" + @path %>/'; </script> <div id="disqus_thread"></div> <script type="text/javascript"> (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = 'http://<%= @config[:disqus] %>.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript=<%= @config[:disqus] %>">comments powered by Disqus.</a></noscript>
But I still had a difficult time getting Disqus to work reliably. I kept getting the dreaded ‘This page cannot be reached by Disqus’ error on some of my blog posts but not on others. Turned out to be a bad error message from Disqus. Wordpress post URLs had a trailing ‘/’ and Toto post URLs didn’t. I modified the code to include a trailing slash and all of my old comments magically appeared.
There were other challenges as well, like creating a sitemap.xml file, changing the way archives were handled, etc. But it was a fun little process to convert the blog.







