Combining Knitr and Jekyll took some effort. This post describes how to get it all working as part of a statistical blogging pipeline.

## Introduction

If you’re reading this, you know that I write a blog about statistics for Inferentialist Consulting. You may also be aware of the knitr package, useful for reproducible research. knitr is a dramatic improvement over its predecessor, Sweave, and the easiest way I’ve found to interweave text and R output. However, until now, I’ve only used knitr in a latex workflow. Now that I’m authoring a blog—I use jekyll—I’d love a similarly easy way to transform R Markdown to jekyll Markdown.

The good news is that most of the plumbing already exists. RStudio has some functionality that exposes R Markdown in a jekyll format. However, the context requires running jekyll as a temporary background process. The missing piece is the ability to export transformed R Markdown into jekyll Markdown.

Luckily, it doesn’t take too much R magic to extend knitr in exactly the way we want. Here’s the code to do the job:

sample.Rmd

input_file = "sample.Rmd"

# Remove the file extension
base_name = gsub("(^.*)\\.(.*$)", "\\1", input_file, fixed=FALSE) # Define the location of the blog; here, a soft link blog_dir = "./blog" posts_dir = paste(blog_dir, "_posts", sep="/") # Define the output file, output_basename = paste(base_name, "md", sep=".") output_file = paste(posts_dir, output_basename, sep="/") # ...and the output path for the figures fig.path = paste(blog_dir, "assets", base_name, "", sep="/") # Set up the hooks for a RStudio jekyll knitr::render_jekyll() # Maybe you want some nice defaults for the figures / images knitr::opts_chunk$set(
fig.width=6,
fig.height=4.5,
fig.path=fig.path,
warning=FALSE,
message=FALSE
)

# Tweak the upload.fun hook so that the blog_dir is removed
# when the Markdown link is written out
knitr::opts_knit$set( upload.fun = function(x){ gsub(blog_dir, "", x) ## _OR_ gsub(blog_dir, "http://blog.inferentialist.com", x) } ) # The default table attributes confuses jekyll, but this works options(xtable.html.table.attributes = "class='foobar'") # Finally, let knitr do its thing. knit(input_file, output = output_file) # Extras #### Verbatim Rmarkdown The following extension adds a verbatim flag which is useful for showcasing the actual Rmd code. I borrowed this idea from Ramnath Vaidyanathan with slight modifications. source_orig = knitr::knit_hooks$get()$source knitr::knit_hooks$set(
source = function(x, options){
if (!is.null(options$verbatim) && options$verbatim){
opts = gsub(",\\s*verbatim\\s*=\\s*TRUE\\s*", "", options$params.src) opts = gsub(",\\s*eval\\s*=\\s*FALSE\\s*", "", opts) bef = sprintf('\n\n {r %s}\n', opts, "\n") stringr::str_c( bef, knitr:::indent_block(paste(x, collapse = '\n'), " "), "\n \n\n" ) } else { source_orig(x, options) } }) #### Debugging Knitr Finally, it can be useful to add debug wrappers around the hooks. For example, this lets you know which hooks are actually called and with what parameters. fdbg = list() for(item in names(knitr::knit_hooks$get())){
fdbg[[item]] = knit_hooks$get(item) ## Create a new environment so that the function is invoked ## with the correct value of item e = new.env() e$item = item
fn = function(...) {
cat("----------", item, "\n")
flush.console()
browser()
fdbg[[item]](...)
}
environment(fn) = e

## The setter doesn't quite work the way you'd expect, so
## use reflection.
cmd = paste("knit_hooks\$set(",item," = fn)", sep="")
eval(parse(text=cmd))
}