diff --git a/.Rbuildignore b/.Rbuildignore
index ead92e5..4ef4e99 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -3,4 +3,6 @@
^\.travis\.yml$
^cran-comments.md$
^CONDUCT\.md$
-^paper$
\ No newline at end of file
+^paper$
+.github
+^_pkgdown\.yaml$
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..0b5aa2c
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,20 @@
+# CONTRIBUTING #
+
+### Please contribute!
+
+We love collaboration.
+
+### Bugs?
+
+* Submit an issue on the [Issues page](https://github.com/databio/simpleCache/issues)
+
+### Code contributions
+
+* Fork this repo to your Github account
+* Clone your version on your account down to your machine from your account, e.g,. `git clone https://github.com/databio/simpleCache.git`
+* Make sure to track progress upstream (i.e., on our version of `simpleCache` at `databio/simpleCache`) by doing `git remote add upstream https://github.com/databio/simpleCache.git`. Before making changes make sure to pull changes in from upstream by doing either `git fetch upstream` then merge later or `git pull upstream` to fetch and merge in one step
+* Make your changes (bonus points for making changes on a new feature branch)
+* Push up to your account
+* Submit a pull request to home base (likely master branch, but check to make sure) at `databio/simpleCache`
+
+### Thanks for contributing!
\ No newline at end of file
diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 0000000..6387c0d
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,8 @@
+
+
+ Session Info
+
+```r
+
+```
+
\ No newline at end of file
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..8d3e248
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,16 @@
+
+
+## Description
+
+
+## Related Issue
+
+
+## Example
+
+
+
\ No newline at end of file
diff --git a/DESCRIPTION b/DESCRIPTION
index d385b12..eaedecd 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,5 +1,5 @@
Package: simpleCache
-Version: 0.3.1
+Version: 0.4.0
Date: 2017-08-21
Title: Simply Caching R Objects
Description: Provides intuitive functions for caching R objects, encouraging
@@ -13,7 +13,6 @@ Description: Provides intuitive functions for caching R objects, encouraging
Authors@R: c(person("VP", "Nagraj", email = "vpnagraj@virginia.edu", role =
c("aut")), person("Nathan", "Sheffield", email = "nathan@code.databio.org",
role = c("aut", "cre")))
-Maintainer: Nathan Sheffield
Suggests:
knitr,
testthat
@@ -21,6 +20,6 @@ Enhances: batchtools
VignetteBuilder: knitr
License: BSD_2_clause + file LICENSE
Encoding: UTF-8
-URL: http://www.github.com/databio/simpleCache
-BugReports: http://www.github.com/databio/simpleCache
+URL: https://www.github.com/databio/simpleCache
+BugReports: https://www.github.com/databio/simpleCache
RoxygenNote: 6.0.1.9000
diff --git a/NAMESPACE b/NAMESPACE
index 38ae188..da5de29 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -10,7 +10,7 @@ export(setCacheDir)
export(setSharedCacheDir)
export(simpleCache)
export(simpleCacheGlobal)
+export(simpleCacheOptions)
export(simpleCacheShared)
export(simpleCacheSharedGlobal)
export(storeCache)
-export(viewCacheDirs)
diff --git a/NEWS b/NEWS
index a162b38..2531bbc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,17 +1,31 @@
# Change log
All notable changes to this project will be documented in this file.
+## [0.4.0] -- Unreleased
+
+ - adds a lifespan arg to simpleCache() to create auto-expiring caches
+ - remove unnecessary parse argument to simpleCache()
+ - viewCacheDirs() renamed to simpleCacheOptions()
+
+## [0.3.1] -- 2017-08-21
+
+ - fixed a bug in unit tests that left behind a test cache in user home dir.
+ - changes cache building to happen in parent.frame()
+ - repaired vignette so R code is displayed properly
+ - added deleteCaches() function and docs
+ - reduced size of unit test cache for speed increase
+
## [0.3.0] -- 2017-08-21
- - Switched default cache dir to tempdir()
+ - switched default cache dir to tempdir()
- changed availCaches() to listCaches()
- - changes cache building to happen in parent.frame(), so that any loaded
+ - changes cache building to happen in globalenv(), so that any loaded
packages are available for cache building
## [0.2.1] -- 2017-07-30
- - Added examples
+ - added examples
## [0.2.0] -- 2017-07-30
@@ -20,4 +34,4 @@ All notable changes to this project will be documented in this file.
## [0.0.1]
- - Long-term stable version
+ - long-term stable version
diff --git a/R/cacheDirectories.R b/R/cacheDirectories.R
index 9ecaabe..d07efd3 100644
--- a/R/cacheDirectories.R
+++ b/R/cacheDirectories.R
@@ -6,7 +6,7 @@
# caches.
#' Sets a global variable specifying the default cache directory for
-#' simpleCache() calls.
+#' \code{\link{simpleCache}} calls.
#'
#' @param cacheDir Directory where caches should be stored
#' @export
@@ -19,7 +19,7 @@ setCacheDir = function(cacheDir) {
#' Set shared cache directory
#'
#' Sets global variable specifying the default cache directory for
-#' simpleCacheShared() calls; this function is simply a helper alias for caching
+#' \code{\link{simpleCacheShared}} calls; this function is simply a helper alias for caching
#' results that will be used across projects.
#'
#' @param sharedCacheDir Directory where shared caches should be stored
@@ -36,11 +36,11 @@ setCacheBuildDir = function(cacheBuildDir) {
options(RBUILD.DIR=cacheBuildDir)
}
-#' View cache directories
+#' View simpleCache options
#'
-#' Views cache directory global variables
+#' Views simpleCache global variables
#' @export
-viewCacheDirs = function() {
+simpleCacheOptions = function() {
message("RESOURCES.RCACHE:\t", getOption("RESOURCES.RCACHE"))
message("RCACHE.DIR:\t", getOption("RCACHE.DIR"))
message("RBUILD.DIR:\t", getOption("RBUILD.DIR"))
@@ -59,7 +59,7 @@ addCacheSearchEnvironment = function(addEnv) {
options(SIMPLECACHE.ENV=append(addEnv, getOption("SIMPLECACHE.ENV")))
}
-#' Sets global option of cache search environments to NULL.
+#' Sets global option of cache search environments to \code{NULL}.
#'
#' @export
resetCacheSearchEnvironment = function() {
diff --git a/R/loadCaches.R b/R/loadCaches.R
index b20981e..cef9a77 100644
--- a/R/loadCaches.R
+++ b/R/loadCaches.R
@@ -4,15 +4,17 @@
#' for stuff you already cached previously, so it won't build any caches.
#'
#' @param cacheNames Vector of caches to load.
+#' @param loadEnvir Environment into which to load each cache.
#' @param ... Additional parameters passed to simpleCache.
#' @export
#' @example
#' R/examples/example.R
-loadCaches = function(cacheNames, ...) {
+loadCaches = function(cacheNames, loadEnvir=NULL, ...) {
+ if (is.null(loadEnvir)) { loadEnvir = parent.frame(n=2) }
for (i in 1:length(cacheNames)) {
# By default, load these caches into the environment that
# calls loadCaches (which is the grandparent, n=2, of the call to
# simpleCache.
- simpleCache(cacheNames[i], loadEnvir=parent.frame(n=2), ...)
+ simpleCache(cacheNames[i], loadEnvir=loadEnvir, ...)
}
}
diff --git a/R/sharedCaches.R b/R/sharedCaches.R
index 4fc0074..3f99a81 100644
--- a/R/sharedCaches.R
+++ b/R/sharedCaches.R
@@ -8,7 +8,7 @@
#' (instead of the typical default PROJECT directory)
#'
-#' @param ... Parameters passed to simpleCache().
+#' @param ... Parameters passed to \code{\link{simpleCache}}.
#' @export
simpleCacheShared = function(...) {
# Since this is a function calling this, I have to set the loadEnvir here,
@@ -22,7 +22,7 @@ simpleCacheShared = function(...) {
#' simpleCache normally loads variables into the calling environment; this
#' ensures that the variables are loaded in the global environment.
#'
-#' @param ... Parameters passed to simpleCache().
+#' @param ... Parameters passed to \code{\link{simpleCache}}.
#' @export
simpleCacheGlobal = function(...) {
simpleCache(..., loadEnvir=globalenv())
@@ -30,7 +30,7 @@ simpleCacheGlobal = function(...) {
#' Helper alias for loading shared caches into the global environment.
#'
-#' @param ... Parameters passed to simpleCache().
+#' @param ... Parameters passed to \code{\link{simpleCache}}.
#' @export
simpleCacheSharedGlobal = function(...) {
simpleCache(..., cacheDir=getOption("RESOURCES.RCACHE"), loadEnvir=globalenv())
diff --git a/R/simpleCache.R b/R/simpleCache.R
index 93f5909..6a08f61 100755
--- a/R/simpleCache.R
+++ b/R/simpleCache.R
@@ -1,15 +1,12 @@
## Package documentation
#' Provides intuitive functions for caching R objects, encouraging faster
#' reproducible and restartable R analysis
-#'
-#' simpleCache provides a function (simpleCache())
#'
-#' @references \url{https://github.com/nsheff/}
-## @import if you import any packages; here.
+#' @references \url{https://github.com/databio/simpleCache}
#' @docType package
-#' @name simpleCache
#' @author Nathan Sheffield
-NULL
+#' @aliases simpleCache-package
+"_PACKAGE"
################################################################################
@@ -23,10 +20,10 @@ NULL
#' troubles if you misuse the caching system. The object should be considered
#' static.
#'
-#' You should pass a bracketed R code snippet like `{ rnorm(500) }` as the
+#' You should pass a bracketed R code snippet like \code{rnorm(500)} as the
#' instruction, and simpleCache will create the object. Alternatively, if the
#' code to create the cache is large, you can put an R script called object.R in
-#' the RBUILD.DIR (the name of the file *must* match the name of the object it
+#' the \code{\link[=setCacheBuildDir]{RBUILD.DIR}} (the name of the file *must* match the name of the object it
#' creates *exactly*). If you don't provide an instruction, the function sources
#' RBUILD.DIR/object.R and caches the result as the object. This source file
@@ -41,46 +38,50 @@ NULL
#' environment variables you use in your instruction code. You can use this
#' using the parameter buildEnvir (just provide a list of named variables).
#'
-#' @param cacheName Unique name for the cache. Be careful.
-#' @param instruction Quoted R code to be evaluated. The returned value of this
+#' @param cacheName A character vector for a unique name for the cache. Be careful.
+#' @param instruction R expression (in braces) to be evaluated. The returned value of this
#' code is what will be cached under the cacheName.
-#' @param buildEnvir You may choose to provide additional variables necessary
-#' for evaluating the code in instruction.
-#' @param reload forces re-loading the cache, even if it exists in the env.
-#' @param recreate forces reconstruction of the cache
-#' @param noload noload is useful for: you want to create the caches, but not
-#' load them if they aren't there (like a cache creation loop).
-#' @param cacheDir The directory where caches are saved (and loaded from).
-#' Defaults to the global RCACHE.DIR variable
-#' @param cacheSubDir You can specify a subdirectory within the cacheDir
-#' variable. Defaults to NULL.
-#' @param assignToVariable By default, simpleCache assigns the cache to a
-#' variable named cacheName; you can overrule that here.
-#' @param loadEnvir Into which environment would you like to load the
-#' variable? Defaults to parent.frame.
+#' @param buildEnvir An environment (or list) providing additional variables
+#' necessary for evaluating the code in instruction.
+#' @param reload Logical indicating whether to force re-loading the cache,
+#' even if it exists in the env.
+#' @param recreate Logical indicating whether to force reconstruction of the
+#' cache
+#' @param noload Logical indicating whether to create but not load the cache.
+#' noload is useful for: you want to create the caches, but not load (like a
+#' cache creation loop).
+#' @param cacheDir Character vector specifying the directory where caches are
+#' saved (and loaded from). Defaults to the variable set by
+#' \code{\link[=setCacheDir]{setCacheDir()}}.
+#' @param cacheSubDir Character vector specifying a subdirectory within the
+#' \code{cacheDir} variable. Defaults to \code{NULL}.
+#' @param assignToVariable Character vector for a variable name to load the
+#' cache into. By default, \code{simpleCache} assigns the cache to a
+#' variable named \code{cacheName}; you can overrule that here.
+#' @param loadEnvir An environment. Into which environment would you like to
+#' load the variable? Defaults to \code{\link[base]{parent.frame}}.
#' @param searchEnvir a vector of environments to search for the already loaded
#' cache.
-#' @param timer Report how long it took to create the cache?
+#' @param timer Logical indicating whether to report how long it took to create
+#' the cache.
#' @param buildDir Location of Build files (files with instructions for use If
#' the instructions argument is not provided). Defaults to RBUILD.DIR
#' global option.
-#' @param parse By default, simpleCache will guess whether you want to parse the
-#' instruction, based on whether it is quoted. You can overwrite the guess
-#' with this parameter; but this may disappear in the future. In general,
-#' you should note quote, but use {} around your instructions.
#' @param nofail By default, simpleCache throws an error if the instructions
#' fail. Use this option to convert this error into a warning. No cache will
#' be created, but simpleCache will not then hard-stop your processing. This
-#' is useful, for example, if you are creating a bunch of caches and it's ok
-#' if some of them do not complete.
-#' @param batchRegistry A batchtools registry object (built with
-#' batchtools::makeRegistry()). If provided, this cache will be created on
+#' is useful, for example, if you are creating a bunch of caches (for
+#' example using \code{lapply}) and it's ok if some of them do not complete.
+#' @param batchRegistry A \code{batchtools} registry object (built with
+#' \code{\link[batchtools]{makeRegistry}}). If provided, this cache will be created on
#' the cluster using your batchtools configuration
#' @param batchResources A list of variables to provide to batchtools for
-#' cluster resource managers. Used as the `res` argument to
-#' batchtools::batchMap()
+#' cluster resource managers. Used as the \code{res} argument to
+#' \code{\link[batchtools]{batchMap}}
+#' @param lifespan Numeric specifying the maximum age of cache, in days, to
+#' allow before automatically triggering \code{recreate=TRUE}.
#' @param pepSettings Experimental untested feature.
-#' @param ignoreLock internal parameter used for batch job submission; don't
+#' @param ignoreLock Internal parameter used for batch job submission; don't
#' touch.
#' @export
#' @example
@@ -90,27 +91,25 @@ simpleCache = function(cacheName, instruction=NULL, buildEnvir=NULL,
cacheDir=getOption("RCACHE.DIR"), cacheSubDir=NULL, timer=FALSE,
buildDir=getOption("RBUILD.DIR"), assignToVariable=NULL,
loadEnvir=parent.frame(), searchEnvir=getOption("SIMPLECACHE.ENV"),
- parse=NULL, nofail=FALSE, batchRegistry=NULL,
- batchResources=NULL, pepSettings=NULL, ignoreLock=FALSE) {
+ nofail=FALSE, batchRegistry=NULL, batchResources=NULL, pepSettings=NULL,
+ ignoreLock=FALSE, lifespan=NULL) {
+
+ if (!"character" %in% class(cacheName)) {
+ stop("simpleCache expects the cacheName variable to be a character vector.")
+ }
# Because R evaluates arguments lazily (only when they are used),
# it will not evaluate the instruction if I first wrap it in a
# primitive substitute call. Then I can evaluate conditionally
# (if the cache needs to be recreated)
instruction = substitute(instruction)
- if (is.null(parse)) {
- if ("character" %in% class(instruction)) {
-
- parse = TRUE
- warning(strwrap("Detected a character instruction; consider wrapping
- in {} instead of quotes."))
- } else {
- parse = FALSE
- }
- }
- if (!is.null(cacheSubDir)) {
- cacheDir = file.path(cacheDir, cacheSubDir)
- }
+ if ("character" %in% class(instruction)) {
+ message("Character instruction; consider wrapping in braces.")
+ parse = TRUE
+ } else { parse = FALSE }
+
+ # Handle directory paths.
+ if (!is.null(cacheSubDir)) { cacheDir = file.path(cacheDir, cacheSubDir) }
if (is.null(cacheDir)) {
message(strwrap("No cacheDir specified. You should set global option
RCACHE.DIR with setCacheDir(), or specify a cacheDir parameter directly
@@ -118,10 +117,6 @@ simpleCache = function(cacheName, instruction=NULL, buildEnvir=NULL,
", initial="", prefix=" "), tempdir())
cacheDir = tempdir()
}
- if (!"character" %in% class(cacheName)) {
- stop("simpleCache expects the cacheName variable to be a character
- vector.")
- }
if (!file.exists(cacheDir)) {
dir.create(cacheDir, recursive=TRUE)
@@ -149,6 +144,12 @@ simpleCache = function(cacheName, instruction=NULL, buildEnvir=NULL,
ret = NULL # The default, in case the cache construction fails.
+ if (.tooOld(cacheFile, lifespan)) {
+ message(sprintf(
+ "Stale cache: '%s' (age > %d day(s))", cacheFile, lifespan))
+ recreate = TRUE
+ }
+
if(cacheExists & !reload & !recreate) {
message("::Object exists (in ", cacheWhere, ")::\t", cacheName)
#return(get(cacheName))
diff --git a/R/storeCache.R b/R/storeCache.R
index 0a1ffc6..b684b51 100644
--- a/R/storeCache.R
+++ b/R/storeCache.R
@@ -1,20 +1,20 @@
#' Stores as a cache an already-produced R object
#'
#' Sometimes you use significant computational power to create an object, but
-#' you didn't cache it with simpleCache. Oops, maybe you wish you had, after the
+#' you didn't cache it with \code{\link{simpleCache}}. Oops, maybe you wish you had, after the
#' fact. This function lets you store an object in the environment so it could
-#' be loaded by future calls to simpleCache.
+#' be loaded by future calls to \code{simpleCache}.
#'
#' This can be used in interactive sessions, but could also be used for another
#' use case: you have a complicated set of instructions (too much to pass as the
-#' instruction argument to simpleCache), so you could just stick a call to
-#' storeCache at the end.
+#' instruction argument to \code{simpleCache}), so you could just stick a call to
+#' \code{storeCache} at the end.
#'
#' @param cacheName Unique name for the cache (and R object to be cached).
#' @param cacheDir The directory where caches are saved (and loaded from).
-#' Defaults to the global RCACHE.DIR variable
+#' Defaults to the global \code{\link[=setCacheDir]{RCACHE.DIR}} variable
#' @param cacheSubDir You can specify a subdirectory within the cacheDir
-#' variable. Defaults to NULL.
+#' variable. Defaults to \code{NULL}.
#' @param recreate Forces reconstruction of the cache
#' @export
#' @example
diff --git a/R/utility.R b/R/utility.R
index 3a7367f..68f9d58 100644
--- a/R/utility.R
+++ b/R/utility.R
@@ -9,24 +9,32 @@
#
# These functions should probably remain interior to the package (not exported)
#
-
-enforceEdgeCharacter = function(string, prependChar="", appendChar="") {
- if (string=="" | is.null(string)) {
- return(string)
- }
- if(!is.null(appendChar)) {
- if (substr(string,nchar(string), nchar(string)) != appendChar) { # +1 ?
- string = paste0(string, appendChar);
- }
- }
- if (!is.null(prependChar)) {
- if (substr(string,1,1) != prependChar) { # +1 ?
- string = paste0(prependChar, string)
- }
- }
- return(string)
+#' Determine if a cache file is sufficiently old to warrant refresh.
+#'
+#' \code{.tooOld} accepts a maximum cache age and checks for an option with
+#' that setting under \code{MAX.CACHE.AGE} if such an argument isn't passed.
+#' If the indicated file exists and is older than the threshold passed or
+#' set as an option, the file is deemed "stale." If an age threshold is
+#' provided, no check for an option is performed. If the file does not
+#' exist or there's not an age threshold directly passed or set as an option,
+#' the result is \code{FALSE}.
+#'
+#' @param pathCacheFile Path to file to ask about staleness.
+#' @param lifespan Maximum file age before it's "stale."
+#' @return \code{TRUE} if the file exists and its age exceeds
+#' \code{lifespan} if given or
+#' \code{getOption("MAX.CACHE.AGE")} if no age threshold is passed
+#' and that option exists; \code{FALSE} otherwise.
+.tooOld = function(pathCacheFile, lifespan=NULL) {
+ if (!utils::file_test("-f", pathCacheFile)) { return(FALSE) }
+ if (is.null(lifespan)) { lifespan = getOption("MAX.CACHE.AGE") }
+ if (is.null(lifespan)) { return(FALSE) }
+ cacheTime = file.info(pathCacheFile)$ctime
+ cacheAge = difftime(Sys.time(), cacheTime, units="days")
+ as.numeric(cacheAge) > as.numeric(lifespan)
}
+
# MATLAB-style timing functions to start/stop timer.
# These functions were based on an idea by some helpful soul on
# Stackoverflow that I can no longer recall...
diff --git a/README.md b/README.md
index 529b67f..faf1a06 100644
--- a/README.md
+++ b/README.md
@@ -26,40 +26,31 @@ be installed as usual:
install.packages("simpleCache")
```
-If you like, you may install the development version directly from github with
-devtools
-
-```
-devtools::install_github("databio/simpleCache")
-```
-
-To install a local copy:
-```
-packageFolder = "~/R/simpleCache"; install.packages(packageFolder, repos=NULL)
-```
-
--------------------------------------------------------------------------------
### Running simpleCache
-`simpleCache` comes with a single primary function that will do almost
+`simpleCache` comes with a single primary function (`simpleCache()`) that will do almost
everything you need. In short, you run it with a few lines like this:
```
library(simpleCache)
setCacheDir(tempdir())
-simpleCache("normSample", { rnorm(1e7, 0,1) }, recreate=TRUE)
+simpleCache("normSample", { rnorm(1e7, 0,1) }, recreate=TRUE)
simpleCache("normSample", { rnorm(1e7, 0,1) })
```
`simpleCache` also interfaces with the `batchtools` package to let you build
-caches on any cluster resource manager. I have produced some [R
-vignettes](vignettes/) to get you started.
-
-* [An introduction to simpleCache](vignettes/simpleCacheIntroduction.Rmd)
-* [Sharing caches across projects](vignettes/sharingCaches.Rmd)
-* [Generating caches on a cluster](vignettes/clusterCaches.Rmd)
+caches on any cluster resource manager.
--------------------------------------------------------------------------------
+### Highlights of exported functions
+
+- `simpleCache()`: Creates and caches or reloads cached results of provided R instruction code
+- `listCaches()`: Lists all of the caches available in the `cacheDir`
+- `deleteCaches()`: Deletes cache(s) from the `cacheDir`
+- `setCacheDir()`: Sets a global option for a cache directory so you don't have to specify one in each `simpleCache` call
+- `simpleCacheOptions()`: Views all of the `simpleCache` global options that have been set
+
### simpleCache Philosophy
The use case I had in mind for `simpleCache` is that you find yourself
@@ -90,6 +81,8 @@ change.
`simpleCache` is licensed under the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). Questions, feature requests and bug reports are welcome via the [issue queue](https://github.com/databio/simpleCache/issues). The maintainer will review pull requests and incorporate contributions at his discretion.
+For more information refer to the contributing document and pull request / issue templates in the [.github folder](https://github.com/databio/simpleCache/tree/master/.github) of this repository.
+
diff --git a/_pkgdown.yaml b/_pkgdown.yaml
new file mode 100644
index 0000000..73cef9d
--- /dev/null
+++ b/_pkgdown.yaml
@@ -0,0 +1,22 @@
+
+template:
+ params:
+ bootswatch: yeti
+
+navbar:
+ left:
+ - text: Vignettes
+ icon: fa-play-circle
+ href: articles/index.html
+ - text: Documentation
+ icon: fa-pencil
+ href: reference/index.html
+ - text: GitHub
+ icon: fa-github fa-lg
+ href: https://github.com/databio/simpleCache
+
+ right:
+ - text: Databio.org
+ href: http://databio.org
+ - text: Software & Data
+ href: http://databio.org/software/
diff --git a/man/dot-tooOld.Rd b/man/dot-tooOld.Rd
new file mode 100644
index 0000000..8f6091c
--- /dev/null
+++ b/man/dot-tooOld.Rd
@@ -0,0 +1,28 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/utility.R
+\name{.tooOld}
+\alias{.tooOld}
+\title{Determine if a cache file is sufficiently old to warrant refresh.}
+\usage{
+.tooOld(pathCacheFile, lifespan = NULL)
+}
+\arguments{
+\item{pathCacheFile}{Path to file to ask about staleness.}
+
+\item{lifespan}{Maximum file age before it's "stale."}
+}
+\value{
+\code{TRUE} if the file exists and its age exceeds
+ \code{lifespan} if given or
+ \code{getOption("MAX.CACHE.AGE")} if no age threshold is passed
+ and that option exists; \code{FALSE} otherwise.
+}
+\description{
+\code{.tooOld} accepts a maximum cache age and checks for an option with
+that setting under \code{MAX.CACHE.AGE} if such an argument isn't passed.
+If the indicated file exists and is older than the threshold passed or
+set as an option, the file is deemed "stale." If an age threshold is
+provided, no check for an option is performed. If the file does not
+exist or there's not an age threshold directly passed or set as an option,
+the result is \code{FALSE}.
+}
diff --git a/man/loadCaches.Rd b/man/loadCaches.Rd
index b247e1b..e4d8d64 100644
--- a/man/loadCaches.Rd
+++ b/man/loadCaches.Rd
@@ -4,11 +4,13 @@
\alias{loadCaches}
\title{Loads pre-made caches}
\usage{
-loadCaches(cacheNames, ...)
+loadCaches(cacheNames, loadEnvir = NULL, ...)
}
\arguments{
\item{cacheNames}{Vector of caches to load.}
+\item{loadEnvir}{Environment into which to load each cache.}
+
\item{...}{Additional parameters passed to simpleCache.}
}
\description{
diff --git a/man/resetCacheSearchEnvironment.Rd b/man/resetCacheSearchEnvironment.Rd
index d83900b..3369c77 100644
--- a/man/resetCacheSearchEnvironment.Rd
+++ b/man/resetCacheSearchEnvironment.Rd
@@ -2,10 +2,10 @@
% Please edit documentation in R/cacheDirectories.R
\name{resetCacheSearchEnvironment}
\alias{resetCacheSearchEnvironment}
-\title{Sets global option of cache search environments to NULL.}
+\title{Sets global option of cache search environments to \code{NULL}.}
\usage{
resetCacheSearchEnvironment()
}
\description{
-Sets global option of cache search environments to NULL.
+Sets global option of cache search environments to \code{NULL}.
}
diff --git a/man/setCacheDir.Rd b/man/setCacheDir.Rd
index de719b4..4c3c969 100644
--- a/man/setCacheDir.Rd
+++ b/man/setCacheDir.Rd
@@ -3,7 +3,7 @@
\name{setCacheDir}
\alias{setCacheDir}
\title{Sets a global variable specifying the default cache directory for
-simpleCache() calls.}
+\code{\link{simpleCache}} calls.}
\usage{
setCacheDir(cacheDir)
}
@@ -12,7 +12,7 @@ setCacheDir(cacheDir)
}
\description{
Sets a global variable specifying the default cache directory for
-simpleCache() calls.
+\code{\link{simpleCache}} calls.
}
\examples{
# choose location to store caches
diff --git a/man/setSharedCacheDir.Rd b/man/setSharedCacheDir.Rd
index 16abc12..9cdb4df 100644
--- a/man/setSharedCacheDir.Rd
+++ b/man/setSharedCacheDir.Rd
@@ -11,6 +11,6 @@ setSharedCacheDir(sharedCacheDir)
}
\description{
Sets global variable specifying the default cache directory for
-simpleCacheShared() calls; this function is simply a helper alias for caching
+\code{\link{simpleCacheShared}} calls; this function is simply a helper alias for caching
results that will be used across projects.
}
diff --git a/man/simpleCache-package.Rd b/man/simpleCache-package.Rd
new file mode 100644
index 0000000..7f2a86a
--- /dev/null
+++ b/man/simpleCache-package.Rd
@@ -0,0 +1,32 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/simpleCache.R
+\docType{package}
+\name{simpleCache-package}
+\alias{simpleCache-package}
+\alias{_PACKAGE}
+\title{Provides intuitive functions for caching R objects, encouraging faster
+reproducible and restartable R analysis}
+\description{
+Provides intuitive functions for caching R objects, encouraging
+reproducible, restartable, and distributed R analysis. The user selects a
+location to store caches, and then provides nothing more than a cache name
+and instructions (R code) for how to produce the R object. Also
+provides some advanced options like environment assignments, recreating or
+reloading caches, and cluster compute bindings (using the 'batchtools'
+package) making it flexible enough for use in large-scale data analysis
+projects.
+}
+\references{
+\url{https://github.com/databio/simpleCache}
+}
+\seealso{
+Useful links:
+\itemize{
+ \item \url{https://www.github.com/databio/simpleCache}
+ \item Report bugs at \url{https://www.github.com/databio/simpleCache}
+}
+
+}
+\author{
+Nathan Sheffield
+}
diff --git a/man/simpleCache.Rd b/man/simpleCache.Rd
index b85688b..8ad7cbc 100644
--- a/man/simpleCache.Rd
+++ b/man/simpleCache.Rd
@@ -1,20 +1,16 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/simpleCache.R
-\docType{package}
\name{simpleCache}
\alias{simpleCache}
-\alias{simpleCache-package}
-\alias{simpleCache}
-\title{Provides intuitive functions for caching R objects, encouraging faster
-reproducible and restartable R analysis}
+\title{Create a new cache or load a previously created cache.}
\usage{
simpleCache(cacheName, instruction = NULL, buildEnvir = NULL,
reload = FALSE, recreate = FALSE, noload = FALSE,
cacheDir = getOption("RCACHE.DIR"), cacheSubDir = NULL, timer = FALSE,
buildDir = getOption("RBUILD.DIR"), assignToVariable = NULL,
loadEnvir = parent.frame(), searchEnvir = getOption("SIMPLECACHE.ENV"),
- parse = NULL, nofail = FALSE, batchRegistry = NULL,
- batchResources = NULL, pepSettings = NULL, ignoreLock = FALSE)
+ nofail = FALSE, batchRegistry = NULL, batchResources = NULL,
+ pepSettings = NULL, ignoreLock = FALSE, lifespan = NULL)
}
\arguments{
\item{cacheName}{Unique name for the cache. Be careful.}
@@ -33,10 +29,10 @@ for evaluating the code in instruction.}
load them if they aren't there (like a cache creation loop).}
\item{cacheDir}{The directory where caches are saved (and loaded from).
-Defaults to the global RCACHE.DIR variable}
+Defaults to the global \code{\link[=setCacheDir]{RCACHE.DIR}} variable}
-\item{cacheSubDir}{You can specify a subdirectory within the cacheDir
-variable. Defaults to NULL.}
+\item{cacheSubDir}{You can specify a subdirectory within the \code{cacheDir}
+variable. Defaults to \code{NULL}.}
\item{timer}{Report how long it took to create the cache?}
@@ -44,42 +40,38 @@ variable. Defaults to NULL.}
the instructions argument is not provided). Defaults to RBUILD.DIR
global option.}
-\item{assignToVariable}{By default, simpleCache assigns the cache to a
-variable named cacheName; you can overrule that here.}
+\item{assignToVariable}{By default, \code{simpleCache} assigns the cache to a
+variable named \code{cacheName}; you can overrule that here.}
\item{loadEnvir}{Into which environment would you like to load the
-variable? Defaults to parent.frame.}
+variable? Defaults to \code{\link[base]{parent.frame}}.}
\item{searchEnvir}{a vector of environments to search for the already loaded
cache.}
-\item{parse}{By default, simpleCache will guess whether you want to parse the
-instruction, based on whether it is quoted. You can overwrite the guess
-with this parameter; but this may disappear in the future. In general,
-you should note quote, but use {} around your instructions.}
-
\item{nofail}{By default, simpleCache throws an error if the instructions
fail. Use this option to convert this error into a warning. No cache will
be created, but simpleCache will not then hard-stop your processing. This
is useful, for example, if you are creating a bunch of caches and it's ok
if some of them do not complete.}
-\item{batchRegistry}{A batchtools registry object (built with
-batchtools::makeRegistry()). If provided, this cache will be created on
+\item{batchRegistry}{A \code{batchtools} registry object (built with
+ \code{\link[batchtools]{makeRegistry}}). If provided, this cache will be created on
the cluster using your batchtools configuration}
\item{batchResources}{A list of variables to provide to batchtools for
-cluster resource managers. Used as the `res` argument to
-batchtools::batchMap()}
+cluster resource managers. Used as the \code{res} argument to
+\code{\link[batchtools]{batchMap}}}
\item{pepSettings}{Experimental untested feature.}
-\item{ignoreLock}{internal parameter used for batch job submission; don't
+\item{ignoreLock}{Internal parameter used for batch job submission; don't
touch.}
+
+\item{lifespan}{Maximum age of cache, in days, to allow before
+automatically triggering \code{recreate=TRUE}.}
}
\description{
-simpleCache provides a function (simpleCache())
-
Given a unique name for an R object, and instructions for how to make that
object, use the simpleCache function to create and cache or load the object.
This should be used for computations that take a long time and generate a
@@ -89,10 +81,10 @@ troubles if you misuse the caching system. The object should be considered
static.
}
\details{
-You should pass a bracketed R code snippet like `{ rnorm(500) }` as the
+You should pass a bracketed R code snippet like \code{rnorm(500)} as the
instruction, and simpleCache will create the object. Alternatively, if the
code to create the cache is large, you can put an R script called object.R in
-the RBUILD.DIR (the name of the file *must* match the name of the object it
+the \code{\link[=setCacheBuildDir]{RBUILD.DIR}} (the name of the file *must* match the name of the object it
creates *exactly*). If you don't provide an instruction, the function sources
RBUILD.DIR/object.R and caches the result as the object. This source file
*must* create an object with the same name of the object. If you already have
@@ -130,9 +122,3 @@ simpleCache("normSample")
# load multiples caches
loadCaches(c("normSample", "normSample2"), reload=TRUE)
}
-\references{
-\url{https://github.com/nsheff/}
-}
-\author{
-Nathan Sheffield
-}
diff --git a/man/simpleCacheGlobal.Rd b/man/simpleCacheGlobal.Rd
index da705b2..019a939 100644
--- a/man/simpleCacheGlobal.Rd
+++ b/man/simpleCacheGlobal.Rd
@@ -9,7 +9,7 @@ ensures that the variables are loaded in the global environment.}
simpleCacheGlobal(...)
}
\arguments{
-\item{...}{Parameters passed to simpleCache().}
+\item{...}{Parameters passed to \code{\link{simpleCache}}.}
}
\description{
Helper alias for loading caches into the global environment.
diff --git a/man/simpleCacheOptions.Rd b/man/simpleCacheOptions.Rd
new file mode 100644
index 0000000..f6c9460
--- /dev/null
+++ b/man/simpleCacheOptions.Rd
@@ -0,0 +1,11 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/cacheDirectories.R
+\name{simpleCacheOptions}
+\alias{simpleCacheOptions}
+\title{View simpleCache options}
+\usage{
+simpleCacheOptions()
+}
+\description{
+Views simpleCache global variables
+}
diff --git a/man/simpleCacheShared.Rd b/man/simpleCacheShared.Rd
index ff0b21f..9061eab 100644
--- a/man/simpleCacheShared.Rd
+++ b/man/simpleCacheShared.Rd
@@ -7,7 +7,7 @@
simpleCacheShared(...)
}
\arguments{
-\item{...}{Parameters passed to simpleCache().}
+\item{...}{Parameters passed to \code{\link{simpleCache}}.}
}
\description{
Helper alias for caching across experiments/people.
diff --git a/man/simpleCacheSharedGlobal.Rd b/man/simpleCacheSharedGlobal.Rd
index b3a06cb..802a788 100644
--- a/man/simpleCacheSharedGlobal.Rd
+++ b/man/simpleCacheSharedGlobal.Rd
@@ -7,7 +7,7 @@
simpleCacheSharedGlobal(...)
}
\arguments{
-\item{...}{Parameters passed to simpleCache().}
+\item{...}{Parameters passed to \code{\link{simpleCache}}.}
}
\description{
Helper alias for loading shared caches into the global environment.
diff --git a/man/storeCache.Rd b/man/storeCache.Rd
index 76b5a66..306b21d 100644
--- a/man/storeCache.Rd
+++ b/man/storeCache.Rd
@@ -11,24 +11,24 @@ storeCache(cacheName, cacheDir = getOption("RCACHE.DIR"),
\item{cacheName}{Unique name for the cache (and R object to be cached).}
\item{cacheDir}{The directory where caches are saved (and loaded from).
-Defaults to the global RCACHE.DIR variable}
+Defaults to the global \code{\link[=setCacheDir]{RCACHE.DIR}} variable}
\item{cacheSubDir}{You can specify a subdirectory within the cacheDir
-variable. Defaults to NULL.}
+variable. Defaults to \code{NULL}.}
\item{recreate}{Forces reconstruction of the cache}
}
\description{
Sometimes you use significant computational power to create an object, but
-you didn't cache it with simpleCache. Oops, maybe you wish you had, after the
+you didn't cache it with \code{\link{simpleCache}}. Oops, maybe you wish you had, after the
fact. This function lets you store an object in the environment so it could
-be loaded by future calls to simpleCache.
+be loaded by future calls to \code{simpleCache}.
}
\details{
This can be used in interactive sessions, but could also be used for another
use case: you have a complicated set of instructions (too much to pass as the
-instruction argument to simpleCache), so you could just stick a call to
-storeCache at the end.
+instruction argument to \code{simpleCache}), so you could just stick a call to
+\code{storeCache} at the end.
}
\examples{
# choose location to store caches
diff --git a/man/viewCacheDirs.Rd b/man/viewCacheDirs.Rd
deleted file mode 100644
index 4eac757..0000000
--- a/man/viewCacheDirs.Rd
+++ /dev/null
@@ -1,11 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/cacheDirectories.R
-\name{viewCacheDirs}
-\alias{viewCacheDirs}
-\title{View cache directories}
-\usage{
-viewCacheDirs()
-}
-\description{
-Views cache directory global variables
-}
diff --git a/paper/paper.bib b/paper/paper.bib
index 7290bf6..3a3d74b 100644
--- a/paper/paper.bib
+++ b/paper/paper.bib
@@ -1,10 +1,10 @@
@Manual{R,
- title = {R: A Language and Environment for Statistical Computing},
- author = {{R Core Team}},
- organization = {R Foundation for Statistical Computing},
- address = {Vienna, Austria},
- year = {2016},
- url = {https://www.R-project.org/},
+ title = {R: A Language and Environment for Statistical Computing},
+ author = {{R Core Team}},
+ organization = {R Foundation for Statistical Computing},
+ address = {Vienna, Austria},
+ year = {2016},
+ url = {https://www.R-project.org/},
}
@Article{batchtools,
@@ -20,23 +20,25 @@ @Article{batchtools
}
@Article{RPIM,
- Author="Sheffield, N. C. and Pierron, G. and Klughammer, J. and Datlinger, P. and Schonegger, A. and Schuster, M. and Hadler, J. and Surdez, D. and Guillemot, D. and Lapouble, E. and Freneaux, P. and Champigneulle, J. and Bouvier, R. and Walder, D. and Ambros, I. M. and Hutter, C. and Sorz, E. and Amaral, A. T. and de Alava, E. and Schallmoser, K. and Strunk, D. and Rinner, B. and Liegl-Atzwanger, B. and Huppertz, B. and Leithner, A. and de Pinieux, G. and Terrier, P. and Laurence, V. and Michon, J. and Ladenstein, R. and Holter, W. and Windhager, R. and Dirksen, U. and Ambros, P. F. and Delattre, O. and Kovar, H. and Bock, C. and Tomazou, E. M. ",
- Title="{{D}{N}{A} methylation heterogeneity defines a disease spectrum in {E}wing sarcoma}",
- Journal="Nat. Med.",
- Year="2017",
- Volume="23",
- Number="3",
- Pages="386--395",
- Month="Mar"
+ author="Sheffield, N. C. and Pierron, G. and Klughammer, J. and Datlinger, P. and Schonegger, A. and Schuster, M. and Hadler, J. and Surdez, D. and Guillemot, D. and Lapouble, E. and Freneaux, P. and Champigneulle, J. and Bouvier, R. and Walder, D. and Ambros, I. M. and Hutter, C. and Sorz, E. and Amaral, A. T. and de Alava, E. and Schallmoser, K. and Strunk, D. and Rinner, B. and Liegl-Atzwanger, B. and Huppertz, B. and Leithner, A. and de Pinieux, G. and Terrier, P. and Laurence, V. and Michon, J. and Ladenstein, R. and Holter, W. and Windhager, R. and Dirksen, U. and Ambros, P. F. and Delattre, O. and Kovar, H. and Bock, C. and Tomazou, E. M. ",
+ title={DNA methylation heterogeneity defines a disease spectrum in Ewing sarcoma},
+ journal={Nature Medicine},
+ year={2017},
+ volume={23},
+ number={3},
+ pages={386-395},
+ month={Mar},
+ doi = {10.1038/nm.4273}
}
@Article{LOLA,
- Author="Sheffield, N. C. and Bock, C. ",
- Title="{{L}{O}{L}{A}: enrichment analysis for genomic region sets and regulatory elements in {R} and {B}ioconductor}",
- Journal="Bioinformatics",
- Year="2016",
- Volume="32",
- Number="4",
- Pages="587--589",
- Month="Feb"
+ author={Sheffield, N. C. and Bock, C.},
+ title="{LOLA: enrichment analysis for genomic region sets and regulatory elements in R and Bioconductor},
+ journal={Bioinformatics},
+ year={2016},
+ volume={32},
+ number={4},
+ pages={587-589},
+ month={Feb},
+ doi = {10.1093/bioinformatics/btv612}
}
diff --git a/tests/testthat/helper-lifespan.R b/tests/testthat/helper-lifespan.R
new file mode 100644
index 0000000..3e578f5
--- /dev/null
+++ b/tests/testthat/helper-lifespan.R
@@ -0,0 +1,20 @@
+# Ancillary functions for cache lifespan tests.
+
+# Build a small data frame to cache.
+buildTestFrame = function() { data.frame(matrix(1:9, nrow=3)) }
+
+# Remove test case's temp cache folder.
+cleanLSTest = function() { unlink(lifespanTestsTmpdir(), recursive=TRUE) }
+
+# Count the number of items in the cache folder.
+countCacheItems = function() { length(list.files(getOption("RCACHE.DIR"))) }
+
+# Generate path to temp folder for test case.
+lifespanTestsTmpdir = function() { file.path(tempdir(), "lifespan") }
+
+# Establish a temp folder and set the cache home location to it.
+setupLSTest = function() {
+ testdir = lifespanTestsTmpdir()
+ if (!file_test("-d", testdir)) { dir.create(testdir) }
+ setCacheDir(lifespanTestsTmpdir())
+}
diff --git a/tests/testthat/test_all.R b/tests/testthat/test_all.R
index 05976d0..949dc66 100644
--- a/tests/testthat/test_all.R
+++ b/tests/testthat/test_all.R
@@ -1,6 +1,39 @@
library(simpleCache)
-context("Test_that")
+context("error checking")
+
+test_that("notifications and messages as expected", {
+
+ # message if cache exists
+ simpleCache("normSample", instruction = {rnorm(5e3, 0,1)}, cacheDir = tempdir(), recreate=TRUE)
+ expect_message(simpleCache("normSample", instruction = {rnorm(5e3, 0,1)}, cacheDir = tempdir(), recreate=FALSE, noload = TRUE), "^::Cache exists")
+ deleteCaches("normSample", force = TRUE)
+
+ # storeCache should not accept non-character cacheName
+ expect_error(storeCache(cacheName = normSample, recreate = TRUE, cacheDir = tempdir()), "storeCache expects the cacheName variable to be a character vector.")
+
+ # message when cacheDir isn't defined
+ expect_message(simpleCache("normSample", { rnorm(5e3, 0,1) }), regexp = "^No cacheDir specified.")
+
+ # error when buildDir is empty without instruction
+ expect_error(simpleCache("normSample", cacheDir = tempdir(), buildDir = tempdir(), recreate = TRUE), "::Error::\tNo instruction or RBuild file provided.")
+
+ # error when buildEnvir includes "instruction"
+ expect_error(simpleCache("normSample", { rnorm(5e3, 0,1) }, buildEnvir = list(instruction="foo"), recreate=TRUE, cacheDir = tempdir()), "Can't provide a variable named 'instruction' in buildEnvir")
+
+ # error when instruction and buildDir are null
+ expect_error(simpleCache("normSample", instruction = NULL, buildDir = NULL, cacheDir = tempdir(), recreate=TRUE))
+
+ # error when cacheName is not character
+ expect_error(simpleCache(12345, instruction = { rnorm(5e3, 0,1) }, buildDir = NULL, cacheDir = tempdir(), recreate=TRUE))
+
+ # message when return is NULL
+ expect_message(simpleCache("normSample", instruction = {normSample <- NULL}, recreate = TRUE, cacheDir = tempdir()), "NULL value returned, no cache created")
+
+ # we must clean up any temporary caches we make
+ deleteCaches("normSample", force=TRUE, cacheDir = tempdir())
+
+})
test_that("Caching respects files existing", {
setCacheDir(tempdir())
@@ -11,7 +44,7 @@ test_that("Caching respects files existing", {
simpleCache("normSample", { rnorm(5e3, 0,1) }, recreate=TRUE)
expect_equal(signif(normSample[1], 6), -1.51637)
- # Should not evaluate:
+ # Should not evaluate
simpleCache("normSample", { rnorm(5e3, 0,1) })
expect_equal(signif(normSample[1], 6), -1.51637)
@@ -26,3 +59,111 @@ test_that("Caching respects files existing", {
})
+context("basic functionality")
+
+test_that("timer works", {
+
+ setCacheDir(tempdir())
+ timeout <- capture_messages(simpleCache("normSample", { rnorm(5e3, 0,1) }, recreate=TRUE, timer = TRUE))[2]
+ expect_match(timeout, "<[0-9][0-9]h [0-9][0-9]m [0-9].[0-9]s>")
+
+ # we must clean up any temporary caches we make
+ deleteCaches("normSample", force=TRUE)
+
+})
+
+test_that("cache can be created without loading", {
+
+ expect_null(simpleCache("normSample", { rnorm(5e3, 0,1) }, recreate = TRUE, noload = TRUE, cacheDir = tempdir()))
+
+ expect_true("normSample.RData" %in% listCaches())
+
+ # we must clean up any temporary caches we make
+ deleteCaches("normSample", force=TRUE)
+
+})
+
+test_that("object can be stored as cache", {
+
+ normSample2 <<- rnorm(5e3,0,1)
+
+ expect_message(storeCache("normSample2", cacheDir = NULL, recreate = TRUE), "^You must set global option RCACHE.DIR")
+
+ expect_message(storeCache("normSample2", cacheDir = tempdir(), recreate = TRUE), "^::Creating cache::")
+
+ expect_message(storeCache("normSample2", cacheDir = tempdir(), recreate = FALSE), "^::Cache already exists")
+
+ # we must clean up any temporary caches we make
+ deleteCaches("normSample2", force=TRUE)
+
+})
+
+test_that("option setting works", {
+
+ # set all options
+ setCacheDir(tempdir())
+ setSharedCacheDir(tempdir())
+ setCacheBuildDir(tempdir())
+ addCacheSearchEnvironment("cacheEnv")
+
+ # capture output and check
+ options_out <- capture_messages(simpleCacheOptions())
+
+ expect_true(grepl(tempdir(), options_out[1]))
+ expect_true(grepl(tempdir(), options_out[2]))
+ expect_true(grepl(tempdir(), options_out[3]))
+ expect_true(grepl("cacheEnv", options_out[4]))
+
+ # reset the cache search option
+ resetCacheSearchEnvironment()
+
+ # check to make sure it is gone
+ options_out <- capture_messages(simpleCacheOptions())
+ expect_true(!grepl("cacheEnv", options_out[4]))
+
+})
+
+test_that("objects pass through in buildEnvir", {
+
+ setCacheDir(tempdir())
+
+ set.seed(1)
+ simpleCache("piSample", { pi^x }, buildEnvir = list(x=2), recreate=TRUE, timer = TRUE)
+ rm(piSample)
+
+ simpleCache("piSample", reload = TRUE)
+
+ expect_equal(signif(piSample, 3), 9.87)
+
+ # we must clean up any temporary caches we make
+ deleteCaches("piSample", force=TRUE)
+
+})
+
+test_that("caches can be loaded", {
+
+ setCacheDir(tempdir())
+
+ simpleCache("loadSample", { rnorm(5e3, 0,1) }, recreate=TRUE)
+ loadCaches("loadSample")
+
+ expect_true("loadSample" %in% ls())
+
+ # we must clean up any temporary caches we make
+ deleteCaches("loadSample", force=TRUE)
+
+})
+context("misc")
+
+test_that("listCaches returns name of given cache", {
+
+ setCacheDir(tempdir())
+ set.seed(1)
+ simpleCache("normSample", { rnorm(5e3, 0,1) }, recreate=TRUE)
+ expect_true("normSample.RData" %in% listCaches())
+
+ # we must clean up any temporary caches we make
+ deleteCaches("normSample", force=TRUE)
+
+})
+
diff --git a/tests/testthat/test_cache_lifespan.R b/tests/testthat/test_cache_lifespan.R
new file mode 100644
index 0000000..914122b
--- /dev/null
+++ b/tests/testthat/test_cache_lifespan.R
@@ -0,0 +1,128 @@
+# test_cache_lifespan.R
+# Tests for enforcing cache lifespan requirement.
+
+# The pattern/them for each test is something like:
+# 1. Ensure the test case has a fresh, clean folder.
+# 2. Create a dummy cache.
+# 3. Check that only 1 file is in the cache.
+# 4. Grab the cache timestamp.
+# 5. Make another simpleCache call.
+# 6. Again check that there's a single cache file and grab the timestamp.
+# 7. Compare timestamps.
+
+context("lifespan")
+
+# Provide clean cache folder (pre-set) for each test case.
+my_test_that = function(description, instruction) {
+ setupLSTest()
+ test_that(description, instruction)
+ cleanLSTest()
+}
+
+# Control loading behavior for these tests to focus on lifespan/recreate effects.
+mySimpleCache = function(...) { simpleCache(..., noload=TRUE) }
+
+# Negative control
+my_test_that("Cache file isn't replaced if no lifespan is specified and recreate=FALSE", {
+ expect_equal(0, countCacheItems())
+ mySimpleCache("testDF", recreate=FALSE, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ t0 = file.info(fp)$ctime
+ mySimpleCache("testDF", recreate=FALSE, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ t1 = file.info(fp)$ctime
+ expect_equal(t0, t1)
+})
+
+# Another sort of control
+my_test_that("Cache file is replaced if no lifespan is specified and recreate=TRUE", {
+ expect_equal(0, countCacheItems())
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ expect_true(file_test("-f", fp))
+ t0 = file.info(fp)$ctime
+ Sys.sleep(1) # Delay so that our time comparison can work.
+ mySimpleCache("testDF", recreate=TRUE, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ t1 = file.info(fp)$ctime
+ expect_true(t1 > t0)
+})
+
+# Specificity
+my_test_that("Cache remains unchanged if younger than explicit lifespan", {
+ expect_equal(0, countCacheItems())
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ expect_true(file_test("-f", fp))
+ t0 = file.info(fp)$ctime
+ mySimpleCache("testDF", lifespan=0.5, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ t1 = file.info(fp)$ctime
+ expect_true(t1 == t0)
+})
+
+# Sensitivity
+my_test_that("Cache is replaced if older than explicit lifespan", {
+ expect_equal(0, countCacheItems())
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ expect_true(file_test("-f", fp))
+ t0 = file.info(fp)$ctime
+ Sys.sleep(1) # Time difference comparison reliability.
+ mySimpleCache("testDF", lifespan=0, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ t1 = file.info(fp)$ctime
+ expect_true(t1 > t0)
+})
+
+# Explicit recreate argument trumps cache lifespan to determine recreation.
+my_test_that("Cache is replaced if recreate=TRUE even if cache is fresh", {
+ expect_equal(0, countCacheItems())
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_true(file_test("-f", fp))
+ expect_equal(1, countCacheItems())
+ t0 = file.info(fp)$ctime
+ Sys.sleep(1) # Time difference comparison reliability.
+ mySimpleCache("testDF", recreate=TRUE, lifespan=0, instruction={ buildTestFrame() })
+ expect_equal(1, countCacheItems())
+ t1 = file.info(fp)$ctime
+ expect_true(t1 > t0)
+})
+
+my_test_that("simpleCache can pick up option specifying max cache age.", {
+ options(MAX.CACHE.AGE = 0)
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_true(file_test("-f", fp))
+ t0 = file.info(fp)$ctime
+ Sys.sleep(1) # Time difference comparison reliability.
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ t1 = file.info(fp)$ctime
+ expect_true(t1 > t0)
+})
+
+my_test_that("Direct lifespan specification is preferred to background option", {
+ options(MAX.CACHE.AGE = 1)
+ fp = file.path(getOption("RCACHE.DIR"), "testDF.RData")
+ expect_false(file_test("-f", fp))
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_true(file_test("-f", fp))
+ t0 = file.info(fp)$ctime
+ Sys.sleep(1)
+ mySimpleCache("testDF", instruction={ buildTestFrame() })
+ expect_equal(t0, file.info(fp)$ctime) # Cache is fresh via MAX.CACHE.AGE.
+ Sys.sleep(1) # Time difference comparison reliability.
+ mySimpleCache("testDF", lifespan=0, instruction={ buildTestFrame() })
+ t1 = file.info(fp)$ctime
+ expect_true(t1 > t0) # Cache is stale via lifespan.
+})