Bending Jekyll To Your Will With Aspect Oriented Programming

These days, when there is a need to create a simple static site I turn to Jekyll. But, while Jekyll is great at what it does I often want to bend it to do something beyond what it can easily do out of the box. Rather than fork Jekyll for my small changes I use Aspect-Oriented Programming (AOP) in a way that may look familiar to anyone who has used event systems or the Drupal hook system. Here's how I do it.

Note: Before we get started I need to point out that the techniques I'm about to describe do not work on Github pages (which support Jekyll).

The Setup

Jekyll_ext is an extension to Jekyll that enables AOP. This needs to be installed alongside Jekyll for this to work. Then, instead of calling jekyll at the command line call ejekyll. The same command line options apply as ejekyll is a wrapper around jekyll while enabling AOP.

What You Get With Jekyll_ext

There are three new ways to extent Jekyll with this extension:

  • AOP.before - this allows a function to run before a method on a class does.
  • AOP.after - this is like API.before but allows a function to be run after a method on a class.
  • APO.around - this wraps a method call in a function. The original method needs to be manually called when it's needed.

More details can be found on the original blog post announcing jekyll_ext and in the source code.

A Simple Example

My original use case that brought me to this method of extending Jekyll was the need for post previews that were the first part of the post before a separator (html comment). While this was a carry over from a Drupal migration it was something I found useful. Here is code that accomplishes this:

module Jekyll
  class Post
    def preview_content
      delimeter = @site.config['content_delimeter'] || '<!-- -**-END-**- -->'
      self.content.split(delimeter)[0]
    end
  end

  AOP.around(Post, :to_liquid) do |post_instance, args, proceed, abort|
    result = proceed.call
    result['preview'] = post_instance.preview_content
    result
  end
end

The first part of this adds the method preview_post to the class Post. The second part wraps the method call to_liquid on the class Post with this function. Inside it starts by calling the original method then adds the variable (which will be accessible in the template) preview.

If you are looking for more examples a good place to start is the author of jekyll_ext repo of extensions.