rprojroot/0000755000176200001440000000000013223174170012312 5ustar liggesusersrprojroot/inst/0000755000176200001440000000000013223155063013267 5ustar liggesusersrprojroot/inst/doc/0000755000176200001440000000000013223155063014034 5ustar liggesusersrprojroot/inst/doc/rprojroot.Rmd0000644000176200001440000003233313215575324016553 0ustar liggesusers--- title: "Finding files in project subdirectories" author: "Kirill Müller" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Finding files in project subdirectories} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- The *rprojroot* package solves a seemingly trivial but annoying problem that occurs sooner or later in any largish project: How to find files in subdirectories? Ideally, file paths are relative to the *project root*. Unfortunately, we cannot always be sure about the current working directory: For instance, in RStudio it's sometimes: - the project root (when running R scripts), - a subdirectory (when building vignettes), - again the project root (when executing chunks of a vignette). ```{r} basename(getwd()) ``` In some cases, it's even outside the project root. This vignette starts with a very brief summary that helps you get started, followed by a longer description of the features. ## TL;DR What is your project: An R package? ```{r} rprojroot::is_r_package ``` Or an RStudio project? ```{r} rprojroot::is_rstudio_project ``` Or something else? ```{r} rprojroot::has_file(".git/index") ``` For now, we assume it's an R package: ```{r} root <- rprojroot::is_r_package ``` The `root` object contains a function that helps locating files below the root of your package, regardless of your current working directory. If you are sure that your working directory is somewhere below your project's root, use the `root$find_file()` function: ```{r} readLines(root$find_file("DESCRIPTION"), 3) ``` You can also construct an accessor to your root using the `root$make_fix_file()` function: ```{r} root_file <- root$make_fix_file() ``` Note that `root_file()` is a *function* that works just like `$find_file()` but will find the files even if the current working directory is outside your project: ```{r} withr::with_dir( "../..", readLines(root_file("DESCRIPTION"), 3) ) ``` If you know the absolute path of some directory below your project, but cannot be sure of your current working directory, pass that absolute path to `root$make_fix_file()`: ```r root_file <- root$make_fix_file("C:\\Users\\User Name\\...") ``` As a last resort, you can get the path of standalone R scripts or vignettes using the `thisfile()` function: ```r root_file <- root$make_fix_file(dirname(thisfile())) ``` The remainder of this vignette describes implementation details and advanced features. ## Project root We assume a self-contained project where all files and directories are located below a common *root* directory. Also, there should be a way to unambiguously identify this root directory. (Often, the root contains a regular file whose name matches a given pattern, and/or whose contents match another pattern.) In this case, the following method reliably finds our project root: - Start the search in any subdirectory of our project - Proceed up the directory hierarchy until the root directory has been identified The Git version control system (and probably many other tools) use a similar approach: A Git command can be executed from within any subdirectory of a repository. ### A simple example The `find_root()` function implements the core functionality. It returns the path to the first directory that matches the filtering criteria, or throws an error if there is no such directory. Filtering criteria are constructed in a generic fashion using the `root_criterion()` function, the `has_file()` function constructs a criterion that checks for the presence of a file with a specific name and specific contents. ```{r} library(rprojroot) # List all files and directories below the root dir(find_root(has_file("DESCRIPTION"))) ``` #### Relative paths to a stable root Here we illustrate the power of *rprojroot* by demonstrating how to access the same file from two different working directories. Let your project be a package called `pkgname` and consider the desired file `rrmake.R` at `pkgname/R/rrmake.R`. First, we show how to access from the `vignettes` directory, and then from the `tests/testthat` directory. ##### Example A: From `vignettes` When your working directory is `pkgname/vignettes`, you can access the `rrmake.R` file by: 1. Supplying a pathname relative to your working directory. Here's two ways to do that: ```{r, eval = FALSE} rel_path_from_vignettes <- "../R/rrmake.R" rel_path_from_vignettes <- file.path("..", "R", "rrmake.R") ##identical ``` 2. Supplying a pathname to the file relative from the root of the package, e.g., ```{r, eval = FALSE} rel_path_from_root <- "R/rrmake.R" rel_path_from_root <- file.path("R", "rrmake.R") ##identical ``` This second method requires finding the root of the package, which can be done with the `has_file()` function: ```{r} has_file("DESCRIPTION") ``` So, using *rprojroot* you can specify the path relative from root in the following manner: ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ``` ##### Example B: From `tests/testthat` When your working directory is `pkgname/tests/testthat`, you can access the `rrmake.R` file by: 1. Supplying a pathname relative to your working directory. ```{r, eval = FALSE} rel_path_from_testthat <- "../../R/rrmake.R" ``` Note that this is different than in the previous example! However, the second method is the same... 2. Supplying a pathname to the file relative from the root of the package. With *rprojroot*, this is the exact same as in the previous example. ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ``` ##### Summary of Examples A and B Since Examples A and B used different working directories, `rel_path_from_vignettes` and `rel_path_from_testthat` were different. This is an issue when trying to re-use the same code. This issue is solved by using *rprojroot*: the function `find_root_file()` finds a file relative from the root, where the root is determined from checking the criterion with `has_file()`. Note that the follow code produces identical results when building the vignette *and* when sourcing the chunk in RStudio, provided that the current working directory is the project root or anywhere below. So, we can check to make sure that *rprojroot* has succesfully determined the correct path: ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) # Find a file relative to the root file.exists(rel_path_from_root) ``` ### Criteria The `has_file()` function (and the more general `root_criterion()`) both return an S3 object of class `root_criterion`: ```{r} has_file("DESCRIPTION") ``` In addition, character values are coerced to `has_file` criteria by default, this coercion is applied automatically by `find_root()`. (This feature is used by the introductory example.) ```{r} as.root_criterion("DESCRIPTION") ``` The return value of these functions can be stored and reused; in fact, the package provides `r length(criteria)` such criteria: ```{r} criteria ``` Defining new criteria is easy: ```{r} has_license <- has_file("LICENSE") has_license is_projecttemplate_project <- has_file("config/global.dcf", "^version: ") is_projecttemplate_project ``` You can also combine criteria via the `|` operator: ```{r} is_r_package | is_rstudio_project ``` ### Shortcuts To avoid specifying the search criteria for the project root every time, shortcut functions can be created. The `find_package_root_file()` is a shortcut for `find_root_file(..., criterion = is_r_package)`: ```{r} # Print first lines of the source for this document head(readLines(find_package_root_file("vignettes", "rprojroot.Rmd"))) ``` To save typing effort, define a shorter alias: ```{r} P <- find_package_root_file # Use a shorter alias file.exists(P("vignettes", "rprojroot.Rmd")) ``` Each criterion actually contains a function that allows finding a file below the root specified by this criterion. As our project does not have a file named `LICENSE`, querying the root results in an error: ```{r error = TRUE} # Use the has_license criterion to find the root R <- has_license$find_file R # Our package does not have a LICENSE file, trying to find the root results in an error R() ``` ### Fixed root We can also create a function that computes a path relative to the root *at creation time*. ```{r} # Define a function that computes file paths below the current root F <- is_r_package$make_fix_file() F # Show contents of the NAMESPACE file in our project readLines(F("NAMESPACE")) ``` This is a more robust alternative to `$find_file()`, because it *fixes* the project directory when `$make_fix_file()` is called, instead of searching for it every time. (For that reason it is also slightly faster, but I doubt this matters in practice.) This function can be used even if we later change the working directory to somewhere outside the project: ```{r} # Print the size of the namespace file, working directory outside the project withr::with_dir( "../..", file.size(F("NAMESPACE")) ) ``` The `make_fix_file()` member function also accepts an optional `path` argument, in case you know your project's root but the current working directory is somewhere outside. The path to the current script or `knitr` document can be obtained using the `thisfile()` function, but it's much easier and much more robust to just run your scripts with the working directory somewhere below your project root. ## `testthat` files Tests run with [`testthat`](https://cran.r-project.org/package=testthat) commonly use files that live below the `tests/testthat` directory. Ideally, this should work in the following situation: - During package development (working directory: package root) - When testing with `devtools::test()` (working directory: `tests/testthat`) - When running `R CMD check` (working directory: a renamed recursive copy of `tests`) The `is_testthat` criterion allows robust lookup of test files. ```{r} is_testthat ``` The example code below lists all files in the [hierarchy](https://github.com/krlmlr/rprojroot/tree/master/tests/testthat/hierarchy) test directory. It uses two project root lookups in total, so that it also works when rendering the vignette (*sigh*): ```{r} dir(is_testthat$find_file("hierarchy", path = is_r_package$find_file())) ``` ### Another example: custom testing utilities The hassle of using saved data files for testing is made even easier by using *rprojroot* in a utility function. For example, suppose you have a testing file at `tests/testthat/test_my_fun.R` which tests the `my_fun()` function: ```{r, eval = FALSE} my_fun_run <- do.call(my_fun, my_args) testthat::test_that( "my_fun() returns expected output", testthat::expect_equal( my_fun_run, expected_output ) ) ``` There are two pieces of information that you'll need every time `test_my_fun.R` is run: `my_args` and `expected_output`. Typically, these objects are saved to `.Rdata` files and saved to the same subdirectory. For example, you could save them to `my_args.Rdata` and `expected_output.Rdata` under the `tests/testthat/testing_data` subdirectory. And, to find them easily in any contexts, you can use *rprojroot*! Since all of the data files live in the same subdirectory, you can create a utility function `get_my_path()` that will always look in that directory for these types of files. And, since the *testthat* package will look for and source the `tests/testthat/helper.R` file before running any tests, you can place a `get_my_path()` in this file and use it throughout your tests: ```{r, eval = FALSE} ## saved to tests/testthat/helper.R get_my_path <- function(file_name) { rprojroot::find_testthat_root_file( "testing_data", filename ) } ``` Now you can ask `get_my_path()` to find your important data files by using the function within your test scripts! ```{r, eval = FALSE} ## Find the correct path with your custom rprojroot helper function path_to_my_args_file <- get_my_path("my_args.Rdata") ## Load the input arguments load(file = path_to_my_args_file) ## Run the function with those arguments my_fun_run <- do.call(my_fun,my_args) ## Load the historical expectation with the helper load(file = get_my_path("expected_output.Rdata")) ## Pass all tests and achieve nirvana testthat::test_that( "my_fun() returns expected output", testthat::expect_equal( my_fun_run, expected_output ) ) ``` For an example in the wild, see the [`test_sheet()` function](https://github.com/tidyverse/readxl/blob/0d9ad4f570f6580ff716e0e9ba5048447048e9f0/tests/testthat/helper.R#L1-L3) in the *readxl* package. ## Summary The *rprojroot* package allows easy access to files below a project root if the project root can be identified easily, e.g. if it is the only directory in the whole hierarchy that contains a specific file. This is a robust solution for finding files in largish projects with a subdirectory hierarchy if the current working directory cannot be assumed fixed. (However, at least initially, the current working directory must be somewhere below the project root.) ## Acknowledgement This package was inspired by the gist ["Stop the working directory insanity"](https://gist.github.com/jennybc/362f52446fe1ebc4c49f) by Jennifer Bryan, and by the way Git knows where its files are. rprojroot/inst/doc/rprojroot.html0000644000176200001440000011315213223155063016765 0ustar liggesusers Finding files in project subdirectories

Finding files in project subdirectories

Kirill Müller

2018-01-03

The rprojroot package solves a seemingly trivial but annoying problem that occurs sooner or later in any largish project: How to find files in subdirectories? Ideally, file paths are relative to the project root.

Unfortunately, we cannot always be sure about the current working directory: For instance, in RStudio it’s sometimes:

basename(getwd())
## [1] "vignettes"

In some cases, it’s even outside the project root.

This vignette starts with a very brief summary that helps you get started, followed by a longer description of the features.

TL;DR

What is your project: An R package?

rprojroot::is_r_package
## Root criterion: contains a file `DESCRIPTION` with contents matching `^Package: `

Or an RStudio project?

rprojroot::is_rstudio_project
## Root criterion: contains a file matching `[.]Rproj$` with contents matching `^Version: ` in the first line

Or something else?

rprojroot::has_file(".git/index")
## Root criterion: contains a file `.git/index`

For now, we assume it’s an R package:

root <- rprojroot::is_r_package

The root object contains a function that helps locating files below the root of your package, regardless of your current working directory. If you are sure that your working directory is somewhere below your project’s root, use the root$find_file() function:

readLines(root$find_file("DESCRIPTION"), 3)
## [1] "Package: rprojroot"                            
## [2] "Title: Finding Files in Project Subdirectories"
## [3] "Version: 1.3-2"

You can also construct an accessor to your root using the root$make_fix_file() function:

root_file <- root$make_fix_file()

Note that root_file() is a function that works just like $find_file() but will find the files even if the current working directory is outside your project:

withr::with_dir(
  "../..",
  readLines(root_file("DESCRIPTION"), 3)
)
## [1] "Package: rprojroot"                            
## [2] "Title: Finding Files in Project Subdirectories"
## [3] "Version: 1.3-2"

If you know the absolute path of some directory below your project, but cannot be sure of your current working directory, pass that absolute path to root$make_fix_file():

root_file <- root$make_fix_file("C:\\Users\\User Name\\...")

As a last resort, you can get the path of standalone R scripts or vignettes using the thisfile() function:

root_file <- root$make_fix_file(dirname(thisfile()))

The remainder of this vignette describes implementation details and advanced features.

Project root

We assume a self-contained project where all files and directories are located below a common root directory. Also, there should be a way to unambiguously identify this root directory. (Often, the root contains a regular file whose name matches a given pattern, and/or whose contents match another pattern.) In this case, the following method reliably finds our project root:

The Git version control system (and probably many other tools) use a similar approach: A Git command can be executed from within any subdirectory of a repository.

A simple example

The find_root() function implements the core functionality. It returns the path to the first directory that matches the filtering criteria, or throws an error if there is no such directory. Filtering criteria are constructed in a generic fashion using the root_criterion() function, the has_file() function constructs a criterion that checks for the presence of a file with a specific name and specific contents.

library(rprojroot)

# List all files and directories below the root
dir(find_root(has_file("DESCRIPTION")))
##  [1] "API"              "DESCRIPTION"      "Makefile"        
##  [4] "NAMESPACE"        "NEWS.md"          "R"               
##  [7] "README.md"        "_pkgdown.yml"     "appveyor.yml"    
## [10] "cran-comments.md" "docs"             "inst"            
## [13] "man"              "readme"           "revdep"          
## [16] "rprojroot.Rcheck" "rprojroot.Rproj"  "tests"           
## [19] "tic.R"            "vignettes"

Relative paths to a stable root

Here we illustrate the power of rprojroot by demonstrating how to access the same file from two different working directories. Let your project be a package called pkgname and consider the desired file rrmake.R at pkgname/R/rrmake.R. First, we show how to access from the vignettes directory, and then from the tests/testthat directory.

Example A: From vignettes

When your working directory is pkgname/vignettes, you can access the rrmake.R file by:

  1. Supplying a pathname relative to your working directory. Here’s two ways to do that:
rel_path_from_vignettes <- "../R/rrmake.R"
rel_path_from_vignettes <- file.path("..", "R", "rrmake.R") ##identical
  1. Supplying a pathname to the file relative from the root of the package, e.g.,
rel_path_from_root <- "R/rrmake.R"
rel_path_from_root <- file.path("R", "rrmake.R") ##identical

This second method requires finding the root of the package, which can be done with the has_file() function:

has_file("DESCRIPTION")
## Root criterion: contains a file `DESCRIPTION`

So, using rprojroot you can specify the path relative from root in the following manner:

# Specify a path/to/file relative to the root
rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION"))
Example B: From tests/testthat

When your working directory is pkgname/tests/testthat, you can access the rrmake.R file by:

  1. Supplying a pathname relative to your working directory.
rel_path_from_testthat <- "../../R/rrmake.R"

Note that this is different than in the previous example! However, the second method is the same…

  1. Supplying a pathname to the file relative from the root of the package. With rprojroot, this is the exact same as in the previous example.
# Specify a path/to/file relative to the root
rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION"))
Summary of Examples A and B

Since Examples A and B used different working directories, rel_path_from_vignettes and rel_path_from_testthat were different. This is an issue when trying to re-use the same code. This issue is solved by using rprojroot: the function find_root_file() finds a file relative from the root, where the root is determined from checking the criterion with has_file().

Note that the follow code produces identical results when building the vignette and when sourcing the chunk in RStudio, provided that the current working directory is the project root or anywhere below. So, we can check to make sure that rprojroot has succesfully determined the correct path:

# Specify a path/to/file relative to the root
rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION"))

# Find a file relative to the root
file.exists(rel_path_from_root)
## [1] TRUE

Criteria

The has_file() function (and the more general root_criterion()) both return an S3 object of class root_criterion:

has_file("DESCRIPTION")
## Root criterion: contains a file `DESCRIPTION`

In addition, character values are coerced to has_file criteria by default, this coercion is applied automatically by find_root(). (This feature is used by the introductory example.)

as.root_criterion("DESCRIPTION")
## Root criterion: contains a file `DESCRIPTION`

The return value of these functions can be stored and reused; in fact, the package provides 9 such criteria:

criteria
## $is_rstudio_project
## Root criterion: contains a file matching `[.]Rproj$` with contents matching `^Version: ` in the first line
## 
## $is_r_package
## Root criterion: contains a file `DESCRIPTION` with contents matching `^Package: `
## 
## $is_remake_project
## Root criterion: contains a file `remake.yml`
## 
## $is_projectile_project
## Root criterion: contains a file `.projectile`
## 
## $is_git_root
## Root criterion: one of
## - contains a directory `.git`
## - contains a file `.git` with contents matching `^gitdir: `
## 
## $is_svn_root
## Root criterion: contains a directory `.svn`
## 
## $is_vcs_root
## Root criterion: one of
## - contains a directory `.git`
## - contains a file `.git` with contents matching `^gitdir: `
## - contains a directory `.svn`
## 
## $is_testthat
## Root criterion: directory name is `testthat` (also look in subdirectories: `tests/testthat`, `testthat`)
## 
## $from_wd
## Root criterion: from current working directory
## 
## attr(,"class")
## [1] "root_criteria"

Defining new criteria is easy:

has_license <- has_file("LICENSE")
has_license
## Root criterion: contains a file `LICENSE`
is_projecttemplate_project <- has_file("config/global.dcf", "^version: ")
is_projecttemplate_project
## Root criterion: contains a file `config/global.dcf` with contents matching `^version: `

You can also combine criteria via the | operator:

is_r_package | is_rstudio_project
## Root criterion: one of
## - contains a file `DESCRIPTION` with contents matching `^Package: `
## - contains a file matching `[.]Rproj$` with contents matching `^Version: ` in the first line

Shortcuts

To avoid specifying the search criteria for the project root every time, shortcut functions can be created. The find_package_root_file() is a shortcut for find_root_file(..., criterion = is_r_package):

# Print first lines of the source for this document
head(readLines(find_package_root_file("vignettes", "rprojroot.Rmd")))
## [1] "---"                                               
## [2] "title: \"Finding files in project subdirectories\""
## [3] "author: \"Kirill Müller\""                         
## [4] "date: \"`r Sys.Date()`\""                          
## [5] "output: rmarkdown::html_vignette"                  
## [6] "vignette: >"

To save typing effort, define a shorter alias:

P <- find_package_root_file

# Use a shorter alias
file.exists(P("vignettes", "rprojroot.Rmd"))
## [1] TRUE

Each criterion actually contains a function that allows finding a file below the root specified by this criterion. As our project does not have a file named LICENSE, querying the root results in an error:

# Use the has_license criterion to find the root
R <- has_license$find_file
R
## function (..., path = ".") 
## {
##     find_root_file(..., criterion = criterion, path = path)
## }
## <environment: 0x55721401cd30>
# Our package does not have a LICENSE file, trying to find the root results in an error
R()
## Error: No root directory found in /tmp/RtmpIOVFMP/Rbuild4ab6ad646f7/rprojroot/vignettes or its parent directories. Root criterion: contains a file `LICENSE`

Fixed root

We can also create a function that computes a path relative to the root at creation time.

# Define a function that computes file paths below the current root
F <- is_r_package$make_fix_file()
F
## function (...) 
## {
##     file.path("/tmp/RtmpIOVFMP/Rbuild4ab6ad646f7/rprojroot", 
##         ...)
## }
## <environment: 0x5572140051a8>
# Show contents of the NAMESPACE file in our project
readLines(F("NAMESPACE"))
##  [1] "# Generated by roxygen2: do not edit by hand"
##  [2] ""                                            
##  [3] "S3method(\"|\",root_criterion)"              
##  [4] "S3method(as.root_criterion,character)"       
##  [5] "S3method(as.root_criterion,default)"         
##  [6] "S3method(as.root_criterion,root_criterion)"  
##  [7] "S3method(format,root_criterion)"             
##  [8] "S3method(print,root_criterion)"              
##  [9] "S3method(str,root_criteria)"                 
## [10] "export(as.root_criterion)"                   
## [11] "export(criteria)"                            
## [12] "export(find_package_root_file)"              
## [13] "export(find_remake_root_file)"               
## [14] "export(find_root)"                           
## [15] "export(find_root_file)"                      
## [16] "export(find_rstudio_root_file)"              
## [17] "export(find_testthat_root_file)"             
## [18] "export(from_wd)"                             
## [19] "export(get_root_desc)"                       
## [20] "export(has_dir)"                             
## [21] "export(has_dirname)"                         
## [22] "export(has_file)"                            
## [23] "export(has_file_pattern)"                    
## [24] "export(is.root_criterion)"                   
## [25] "export(is_git_root)"                         
## [26] "export(is_projectile_project)"               
## [27] "export(is_r_package)"                        
## [28] "export(is_remake_project)"                   
## [29] "export(is_rstudio_project)"                  
## [30] "export(is_svn_root)"                         
## [31] "export(is_testthat)"                         
## [32] "export(is_vcs_root)"                         
## [33] "export(root_criterion)"                      
## [34] "export(thisfile)"                            
## [35] "export(thisfile_knit)"                       
## [36] "export(thisfile_r)"                          
## [37] "export(thisfile_rscript)"                    
## [38] "export(thisfile_source)"                     
## [39] "import(backports)"                           
## [40] "importFrom(utils,str)"                       
## [41] "importFrom(utils,tail)"

This is a more robust alternative to $find_file(), because it fixes the project directory when $make_fix_file() is called, instead of searching for it every time. (For that reason it is also slightly faster, but I doubt this matters in practice.)

This function can be used even if we later change the working directory to somewhere outside the project:

# Print the size of the namespace file, working directory outside the project
withr::with_dir(
  "../..",
  file.size(F("NAMESPACE"))
)
## [1] 1010

The make_fix_file() member function also accepts an optional path argument, in case you know your project’s root but the current working directory is somewhere outside. The path to the current script or knitr document can be obtained using the thisfile() function, but it’s much easier and much more robust to just run your scripts with the working directory somewhere below your project root.

testthat files

Tests run with testthat commonly use files that live below the tests/testthat directory. Ideally, this should work in the following situation:

The is_testthat criterion allows robust lookup of test files.

is_testthat
## Root criterion: directory name is `testthat` (also look in subdirectories: `tests/testthat`, `testthat`)

The example code below lists all files in the hierarchy test directory. It uses two project root lookups in total, so that it also works when rendering the vignette (sigh):

dir(is_testthat$find_file("hierarchy", path = is_r_package$find_file()))
## [1] "DESCRIPTION"     "a"               "b"               "c"              
## [5] "hierarchy.Rproj"

Another example: custom testing utilities

The hassle of using saved data files for testing is made even easier by using rprojroot in a utility function. For example, suppose you have a testing file at tests/testthat/test_my_fun.R which tests the my_fun() function:

my_fun_run <- do.call(my_fun, my_args)

testthat::test_that(
  "my_fun() returns expected output",
  testthat::expect_equal(
    my_fun_run,
    expected_output
  )
)

There are two pieces of information that you’ll need every time test_my_fun.R is run: my_args and expected_output. Typically, these objects are saved to .Rdata files and saved to the same subdirectory. For example, you could save them to my_args.Rdata and expected_output.Rdata under the tests/testthat/testing_data subdirectory. And, to find them easily in any contexts, you can use rprojroot!

Since all of the data files live in the same subdirectory, you can create a utility function get_my_path() that will always look in that directory for these types of files. And, since the testthat package will look for and source the tests/testthat/helper.R file before running any tests, you can place a get_my_path() in this file and use it throughout your tests:

## saved to tests/testthat/helper.R
get_my_path <- function(file_name) {
  rprojroot::find_testthat_root_file(
    "testing_data", filename
  )
}

Now you can ask get_my_path() to find your important data files by using the function within your test scripts!

## Find the correct path with your custom rprojroot helper function
path_to_my_args_file <- get_my_path("my_args.Rdata")

## Load the input arguments
load(file = path_to_my_args_file)

## Run the function with those arguments
my_fun_run <- do.call(my_fun,my_args)

## Load the historical expectation with the helper
load(file = get_my_path("expected_output.Rdata"))

## Pass all tests and achieve nirvana
testthat::test_that(
  "my_fun() returns expected output",
  testthat::expect_equal(
    my_fun_run,
    expected_output
  )
)

For an example in the wild, see the test_sheet() function in the readxl package.

Summary

The rprojroot package allows easy access to files below a project root if the project root can be identified easily, e.g. if it is the only directory in the whole hierarchy that contains a specific file. This is a robust solution for finding files in largish projects with a subdirectory hierarchy if the current working directory cannot be assumed fixed. (However, at least initially, the current working directory must be somewhere below the project root.)

Acknowledgement

This package was inspired by the gist “Stop the working directory insanity” by Jennifer Bryan, and by the way Git knows where its files are.

rprojroot/inst/doc/rprojroot.R0000644000176200001440000001266213223155063016226 0ustar liggesusers## ------------------------------------------------------------------------ basename(getwd()) ## ------------------------------------------------------------------------ rprojroot::is_r_package ## ------------------------------------------------------------------------ rprojroot::is_rstudio_project ## ------------------------------------------------------------------------ rprojroot::has_file(".git/index") ## ------------------------------------------------------------------------ root <- rprojroot::is_r_package ## ------------------------------------------------------------------------ readLines(root$find_file("DESCRIPTION"), 3) ## ------------------------------------------------------------------------ root_file <- root$make_fix_file() ## ------------------------------------------------------------------------ withr::with_dir( "../..", readLines(root_file("DESCRIPTION"), 3) ) ## ------------------------------------------------------------------------ library(rprojroot) # List all files and directories below the root dir(find_root(has_file("DESCRIPTION"))) ## ---- eval = FALSE------------------------------------------------------- # rel_path_from_vignettes <- "../R/rrmake.R" # rel_path_from_vignettes <- file.path("..", "R", "rrmake.R") ##identical # ## ---- eval = FALSE------------------------------------------------------- # rel_path_from_root <- "R/rrmake.R" # rel_path_from_root <- file.path("R", "rrmake.R") ##identical ## ------------------------------------------------------------------------ has_file("DESCRIPTION") ## ------------------------------------------------------------------------ # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ## ---- eval = FALSE------------------------------------------------------- # rel_path_from_testthat <- "../../R/rrmake.R" ## ------------------------------------------------------------------------ # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ## ------------------------------------------------------------------------ # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) # Find a file relative to the root file.exists(rel_path_from_root) ## ------------------------------------------------------------------------ has_file("DESCRIPTION") ## ------------------------------------------------------------------------ as.root_criterion("DESCRIPTION") ## ------------------------------------------------------------------------ criteria ## ------------------------------------------------------------------------ has_license <- has_file("LICENSE") has_license is_projecttemplate_project <- has_file("config/global.dcf", "^version: ") is_projecttemplate_project ## ------------------------------------------------------------------------ is_r_package | is_rstudio_project ## ------------------------------------------------------------------------ # Print first lines of the source for this document head(readLines(find_package_root_file("vignettes", "rprojroot.Rmd"))) ## ------------------------------------------------------------------------ P <- find_package_root_file # Use a shorter alias file.exists(P("vignettes", "rprojroot.Rmd")) ## ----error = TRUE-------------------------------------------------------- # Use the has_license criterion to find the root R <- has_license$find_file R # Our package does not have a LICENSE file, trying to find the root results in an error R() ## ------------------------------------------------------------------------ # Define a function that computes file paths below the current root F <- is_r_package$make_fix_file() F # Show contents of the NAMESPACE file in our project readLines(F("NAMESPACE")) ## ------------------------------------------------------------------------ # Print the size of the namespace file, working directory outside the project withr::with_dir( "../..", file.size(F("NAMESPACE")) ) ## ------------------------------------------------------------------------ is_testthat ## ------------------------------------------------------------------------ dir(is_testthat$find_file("hierarchy", path = is_r_package$find_file())) ## ---- eval = FALSE------------------------------------------------------- # my_fun_run <- do.call(my_fun, my_args) # # testthat::test_that( # "my_fun() returns expected output", # testthat::expect_equal( # my_fun_run, # expected_output # ) # ) ## ---- eval = FALSE------------------------------------------------------- # ## saved to tests/testthat/helper.R # get_my_path <- function(file_name) { # rprojroot::find_testthat_root_file( # "testing_data", filename # ) # } ## ---- eval = FALSE------------------------------------------------------- # ## Find the correct path with your custom rprojroot helper function # path_to_my_args_file <- get_my_path("my_args.Rdata") # # ## Load the input arguments # load(file = path_to_my_args_file) # # ## Run the function with those arguments # my_fun_run <- do.call(my_fun,my_args) # # ## Load the historical expectation with the helper # load(file = get_my_path("expected_output.Rdata")) # # ## Pass all tests and achieve nirvana # testthat::test_that( # "my_fun() returns expected output", # testthat::expect_equal( # my_fun_run, # expected_output # ) # ) rprojroot/tests/0000755000176200001440000000000012526472104013457 5ustar liggesusersrprojroot/tests/testthat.R0000644000176200001440000000007612526472104015445 0ustar liggesuserslibrary(testthat) library(rprojroot) test_check("rprojroot") rprojroot/tests/testthat/0000755000176200001440000000000013223174170015314 5ustar liggesusersrprojroot/tests/testthat/vcs/0000755000176200001440000000000013170752070016111 5ustar liggesusersrprojroot/tests/testthat/vcs/svn.zip0000644000176200001440000002360413170752070017450 0ustar liggesusersPK 6}/Jsvn/UT ({X'=zXux PK6}/Jsvn/DESCRIPTIONUT ({X({Xux =J1yKW3 HT0j⚹LB$dl|1*ݞ?ӡ>@ %F$v6I̐ A&P"xg=!s1Q)^ ^A-1iUI =Zsp{`wt|ū#Z>da 89hY)Jm̿O_"2ќ+|lXB^˺tkh`FGCoyw_݈PK 6}/J svn/.svn/UT ({X'=zXux PK 6}/JMsvn/.svn/formatUT ({X({Xux 12 PK6}/J 'Rsvn/.svn/wc.dbUT ({X({Xux [ly:WkFS%pxo]YeѦ oApX)RKRAJ%}I4A^CmzyiH7-y-$M (ǶgI39s\T,W60GeEa^k6 x1fw1Jz=g1ֳ3>2^mV.ַ|ycnQV6+;r6Cץ4EN c:3i9өΓxROzR7Az;. #3˹kktp糙jsj&{~/Ib^~Cz~px8ܬL_ót^fyɧLISFRVH\R%T#QM3U"$ʧSF\գ>=%?vKd~=w)' =Kuj|p#ɝ1n ̱'+0cJgՓ5a*SB, z3}Op -v{~"dDW%;'cA-{}g_;7;5~q8c<<>ݨAd'iwhEzCMʪlɨiČj"z9H&OzBz"O,y^G;~_ ZNOE)vf5'W/٧#?~ ;d;F|ȞGB>n46ưC>Nh=8w>?h &clw*ÿ6>) /t>~P ]\oG9|1~wךoֳXzu岶NZۙ=]3g؛5 ^%nRÎS%m"ۯa|t=se[ngߵ*ץ*~xvj$'=!KW Cš_N4Q`Ǟ/J<ˢ_'[dk]EkTM/-Z"ձg z{ב0F1rV#ۑ!";c؃5yau{s:魲Fy.\W կ?îkw⳸n:Xg^@_j̣ytm i7&:5r^ÞGQ1MCP$H%{0*N˻Ʊϼd:fsDnϽikpU\cGýnK!F>36h??1/;[ -_g82.߽%Kh* zc}Rs+y&k|O@h{_뚸#YwL5_hމ Gݿӱ+LNֿM)$<9"ӮD]J`y;^_FބPK 6}/JMsvn/.svn/entriesUT ({X({Xux 12 PK .J svn/.svn/tmp/UT '=zX'=zXux PK 6}/Jsvn/.svn/pristine/UT ({X({Xux PK 6}/Jsvn/.svn/pristine/f0/UT ({X({Xux PK6}/Jash߯c&/pGr3fg$O0؋gR /6a`l+8.!%PmǔɎ5UwVGޠO:]_C9hwvPS:= ڨjrAVS # l`LijR֧5x٦vԱ:D4x붧ԠiW+I@ĕ~~PK 6}/Jsvn/.svn/pristine/f3/UT ({X({Xux PK 6}/JyEFsvn/.svn/pristine/f3/f30dae958ef83fc13091258906c050936e39b8f9.svn-baseUT ({X({Xux File b in root PK 6}/Jsvn/.svn/pristine/da/UT ({X({Xux PK 6}/JFsvn/.svn/pristine/da/da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-baseUT ({X({Xux PK 6}/Jsvn/.svn/pristine/9e/UT ({X({Xux PK 6}/J %JFsvn/.svn/pristine/9e/9ed97191f4672ff9ef5d9659438d776ea57fb6ba.svn-baseUT ({X({Xux File b PK 6}/Jsvn/.svn/pristine/1f/UT ({X({Xux PK6}/JFsvn/.svn/pristine/1f/1fff0ad79f00c81b19245903e27229dff1771fd4.svn-baseUT ({X({Xux =J1yKW3 HT0j⚹LB$dl|1*ݞ?ӡ>@ %F$v6I̐ A&P"xg=!s1Q)^ ^A-1iUI =Zsp{`wt|ū#Z>da 89hY)Jm̿O_"2ќ+|lXB^˺tkh`FGCoyw_݈PK 6}/Jsvn/.svn/wc.db-journalUT ({X({Xux PK 6}/Jsvn/a/UT ({X({Xux PK 6}/Jsvn/a/b/UT ({X({Xux PK 6}/J svn/a/b/aUT ({X({Xux PK 6}/J %J svn/a/b/bUT ({X({Xux File b PK 6}/J svn/a/b/c/UT ({X({Xux PK 6}/J svn/a/b/c/dUT ({X({Xux PK6}/Jash߯c&/pGr3fg$O0؋gR /6a`l+8.!%PmǔɎ5UwVGޠO:]_C9hwvPS:= ڨjrAVS # l`LijR֧5x٦vԱ:D4x붧ԠiW+I@ĕ~~PK 6}/JyEsvn/bUT ({X({Xux File b in root PK 6}/Jsvn/cUT ({X({Xux PK 6}/JAsvn/UT({Xux PK6}/J>svn/DESCRIPTIONUT({Xux PK 6}/J Acsvn/.svn/UT({Xux PK 6}/JMsvn/.svn/formatUT({Xux PK6}/J 'Rsvn/.svn/wc.dbUT({Xux PK 6}/JMsvn/.svn/entriesUT({Xux PK .J Asvn/.svn/tmp/UT'=zXux PK 6}/JA svn/.svn/pristine/UT({Xux PK 6}/JAlsvn/.svn/pristine/f0/UT({Xux PK6}/Jas@ %F$v6I̐ A&P"xg=!s1Q)^ ^A-1iUI =Zsp{`wt|ū#Z>da 89hY)Jm̿O_"2ќ+|lXB^˺tkh`FGCoyw_݈PK .Jgit/a/UT @zX@zXux PK .Jgit/a/b/UT @zX@zXux PK .J git/a/b/aUT @zX@zXux PK .J %J git/a/b/bUT @zX@zXux File b PK .J git/a/b/c/UT @zX@zXux PK .J git/a/b/c/dUT @zX@zXux PK Y.J git/.git/UT ZAzX=zXux PK `.Jgit/.git/hooks/UT =zX=zXux PK`.JO $git/.git/hooks/applypatch-msg.sampleUT =zX=zXux U]N1 s *HHp.nS-l[^o^ܭ7>ɩZ{B!"0([J8˽V&ZfTA=;H9/-Ov`&F3j.[K?@#rvDO BYq+7Sy:Qfm(}DJ 9CSQ ^&4VB09eٝh}6ЃV` Br)}??M PK`.JL $git/.git/hooks/pre-applypatch.sampleUT =zX=zXux U[N1 EK:@VVB=DL&Q>nq,o#S!pWcHƞjO8/ 霷.Eh_p*^L|huV#iت7 Q>ޮ"\'yvFi[R^GgpP|XCMh4`KLZ)0x,W㲵ol6DkȢ;xdi #FQnapB7\>cZŗ6z7"<ϑV\>%2O0 o9J[F 8UVmK(OPRpvs'+aε{@zhngPK`.J git/.git/hooks/commit-msg.sampleUT =zX=zXux }_o0şOqH+VMJ" XD&7l|w&E=Re M]C͍F^S~WrݶҡZVTɷi;OЊ Lշ"0h l'>Oպo ޒ\i ap(Hk{*uFwF G'$d OYo:ye 皒MRϗ >!-7)q]ͳ`:T|G"mm/#U1EY)*R])H6ڛ*?A _H~ uPN6N p8Waj{wypjGXOw|-/]2c\+ }FLj'#(9^j=^k.P~Y8cA1PG8jG䈐d}7+Yg4 _{]EPK`.JI !git/.git/hooks/pre-receive.sampleUT =zX=zXux uPN0<_1}@[ʑ*HV"!UnM;B;vʣqzg3:ZZ; :*Ҙ lVbCZQm2<+MʷWP& Y:Q;앓hJd텄^ի%i$㒟jBk=hq/BK/E3UM2R;TG֡I/y:M4[,R +~EkâveKL q(h_uԌMkS6g9o5^q{~㱯a~"M%qpQ,kbbPK`.J!D%ugit/.git/hooks/update.sampleUT =zX=zXux WQo"7~f܂`IҷHuM*Um:EfnM]]8HH1g曙ofLd&DA7GI+[2NR\ ELŏLJes2l)Ւ4<rA-2 Pc.xǐ6¤z }D%'~!ƁWfbRDI=SWs@ #'vd"X +#S8 zfJeIhڤܤ E-$_%'-\29LH52 {a֗a2Jpt)П4FaOw~˵E$S͝GKY쮤-# P^5m4#zBxJΘ9}[7wfP \jni}J\kWG:IqL{mk).Z| =mn_mF>0.pJp{q`GI*pݓ !X/u;Կcv?15EVY"eʇ!H}nfs}p-;Xqds|(Fu}Բ+&'@(s5 ϟ =wbmU,LA:fW5 :aNpC;]qc@bS*7USݝpt]+!&_󚓝ZBѓVGkXټ9Ww]gDoeg ƚح,b @vJtՎP#n>=>n%-|@Ux|` :m7Pz9YqnU4k˛3k@jFyFG2LU mmFP%;p$끕^ ؛2/[/vM gaCŴ'QJ۩A!Qޭ5' +G6 $R _>)!JÉl\k,)ޮy?PK`.J(git/.git/hooks/prepare-commit-msg.sampleUT =zX=zXux uS]s0|&3M?,[;L) ig[T\Iɏ$9! =e˥ԥ&$ Sz {a|PJzP:'Z,{)ZMb$}QZLύTJx #cQ<%ƀ1Foh#hVX̻4!H& U*G!K3F_h 8/rAbiǺ^Ω8(,Fb%`DWe$0lp u2qlupށh)4Q8Av#{J,+V!bl<-#4Gl>%6fܙO6mc=BV͠ӳ0X)Ω3i46vpq!mfQVcMp*%u 𸕕DTŕX!%B_Kqg"l!jX%H7ͧ92dt~@'rp6>.xNf-3(sCY (oP@Sz38= ;=҄‡>xMHlpk%*2'٫41NTA~!,|]|zw9i㨙,Aq8-_dt㲟Zz%)Qx:zDv~˓PK`.Jz" git/.git/hooks/pre-rebase.sampleUT =zX=zXux XkoF,[E>۸AndıGPbMr3(jsg"-+b﹏ѓofU$zBl4G4?<~NL9, Q*G{ԯhFi-et]ﵱ Zf"cKpZI Ţ$(KKcU<ժ`%xh!)|,̦R?V,f1(y.G*՚%TBBZ358ԕZ3ih- x&Ma0,(|fۄJ,*J1wZqԘ {(ZWjmĚj㢪,<0ɮ% &(^B5xJ4(.ǰ7aBZy"S疲A U" z`Uz3섵F,+>QDO'429wNZfd3̍l0z̦X<~~yvqCwwQ@t % $H+H+b94c(G*@SK#{H7@% w6U{R)@A6/KOSq\e乫 .` 俭ww+EϿS5JfSE,|ݳ&u5h<물>[H( ͉*%!'ۚt<|  뙸sZe>r[oBclvkj+H-QfKv0;HOJFFmXw2\3Npg9=A7:vpưHwn5ҫz2 ۛĪI"$%[F(ר'0v/ ` ެ6J&؄rA,goqx^%GiCQƳStg~3c Qqzw$ۈfLbr<ݓg8wt^a|(sYp+rGpt4{Wj4r7 tN#Jr^J˷o]L#>5 BmwM?7Moί_Pv;\B'f<^ 4D cMߦcɔX(RF0.xzp?"zJoXN^AW,_EeI"|(3. J2-c6 Hdes=Kz}7F W1@ +V&S,Sң~Qg(ve@f+_ gu%q+ 6D0YBQ73'/`KVg.1Bo\ /$:RVn2Ç7=7,. 0xx%%FyXc+]zz@Y~r:UVFmY7 T/Dc&r?Roy"'e-k-@?^F^]^_z;o`+o~ņc O[`Tk{x4tJh;HE`?(%lغʒ-|:Vhwq.A_WI% ˗ݢM;f `9 S\$HyJ*F $Cql;H'Nh8ZT]@wmm8|Ra]/`L/zxgq{ @f;>$k.օ53Wco{!nZ;!aW ʹyt 1W2_!w8^yVӆ2r zQ/c6k]^γ=4!m)goyKp&? t3ș6͜1\ ?w紇Mķ3W/ )>ɇBo=p'K,Z,eKEUu3H>h_SD*{Lq{ u?6&~%~c&V5ߟPKT.J7"Fgit/.git/configUT PAzXPAzXux =A 0ur{I$wsL@j;fY ʝp ('w#&Tn3οP3cN$ں4)v8uO_Y ~2PK`.J7?Igit/.git/descriptionUT =zX=zXux  KMMQ(J-/,/VHM,Q(,VHIUPOI-N.,(SW(Wʧ"iPK W.Jgit/.git/logs/UT UAzXUAzXux PKY.JzxBgit/.git/logs/HEADUT YAzXUAzXux ;0kr-A:u!z! HV .L .\ }C2XA g+QApL5 3PawC1)龝y4chQ TJaniN&oFfJ*kX:4B2sڰ&o8.)TSѼPK W.Jgit/.git/logs/refs/UT UAzXUAzXux PK W.Jgit/.git/logs/refs/heads/UT UAzXUAzXux PKY.JzxBgit/.git/logs/refs/heads/masterUT YAzXUAzXux ;0kr-A:u!z! HV .L .\ }C2XA g+QApL5 3PawC1)龝y4chQ TJaniN&oFfJ*kX:4B2sڰ&o8.)TSѼPK `.J+is git/.git/HEADUT =zX=zXux ref: refs/heads/master PKY.Jڅ{git/.git/indexUT YAzXYAzXux s rf```b*M|whV{c000`F1AKb=po盽,qn` πO?jCT}4{kݚʣnz<5Q?I?9aPs6v9)̱fR>,\ -?`½s IGd\1K$2&T\z8OWmj'ԢĢJ,=!A@*\kgWg {xs\W;j` ɻrs1OiNi~"`  OLf0T0Rl:í+^.Mm~q'+eE*k_V*PK `.Jgit/.git/branches/UT =zX=zXux PK `.Jgit/.git/refs/UT =zX=zXux PK `.Jgit/.git/refs/tags/UT =zX=zXux PK Y.Jgit/.git/refs/heads/UT YAzX=zXux PK Y.JY))git/.git/refs/heads/masterUT YAzXYAzXux 68636ba53c0af48b81340540deb025822c8a5843 PK Y.J"Cgit/.git/COMMIT_EDITMSGUT YAzXUAzXux add hierarchy PK `.Jgit/.git/info/UT =zX=zXux PK`.Jw=!git/.git/info/excludeUT =zX=zXux -A 0Dbv/\yq۟6؍g7Ǽ hc)iX& kOo@.miuk6p72)AȄgKlK s7Qq=ZƏȜ< uY^1+ >bN8Z#Eù깆PK W.Jgit/.git/rr-cache/UT UAzXUAzXux PK Y.Jgit/.git/objects/UT YAzX=zXux PK X.Jgit/.git/objects/11/UT WAzXWAzXux PK X.JP4:git/.git/objects/11/0eb5a45dc2e0464f870e9ba3fe02e034896a17UT WAzXWAzXux x=J@]S\J ]X-.PJՅ\2C3Ý X͝/Jַ0Y\Q' #+}[(kL4jO2q4tʁHx#; UYW 0egZxnwlyGc[UzCb䢦؄}! gh.D{ƠO@6-`^*QxisƄ$qcGJ_PK X.Jgit/.git/objects/a5/UT WAzXWAzXux PK X.Jc'X:git/.git/objects/a5/1ca34cde8238dd99ac22001b1f9f3090dece5fUT WAzXWAzXux xKOR04epIUHRS(/S PK X.Jgit/.git/objects/e6/UT WAzXWAzXux PK X.J:git/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391UT WAzXWAzXux xKOR0` PK `.Jgit/.git/objects/pack/UT =zX=zXux PK .Jgit/.git/objects/4b/UT @zX@zXux PK .J: :git/.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904UT @zX@zXux x+)JMU0` ,PK X.Jgit/.git/objects/30/UT WAzXWAzXux PK X.JWtu:git/.git/objects/30/e02be1a85ca418689078d43ae19e2d26b7ab42UT WAzXWAzXux x]N0ǽSGLй3偞ACi2OoDzTTZ'In}'0) H_$c3TLZE:_a6Y}}E:h:VKos#NcI)1HqPR)0V܂ .qYidOT"M~r[<{"fTbHSԅ%ت A&jQo_]AV*R <4tsyPK Y.Jgit/.git/objects/2a/UT YAzXYAzXux PK Y.J[..:git/.git/objects/2a/26db49a6962700da5bd4084ae0e5a22d6583eeUT YAzXYAzXux x+)JMU0d040031QHax6M9{wk+qIOD&PK Y.Jgit/.git/objects/6e/UT YAzXYAzXux PK Y.J++:git/.git/objects/6e/d4c082894affb09de26ff4679e444e1c376483UT YAzXYAzXux x+)JMU0`01$:O$l1a1cB PK Y.Jgit/.git/objects/93/UT YAzXYAzXux PK Y.JTp+:git/.git/objects/93/f3e6d4c33c7d336913484b08d11d7f26c5382cUT YAzXYAzXux x+)JMU04`040031Qpq v cۺ$7vً1=071D+:o(K<?fI Kek;s| C%}4{kݚʣnz<*ZXQTP`@ኘ%*X=}EPK W.Jgit/.git/objects/cf/UT UAzXUAzXux PK W.J8:git/.git/objects/cf/3d5641dfc957f7efd3eb04931cae565ef61917UT UAzXUAzXux x 1@Qϩb Îw$;Cfc%XxK~3$FK˚8BEN,K7&:eҟۮ8Lv|:kMmǷ0|YWY=FPK `.Jgit/.git/objects/info/UT =zX=zXux PK Y.Jgit/.git/objects/68/UT YAzXWAzXux PK Y.J~?i:git/.git/objects/68/636ba53c0af48b81340540deb025822c8a5843UT YAzXYAzXux xMJ1 ]?fҟ)IRy#͝h߯c&/pGr3fg$O0؋gR /6a`l+8.!%PmǔɎ5UwVGޠO:]_C9hwvPS:= ڨjrAVS # l`LijR֧5x٦vԱ:D4x붧ԠiW+I@ĕ~~PK .JyEgit/bUT @zX@zXux File b in root PK .Jgit/cUT @zX@zXux PK .JAgit/UT@zXux PK.J>git/DESCRIPTIONUT@zXux PK .JAcgit/a/UT@zXux PK .JAgit/a/b/UT@zXux PK .J git/a/b/aUT@zXux PK .J %J (git/a/b/bUT@zXux PK .J Argit/a/b/c/UT@zXux PK .J git/a/b/c/dUT@zXux PK Y.J Agit/.git/UTZAzXux PK `.JA>git/.git/hooks/UT=zXux PK`.JO $git/.git/hooks/applypatch-msg.sampleUT=zXux PK`.JL $git/.git/hooks/pre-applypatch.sampleUT=zXux PK`.J !cgit/.git/hooks/post-update.sampleUT=zXux PK`.J؏DHgit/.git/hooks/pre-push.sampleUT=zXux PK`.J%0\j = git/.git/hooks/pre-commit.sampleUT=zXux PK`.J :git/.git/hooks/commit-msg.sampleUT=zXux PK`.JI !git/.git/hooks/pre-receive.sampleUT=zXux PK`.J!D%u/git/.git/hooks/update.sampleUT=zXux PK`.J(git/.git/hooks/prepare-commit-msg.sampleUT=zXux PK`.Jz" git/.git/hooks/pre-rebase.sampleUT=zXux PKT.J7"F,"git/.git/configUTPAzXux PK`.J7?I"git/.git/descriptionUT=zXux PK W.JA#git/.git/logs/UTUAzXux PKY.JzxB#git/.git/logs/HEADUTYAzXux PK W.JA$git/.git/logs/refs/UTUAzXux PK W.JA %git/.git/logs/refs/heads/UTUAzXux PKY.JzxB\%git/.git/logs/refs/heads/masterUTYAzXux PK `.J+is \&git/.git/HEADUT=zXux PKY.Jڅ{&git/.git/indexUTYAzXux PK `.JA}(git/.git/branches/UT=zXux PK `.JA(git/.git/refs/UT=zXux PK `.JA)git/.git/refs/tags/UT=zXux PK Y.JA^)git/.git/refs/heads/UTYAzXux PK Y.JY)))git/.git/refs/heads/masterUTYAzXux PK Y.J"C)*git/.git/COMMIT_EDITMSGUTYAzXux PK `.JA*git/.git/info/UT=zXux PK`.Jw=!*git/.git/info/excludeUT=zXux PK W.JA+git/.git/rr-cache/UTUAzXux PK Y.JA,git/.git/objects/UTYAzXux PK X.JAc,git/.git/objects/11/UTWAzXux PK X.JP4:$,git/.git/objects/11/0eb5a45dc2e0464f870e9ba3fe02e034896a17UTWAzXux PK X.JA.git/.git/objects/a5/UTWAzXux PK X.Jc'X:$].git/.git/objects/a5/1ca34cde8238dd99ac22001b1f9f3090dece5fUTWAzXux PK X.JA.git/.git/objects/e6/UTWAzXux PK X.J:$>/git/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391UTWAzXux PK `.JA/git/.git/objects/pack/UT=zXux PK .JA0git/.git/objects/4b/UT@zXux PK .J: :$_0git/.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904UT@zXux PK X.JA0git/.git/objects/30/UTWAzXux PK X.JWtu:$01git/.git/objects/30/e02be1a85ca418689078d43ae19e2d26b7ab42UTWAzXux PK Y.JA2git/.git/objects/2a/UTYAzXux PK Y.J[..:$3git/.git/objects/2a/26db49a6962700da5bd4084ae0e5a22d6583eeUTYAzXux PK Y.JA3git/.git/objects/6e/UTYAzXux PK Y.J++:$3git/.git/objects/6e/d4c082894affb09de26ff4679e444e1c376483UTYAzXux PK Y.JA4git/.git/objects/93/UTYAzXux PK Y.JTp+:$4git/.git/objects/93/f3e6d4c33c7d336913484b08d11d7f26c5382cUTYAzXux PK W.JA6git/.git/objects/cf/UTUAzXux PK W.J8:$P6git/.git/objects/cf/3d5641dfc957f7efd3eb04931cae565ef61917UTUAzXux PK `.JAJ7git/.git/objects/info/UT=zXux PK Y.JA7git/.git/objects/68/UTYAzXux PK Y.J~?i:$7git/.git/objects/68/636ba53c0af48b81340540deb025822c8a5843UTYAzXux PK X.JE: :$9git/.git/objects/68/21c186de959771d06bbd41d5fe9d4271ee675dUTWAzXux PK Y.JA9git/.git/objects/7e/UTYAzXux PK Y.Jcc:$9git/.git/objects/7e/29db8b3b97c863c3b6533890a3015231cddf61UTYAzXux PK Y.J:git/.git/MERGE_RRUTYAzXux PK.Jas [aut, cre]") Description: What the package does (one paragraph) Depends: R (>= 3.2.0) License: GPL-3 LazyData: true Encoding: UTF-8 rprojroot/tests/testthat/hierarchy/b0000644000176200001440000000001712532326106017434 0ustar liggesusersFile b in root rprojroot/NAMESPACE0000644000176200001440000000176213215575324013546 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("|",root_criterion) S3method(as.root_criterion,character) S3method(as.root_criterion,default) S3method(as.root_criterion,root_criterion) S3method(format,root_criterion) S3method(print,root_criterion) S3method(str,root_criteria) export(as.root_criterion) export(criteria) export(find_package_root_file) export(find_remake_root_file) export(find_root) export(find_root_file) export(find_rstudio_root_file) export(find_testthat_root_file) export(from_wd) export(get_root_desc) export(has_dir) export(has_dirname) export(has_file) export(has_file_pattern) export(is.root_criterion) export(is_git_root) export(is_projectile_project) export(is_r_package) export(is_remake_project) export(is_rstudio_project) export(is_svn_root) export(is_testthat) export(is_vcs_root) export(root_criterion) export(thisfile) export(thisfile_knit) export(thisfile_r) export(thisfile_rscript) export(thisfile_source) import(backports) importFrom(utils,str) importFrom(utils,tail) rprojroot/NEWS.md0000644000176200001440000000515613217155361013423 0ustar liggesusers## rprojroot 1.3-2 (2017-12-22) - Availability of suggested packages knitr and rmarkdown, and pandoc, is now checked before running the corresponding tests. # rprojroot 1.3-1 (2017-12-18) - Adapt to testthat 2.0.0. - New `thisfile()`, moved from kimisc (#8). - Add more examples to vignette (#26, @BarkleyBG). - Detect `.git` directories created with `git clone --separate-git-dir=...` (#24, @karldw). # rprojroot 1.2 (2017-01-15) - New root criteria - `is_projectile_project` recognize projectile projects (#21). - `has_dir()` constructs root criteria that check for existence of a directory. - `is_git_root`, `is_svn_root` and `is_vcs_root` look for a version control system root (#19). - New function - `get_root_desc()` returns the description of the criterion that applies to a given root, useful for composite criteria created with `|`. - Minor enhancements - Improve formatting of alternative criteria (#18). - If root cannot be found, the start path is shown in the error message. - Internal - The `$testfun` member of the `rprojroot` S3 class is now a list of functions instead of a function. # rprojroot 1.1 (2016-10-29) - Compatibility - Compatible with R >= 3.0.0 with the help of the `backports` package. - New root criteria - `is_remake_project` and `find_remake_root_file()` look for [remake](https://github.com/richfitz/remake) project (#17). - `is_testthat` and `find_testthat_root_file()` that looks for `tests/testthat` root (#14). - `from_wd`, useful for creating accessors to a known path (#11). - Minor enhancement - Criteria can be combined with the `|` operator (#15). - Documentation - Add package documentation with a few examples (#13). - Clarify difference between `find_file()` and `make_fix_file()` in vignette (#9). - Remove unexported functions from documentation and examples (#10). - Use `pkgdown` to create website. - Testing - Use Travis instead of wercker. Travis tests three R versions, and OS X. - Improve AppVeyor testing. # rprojroot 1.0-2 (2016-03-28) - Fix test that fails on Windows only on CRAN. # rprojroot 1.0 (2016-03-26) Initial CRAN release. - S3 class `root_criterion`: - Member functions: `find_file()` and `make_fix_file()` - `root_criterion()` - `as.root_criterion()` - `is.root_criterion()` - `has_file()` - `has_file_pattern()` - Built-in criteria: - `is_r_package` - `is_rstudio_project` - Getting started: - `find_package_root_file()` - `find_rstudio_root_file()` - Use a custom notion of a project root: - `find_root()` - `find_root_file()` - Vignette rprojroot/R/0000755000176200001440000000000013216015313012506 5ustar liggesusersrprojroot/R/has-file.R0000644000176200001440000001316113215575324014337 0ustar liggesusersformat_lines <- function(n) { if (n == 1) "line" else paste0(n, " lines") } #' @details #' The `has_file()` function constructs a criterion that checks for the #' existence of a specific file (which itself can be in a subdirectory of the #' root) with specific contents. #' #' @rdname root_criterion #' @param filepath File path (can contain directories) #' @param contents Regular expression to match the file contents #' @inheritParams base::readLines #' @export has_file <- function(filepath, contents = NULL, n = -1L) { force(filepath) force(contents) force(n) testfun <- eval(bquote(function(path) { testfile <- file.path(path, .(filepath)) if (!file.exists(testfile)) return(FALSE) if (is_dir(testfile)) return(FALSE) match_contents(testfile, .(contents), .(n)) })) desc <- paste0( "contains a file `", filepath, "`", if (!is.null(contents)) { paste0(" with contents matching `", contents, "`", if (n >= 0L) paste0(" in the first ", format_lines(n))) }) root_criterion(testfun, desc) } #' @details #' The `has_dir()` function constructs a criterion that checks for the #' existence of a specific directory. #' #' @rdname root_criterion #' @export has_dir <- function(filepath) { force(filepath) testfun <- eval(bquote(function(path) { testfile <- file.path(path, .(filepath)) if (!file.exists(testfile)) return(FALSE) is_dir(testfile) })) desc <- paste0("contains a directory `", filepath, "`") root_criterion(testfun, desc) } #' @details #' The `has_file_pattern()` function constructs a criterion that checks for the #' existence of a file that matches a pattern, with specific contents. #' #' @rdname root_criterion #' @param pattern Regular expression to match the file name #' @inheritParams base::readLines #' @export has_file_pattern <- function(pattern, contents = NULL, n = -1L) { force(pattern) force(contents) force(n) testfun <- eval(bquote(function(path) { files <- list_files(path, .(pattern)) for (f in files) { if (!match_contents(f, .(contents), .(n))) { next } return(TRUE) } return(FALSE) })) desc <- paste0( "contains a file matching `", pattern, "`", if (!is.null(contents)) { paste0(" with contents matching `", contents, "`", if (n >= 0L) paste0(" in the first ", format_lines(n))) }) root_criterion(testfun, desc) } #' @details #' The `has_dirname()` function constructs a criterion that checks if the #' [base::dirname()] has a specific name. #' #' @rdname root_criterion #' @param dirname A directory name, without subdirectories #' @export has_dirname <- function(dirname, subdir = NULL) { force(dirname) testfun <- eval(bquote(function(path) { dir.exists(file.path(dirname(path), .(dirname))) })) desc <- paste0("directory name is `", dirname, "`") root_criterion(testfun, desc, subdir = subdir) } #' @export is_rstudio_project <- has_file_pattern("[.]Rproj$", contents = "^Version: ", n = 1L) #' @export is_r_package <- has_file("DESCRIPTION", contents = "^Package: ") #' @export is_remake_project <- has_file("remake.yml") #' @export is_projectile_project <- has_file(".projectile") #' @export is_git_root <- has_dir(".git") | has_file(".git", contents = "^gitdir: ") #' @export is_svn_root <- has_dir(".svn") #' @export is_vcs_root <- is_git_root | is_svn_root #' @export is_testthat <- has_dirname("testthat", c("tests/testthat", "testthat")) #' @export from_wd <- root_criterion(function(path) TRUE, "from current working directory") #' Prespecified criteria #' #' This is a collection of commonly used root criteria. #' #' @export criteria <- structure( list( is_rstudio_project = is_rstudio_project, is_r_package = is_r_package, is_remake_project = is_remake_project, is_projectile_project = is_projectile_project, is_git_root = is_git_root, is_svn_root = is_svn_root, is_vcs_root = is_vcs_root, is_testthat = is_testthat, from_wd = from_wd ), class = "root_criteria") #' @export #' @importFrom utils str str.root_criteria <- function(object, ...) { str(lapply(object, format)) } #' @details #' `is_rstudio_project` looks for a file with extension `.Rproj`. #' #' @rdname criteria #' @export "is_rstudio_project" #' @details #' `is_r_package` looks for a `DESCRIPTION` file. #' #' @rdname criteria #' @export "is_r_package" #' @details #' `is_remake_project` looks for a `remake.yml` file. #' #' @rdname criteria #' @export "is_remake_project" #' @details #' `is_projectile_project` looks for a `.projectile` file. #' #' @rdname criteria #' @export "is_projectile_project" #' @details #' `is_git_project` looks for a `.git` directory. #' #' @rdname criteria #' @export "is_git_root" #' @details #' `is_svn_project` looks for a `.svn` directory. #' #' @rdname criteria #' @export "is_svn_root" #' @details #' `is_vcs_project` looks for the root of a version control #' system, currently only Git and SVN are supported. #' #' @rdname criteria #' @export "is_vcs_root" #' @details #' `is_testthat` looks for the `testthat` directory, works when #' developing, testing, and checking a package. #' #' @rdname criteria #' @export "is_testthat" #' @details #' `from_wd` uses the current working directory. #' #' @rdname criteria #' @export "from_wd" list_files <- function(path, filename) { files <- dir(path = path, pattern = filename, all.files = TRUE, full.names = TRUE) dirs <- is_dir(files) files <- files[!dirs] files } is_dir <- function(x) { dir.exists(x) } match_contents <- function(f, contents, n) { if (is.null(contents)) { return(TRUE) } fc <- readLines(f, n) any(grepl(contents, fc)) } rprojroot/R/shortcut.R0000644000176200001440000000054513170752070014517 0ustar liggesusers#' @rdname find_root_file #' @export find_rstudio_root_file <- is_rstudio_project$find_file #' @rdname find_root_file #' @export find_package_root_file <- is_r_package$find_file #' @rdname find_root_file #' @export find_remake_root_file <- is_remake_project$find_file #' @rdname find_root_file #' @export find_testthat_root_file <- is_testthat$find_file rprojroot/R/thisfile.R0000644000176200001440000000602413216015313014442 0ustar liggesusers#' @title Determines the path of the currently running script #' @description \R does not store nor export the path of the currently running #' script. This is an attempt to circumvent this limitation by applying #' heuristics (such as call stack and argument inspection) that work in many #' cases. #' **CAVEAT**: Use this function only if your workflow does not permit other #' solution: if a script needs to know its location, it should be set outside #' the context of the script if possible. #' #' @details This functions currently work only if the script was `source`d, #' processed with `knitr`, #' or run with `Rscript` or using the `--file` parameter to the #' `R` executable. For code run with `Rscript`, the exact value #' of the parameter passed to `Rscript` is returned. #' @return The path of the currently running script, NULL if it cannot be #' determined. #' @seealso [base::source()], [utils::Rscript()], [base::getwd()] #' @references [http://stackoverflow.com/q/1815606/946850]() #' @author Kirill Müller, Hadley Wickham, Michael R. Head #' @examples #' \dontrun{thisfile()} #' @export thisfile <- function() { if (!is.null(res <- thisfile_source())) res else if (!is.null(res <- thisfile_r())) res else if (!is.null(res <- thisfile_rscript())) res else if (!is.null(res <- thisfile_knit())) res else NULL } #' @rdname thisfile #' @export thisfile_source <- function() { for (i in -(1:sys.nframe())) { if (identical(args(sys.function(i)), args(base::source))) return (normalizePath(sys.frame(i)$ofile)) } NULL } #' @rdname thisfile #' @importFrom utils tail #' @export thisfile_r <- function() { cmd_args <- commandArgs(trailingOnly = FALSE) if (!grepl("^R(?:|term)(?:|[.]exe)$", basename(cmd_args[[1L]]), ignore.case = TRUE)) return (NULL) cmd_args_trailing <- commandArgs(trailingOnly = TRUE) leading_idx <- seq.int(from=1, length.out=length(cmd_args) - length(cmd_args_trailing)) cmd_args <- cmd_args[leading_idx] file_idx <- c(which(cmd_args == "-f") + 1, which(grepl("^--file=", cmd_args))) res <- gsub("^(?:|--file=)(.*)$", "\\1", cmd_args[file_idx]) # If multiple --file arguments are given, R uses the last one res <- tail(res[res != ""], 1) if (length(res) > 0) return (res) NULL } #' @rdname thisfile #' @importFrom utils tail #' @export thisfile_rscript <- function() { cmd_args <- commandArgs(trailingOnly = FALSE) if (!grepl("^R(?:term|script)(?:|[.]exe)$", basename(cmd_args[[1L]]), ignore.case = TRUE)) return(NULL) cmd_args_trailing <- commandArgs(trailingOnly = TRUE) leading_idx <- seq.int(from=1, length.out=length(cmd_args) - length(cmd_args_trailing)) cmd_args <- cmd_args[leading_idx] res <- gsub("^(?:--file=(.*)|.*)$", "\\1", cmd_args) # If multiple --file arguments are given, R uses the last one res <- tail(res[res != ""], 1) if (length(res) > 0) return (res) NULL } #' @rdname thisfile #' @export thisfile_knit <- function() { if (requireNamespace("knitr")) { return (knitr::current_input(dir = TRUE)) } NULL } rprojroot/R/file.R0000644000176200001440000000211513215575324013563 0ustar liggesusers#' File paths relative to the root of a directory hierarchy #' #' Append an arbitrary number of path components to the root using #' [base::file.path()]. #' #' The `find_root_file()` function is a simple wrapper around #' [find_root()] that #' appends an arbitrary number of path components to the root using #' [base::file.path()]. #' #' @param criterion A criterion, will be coerced using #' [as.root_criterion()] #' @param path The start directory #' @param ... Further path components passed to [file.path()] #' @return The normalized path of the root as specified by the search criteria, #' with the additional path components appended. #' Throws an error if no root is found #' #' @examples #' \dontrun{ #' find_package_root_file("tests", "testthat.R") #' has_file("DESCRIPTION", "^Package: ")$find_file #' has_file("DESCRIPTION", "^Package: ")$make_fix_file(".") #' } #' #' @seealso [find_root()] [utils::glob2rx()] [base::file.path()] #' #' @export find_root_file <- function(..., criterion, path = ".") { root <- find_root(criterion = criterion, path = path) file.path(root, ...) } rprojroot/R/rprojroot-package.R0000644000176200001440000000055113170752070016272 0ustar liggesusers#' @details #' See the "Value" section in [root_criterion()] for documentation #' of root criterion objects, and [criteria()] for useful predefined #' root criteria. #' #' @examples #' criteria #' \dontrun{ #' is_r_package$find_file("NAMESPACE") #' root_fun <- is_r_package$make_fix_file() #' root_fun("NAMESPACE") #' } #' @import backports #' @api "_PACKAGE" rprojroot/R/root.R0000644000176200001440000000461313215575324013634 0ustar liggesusers#' Find the root of a directory hierarchy #' #' A \emph{root} is defined as a directory that contains a regular file #' whose name matches a given pattern and which optionally contains a given text. #' The search for a root starts at a given directory (the working directory #' by default), and proceeds up the directory hierarchy. #' #' Starting from the working directory, the `find_root()` function searches #' for the root. #' If a root is found, the `...` arguments are used to construct a path; #' thus, if no extra arguments are given, the root is returned. #' If no root is found, an error is thrown. #' #' @inheritParams find_root_file #' @return The normalized path of the root as specified by the search criterion. #' Throws an error if no root is found #' #' @examples #' \dontrun{ #' find_root(glob2rx("DESCRIPTION"), "^Package: ") #' } #' #' @seealso [utils::glob2rx()] [file.path()] #' #' @export find_root <- function(criterion, path = ".") { criterion <- as.root_criterion(criterion) start_path <- get_start_path(path, criterion$subdir) path <- start_path for (i in seq_len(.MAX_DEPTH)) { for (f in criterion$testfun) { if (f(path)) { return(path) } } if (is_root(path)) { stop("No root directory found in ", start_path, " or its parent directories. ", paste(format(criterion), collapse = "\n"), call. = FALSE) } path <- dirname(path) } stop("Maximum search of ", .MAX_DEPTH, " exceeded. Last path: ", path) } .MAX_DEPTH <- 100L get_start_path <- function(path, subdirs) { path <- normalizePath(path, winslash = "/", mustWork = TRUE) for (subdir in subdirs) { subdir_path <- file.path(path, subdir) if (dir.exists(subdir_path)) { return(subdir_path) } } path } # Borrowed from devtools is_root <- function(path) { identical(normalizePath(path, winslash = "/"), normalizePath(dirname(path), winslash = "/")) } #' @rdname find_root #' @description `get_root_desc()` returns the description of the criterion #' for a root path. This is especially useful for composite root criteria #' created with [|.root_criterion()]. #' @export get_root_desc <- function(criterion, path) { for (i in seq_along(criterion$testfun)) { if (criterion$testfun[[i]](path)) { return(criterion$desc[[i]]) } } stop("path is not a root. ", paste(format(criterion), collapse = "\n"), call. = FALSE) } rprojroot/R/criterion.R0000644000176200001440000001007313215575324014644 0ustar liggesusers#' Is a directory the project root? #' #' Objects of the `root_criterion` class decide if a #' given directory is a project root. #' #' Construct criteria using `root_criterion` in a very general fashion #' by specifying a function with a `path` argument, and a description. #' #' @param testfun A function with one parameter that returns `TRUE` #' if the directory specified by this parameter is the project root, #' and `FALSE` otherwise. Can also be a list of such functions. #' @param desc A textual description of the test criterion, of the same length #' as `testfun` #' @param subdir Subdirectories to start the search in, if found #' #' @return #' An S3 object of class `root_criterion` wit the following members: #' #' @include rrmake.R #' @export #' #' @examples #' root_criterion(function(path) file.exists(file.path(path, "somefile")), "has somefile") #' has_file("DESCRIPTION") #' is_r_package #' is_r_package$find_file #' \dontrun{ #' is_r_package$make_fix_file(".") #' } root_criterion <- function(testfun, desc, subdir = NULL) { testfun <- check_testfun(testfun) stopifnot(length(desc) == length(testfun)) full_desc <- paste0( desc, if (!is.null(subdir)) paste0( " (also look in subdirectories: ", paste0("`", subdir, "`", collapse = ", "), ")" ) ) criterion <- structure( list( #' @return #' \describe{ #' \item{`testfun`}{The `testfun` argument} testfun = testfun, #' \item{`desc`}{The `desc` argument} desc = full_desc, #' \item{`subdir`}{The `subdir` argument} subdir = subdir ), class = "root_criterion" ) #' \item{`find_file`}{A function with `...` argument that returns #' for a path relative to the root specified by this criterion. #' The optional `path` argument specifies the starting directory, #' which defaults to `"."`. #' } criterion$find_file <- make_find_root_file(criterion) #' \item{`make_fix_file`}{A function with a `path` argument that #' returns a function that finds paths relative to the root. For a #' criterion `cr`, the result of `cr$make_fix_file(".")(...)` #' is identical to `cr$find_file(...)`. The function created by #' `make_fix_file` can be saved to a variable to be more independent #' of the current working directory. #' } #' } criterion$make_fix_file <- function(path = getwd()) make_fix_root_file(criterion, path) criterion } check_testfun <- function(testfun) { if (is.function(testfun)) { testfun <- list(testfun) } for (f in testfun) { if (!isTRUE(all.equal(names(formals(f)), "path"))) { stop("All functions in testfun must have exactly one argument 'path'") } } testfun } #' @rdname root_criterion #' @param x An object #' @export is.root_criterion <- function(x) { inherits(x, "root_criterion") } #' @rdname root_criterion #' @export as.root_criterion <- function(x) UseMethod("as.root_criterion", x) #' @details #' The `as.root_criterion()` function accepts objects of class #' `root_criterion`, and character values; the latter will be #' converted to criteria using `has_file`. #' #' @rdname root_criterion #' @export as.root_criterion.character <- function(x) { has_file(x) } #' @rdname root_criterion #' @export as.root_criterion.root_criterion <- identity #' @export as.root_criterion.default <- function(x) { stop("Cannot coerce ", x, " to type root_criterion.") } #' @export format.root_criterion <- function(x, ...) { if (length(x$desc) > 1) { c("Root criterion: one of", paste0("- ", x$desc)) } else { paste0("Root criterion: ", x$desc) } } #' @export print.root_criterion <- function(x, ...) { cat(format(x), sep = "\n") invisible(x) } #' @export #' @rdname root_criterion #' @details Root criteria can be combined with the `|` operator. The result is a #' composite root criterion that requires either of the original criteria to #' match. #' @param y An object `|.root_criterion` <- function(x, y) { stopifnot(is.root_criterion(y)) root_criterion( c(x$testfun, y$testfun), c(x$desc, y$desc) ) } rprojroot/R/rrmake.R0000644000176200001440000000053313037124543014122 0ustar liggesusersmake_find_root_file <- function(criterion) { force(criterion) eval(bquote(function(..., path = ".") { find_root_file(..., criterion = criterion, path = path) })) } make_fix_root_file <- function(criterion, path) { root <- find_root(criterion = criterion, path = path) eval(bquote(function(...) { file.path(.(root), ...) })) } rprojroot/vignettes/0000755000176200001440000000000013223155063014322 5ustar liggesusersrprojroot/vignettes/rprojroot.Rmd0000644000176200001440000003233313215575324017041 0ustar liggesusers--- title: "Finding files in project subdirectories" author: "Kirill Müller" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Finding files in project subdirectories} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- The *rprojroot* package solves a seemingly trivial but annoying problem that occurs sooner or later in any largish project: How to find files in subdirectories? Ideally, file paths are relative to the *project root*. Unfortunately, we cannot always be sure about the current working directory: For instance, in RStudio it's sometimes: - the project root (when running R scripts), - a subdirectory (when building vignettes), - again the project root (when executing chunks of a vignette). ```{r} basename(getwd()) ``` In some cases, it's even outside the project root. This vignette starts with a very brief summary that helps you get started, followed by a longer description of the features. ## TL;DR What is your project: An R package? ```{r} rprojroot::is_r_package ``` Or an RStudio project? ```{r} rprojroot::is_rstudio_project ``` Or something else? ```{r} rprojroot::has_file(".git/index") ``` For now, we assume it's an R package: ```{r} root <- rprojroot::is_r_package ``` The `root` object contains a function that helps locating files below the root of your package, regardless of your current working directory. If you are sure that your working directory is somewhere below your project's root, use the `root$find_file()` function: ```{r} readLines(root$find_file("DESCRIPTION"), 3) ``` You can also construct an accessor to your root using the `root$make_fix_file()` function: ```{r} root_file <- root$make_fix_file() ``` Note that `root_file()` is a *function* that works just like `$find_file()` but will find the files even if the current working directory is outside your project: ```{r} withr::with_dir( "../..", readLines(root_file("DESCRIPTION"), 3) ) ``` If you know the absolute path of some directory below your project, but cannot be sure of your current working directory, pass that absolute path to `root$make_fix_file()`: ```r root_file <- root$make_fix_file("C:\\Users\\User Name\\...") ``` As a last resort, you can get the path of standalone R scripts or vignettes using the `thisfile()` function: ```r root_file <- root$make_fix_file(dirname(thisfile())) ``` The remainder of this vignette describes implementation details and advanced features. ## Project root We assume a self-contained project where all files and directories are located below a common *root* directory. Also, there should be a way to unambiguously identify this root directory. (Often, the root contains a regular file whose name matches a given pattern, and/or whose contents match another pattern.) In this case, the following method reliably finds our project root: - Start the search in any subdirectory of our project - Proceed up the directory hierarchy until the root directory has been identified The Git version control system (and probably many other tools) use a similar approach: A Git command can be executed from within any subdirectory of a repository. ### A simple example The `find_root()` function implements the core functionality. It returns the path to the first directory that matches the filtering criteria, or throws an error if there is no such directory. Filtering criteria are constructed in a generic fashion using the `root_criterion()` function, the `has_file()` function constructs a criterion that checks for the presence of a file with a specific name and specific contents. ```{r} library(rprojroot) # List all files and directories below the root dir(find_root(has_file("DESCRIPTION"))) ``` #### Relative paths to a stable root Here we illustrate the power of *rprojroot* by demonstrating how to access the same file from two different working directories. Let your project be a package called `pkgname` and consider the desired file `rrmake.R` at `pkgname/R/rrmake.R`. First, we show how to access from the `vignettes` directory, and then from the `tests/testthat` directory. ##### Example A: From `vignettes` When your working directory is `pkgname/vignettes`, you can access the `rrmake.R` file by: 1. Supplying a pathname relative to your working directory. Here's two ways to do that: ```{r, eval = FALSE} rel_path_from_vignettes <- "../R/rrmake.R" rel_path_from_vignettes <- file.path("..", "R", "rrmake.R") ##identical ``` 2. Supplying a pathname to the file relative from the root of the package, e.g., ```{r, eval = FALSE} rel_path_from_root <- "R/rrmake.R" rel_path_from_root <- file.path("R", "rrmake.R") ##identical ``` This second method requires finding the root of the package, which can be done with the `has_file()` function: ```{r} has_file("DESCRIPTION") ``` So, using *rprojroot* you can specify the path relative from root in the following manner: ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ``` ##### Example B: From `tests/testthat` When your working directory is `pkgname/tests/testthat`, you can access the `rrmake.R` file by: 1. Supplying a pathname relative to your working directory. ```{r, eval = FALSE} rel_path_from_testthat <- "../../R/rrmake.R" ``` Note that this is different than in the previous example! However, the second method is the same... 2. Supplying a pathname to the file relative from the root of the package. With *rprojroot*, this is the exact same as in the previous example. ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) ``` ##### Summary of Examples A and B Since Examples A and B used different working directories, `rel_path_from_vignettes` and `rel_path_from_testthat` were different. This is an issue when trying to re-use the same code. This issue is solved by using *rprojroot*: the function `find_root_file()` finds a file relative from the root, where the root is determined from checking the criterion with `has_file()`. Note that the follow code produces identical results when building the vignette *and* when sourcing the chunk in RStudio, provided that the current working directory is the project root or anywhere below. So, we can check to make sure that *rprojroot* has succesfully determined the correct path: ```{r} # Specify a path/to/file relative to the root rel_path_from_root <- find_root_file("R", "rrmake.R", criterion = has_file("DESCRIPTION")) # Find a file relative to the root file.exists(rel_path_from_root) ``` ### Criteria The `has_file()` function (and the more general `root_criterion()`) both return an S3 object of class `root_criterion`: ```{r} has_file("DESCRIPTION") ``` In addition, character values are coerced to `has_file` criteria by default, this coercion is applied automatically by `find_root()`. (This feature is used by the introductory example.) ```{r} as.root_criterion("DESCRIPTION") ``` The return value of these functions can be stored and reused; in fact, the package provides `r length(criteria)` such criteria: ```{r} criteria ``` Defining new criteria is easy: ```{r} has_license <- has_file("LICENSE") has_license is_projecttemplate_project <- has_file("config/global.dcf", "^version: ") is_projecttemplate_project ``` You can also combine criteria via the `|` operator: ```{r} is_r_package | is_rstudio_project ``` ### Shortcuts To avoid specifying the search criteria for the project root every time, shortcut functions can be created. The `find_package_root_file()` is a shortcut for `find_root_file(..., criterion = is_r_package)`: ```{r} # Print first lines of the source for this document head(readLines(find_package_root_file("vignettes", "rprojroot.Rmd"))) ``` To save typing effort, define a shorter alias: ```{r} P <- find_package_root_file # Use a shorter alias file.exists(P("vignettes", "rprojroot.Rmd")) ``` Each criterion actually contains a function that allows finding a file below the root specified by this criterion. As our project does not have a file named `LICENSE`, querying the root results in an error: ```{r error = TRUE} # Use the has_license criterion to find the root R <- has_license$find_file R # Our package does not have a LICENSE file, trying to find the root results in an error R() ``` ### Fixed root We can also create a function that computes a path relative to the root *at creation time*. ```{r} # Define a function that computes file paths below the current root F <- is_r_package$make_fix_file() F # Show contents of the NAMESPACE file in our project readLines(F("NAMESPACE")) ``` This is a more robust alternative to `$find_file()`, because it *fixes* the project directory when `$make_fix_file()` is called, instead of searching for it every time. (For that reason it is also slightly faster, but I doubt this matters in practice.) This function can be used even if we later change the working directory to somewhere outside the project: ```{r} # Print the size of the namespace file, working directory outside the project withr::with_dir( "../..", file.size(F("NAMESPACE")) ) ``` The `make_fix_file()` member function also accepts an optional `path` argument, in case you know your project's root but the current working directory is somewhere outside. The path to the current script or `knitr` document can be obtained using the `thisfile()` function, but it's much easier and much more robust to just run your scripts with the working directory somewhere below your project root. ## `testthat` files Tests run with [`testthat`](https://cran.r-project.org/package=testthat) commonly use files that live below the `tests/testthat` directory. Ideally, this should work in the following situation: - During package development (working directory: package root) - When testing with `devtools::test()` (working directory: `tests/testthat`) - When running `R CMD check` (working directory: a renamed recursive copy of `tests`) The `is_testthat` criterion allows robust lookup of test files. ```{r} is_testthat ``` The example code below lists all files in the [hierarchy](https://github.com/krlmlr/rprojroot/tree/master/tests/testthat/hierarchy) test directory. It uses two project root lookups in total, so that it also works when rendering the vignette (*sigh*): ```{r} dir(is_testthat$find_file("hierarchy", path = is_r_package$find_file())) ``` ### Another example: custom testing utilities The hassle of using saved data files for testing is made even easier by using *rprojroot* in a utility function. For example, suppose you have a testing file at `tests/testthat/test_my_fun.R` which tests the `my_fun()` function: ```{r, eval = FALSE} my_fun_run <- do.call(my_fun, my_args) testthat::test_that( "my_fun() returns expected output", testthat::expect_equal( my_fun_run, expected_output ) ) ``` There are two pieces of information that you'll need every time `test_my_fun.R` is run: `my_args` and `expected_output`. Typically, these objects are saved to `.Rdata` files and saved to the same subdirectory. For example, you could save them to `my_args.Rdata` and `expected_output.Rdata` under the `tests/testthat/testing_data` subdirectory. And, to find them easily in any contexts, you can use *rprojroot*! Since all of the data files live in the same subdirectory, you can create a utility function `get_my_path()` that will always look in that directory for these types of files. And, since the *testthat* package will look for and source the `tests/testthat/helper.R` file before running any tests, you can place a `get_my_path()` in this file and use it throughout your tests: ```{r, eval = FALSE} ## saved to tests/testthat/helper.R get_my_path <- function(file_name) { rprojroot::find_testthat_root_file( "testing_data", filename ) } ``` Now you can ask `get_my_path()` to find your important data files by using the function within your test scripts! ```{r, eval = FALSE} ## Find the correct path with your custom rprojroot helper function path_to_my_args_file <- get_my_path("my_args.Rdata") ## Load the input arguments load(file = path_to_my_args_file) ## Run the function with those arguments my_fun_run <- do.call(my_fun,my_args) ## Load the historical expectation with the helper load(file = get_my_path("expected_output.Rdata")) ## Pass all tests and achieve nirvana testthat::test_that( "my_fun() returns expected output", testthat::expect_equal( my_fun_run, expected_output ) ) ``` For an example in the wild, see the [`test_sheet()` function](https://github.com/tidyverse/readxl/blob/0d9ad4f570f6580ff716e0e9ba5048447048e9f0/tests/testthat/helper.R#L1-L3) in the *readxl* package. ## Summary The *rprojroot* package allows easy access to files below a project root if the project root can be identified easily, e.g. if it is the only directory in the whole hierarchy that contains a specific file. This is a robust solution for finding files in largish projects with a subdirectory hierarchy if the current working directory cannot be assumed fixed. (However, at least initially, the current working directory must be somewhere below the project root.) ## Acknowledgement This package was inspired by the gist ["Stop the working directory insanity"](https://gist.github.com/jennybc/362f52446fe1ebc4c49f) by Jennifer Bryan, and by the way Git knows where its files are. rprojroot/MD50000644000176200001440000000512113223174170012621 0ustar liggesusersd0b3abe3383fbe1f56462195b14233a2 *DESCRIPTION df6dc7704eb1557c3f1aa6ab378d7b83 *NAMESPACE 11c6882f2f6e7567029434d2a555608b *NEWS.md 68cbd2cce6bbda071f1279dd350f66fc *R/criterion.R 7144083716912088331ca9488db40c63 *R/file.R 5b7e4b29d509c702d2f625f8d7ac7d17 *R/has-file.R 05b6a4f0f6bd67e4ed61a516033fb677 *R/root.R 0688a81a507c7639e2b2cec0edad2dbf *R/rprojroot-package.R dd227290335dea57e2a1031a5b5beb35 *R/rrmake.R 4de9a9bbf48372e1505dd1550bee0418 *R/shortcut.R fa8799827f070a4fe1632f606c876f70 *R/thisfile.R 521e2e3e8ce08f8e9186d76a6c8d1324 *build/vignette.rds 9513fbabdcab89737e27a52092b3b66f *inst/doc/rprojroot.R 57960a65eb4df41bfabc23f3e3bb4f5f *inst/doc/rprojroot.Rmd 319f6bd51fe92f18e7310b416db7c21a *inst/doc/rprojroot.html 6a14df38876e8de0b3a24e689aa98cf7 *man/criteria.Rd 5256c80494573721ce5baa623ba0906d *man/find_root.Rd 3697cb7d1313279aac3b0abdda1f1a28 *man/find_root_file.Rd 96f94ac13cabb29dc4399de5702bbc70 *man/root_criterion.Rd a7d033b76a25c7abfb137de00b3da294 *man/rprojroot-package.Rd 9fb39ae7ae2d3b958f7eb6623ba04c0e *man/thisfile.Rd 1d802d92f687ffbb11ee26ae68396d94 *tests/testthat.R 3e6320af0b5c1a4ab2bc220759c31553 *tests/testthat/hierarchy/DESCRIPTION d41d8cd98f00b204e9800998ecf8427e *tests/testthat/hierarchy/a/b/a b16de7308a1f8d6f4f98b1a558ea957d *tests/testthat/hierarchy/a/b/b d41d8cd98f00b204e9800998ecf8427e *tests/testthat/hierarchy/a/b/c/d d41d8cd98f00b204e9800998ecf8427e *tests/testthat/hierarchy/a/remake.yml 55e116ea754236d78e4e6342adbe3661 *tests/testthat/hierarchy/b d41d8cd98f00b204e9800998ecf8427e *tests/testthat/hierarchy/c 3936ed002c1dd1fa5dc7a13d99d5df86 *tests/testthat/hierarchy/hierarchy.Rproj d41d8cd98f00b204e9800998ecf8427e *tests/testthat/package/DESCRIPTION d41d8cd98f00b204e9800998ecf8427e *tests/testthat/package/tests/testthat.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/package/tests/testthat/test-something.R f66f033a6ae6f3edfbc2b234a70031da *tests/testthat/scripts/thisfile-cat.R 1842225c060e51ad4fd7a44cf6dc2c68 *tests/testthat/scripts/thisfile.R b4eea69f30e5e903f792b50357b04e40 *tests/testthat/scripts/thisfile.Rmd d41d8cd98f00b204e9800998ecf8427e *tests/testthat/startup.Rs 42d75002ec598f586b253378d63092d8 *tests/testthat/test-criterion.R ce3ca96d5d38e1c0972d639a81f659c1 *tests/testthat/test-make.R 8bfd90319b3d590a0fdb99edbdefa703 *tests/testthat/test-root.R ec33c4973b9fac9b680322d60d6807ac *tests/testthat/test-testthat.R e2b585b214585bd7391e0b94fcd7eb3a *tests/testthat/test-thisfile.R d8879d25ee21b0f84992020d95500aaf *tests/testthat/vcs/git.zip 28e9555632b66c264d026cd065dda0db *tests/testthat/vcs/svn.zip 57960a65eb4df41bfabc23f3e3bb4f5f *vignettes/rprojroot.Rmd rprojroot/build/0000755000176200001440000000000013223155063013411 5ustar liggesusersrprojroot/build/vignette.rds0000644000176200001440000000034113223155063015746 0ustar liggesusersmQ0  `Lxnx ŋ!":3ěO.av}m L-L ) 7 +K)RъۈqXN+qTDLHF+"תD{>0@g<)&!-)'?h4rGﵐ=gw+S އQäh[:5o< 4`4O*]C~ 5rprojroot/DESCRIPTION0000644000176200001440000000205413223174170014021 0ustar liggesusersPackage: rprojroot Title: Finding Files in Project Subdirectories Version: 1.3-2 Authors@R: person(given = "Kirill", family = "Müller", role = c("aut", "cre"), email = "krlmlr+r@mailbox.org") Description: Robust, reliable and flexible paths to files below a project root. The 'root' of a project is defined as a directory that matches a certain criterion, e.g., it contains a certain regular file. Depends: R (>= 3.0.0) Imports: backports Suggests: testthat, mockr, knitr, withr, rmarkdown VignetteBuilder: knitr License: GPL-3 LazyData: true Encoding: UTF-8 URL: https://github.com/krlmlr/rprojroot, https://krlmlr.github.io/rprojroot BugReports: https://github.com/krlmlr/rprojroot/issues RoxygenNote: 6.0.1 Collate: 'rrmake.R' 'criterion.R' 'file.R' 'has-file.R' 'root.R' 'rprojroot-package.R' 'shortcut.R' 'thisfile.R' NeedsCompilation: no Packaged: 2018-01-03 13:27:15 UTC; muelleki Author: Kirill Müller [aut, cre] Maintainer: Kirill Müller Repository: CRAN Date/Publication: 2018-01-03 15:36:24 UTC rprojroot/man/0000755000176200001440000000000013215575324013074 5ustar liggesusersrprojroot/man/find_root.Rd0000644000176200001440000000270713215575324015354 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/root.R \name{find_root} \alias{find_root} \alias{get_root_desc} \title{Find the root of a directory hierarchy} \usage{ find_root(criterion, path = ".") get_root_desc(criterion, path) } \arguments{ \item{criterion}{A criterion, will be coerced using \code{\link[=as.root_criterion]{as.root_criterion()}}} \item{path}{The start directory} } \value{ The normalized path of the root as specified by the search criterion. Throws an error if no root is found } \description{ A \emph{root} is defined as a directory that contains a regular file whose name matches a given pattern and which optionally contains a given text. The search for a root starts at a given directory (the working directory by default), and proceeds up the directory hierarchy. \code{get_root_desc()} returns the description of the criterion for a root path. This is especially useful for composite root criteria created with \code{\link[=|.root_criterion]{|.root_criterion()}}. } \details{ Starting from the working directory, the \code{find_root()} function searches for the root. If a root is found, the \code{...} arguments are used to construct a path; thus, if no extra arguments are given, the root is returned. If no root is found, an error is thrown. } \examples{ \dontrun{ find_root(glob2rx("DESCRIPTION"), "^Package: ") } } \seealso{ \code{\link[utils:glob2rx]{utils::glob2rx()}} \code{\link[=file.path]{file.path()}} } rprojroot/man/find_root_file.Rd0000644000176200001440000000314213215575324016345 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R, R/shortcut.R \name{find_root_file} \alias{find_root_file} \alias{find_rstudio_root_file} \alias{find_package_root_file} \alias{find_remake_root_file} \alias{find_testthat_root_file} \title{File paths relative to the root of a directory hierarchy} \usage{ find_root_file(..., criterion, path = ".") find_rstudio_root_file(..., path = ".") find_package_root_file(..., path = ".") find_remake_root_file(..., path = ".") find_testthat_root_file(..., path = ".") } \arguments{ \item{...}{Further path components passed to \code{\link[=file.path]{file.path()}}} \item{criterion}{A criterion, will be coerced using \code{\link[=as.root_criterion]{as.root_criterion()}}} \item{path}{The start directory} } \value{ The normalized path of the root as specified by the search criteria, with the additional path components appended. Throws an error if no root is found } \description{ Append an arbitrary number of path components to the root using \code{\link[base:file.path]{base::file.path()}}. } \details{ The \code{find_root_file()} function is a simple wrapper around \code{\link[=find_root]{find_root()}} that appends an arbitrary number of path components to the root using \code{\link[base:file.path]{base::file.path()}}. } \examples{ \dontrun{ find_package_root_file("tests", "testthat.R") has_file("DESCRIPTION", "^Package: ")$find_file has_file("DESCRIPTION", "^Package: ")$make_fix_file(".") } } \seealso{ \code{\link[=find_root]{find_root()}} \code{\link[utils:glob2rx]{utils::glob2rx()}} \code{\link[base:file.path]{base::file.path()}} } rprojroot/man/criteria.Rd0000644000176200001440000000247713170752070015172 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/has-file.R \docType{data} \name{criteria} \alias{criteria} \alias{is_rstudio_project} \alias{is_r_package} \alias{is_remake_project} \alias{is_projectile_project} \alias{is_git_root} \alias{is_svn_root} \alias{is_vcs_root} \alias{is_testthat} \alias{from_wd} \title{Prespecified criteria} \format{An object of class \code{root_criteria} of length 9.} \usage{ criteria is_rstudio_project is_r_package is_remake_project is_projectile_project is_git_root is_svn_root is_vcs_root is_testthat from_wd } \description{ This is a collection of commonly used root criteria. } \details{ \code{is_rstudio_project} looks for a file with extension \code{.Rproj}. \code{is_r_package} looks for a \code{DESCRIPTION} file. \code{is_remake_project} looks for a \code{remake.yml} file. \code{is_projectile_project} looks for a \code{.projectile} file. \code{is_git_project} looks for a \code{.git} directory. \code{is_svn_project} looks for a \code{.svn} directory. \code{is_vcs_project} looks for the root of a version control system, currently only Git and SVN are supported. \code{is_testthat} looks for the \code{testthat} directory, works when developing, testing, and checking a package. \code{from_wd} uses the current working directory. } \keyword{datasets} rprojroot/man/root_criterion.Rd0000644000176200001440000000740513215575324016432 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/criterion.R, R/has-file.R \name{root_criterion} \alias{root_criterion} \alias{is.root_criterion} \alias{as.root_criterion} \alias{as.root_criterion.character} \alias{as.root_criterion.root_criterion} \alias{|.root_criterion} \alias{has_file} \alias{has_dir} \alias{has_file_pattern} \alias{has_dirname} \title{Is a directory the project root?} \usage{ root_criterion(testfun, desc, subdir = NULL) is.root_criterion(x) as.root_criterion(x) \method{as.root_criterion}{character}(x) \method{as.root_criterion}{root_criterion}(x) \method{|}{root_criterion}(x, y) has_file(filepath, contents = NULL, n = -1L) has_dir(filepath) has_file_pattern(pattern, contents = NULL, n = -1L) has_dirname(dirname, subdir = NULL) } \arguments{ \item{testfun}{A function with one parameter that returns \code{TRUE} if the directory specified by this parameter is the project root, and \code{FALSE} otherwise. Can also be a list of such functions.} \item{desc}{A textual description of the test criterion, of the same length as \code{testfun}} \item{subdir}{Subdirectories to start the search in, if found} \item{x}{An object} \item{y}{An object} \item{filepath}{File path (can contain directories)} \item{contents}{Regular expression to match the file contents} \item{n}{integer. The (maximal) number of lines to read. Negative values indicate that one should read up to the end of input on the connection.} \item{pattern}{Regular expression to match the file name} \item{dirname}{A directory name, without subdirectories} } \value{ An S3 object of class \code{root_criterion} wit the following members: \describe{ \item{\code{testfun}}{The \code{testfun} argument} \item{\code{desc}}{The \code{desc} argument} \item{\code{subdir}}{The \code{subdir} argument} \item{\code{find_file}}{A function with \code{...} argument that returns for a path relative to the root specified by this criterion. The optional \code{path} argument specifies the starting directory, which defaults to \code{"."}. } \item{\code{make_fix_file}}{A function with a \code{path} argument that returns a function that finds paths relative to the root. For a criterion \code{cr}, the result of \code{cr$make_fix_file(".")(...)} is identical to \code{cr$find_file(...)}. The function created by \code{make_fix_file} can be saved to a variable to be more independent of the current working directory. } } } \description{ Objects of the \code{root_criterion} class decide if a given directory is a project root. } \details{ Construct criteria using \code{root_criterion} in a very general fashion by specifying a function with a \code{path} argument, and a description. The \code{as.root_criterion()} function accepts objects of class \code{root_criterion}, and character values; the latter will be converted to criteria using \code{has_file}. Root criteria can be combined with the \code{|} operator. The result is a composite root criterion that requires either of the original criteria to match. The \code{has_file()} function constructs a criterion that checks for the existence of a specific file (which itself can be in a subdirectory of the root) with specific contents. The \code{has_dir()} function constructs a criterion that checks for the existence of a specific directory. The \code{has_file_pattern()} function constructs a criterion that checks for the existence of a file that matches a pattern, with specific contents. The \code{has_dirname()} function constructs a criterion that checks if the \code{\link[base:dirname]{base::dirname()}} has a specific name. } \examples{ root_criterion(function(path) file.exists(file.path(path, "somefile")), "has somefile") has_file("DESCRIPTION") is_r_package is_r_package$find_file \dontrun{ is_r_package$make_fix_file(".") } } rprojroot/man/thisfile.Rd0000644000176200001440000000270513215575324015176 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/thisfile.R \name{thisfile} \alias{thisfile} \alias{thisfile_source} \alias{thisfile_r} \alias{thisfile_rscript} \alias{thisfile_knit} \title{Determines the path of the currently running script} \usage{ thisfile() thisfile_source() thisfile_r() thisfile_rscript() thisfile_knit() } \value{ The path of the currently running script, NULL if it cannot be determined. } \description{ \R does not store nor export the path of the currently running script. This is an attempt to circumvent this limitation by applying heuristics (such as call stack and argument inspection) that work in many cases. \strong{CAVEAT}: Use this function only if your workflow does not permit other solution: if a script needs to know its location, it should be set outside the context of the script if possible. } \details{ This functions currently work only if the script was \code{source}d, processed with \code{knitr}, or run with \code{Rscript} or using the \code{--file} parameter to the \code{R} executable. For code run with \code{Rscript}, the exact value of the parameter passed to \code{Rscript} is returned. } \examples{ \dontrun{thisfile()} } \references{ \url{http://stackoverflow.com/q/1815606/946850} } \seealso{ \code{\link[base:source]{base::source()}}, \code{\link[utils:Rscript]{utils::Rscript()}}, \code{\link[base:getwd]{base::getwd()}} } \author{ Kirill Müller, Hadley Wickham, Michael R. Head } rprojroot/man/rprojroot-package.Rd0000644000176200001440000000207313170752070017011 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rprojroot-package.R \docType{package} \name{rprojroot-package} \alias{rprojroot} \alias{rprojroot-package} \title{rprojroot: Finding Files in Project Subdirectories} \description{ Robust, reliable and flexible paths to files below a project root. The 'root' of a project is defined as a directory that matches a certain criterion, e.g., it contains a certain regular file. } \details{ See the "Value" section in \code{\link[=root_criterion]{root_criterion()}} for documentation of root criterion objects, and \code{\link[=criteria]{criteria()}} for useful predefined root criteria. } \examples{ criteria \dontrun{ is_r_package$find_file("NAMESPACE") root_fun <- is_r_package$make_fix_file() root_fun("NAMESPACE") } } \seealso{ Useful links: \itemize{ \item \url{https://github.com/krlmlr/rprojroot} \item \url{https://krlmlr.github.io/rprojroot} \item Report bugs at \url{https://github.com/krlmlr/rprojroot/issues} } } \author{ \strong{Maintainer}: Kirill Müller \email{krlmlr+r@mailbox.org} }