Testing Example Code In Your Jekyll Posts
Blocks of code in blog posts and articles often contain errors. I see it frequently, in other people’s writing and my own. Code examples are usually not tested, or even run through a compiler/interpreter, so errors are not surprising.
I’d like my code examples to be as good as the real code that I write. Ideally, all code examples would have tests, which are run before the site is deployed, as part of a CI build process.
And so, I created a Jekyll plugin to enable that workflow.
jekyll-include_snippet
jekyll-include_snippet is a plugin for Jekyll that allows snippets of text to be included from other files. This allows code to be kept separately from the markdown, which makes it easier to test.
The rest of this article will be a short example of how to use the plugin.
The Code
All the code is kept in a single file.
In this example, that file is code/dog.rb
:
class Dog
def initialize
@flipped = false
end
# begin-snippet: flip
def flip
@flipped = !@flipped
end
# end-snippet
# begin-snippet: speak
def speak
@flipped ? "ɟooʍ" : "woof"
end
# end-snippet
end
The Markdown
In the YAML frontmatter, specify the path to the code with snippet_source
.
In the markdown, use the include_snippet
liquid tag to include bits of code.
---
title: "Look At My Dog Class"
snippet_source: "code/dog.rb"
---
In this article I'm going to share my `Dog` class with you.
Here is the `flip` method:
```ruby
{% include_snippet flip %}
```
Here is the `speak` method:
```ruby
{% include_snippet speak %}
```
And here is the whole class:
```ruby
{% include_snippet everything %}
```
The markdown above will render the following.
The Rendered Output
In this article I’m going to share my Dog
class with you.
Here is the flip
method:
def flip
@flipped = !@flipped
end
Here is the speak
method:
def speak
@flipped ? "ɟooʍ" : "woof"
end
And here is the whole class:
class Dog
def initialize
@flipped = false
end
def flip
@flipped = !@flipped
end
def speak
@flipped ? "ɟooʍ" : "woof"
end
end
The Tests
Testing the code is no different to testing code in any other Ruby project. I’m using RSpec, but you could easily use another framework, like MiniTest.
Add RSpec to your Gemfile:
source 'https://rubygems.org'
gem 'jekyll', '~> 3.7'
gem 'rspec', '~> 3.7'
Install everything with:
bundle install
Generate the conventional RSpec files with:
bundle exec rspec --init
Then write your tests in the spec
directory:
# spec/dog_spec.rb
require_relative '../code/dog'
RSpec.describe Dog do
it 'can woof and flip' do
expect(subject.speak).to eq("woof")
subject.flip
expect(subject.speak).to eq("ɟooʍ")
subject.flip
expect(subject.speak).to eq("woof")
end
end
Finally, all the tests can be run with:
bundle exec rspec
Conclusion
Blog posts and articles often contain incorrect code examples. The jekyll-include_snippet plugin can be used to separate code from markdown, which allows the code to be tested more easily.
The plugin is able to include snippets from more than one file. See the README on GitHub for the documentation.
It’s comforting to know that my example code actually works.
This is how I will be writing articles here, from now on.
In fact, this article has been written with jekyll-include_snippet
, so I’ve got a weird Inception situation happening.
Thank you to Christian Grobmeier for giving feedback on a draft of this article.
Got questions? Comments? Milk?
Shoot an email to [email protected] or hit me up on Twitter (@tom_dalling).