R: sourcing files using a relative path
RR Problem Overview
Sourcing files using a relative path is useful when dealing with large codebases. Other programming languages have well-defined mechanisms for sourcing files using a path relative to the directory of the file being sourced into. An example is Ruby's require_relative
. What is a good way to implement relative path sourcing in R?
Below is what I pieced together a while back using various recipes and R forum posts. It's worked well for me for straight development but is not robust. For example, it breaks when the files are loaded via the testthat
library, specifically auto_test()
. rscript_stack()
returns character(0)
.
# Returns the stack of RScript files
rscript_stack <- function() {
Filter(Negate(is.null), lapply(sys.frames(), function(x) x$ofile))
}
# Returns the current RScript file path
rscript_current <- function() {
stack <- rscript_stack()
r <- as.character(stack[length(stack)])
first_char <- substring(r, 1, 1)
if (first_char != '~' && first_char != .Platform$file.sep) {
r <- file.path(getwd(), r)
}
r
}
# Sources relative to the current script
source_relative <- function(relative_path, ...) {
source(file.path(dirname(rscript_current()), relative_path), ...)
}
Do you know of a better source_relative
implementation?
R Solutions
Solution 1 - R
After a discussion with @hadley on GitHub, I realized that my question goes against the common development patterns in R.
It seems that in R files that are sourced often assume that the working directory (getwd()
) is set to the directory they are in. To make this work, source
has a chdir
argument whose default value is FALSE
. When set to TRUE
, it will change the working directory to the directory of the file being sourced.
In summary:
-
Assume that
source
is always relative because the working directory of the file being sourced is set to the directory where the file is. -
To make this work, always set
chdir=T
when you source files from another directory, e.g.,source('lib/stats/big_stats.R', chdir=T)
.
For convenient sourcing of entire directories in a predictable way I wrote sourceDir
, which sources files in a directory in alphabetical order.
sourceDir <- function (path, pattern = "\\.[rR]$", env = NULL, chdir = TRUE)
{
files <- sort(dir(path, pattern, full.names = TRUE))
lapply(files, source, chdir = chdir)
}