Martin Nyaga

Jekyll Remake

February 20th, 2017


This started out as a kind of thought experiment sometime back. I wanted to make a really simple blog in ruby.

I had played around with Jekyll, but it wasn't for my tastes. I was rather uncomfortable with the whole bundle exec jekyll serve business. I wanted to have full control of my blog and its internals, be able to add anything custom if I needed to, and to use my good old rails s to run things.

So when I accidentally deleted the source code to my previous website, I ended up building a kind of minimalist jekyll as a replacement, and the result is this very site you read. It was actually really simple.

How it works

Basically, this site is a is a bunch of static haml templates with Rails sitting in between doing all the dynamic routing and serving the web pages. None of the content you read here is coming from a database, although I did maintain support for Activerecord and SQlite in case I needed some database functionality sometime in the future.

I will simplify the code abit for purposes of this post, but hopefully you will see the main idea.

I have a static/posts directory. where files for each post live as haml templates. Haml felt minimal enough that I didn't need to bother with liquid or markdown templates like Jekyll does.

The way files are named is what really glues things together. Each file is named as follows:

{title_slug}-{date_of_publishing}.haml

The title slug is the name that appears in the url. This is also the name that appears on the page that lists all the posts, just that it has underscores removed and is converted to title case. For example, the title slug for this post is: jekyll_remake .

The date of publishing is a valid date that can be parsed by Ruby's Date when the underscores are turned into spaces. For example 20th_Feb_2017 .

So the full name of the file containing this post that you are reading is: jekyll_remake-20th_Feb_2017.haml .

I then used a straightforward implementation of an Entry class that would parse and carry this filename data.

class Entry
  attr_reader :filename, :slug, :date, :title
  def initialize(directory, filename)
    @filename = directory + '/' + filename

    split_filename = filename.split("-")

    @slug = split_filename.first
    @date = Date.parse(split_filename.last.humanize)
    @title = slug.humanize.titleize
  end
end

This class is used in a PostSource class that fetches files from a certain directory and initializes entries. It's kind of like a Post model, only that it doesn't fetch from a database.

Here's the code for that class.

# Class to handle posts logic
class PostSource
  attr_reader :directory
  
  def initialize(directory)
    @directory = directory
  end

  # Return the entry to a specific post
  # given by a slug
  def find(slug)
    all.select {|entry|
      entry.slug == slug
    }.first
  end

  # Returns all entries in a directory
  # sorted in reverse Chronological order
  # by date
  def all
    entries =
      Dir["#{full_directory}/*"].map do |filename|
        # Get file name without extension
        filename = filename.split("/").last.split(".").first

        # Return an entry
        Entry.new(directory, filename)
      end
      
    # Sort entries in reverese order by date
    entries.sort{|a, b| b.date <=> a.date }
  end

  def full_directory
    Rails.root.to_s + '/app/views/' + directory
  end
end

So in my posts_controller#show method, I have something like the following:

def show
  @post = PostSource.new('static/posts').find(params[:slug])

  if @post.nil?
    render 'templates/404'
  else
    render @post.filename
  end
end

And really that's all there is to it! So to create a new post, I can just create a new appropriately named file in the correct folder, and things will work.

This approach is great because If I want to have categorised posts, I can do so by storing things in separate folders and initializing the PostSource with the appropriate directory. That's actually how the Musings and Software sections of this website work.

The best part so far has been that since everything is in Haml, I can remain as minimal or get as complex as I like with the views, and still not feel like I'm writing raw HTML.

Takeaways

This was really just a short curiosity escapade that ended up in a new simple website for myself. Perhaps the major takeaway is that something like Jekyll isn't very complicated to implement by yourself in principle. It's the wealth of features, themes and community that make it significantly more useful.

Still, if you can't stand writing bundle exec jekyll serve then you can always roll your own blog-aware rails app fairly easily.