Dr. Jekyll man and this is my hyde side!
03 March 2010It's that time of year again! The time of year where I decide to revive the blog - which seems to becoming common practice for me!
According to the posting history it has been over a year since I showed this place any love! So, with the start of spring, I'm giving the blog new life and much needed TLC.
Well the major change in the revision is that I've ditched Wordpress - nice! The blog is now running, or should I say generated by Jekyll - which is a static site generator written in Ruby.
For some reason, unbeknown to me, I grew to dislike writing any blogs in Wordpress, hell logging in even became painful for some reason! Especially when I forgot my password, twice :(, bloody idiot. I think one of the reasons I grew to dislike Wordpress was the flaky-ness you get from the WYSIWYG, seems more much logical to be writing my posts in markdown with the odd bit of HTML, as after all I should know HTML - right? :) Wordpress also felt bloated, slow and just plain old eugh! Furthermore anyone who thinks using tabs (instead of spaces) in their code base is a good idea ought to be taken out and shot in the head with a bolt gun, preferably nailed to the floor (wow where did that come from?).
Jekyll
There were several things I wanted when moving the blog to Jekyll.
- Maintain the support for comments.
- Gist for inserting code snippets.
- Maintain the archive and category listings.
- Integrate twitter, flickr and last.fm, like I had with Wordpress.
For comments I went with Disqus which uses JavaScript to display comments for each post, this was the simplest solution and a popular one also. For the rest of the implementations I wanted it was time to create a fork!
The inevitable fork
It doesn't take long before you begin forking Jekyll and filling it with customisations for your situation, in fact this seems to be common practice evident by the number of forks - it is one of the most forked projects on github.
Before reinventing the wheel I decided to check out several other forks to see if they had the features I required - they did! I found the features spread over several repositories from the following github users newbamboo, cantorrodista and henrik.
The newbamboo fork offered support for embedding gists at compile time instead of via JavaScript. I wanted to embed the gists HTML rather than using JavaScript because I'm likely to be having several gists per coding post and didn't want the page bogged down with several JavaScript calls in the middle of the document. I cherry-picked the needed commit from the repo and also made some additions that allowed me to cache the downloaded gists (save fetching them whenever I regenerate the site) and also support for specifying a snippet file to use, mainly for use in multi-file gists.
cantorrodista's fork allowed me to generate archive index pages for each year and month, similar to how wordpress does. I implemented category index generation using the same method as cantorrodista was using to generate the archive stuff.
Finally I decided I wanted HAML support for Jekyll, I'm a hardcore HAML fan and it hurts to be without it! I tried initially to get along with Jekyll's choice of templating, Liquid but I found it horrendous and limiting - often filling the template with kak because of the way looping works. I understand why it was chosen because it means you can display the data without being able to execute ruby code, as Jekyll is used on github pages. However, there should be an option to choose whatever you want and github can just limit it to Liquid on their servers!
I had problems trying to merge in Henrik's changes, lots of conflicts that I was unsure of the correct output so I decided to lift out the needed bits of code manually and implement them in my fork. Along the way I also fixed a few issues and made it a bit more flexible (for example you can now supply HAML options in the _config.yml file).
My fork
My fork is on my github account the source code for this blog is also on there which will have examples of the different features added to Jekyll in the fork.
Twitter, Flickr, Last.fm integration
To integrate the services I wrote some ruby scripts which pull the relevant data down from each service and format it into presentable HTML before saving this to a file for the server which could then be included into the layout.
The scripts and the jekyll command (to regenerate the site) are called via a cronjob every 5 minutes at the moment, if this becomes a problem I'll increase the time, or split the scripts up (for example call flickr every day not 5 minutes).
Here is the script used to get my twitter feed, the others can be found on the source code for this blog (on my github).
$:.unshift(File.dirname(__FILE__))
require 'rubygems'require 'open-uri'require 'nokogiri'
require 'date_helpers'include DateHelpers
url = 'http://twitter.com/statuses/user_timeline/14274164.rss'filename = File.join(File.dirname(__FILE__), '..', '_includes', 'twitter.html')
doc = Nokogiri::XML(open(url))
File.open(filename, 'w') do |f| f.puts '<ul class="twitter_feed">' doc.xpath('.//item').slice(0..5).each do |item| desc = item.at_xpath('description').text desc = desc.gsub(/(.+): /, '')
link = item.at_xpath('link').text date = item.at_xpath('pubDate').text
# Skip items that start with @ don't need those on the site =) unless desc =~ /^@/ # Link up @username desc.gsub!(/(?!\\s+)@([A-Za-z0-9_]+)/, '<a class="user" href="http://twitter.com/\\1">@\\1</a>') # Link up hashtags. desc.gsub!(/#([A-Za-z0-9_]+)/, '<a class="hash" href="http://twitter.com/#search?q=%23\\1">#\\1</a>') # Finally convert new lines to br's desc.gsub!(/\/, '<br />') f.puts %Q{\\t<li>#{desc} <a href="#{link}">#{time_ago_in_words(Time.parse(date))} ago</a></li>} end end f.puts '</ul>'endPingomatic
I also wrote a script which can be called when publishing the blog which tells pingomatic of new content. Pingomatic should then tell the subscribed services that new content has been published!
Migration of posts
Importing went fairly smooth and I used the provided wordpress important script in Jekyll to do the bulk of the importing, I did have to edit most of the posts though as they had several errors - a lot were due to several plugins I used in wordpress.
Nginx setup
I use Nginx to serve all my sites and along with the move of the blog I decided to cleanup the 'vhost' file for the blog, so for anyone interested here it is.
server { listen 80; server_name .27smiles.co.uk www.27smiles.com; rewrite ^/(.*) http://27smiles.com/$1 permanent;}
server { listen 80; server_name 27smiles.com; root /home/rich/apps/27smiles/_site;
access_log /home/rich/apps/27smiles/log/access.log combined; error_log /home/rich/apps/27smiles/log/error.log;
index index.html;
# Set expires for static content. location ~ ^/(images|stylesheets|javascript|favicon\\.ico|atom\\.xml)/ { expires 30d; break; }
# Rewrite rules for Rails blog. rewrite ^/categories/(.*+)$ /category/$1 permanent; # /categories/meh -> /category/meh # Rewrite rules from Wordpress -> Jekyll move. rewrite "^/([0-9]{4})/([0-9]{2})/([0-9]{2})/(.+)/comment(.*)$" /$1/$2/$3/$4/ permanent; rewrite "^/([0-9]{4})/([0-9]{1})/([0-9]{1})/(.+)/(.*)$" /$1/0$2/0$3/$4/ permanent;}Deployment / Semi-public git!
The entire blog is hosted in a git repository and is publicly accessible on my github account. I came across with one issue however, when I'm writing a blog post and it's in draft form I ideally don't want to make this public yet but I wanted to be able to share the progress between home and work. I first tried (as I have with this post) to bump the posts into a '_drafts' folder and make commits with the progression and only push to the repository on my fileserver (which is private) and then push to the github one when the post is made live. However upon reflection I've since decided that this would be messy and fill the commit history with minor changes so I have decided that I will create a branch for each post, share this between work and home then, when ready, merge it back into master and delete the branch.
To make deployment as simple as possible I wanted to make use of git's hooks. A friend was kind enough to give me the post-receive hook code he uses for one of his webby sites. I adapted it a little to suite the project at hand:
- Wrapped the entire code in a check to make sure it was the master branch; I don't need the site generating for all the 'post' branches I'll be creating.
- Calls the twitter, flickr, last.fm and pingomatic scripts before generating the site.
Here is my post-receive hook.
#!/bin/shwhile read oldrev newrev refnamedo if [ "$refname" == "refs/heads/master" ]; then WORKDIR=/home/rich/apps/27smiles export GIT_DIR=$WORKDIR/.git pushd $WORKDIR >/dev/null git pull --quiet >/dev/null /opt/rubyee/bin/ruby -S _scripts/twitter.rb /opt/rubyee/bin/ruby -S _scripts/flickr.rb /opt/rubyee/bin/ruby -S _scripts/lastfm.rb /opt/rubyee/bin/jekyll # Finally update blogging services of new content. /opt/rubyee/bin/ruby -S _scripts/pingomatic.rb popd >/dev/null fidoneNow to publish a blog entry it's simply a matter of pushing to the git repository which should give you something like this.
Configuration from ./_config.ymlBuilding site: . -> ./_siteSuccessfully generated site: . -> ./_siteBlo.gs: Ping sent.Technorati: Ping sent.Feed Burner: Ping sent.Google Blog Search: Ping sent.Bloglines: Ping sent.Categories
Archives
About Me
Hello! I'm Rich, this is my personal blog. I'm a web developer with a passion for Ruby, Python and HTML/CSS.
I'm currently based in Birmingham and work for Namesco as a PHP developer.

Blog Feed









