R: sourcing files using a relative path

r

Solution

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)
}

Problem

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?

Original source

Related problems