This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-rprojroot.

commit f0ff916eba451d3fde04d83c58c89e26be7c696d
Author: Andreas Tille <[email protected]>
Date:   Mon Oct 2 00:10:34 2017 +0200

    New upstream version 1.2
---
 DESCRIPTION                                        |  28 ++
 MD5                                                |  38 +++
 NAMESPACE                                          |  35 +++
 NEWS.md                                            |  71 +++++
 R/criterion.R                                      | 151 ++++++++++
 R/file.R                                           |  32 ++
 R/has-file.R                                       | 249 ++++++++++++++++
 R/root.R                                           |  85 ++++++
 R/rprojroot-package.R                              |  15 +
 R/rrmake.R                                         |  13 +
 R/shortcut.R                                       |  15 +
 build/vignette.rds                                 | Bin 0 -> 225 bytes
 inst/doc/rprojroot.R                               |  94 ++++++
 inst/doc/rprojroot.Rmd                             | 301 +++++++++++++++++++
 inst/doc/rprojroot.html                            | 331 +++++++++++++++++++++
 man/criteria.Rd                                    |  62 ++++
 man/find_root.Rd                                   |  47 +++
 man/find_root_file.Rd                              |  54 ++++
 man/root_criterion.Rd                              | 120 ++++++++
 man/rprojroot-package.Rd                           |  39 +++
 tests/testthat.R                                   |   4 +
 tests/testthat/hierarchy/DESCRIPTION               |   9 +
 tests/testthat/hierarchy/a/b/a                     |   0
 tests/testthat/hierarchy/a/b/b                     |   1 +
 tests/testthat/hierarchy/a/b/c/d                   |   0
 tests/testthat/hierarchy/a/remake.yml              |   0
 tests/testthat/hierarchy/b                         |   1 +
 tests/testthat/hierarchy/c                         |   0
 tests/testthat/hierarchy/hierarchy.Rproj           |  21 ++
 tests/testthat/package/DESCRIPTION                 |   0
 tests/testthat/package/tests/testthat.R            |   0
 .../package/tests/testthat/test-something.R        |   0
 tests/testthat/test-criterion.R                    |  49 +++
 tests/testthat/test-make.R                         |  13 +
 tests/testthat/test-root.R                         | 197 ++++++++++++
 tests/testthat/test-testthat.R                     |  17 ++
 tests/testthat/vcs/git.zip                         | Bin 0 -> 22155 bytes
 tests/testthat/vcs/svn.zip                         | Bin 0 -> 10116 bytes
 vignettes/rprojroot.Rmd                            | 301 +++++++++++++++++++
 39 files changed, 2393 insertions(+)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..52b5a95
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,28 @@
+Package: rprojroot
+Title: Finding Files in Project Subdirectories
+Version: 1.2
+Authors@R: person(given = "Kirill", family = "Müller", role = c("aut",
+        "cre"), email = "[email protected]")
+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, 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: 5.0.1.9000
+Collate: 'rrmake.R' 'criterion.R' 'file.R' 'has-file.R' 'root.R'
+        'rprojroot-package.R' 'shortcut.R'
+NeedsCompilation: no
+Packaged: 2017-01-16 11:50:23 UTC; muelleki
+Author: Kirill Müller [aut, cre]
+Maintainer: Kirill Müller <[email protected]>
+Repository: CRAN
+Date/Publication: 2017-01-16 14:16:04
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..c64e4b3
--- /dev/null
+++ b/MD5
@@ -0,0 +1,38 @@
+09fc8e111b014442f6569ac39cfff43f *DESCRIPTION
+04765b617541cee07297676a210d25d3 *NAMESPACE
+2d0469a219c83ed66c4e2695d4ff2d1c *NEWS.md
+da5b8d6d5d1ea8a0aa1c4a1cfed314ff *R/criterion.R
+3283d4a6f17606ad0193bace804ed012 *R/file.R
+1050ecdd048dce13bbf81615de85489f *R/has-file.R
+d87a8501549770bd80068475e78671fe *R/root.R
+0688a81a507c7639e2b2cec0edad2dbf *R/rprojroot-package.R
+dd227290335dea57e2a1031a5b5beb35 *R/rrmake.R
+4de9a9bbf48372e1505dd1550bee0418 *R/shortcut.R
+0415d9530ea3a983814164d735e5db9e *build/vignette.rds
+0634afa63b0e9c96760bcdce54655942 *inst/doc/rprojroot.R
+7855fbb459b9e137bc458294b20db80c *inst/doc/rprojroot.Rmd
+9e32800aeeef65fcddc218dcaa367682 *inst/doc/rprojroot.html
+6a14df38876e8de0b3a24e689aa98cf7 *man/criteria.Rd
+df64533edc92ee73830a13070b418d54 *man/find_root.Rd
+5accd629c3b4aa22c6a484b2a52ed0a2 *man/find_root_file.Rd
+4a89be5e4f191328f2a7e8b6f31a8ba6 *man/root_criterion.Rd
+a7d033b76a25c7abfb137de00b3da294 *man/rprojroot-package.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
+06e74a052aa3a2ab9a51a5135802a55b *tests/testthat/test-criterion.R
+ce3ca96d5d38e1c0972d639a81f659c1 *tests/testthat/test-make.R
+006eb32f50098d057c0a9cfb6ac4d0ba *tests/testthat/test-root.R
+ec33c4973b9fac9b680322d60d6807ac *tests/testthat/test-testthat.R
+d8879d25ee21b0f84992020d95500aaf *tests/testthat/vcs/git.zip
+28e9555632b66c264d026cd065dda0db *tests/testthat/vcs/svn.zip
+7855fbb459b9e137bc458294b20db80c *vignettes/rprojroot.Rmd
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..9dafdaf
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,35 @@
+# 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)
+import(backports)
+importFrom(utils,str)
diff --git a/NEWS.md b/NEWS.md
new file mode 100644
index 0000000..18da147
--- /dev/null
+++ b/NEWS.md
@@ -0,0 +1,71 @@
+# 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
diff --git a/R/criterion.R b/R/criterion.R
new file mode 100644
index 0000000..35dd60c
--- /dev/null
+++ b/R/criterion.R
@@ -0,0 +1,151 @@
+#' 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)
+  )
+}
diff --git a/R/file.R b/R/file.R
new file mode 100644
index 0000000..45ad46f
--- /dev/null
+++ b/R/file.R
@@ -0,0 +1,32 @@
+#' 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, ...)
+}
diff --git a/R/has-file.R b/R/has-file.R
new file mode 100644
index 0000000..a03251c
--- /dev/null
+++ b/R/has-file.R
@@ -0,0 +1,249 @@
+format_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")
+
+#' @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))
+}
diff --git a/R/root.R b/R/root.R
new file mode 100644
index 0000000..4ab40ff
--- /dev/null
+++ b/R/root.R
@@ -0,0 +1,85 @@
+#' 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)
+}
diff --git a/R/rprojroot-package.R b/R/rprojroot-package.R
new file mode 100644
index 0000000..d427a00
--- /dev/null
+++ b/R/rprojroot-package.R
@@ -0,0 +1,15 @@
+#' @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"
diff --git a/R/rrmake.R b/R/rrmake.R
new file mode 100644
index 0000000..127725f
--- /dev/null
+++ b/R/rrmake.R
@@ -0,0 +1,13 @@
+make_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), ...)
+  }))
+}
diff --git a/R/shortcut.R b/R/shortcut.R
new file mode 100644
index 0000000..8cdb366
--- /dev/null
+++ b/R/shortcut.R
@@ -0,0 +1,15 @@
+#' @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
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..2349dfe
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/inst/doc/rprojroot.R b/inst/doc/rprojroot.R
new file mode 100644
index 0000000..056fb77
--- /dev/null
+++ b/inst/doc/rprojroot.R
@@ -0,0 +1,94 @@
+## ------------------------------------------------------------------------
+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")))
+
+# Find a file relative to the root
+file.exists(find_root_file("R", "root.R", criterion = has_file("DESCRIPTION")))
+
+## ------------------------------------------------------------------------
+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()))
+
diff --git a/inst/doc/rprojroot.Rmd b/inst/doc/rprojroot.Rmd
new file mode 100644
index 0000000..28d725d
--- /dev/null
+++ b/inst/doc/rprojroot.Rmd
@@ -0,0 +1,301 @@
+---
+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\\...")
+```
+
+Get the path of standalone R scripts or vignettes
+using the `thisfile()` function in the `kimisc` package:
+
+```r
+root_file <- root$make_fix_file(dirname(kimisc::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")))
+
+# Find a file relative to the root
+file.exists(find_root_file("R", "root.R", criterion = has_file("DESCRIPTION")))
+```
+
+Note that the following 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.
+
+
+### 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.
+Take a look at the `thisfile()` function in the `kimisc` package for getting
+the path to the current script or `knitr` document.
+
+
+## `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()))
+```
+
+
+## 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.
diff --git a/inst/doc/rprojroot.html b/inst/doc/rprojroot.html
new file mode 100644
index 0000000..997af2d
--- /dev/null
+++ b/inst/doc/rprojroot.html
@@ -0,0 +1,331 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml";>
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<meta name="author" content="Kirill Müller" />
+
+<meta name="date" content="2017-01-16" />
+
+<title>Finding files in project subdirectories</title>
+
+
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+div.sourceCode { overflow-x: auto; }
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+  margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; line-height: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; 
color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code > span.dt { color: #902000; } /* DataType */
+code > span.dv { color: #40a070; } /* DecVal */
+code > span.bn { color: #40a070; } /* BaseN */
+code > span.fl { color: #40a070; } /* Float */
+code > span.ch { color: #4070a0; } /* Char */
+code > span.st { color: #4070a0; } /* String */
+code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code > span.ot { color: #007020; } /* Other */
+code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code > span.fu { color: #06287e; } /* Function */
+code > span.er { color: #ff0000; font-weight: bold; } /* Error */
+code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* 
Warning */
+code > span.cn { color: #880000; } /* Constant */
+code > span.sc { color: #4070a0; } /* SpecialChar */
+code > span.vs { color: #4070a0; } /* VerbatimString */
+code > span.ss { color: #bb6688; } /* SpecialString */
+code > span.im { } /* Import */
+code > span.va { color: #19177c; } /* Variable */
+code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code > span.op { color: #666666; } /* Operator */
+code > span.bu { } /* BuiltIn */
+code > span.ex { } /* Extension */
+code > span.pp { color: #bc7a00; } /* Preprocessor */
+code > span.at { color: #7d9029; } /* Attribute */
+code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* 
Annotation */
+code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* 
CommentVar */
+code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* 
Information */
+</style>
+
+
+
+<link 
href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20bot
 [...]
+
+</head>
+
+<body>
+
+
+
+
+<h1 class="title toc-ignore">Finding files in project subdirectories</h1>
+<h4 class="author"><em>Kirill Müller</em></h4>
+<h4 class="date"><em>2017-01-16</em></h4>
+
+
+
+<p>The <code>rprojroot</code> 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 <em>project 
root</em>.</p>
+<p>Unfortunately, we cannot always be sure about the current working 
directory: For instance, in RStudio it’s sometimes:</p>
+<ul>
+<li>the project root (when running R scripts),</li>
+<li>a subdirectory (when building vignettes),</li>
+<li>again the project root (when executing chunks of a vignette).</li>
+</ul>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">basename</span>(<span 
class="kw">getwd</span>())</code></pre></div>
+<pre><code>## [1] &quot;vignettes&quot;</code></pre>
+<p>In some cases, it’s even outside the project root.</p>
+<p>This vignette starts with a very brief summary that helps you get started, 
followed by a longer description of the features.</p>
+<div id="tldr" class="section level2">
+<h2>TL;DR</h2>
+<p>What is your project: An R package?</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">rprojroot::is_r_package</code></pre></div>
+<pre><code>## Root criterion: contains a file `DESCRIPTION` with contents 
matching `^Package: `</code></pre>
+<p>Or an RStudio project?</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">rprojroot::is_rstudio_project</code></pre></div>
+<pre><code>## Root criterion: contains a file matching `[.]Rproj$` with 
contents matching `^Version: ` in the first line</code></pre>
+<p>Or something else?</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">rprojroot::<span class="kw">has_file</span>(<span 
class="st">&quot;.git/index&quot;</span>)</code></pre></div>
+<pre><code>## Root criterion: contains a file `.git/index`</code></pre>
+<p>For now, we assume it’s an R package:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">root &lt;-<span class="st"> </span>rprojroot::is_r_package</code></pre></div>
+<p>The <code>root</code> 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 <code>root$find_file()</code> function:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">readLines</span>(root$<span 
class="kw">find_file</span>(<span class="st">&quot;DESCRIPTION&quot;</span>), 
<span class="dv">3</span>)</code></pre></div>
+<pre><code>## [1] &quot;Package: rprojroot&quot;                            
+## [2] &quot;Title: Finding Files in Project Subdirectories&quot;
+## [3] &quot;Version: 1.2&quot;</code></pre>
+<p>You can also construct an accessor to your root using the 
<code>root$make_fix_file()</code> function:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">root_file &lt;-<span class="st"> </span>root$<span 
class="kw">make_fix_file</span>()</code></pre></div>
+<p>Note that <code>root_file()</code> is a <em>function</em> that works just 
like <code>$find_file()</code> but will find the files even if the current 
working directory is outside your project:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">withr::<span class="kw">with_dir</span>(
+  <span class="st">&quot;../..&quot;</span>,
+  <span class="kw">readLines</span>(<span class="kw">root_file</span>(<span 
class="st">&quot;DESCRIPTION&quot;</span>), <span class="dv">3</span>)
+)</code></pre></div>
+<pre><code>## [1] &quot;Package: rprojroot&quot;                            
+## [2] &quot;Title: Finding Files in Project Subdirectories&quot;
+## [3] &quot;Version: 1.2&quot;</code></pre>
+<p>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 
<code>root$make_fix_file()</code>:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">root_file &lt;-<span class="st"> </span>root$<span 
class="kw">make_fix_file</span>(<span class="st">&quot;C:</span><span 
class="ch">\\</span><span class="st">Users</span><span 
class="ch">\\</span><span class="st">User Name</span><span 
class="ch">\\</span><span class="st">...&quot;</span>)</code></pre></div>
+<p>Get the path of standalone R scripts or vignettes using the 
<code>thisfile()</code> function in the <code>kimisc</code> package:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">root_file &lt;-<span class="st"> </span>root$<span 
class="kw">make_fix_file</span>(<span class="kw">dirname</span>(kimisc::<span 
class="kw">thisfile</span>()))</code></pre></div>
+<p>The remainder of this vignette describes implementation details and 
advanced features.</p>
+</div>
+<div id="project-root" class="section level2">
+<h2>Project root</h2>
+<p>We assume a self-contained project where all files and directories are 
located below a common <em>root</em> 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:</p>
+<ul>
+<li>Start the search in any subdirectory of our project</li>
+<li>Proceed up the directory hierarchy until the root directory has been 
identified</li>
+</ul>
+<p>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.</p>
+<div id="a-simple-example" class="section level3">
+<h3>A simple example</h3>
+<p>The <code>find_root()</code> 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 <code>root_criterion()</code> 
function, the <code>has_file()</code> function constructs a criterion that 
checks for the presence of a file with a specific name and specific 
contents.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">library</span>(rprojroot)
+
+<span class="co"># List all files and directories below the root</span>
+<span class="kw">dir</span>(<span class="kw">find_root</span>(<span 
class="kw">has_file</span>(<span 
class="st">&quot;DESCRIPTION&quot;</span>)))</code></pre></div>
+<pre><code>##  [1] &quot;API&quot;              &quot;DESCRIPTION&quot;      
&quot;Makefile&quot;        
+##  [4] &quot;NAMESPACE&quot;        &quot;NEWS.md&quot;          
&quot;R&quot;               
+##  [7] &quot;README.md&quot;        &quot;_pkgdown.yml&quot;     
&quot;appveyor.yml&quot;    
+## [10] &quot;cran-comments.md&quot; &quot;docs&quot;             
&quot;inst&quot;            
+## [13] &quot;man&quot;              &quot;readme&quot;           
&quot;revdep&quot;          
+## [16] &quot;rprojroot.Rproj&quot;  &quot;tests&quot;            
&quot;tic.R&quot;           
+## [19] &quot;vignettes&quot;</code></pre>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Find a file relative to the root</span>
+<span class="kw">file.exists</span>(<span 
class="kw">find_root_file</span>(<span class="st">&quot;R&quot;</span>, <span 
class="st">&quot;root.R&quot;</span>, <span class="dt">criterion =</span> <span 
class="kw">has_file</span>(<span 
class="st">&quot;DESCRIPTION&quot;</span>)))</code></pre></div>
+<pre><code>## [1] TRUE</code></pre>
+<p>Note that the following code produces identical results when building the 
vignette <em>and</em> when sourcing the chunk in RStudio, provided that the 
current working directory is the project root or anywhere below.</p>
+</div>
+<div id="criteria" class="section level3">
+<h3>Criteria</h3>
+<p>The <code>has_file()</code> function (and the more general 
<code>root_criterion()</code>) both return an S3 object of class 
<code>root_criterion</code>:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">has_file</span>(<span 
class="st">&quot;DESCRIPTION&quot;</span>)</code></pre></div>
+<pre><code>## Root criterion: contains a file `DESCRIPTION`</code></pre>
+<p>In addition, character values are coerced to <code>has_file</code> criteria 
by default, this coercion is applied automatically by <code>find_root()</code>. 
(This feature is used by the introductory example.)</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">as.root_criterion</span>(<span 
class="st">&quot;DESCRIPTION&quot;</span>)</code></pre></div>
+<pre><code>## Root criterion: contains a file `DESCRIPTION`</code></pre>
+<p>The return value of these functions can be stored and reused; in fact, the 
package provides 9 such criteria:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">criteria</code></pre></div>
+<pre><code>## $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: contains a directory `.git`
+## 
+## $is_svn_root
+## Root criterion: contains a directory `.svn`
+## 
+## $is_vcs_root
+## Root criterion: one of
+## - contains a directory `.git`
+## - 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(,&quot;class&quot;)
+## [1] &quot;root_criteria&quot;</code></pre>
+<p>Defining new criteria is easy:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">has_license &lt;-<span class="st"> </span><span 
class="kw">has_file</span>(<span class="st">&quot;LICENSE&quot;</span>)
+has_license</code></pre></div>
+<pre><code>## Root criterion: contains a file `LICENSE`</code></pre>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">is_projecttemplate_project &lt;-<span class="st"> </span><span 
class="kw">has_file</span>(<span 
class="st">&quot;config/global.dcf&quot;</span>, <span 
class="st">&quot;^version: &quot;</span>)
+is_projecttemplate_project</code></pre></div>
+<pre><code>## Root criterion: contains a file `config/global.dcf` with 
contents matching `^version: `</code></pre>
+<p>You can also combine criteria via the <code>|</code> operator:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">is_r_package |<span class="st"> </span>is_rstudio_project</code></pre></div>
+<pre><code>## 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</code></pre>
+</div>
+<div id="shortcuts" class="section level3">
+<h3>Shortcuts</h3>
+<p>To avoid specifying the search criteria for the project root every time, 
shortcut functions can be created. The <code>find_package_root_file()</code> is 
a shortcut for <code>find_root_file(..., criterion = is_r_package)</code>:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Print first lines of the source for this document</span>
+<span class="kw">head</span>(<span class="kw">readLines</span>(<span 
class="kw">find_package_root_file</span>(<span 
class="st">&quot;vignettes&quot;</span>, <span 
class="st">&quot;rprojroot.Rmd&quot;</span>)))</code></pre></div>
+<pre><code>## [1] &quot;---&quot;                                              
 
+## [2] &quot;title: \&quot;Finding files in project subdirectories\&quot;&quot;
+## [3] &quot;author: \&quot;Kirill Müller\&quot;&quot;                         
+## [4] &quot;date: \&quot;`r Sys.Date()`\&quot;&quot;                          
+## [5] &quot;output: rmarkdown::html_vignette&quot;                  
+## [6] &quot;vignette: &gt;&quot;</code></pre>
+<p>To save typing effort, define a shorter alias:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">P 
&lt;-<span class="st"> </span>find_package_root_file
+
+<span class="co"># Use a shorter alias</span>
+<span class="kw">file.exists</span>(<span class="kw">P</span>(<span 
class="st">&quot;vignettes&quot;</span>, <span 
class="st">&quot;rprojroot.Rmd&quot;</span>))</code></pre></div>
+<pre><code>## [1] TRUE</code></pre>
+<p>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 <code>LICENSE</code>, querying the root results in an error:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Use the has_license criterion to find the root</span>
+R &lt;-<span class="st"> </span>has_license$find_file
+R</code></pre></div>
+<pre><code>## function (..., path = &quot;.&quot;) 
+## {
+##     find_root_file(..., criterion = criterion, path = path)
+## }
+## &lt;environment: 0x55ca0ef0cf10&gt;</code></pre>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Our package does not have a LICENSE file, trying to find 
the root results in an error</span>
+<span class="kw">R</span>()</code></pre></div>
+<pre><code>## Error: No root directory found in 
/tmp/Rtmp76Lko7/Rbuild36db711fd839/rprojroot/vignettes or its parent 
directories. Root criterion: contains a file `LICENSE`</code></pre>
+</div>
+<div id="fixed-root" class="section level3">
+<h3>Fixed root</h3>
+<p>We can also create a function that computes a path relative to the root 
<em>at creation time</em>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Define a function that computes file paths below the 
current root</span>
+F &lt;-<span class="st"> </span>is_r_package$<span 
class="kw">make_fix_file</span>()
+F</code></pre></div>
+<pre><code>## function (...) 
+## {
+##     file.path(&quot;/tmp/Rtmp76Lko7/Rbuild36db711fd839/rprojroot&quot;, 
+##         ...)
+## }
+## &lt;environment: 0x55ca0cd18718&gt;</code></pre>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Show contents of the NAMESPACE file in our project</span>
+<span class="kw">readLines</span>(<span class="kw">F</span>(<span 
class="st">&quot;NAMESPACE&quot;</span>))</code></pre></div>
+<pre><code>##  [1] &quot;# Generated by roxygen2: do not edit by hand&quot;
+##  [2] &quot;&quot;                                            
+##  [3] &quot;S3method(\&quot;|\&quot;,root_criterion)&quot;              
+##  [4] &quot;S3method(as.root_criterion,character)&quot;       
+##  [5] &quot;S3method(as.root_criterion,default)&quot;         
+##  [6] &quot;S3method(as.root_criterion,root_criterion)&quot;  
+##  [7] &quot;S3method(format,root_criterion)&quot;             
+##  [8] &quot;S3method(print,root_criterion)&quot;              
+##  [9] &quot;S3method(str,root_criteria)&quot;                 
+## [10] &quot;export(as.root_criterion)&quot;                   
+## [11] &quot;export(criteria)&quot;                            
+## [12] &quot;export(find_package_root_file)&quot;              
+## [13] &quot;export(find_remake_root_file)&quot;               
+## [14] &quot;export(find_root)&quot;                           
+## [15] &quot;export(find_root_file)&quot;                      
+## [16] &quot;export(find_rstudio_root_file)&quot;              
+## [17] &quot;export(find_testthat_root_file)&quot;             
+## [18] &quot;export(from_wd)&quot;                             
+## [19] &quot;export(get_root_desc)&quot;                       
+## [20] &quot;export(has_dir)&quot;                             
+## [21] &quot;export(has_dirname)&quot;                         
+## [22] &quot;export(has_file)&quot;                            
+## [23] &quot;export(has_file_pattern)&quot;                    
+## [24] &quot;export(is.root_criterion)&quot;                   
+## [25] &quot;export(is_git_root)&quot;                         
+## [26] &quot;export(is_projectile_project)&quot;               
+## [27] &quot;export(is_r_package)&quot;                        
+## [28] &quot;export(is_remake_project)&quot;                   
+## [29] &quot;export(is_rstudio_project)&quot;                  
+## [30] &quot;export(is_svn_root)&quot;                         
+## [31] &quot;export(is_testthat)&quot;                         
+## [32] &quot;export(is_vcs_root)&quot;                         
+## [33] &quot;export(root_criterion)&quot;                      
+## [34] &quot;import(backports)&quot;                           
+## [35] &quot;importFrom(utils,str)&quot;</code></pre>
+<p>This is a more robust alternative to <code>$find_file()</code>, because it 
<em>fixes</em> the project directory when <code>$make_fix_file()</code> is 
called, instead of searching for it every time. (For that reason it is also 
slightly faster, but I doubt this matters in practice.)</p>
+<p>This function can be used even if we later change the working directory to 
somewhere outside the project:</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="co"># Print the size of the namespace file, working directory 
outside the project</span>
+withr::<span class="kw">with_dir</span>(
+  <span class="st">&quot;../..&quot;</span>,
+  <span class="kw">file.size</span>(<span class="kw">F</span>(<span 
class="st">&quot;NAMESPACE&quot;</span>))
+)</code></pre></div>
+<pre><code>## [1] 880</code></pre>
+<p>The <code>make_fix_file()</code> member function also accepts an optional 
<code>path</code> argument, in case you know your project’s root but the 
current working directory is somewhere outside. Take a look at the 
<code>thisfile()</code> function in the <code>kimisc</code> package for getting 
the path to the current script or <code>knitr</code> document.</p>
+</div>
+</div>
+<div id="testthat-files" class="section level2">
+<h2><code>testthat</code> files</h2>
+<p>Tests run with <a 
href="https://cran.r-project.org/package=testthat";><code>testthat</code></a> 
commonly use files that live below the <code>tests/testthat</code> directory. 
Ideally, this should work in the following situation:</p>
+<ul>
+<li>During package development (working directory: package root)</li>
+<li>When testing with <code>devtools::test()</code> (working directory: 
<code>tests/testthat</code>)</li>
+<li>When running <code>R CMD check</code> (working directory: a renamed 
recursive copy of <code>tests</code>)</li>
+</ul>
+<p>The <code>is_testthat</code> criterion allows robust lookup of test 
files.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r">is_testthat</code></pre></div>
+<pre><code>## Root criterion: directory name is `testthat` (also look in 
subdirectories: `tests/testthat`, `testthat`)</code></pre>
+<p>The example code below lists all files in the <a 
href="https://github.com/krlmlr/rprojroot/tree/master/tests/testthat/hierarchy";>hierarchy</a>
 test directory. It uses two project root lookups in total, so that it also 
works when rendering the vignette (<em>sigh</em>):</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode 
r"><span class="kw">dir</span>(is_testthat$<span 
class="kw">find_file</span>(<span class="st">&quot;hierarchy&quot;</span>, 
<span class="dt">path =</span> is_r_package$<span 
class="kw">find_file</span>()))</code></pre></div>
+<pre><code>## [1] &quot;DESCRIPTION&quot;     &quot;a&quot;               
&quot;b&quot;               &quot;c&quot;              
+## [5] &quot;hierarchy.Rproj&quot;</code></pre>
+</div>
+<div id="summary" class="section level2">
+<h2>Summary</h2>
+<p>The <code>rprojroot</code> 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.)</p>
+</div>
+<div id="acknowledgement" class="section level2">
+<h2>Acknowledgement</h2>
+<p>This package was inspired by the gist <a 
href="https://gist.github.com/jennybc/362f52446fe1ebc4c49f";>“Stop the working 
directory insanity”</a> by Jennifer Bryan, and by the way Git knows where its 
files are.</p>
+</div>
+
+
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+  (function () {
+    var script = document.createElement("script");
+    script.type = "text/javascript";
+    script.src  = 
"https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";;
+    document.getElementsByTagName("head")[0].appendChild(script);
+  })();
+</script>
+
+</body>
+</html>
diff --git a/man/criteria.Rd b/man/criteria.Rd
new file mode 100644
index 0000000..d8ad0ef
--- /dev/null
+++ b/man/criteria.Rd
@@ -0,0 +1,62 @@
+% 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}
diff --git a/man/find_root.Rd b/man/find_root.Rd
new file mode 100644
index 0000000..9f2c085
--- /dev/null
+++ b/man/find_root.Rd
@@ -0,0 +1,47 @@
+% 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()}}
+}
diff --git a/man/find_root_file.Rd b/man/find_root_file.Rd
new file mode 100644
index 0000000..c97d51e
--- /dev/null
+++ b/man/find_root_file.Rd
@@ -0,0 +1,54 @@
+% 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()}}
+}
diff --git a/man/root_criterion.Rd b/man/root_criterion.Rd
new file mode 100644
index 0000000..d47d910
--- /dev/null
+++ b/man/root_criterion.Rd
@@ -0,0 +1,120 @@
+% 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(".")
+}
+}
diff --git a/man/rprojroot-package.Rd b/man/rprojroot-package.Rd
new file mode 100644
index 0000000..4090994
--- /dev/null
+++ b/man/rprojroot-package.Rd
@@ -0,0 +1,39 @@
+% 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{[email protected]}
+
+}
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..49fa1b6
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,4 @@
+library(testthat)
+library(rprojroot)
+
+test_check("rprojroot")
diff --git a/tests/testthat/hierarchy/DESCRIPTION 
b/tests/testthat/hierarchy/DESCRIPTION
new file mode 100644
index 0000000..110eb5a
--- /dev/null
+++ b/tests/testthat/hierarchy/DESCRIPTION
@@ -0,0 +1,9 @@
+Package: hierarchy
+Title: What the Package Does (one line, title case)
+Version: 0.0-0
+Authors@R: as.person("Kirill Müller <[email protected]> [aut, cre]")
+Description: What the package does (one paragraph)
+Depends: R (>= 3.2.0)
+License: GPL-3
+LazyData: true
+Encoding: UTF-8
diff --git a/tests/testthat/hierarchy/a/b/a b/tests/testthat/hierarchy/a/b/a
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/hierarchy/a/b/b b/tests/testthat/hierarchy/a/b/b
new file mode 100644
index 0000000..6821c18
--- /dev/null
+++ b/tests/testthat/hierarchy/a/b/b
@@ -0,0 +1 @@
+File b
diff --git a/tests/testthat/hierarchy/a/b/c/d b/tests/testthat/hierarchy/a/b/c/d
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/hierarchy/a/remake.yml 
b/tests/testthat/hierarchy/a/remake.yml
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/hierarchy/b b/tests/testthat/hierarchy/b
new file mode 100644
index 0000000..a51ca34
--- /dev/null
+++ b/tests/testthat/hierarchy/b
@@ -0,0 +1 @@
+File b in root
diff --git a/tests/testthat/hierarchy/c b/tests/testthat/hierarchy/c
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/hierarchy/hierarchy.Rproj 
b/tests/testthat/hierarchy/hierarchy.Rproj
new file mode 100644
index 0000000..30e02be
--- /dev/null
+++ b/tests/testthat/hierarchy/hierarchy.Rproj
@@ -0,0 +1,21 @@
+Version: 1.0
+
+RestoreWorkspace: No
+SaveWorkspace: No
+AlwaysSaveHistory: Default
+
+EnableCodeIndexing: Yes
+UseSpacesForTab: Yes
+NumSpacesForTab: 2
+Encoding: UTF-8
+
+RnwWeave: knitr
+LaTeX: pdfLaTeX
+
+AutoAppendNewline: Yes
+StripTrailingWhitespace: Yes
+
+BuildType: Package
+PackageUseDevtools: Yes
+PackageInstallArgs: --no-multiarch --with-keep.source
+PackageRoxygenize: rd,collate,namespace
diff --git a/tests/testthat/package/DESCRIPTION 
b/tests/testthat/package/DESCRIPTION
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/package/tests/testthat.R 
b/tests/testthat/package/tests/testthat.R
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/package/tests/testthat/test-something.R 
b/tests/testthat/package/tests/testthat/test-something.R
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testthat/test-criterion.R b/tests/testthat/test-criterion.R
new file mode 100644
index 0000000..dc5dca8
--- /dev/null
+++ b/tests/testthat/test-criterion.R
@@ -0,0 +1,49 @@
+context("criterion")
+
+test_that("root_criterion", {
+  expect_error(root_criterion(5, "Bogus"), "must have exactly one argument")
+  expect_error(root_criterion(identity, "Bogus"), "must have exactly one 
argument")
+  expect_true(is.root_criterion(root_criterion(function(path) FALSE, "Never")))
+})
+
+test_that("is.root_criterion", {
+  expect_true(is.root_criterion(has_file("DESCRIPTION")))
+  expect_false(is.root_criterion("DESCRIPTION"))
+  expect_true(is.root_criterion(as.root_criterion("DESCRIPTION")))
+  expect_equal(as.root_criterion("x"), has_file("x"))
+  expect_error(as.root_criterion(5), "Cannot coerce")
+})
+
+test_that("Absolute paths are returned", {
+  expect_equal(find_root("testthat.R"),
+               normalizePath(find_root("testthat.R"), winslash = "/"))
+})
+
+test_that("Formatting", {
+  expect_match(paste(format(is_r_package), collapse = "\n"),
+               "^Root criterion: .*DESCRIPTION")
+  expect_output(print(is_r_package), "^Root criterion: .*DESCRIPTION")
+  expect_output(print(is_vcs_root), "^Root criterion: one of\n- .*[.]git.*\n- 
.*[.]svn")
+})
+
+test_that("Formatting criteria", {
+  ret <- character()
+  with_mock(
+    `base::cat` = function(..., sep = "") ret <<- c(ret, paste(..., sep = 
sep)),
+     str(criteria)
+  )
+  expect_match(ret[[1]], "^List of ")
+})
+
+test_that("Combining criteria", {
+  skip_on_cran()
+
+  comb_crit <- is_r_package | is_rstudio_project
+
+  expect_true(is.root_criterion(comb_crit))
+
+  expect_match(paste0(format(comb_crit), collapse = "\n"), "\n- .*\n- ")
+
+  expect_equal(find_root(comb_crit, "hierarchy"),
+               find_root(is_rstudio_project, "hierarchy/a"))
+})
diff --git a/tests/testthat/test-make.R b/tests/testthat/test-make.R
new file mode 100644
index 0000000..f990838
--- /dev/null
+++ b/tests/testthat/test-make.R
@@ -0,0 +1,13 @@
+context("make")
+
+test_that("Shortcuts", {
+  expect_equal(make_find_root_file("testthat.R")("testthat"),
+               normalizePath(getwd(), winslash = "/"))
+
+  R <- make_fix_root_file("testthat.R", getwd())
+  oldwd <- setwd("~")
+  on.exit(setwd(oldwd))
+
+  expect_equal(normalizePath(R("testthat"), mustWork = TRUE),
+               normalizePath(oldwd, mustWork = TRUE))
+})
diff --git a/tests/testthat/test-root.R b/tests/testthat/test-root.R
new file mode 100644
index 0000000..061ec8f
--- /dev/null
+++ b/tests/testthat/test-root.R
@@ -0,0 +1,197 @@
+context("root")
+
+test_that("has_file", {
+  wd <- normalizePath(getwd(), winslash = "/")
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- hierarchy(1L)
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root("a", path = path), hierarchy(3L)),
+    expect_equal(find_root("b", path = path), hierarchy(3L)),
+    expect_equal(find_root("b/a", path = path), hierarchy(2L)),
+    expect_equal(find_root_file("c", criterion = "b/a", path = path),
+                 file.path(hierarchy(2L), "c")),
+    expect_equal(find_root("c", path = path), hierarchy(1L)),
+    expect_equal(find_root("d", path = path), hierarchy(4L)),
+    expect_equal(find_root(has_file("DESCRIPTION", "^Package: ", 1), path = 
path), hierarchy(1L)),
+    expect_equal(find_root(has_file("DESCRIPTION", "^Package: "), path = 
path), hierarchy(1L)),
+    expect_error(find_root("test-root.R", path = path),
+                 "No root directory found.* file `.*`"),
+    expect_error(find_root("rprojroot.Rproj", path = path),
+                 "No root directory found.* file `.*`"),
+    expect_error(find_root(has_file("e", "f"), path = path),
+                 "No root directory found.* file `.*` with contents"),
+    expect_error(find_root(has_file("e", "f", 1), path = path),
+                 "No root directory found.* file `.*` with contents .* in the 
first line")
+  )
+})
+
+test_that("has_file_pattern", {
+  wd <- normalizePath(getwd(), winslash = "/")
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- hierarchy(1L)
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(has_file_pattern(glob2rx("a")), path = path), 
hierarchy(3L)),
+    expect_equal(find_root(has_file_pattern(glob2rx("b")), path = path), 
hierarchy(3L)),
+    expect_equal(find_root(has_file_pattern("[ab]", "File b"), path = path),
+                 hierarchy(3L)),
+    expect_equal(find_root(has_file_pattern("[ab]", "File b in root"), path = 
path),
+                 hierarchy(1L)),
+    expect_equal(find_root(has_file_pattern(glob2rx("c")), path = path), 
hierarchy(1L)),
+    expect_equal(find_root(has_file_pattern(glob2rx("d")), path = path), 
hierarchy(4L)),
+    expect_equal(find_root(has_file_pattern(glob2rx("DESCRIPTION"), "^Package: 
", 1), path = path), hierarchy(1L)),
+    expect_equal(find_root(has_file_pattern(glob2rx("DESCRIPTION"), "^Package: 
"), path = path), hierarchy(1L)),
+    expect_error(find_root(has_file_pattern(glob2rx("test-root.R")), path = 
path),
+                 "No root directory found.* file matching "),
+    expect_error(find_root(has_file_pattern(glob2rx("rprojroot.Rproj")), path 
= path),
+                 "No root directory found.* file matching "),
+    expect_error(find_root(has_file_pattern(glob2rx("e"), "f"), path = path),
+                 "No root directory found.* with contents"),
+    expect_error(find_root(has_file_pattern(glob2rx("e"), "f", 1), path = 
path),
+                 "No root directory found.* with contents .* in the first 
line")
+  )
+})
+
+test_that("has_dir", {
+  wd <- normalizePath(getwd(), winslash = "/")
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- hierarchy(1L)
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(has_dir("a"), path = path), hierarchy(1L)),
+    expect_equal(find_root(has_dir("b"), path = path), hierarchy(2L)),
+    expect_equal(find_root_file("c", criterion = has_dir("b"), path = path),
+                 file.path(hierarchy(2L), "c")),
+    expect_equal(find_root(has_dir("c"), path = path), hierarchy(3L)),
+    expect_error(find_root(has_dir("d"), path = path),
+                 "No root directory found.* a directory `.*`"),
+    expect_error(find_root(has_dir("rprojroot.Rproj"), path = path),
+                 "No root directory found.* a directory `.*`"),
+    TRUE
+  )
+})
+
+test_that("has_dirname", {
+  wd <- normalizePath(getwd(), winslash = "/")
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- hierarchy(1L)
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(has_dirname("a"), path = path), hierarchy(2L)),
+    expect_equal(find_root(has_dirname("b"), path = path), hierarchy(3L)),
+    expect_equal(find_root_file("c", criterion = has_dirname("b"), path = 
path),
+                 file.path(hierarchy(3L), "c")),
+    expect_equal(find_root(has_dirname("c"), path = path), hierarchy(4L)),
+    expect_error(find_root(has_dirname("d"), path = path),
+                 "No root directory found.* is `.*`"),
+    expect_error(find_root(has_dirname("rprojroot.Rproj"), path = path),
+                 "No root directory found.* is `.*`"),
+    TRUE
+  )
+})
+
+test_that("concrete criteria", {
+  wd <- normalizePath(getwd(), winslash = "/")
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  # HACK
+  writeLines(character(), file.path(hierarchy(3L), ".projectile"))
+
+  stop_path <- hierarchy(0L)
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(is_rstudio_project, path = path), hierarchy(1L)),
+    expect_equal(find_root(is_remake_project, path = path), hierarchy(2L)),
+    expect_equal(find_root(is_projectile_project, path = path), hierarchy(3L)),
+    TRUE
+  )
+})
+
+test_that("is_svn_root", {
+  temp_dir <- tempfile("svn")
+  unzip("vcs/svn.zip", exdir = temp_dir)
+  wd <- normalizePath(temp_dir, winslash = "/")
+
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "svn", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- normalizePath(tempdir(), winslash = "/")
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(is_svn_root, path = path), hierarchy(1L)),
+    expect_equal(find_root(is_vcs_root, path = path), hierarchy(1L)),
+    expect_error(find_root(is_svn_root, path = hierarchy(0L)),
+                 "No root directory found.* a directory `.*`"),
+    expect_error(find_root(is_vcs_root, path = hierarchy(0L)),
+                 "No root directory found.* a directory `.*`"),
+    TRUE
+  )
+})
+
+test_that("is_git_root", {
+  temp_dir <- tempfile("git")
+  unzip("vcs/git.zip", exdir = temp_dir)
+  wd <- normalizePath(temp_dir, winslash = "/")
+
+  hierarchy <- function(n = 0L) {
+    do.call(file.path, list(wd, "git", "a", "b", "c")[seq_len(n + 1L)])
+  }
+
+  stop_path <- normalizePath(tempdir(), winslash = "/")
+  path <- hierarchy(4L)
+
+  with_mock(
+    `rprojroot:::is_root` = function(x) x == stop_path,
+    expect_equal(find_root(is_git_root, path = path), hierarchy(1L)),
+    expect_equal(find_root(is_vcs_root, path = path), hierarchy(1L)),
+    expect_error(find_root(is_git_root, path = hierarchy(0L)),
+                 "No root directory found.* a directory `.*`"),
+    expect_error(find_root(is_vcs_root, path = hierarchy(0L)),
+                 "No root directory found.* a directory `.*`"),
+    TRUE
+  )
+})
+
+test_that("finds root", {
+  skip_on_cran()
+  # Checks that search for root actually terminates
+  expect_error(find_root("/"), "No root directory found.* file `.*`")
+})
+
+test_that("stops if depth reached", {
+  find_root_mocked <- find_root
+  mock_env <- new.env()
+  mock_env$dirname <- identity
+  environment(find_root_mocked) <- mock_env
+
+  # Checks that search for root terminates for very deep hierarchies
+  expect_error(find_root_mocked(""), "Maximum search of [0-9]+ exceeded")
+})
diff --git a/tests/testthat/test-testthat.R b/tests/testthat/test-testthat.R
new file mode 100644
index 0000000..087c47a
--- /dev/null
+++ b/tests/testthat/test-testthat.R
@@ -0,0 +1,17 @@
+context("testthat")
+
+test_that("is_testthat", {
+  expect_match(paste(format(is_testthat), collapse = "\n"),
+               "^.*directory name is `testthat` .* 
subdirectories.*`tests/testthat`.*`testthat`.*$")
+  expect_match(paste(format(is_testthat), collapse = "\n"),
+               "directory name is `testthat` .* 
subdirectories.*`tests/testthat`.*`testthat`.*")
+
+  testthat_path <- normalizePath("package/tests/testthat", winslash = "/")
+  expect_equal(is_testthat$find_file(path = "package"), testthat_path)
+  expect_equal(is_testthat$find_file(path = "package/tests"), testthat_path)
+  expect_equal(is_testthat$find_file(path = "package/tests/testthat"), 
testthat_path)
+})
+
+test_that("dogfood", {
+  expect_true(file.exists(is_testthat$find_file("hierarchy", "a", "b", "c", 
"d")))
+})
diff --git a/tests/testthat/vcs/git.zip b/tests/testthat/vcs/git.zip
new file mode 100644
index 0000000..1b3ca57
Binary files /dev/null and b/tests/testthat/vcs/git.zip differ
diff --git a/tests/testthat/vcs/svn.zip b/tests/testthat/vcs/svn.zip
new file mode 100644
index 0000000..0f3fbd7
Binary files /dev/null and b/tests/testthat/vcs/svn.zip differ
diff --git a/vignettes/rprojroot.Rmd b/vignettes/rprojroot.Rmd
new file mode 100644
index 0000000..28d725d
--- /dev/null
+++ b/vignettes/rprojroot.Rmd
@@ -0,0 +1,301 @@
+---
+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\\...")
+```
+
+Get the path of standalone R scripts or vignettes
+using the `thisfile()` function in the `kimisc` package:
+
+```r
+root_file <- root$make_fix_file(dirname(kimisc::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")))
+
+# Find a file relative to the root
+file.exists(find_root_file("R", "root.R", criterion = has_file("DESCRIPTION")))
+```
+
+Note that the following 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.
+
+
+### 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.
+Take a look at the `thisfile()` function in the `kimisc` package for getting
+the path to the current script or `knitr` document.
+
+
+## `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()))
+```
+
+
+## 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.

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/debian-med/r-cran-rprojroot.git

_______________________________________________
debian-med-commit mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit

Reply via email to