Skip to content

Instantly share code, notes, and snippets.

@eddjberry
Last active July 27, 2020 12:50
Show Gist options
  • Save eddjberry/d2918b05b9f12e24db46167b675b9e1f to your computer and use it in GitHub Desktop.
Save eddjberry/d2918b05b9f12e24db46167b675b9e1f to your computer and use it in GitHub Desktop.
Knit a directory of files from the command line
#!/usr/bin/env Rscript
# to run from command line:
## chmod +x knit_dir.R
## ./knit_dir.R <dir-name>
# from https://stackoverflow.com/a/49950761
# to avoid conflicts between packages
# breaking things
clean_search <- function() {
defaults <- c(".GlobalEnv",
paste0("package:", getOption("defaultPackages")),
"Autoloads",
"package:base")
currentList <- search()
deletes <- setdiff(currentList, defaults)
for (entry in deletes)
detach(entry, character.only = TRUE)
}
# function to knit directory
knit_dir <- function(dir) {
# create the full path
full_dir <- normalizePath(dir)
# list the Rmd files with full names
files <-
list.files(full_dir, pattern = '*.Rmd$', full.names = TRUE)
# render the files using all output formats in the YAML
purrr::map(files, function(file) {
# clean search list to avoid conflicts
clean_search()
# render the file using all
# output formats in a new env
rmarkdown::render(file,
output_format = "all",
envir = new.env())
})
}
# pull out the first command line argument
dir <- commandArgs(trailingOnly = TRUE)[1]
# run the function
knit_dir(dir)
@eddjberry
Copy link
Author

This is awesome, thanks for sharing! Two minor comments that might be helpful

  full_dir <- here::here(dir)

I would recommend using fs::path_abs(dir) or normalizePath(dir) here instead. If you're running from the command line you'd probably expect the directory to be relative to where you run the command, but here() could move that on you. Eg. the (unlikely) scenario where you have docs/docs in your project root and run knit_dir.R docs from inside docs/ will try the first docs/ rather than docs/docs

  # render the files using all output formats in the YAML
  purrr::map(files, rmarkdown::render, output_format = 'all')

You might want to move rmarkdown::render into an anonymous function so that you can render each document in a new environment.

purrr::map(files, function(file) {
  rmarkdown::render(file, output_format = "all", envir = new.env())
}

This ensures that each rmd render is performed in a fresh environment. You might even want to go as far as using envir = new.env(parent = emptyenv()).

Thanks a lot for your comment. I've made those changes :)

@eddjberry
Copy link
Author

I removed the parent = emptyenv() bit as this was causing an error when having

date: "17/12/2019 (updated: `r Sys.Date()`)"

in my YAML header (could not find function "Sys.Date")

@gadenbuie
Copy link

Glad that the comments were helpful! On second thought parent = emptyenv() is certainly way too conservative!

@eddjberry
Copy link
Author

Have added the cleanSearch() function from https://stackoverflow.com/a/49950761 to fix conflicts between packages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment