Newer
Older
# Do this in a separate file to see the generated help:
#library(devtools)
#document()
#load_all(as.package("../../onlineforecast"))
#?cache_name
#' Caching of the value returned by a function
#'
#' Use it in the beginning of a function, which runs a time consuming calculation, like fitting a model using optimization.
#'
#' It makes a cache name, which can be used to save a unique cache file (see \code{\link{cache_save}()}).
#'
#' The \code{cache_name} function must receive all the objects (in \code{...}) which influence the value of the function. It simply calculates a checksum using the \code{digest} package.
#'
#' Further, it finds the name of the calling function and its definition, such that if anything changes in the function definition, then the cache file name changes too.
#'
#' @title Generation of a name for a cache file for the value of a function.
#' @param ... The objects from which to calculate cache file name.
#' If no objects given, then all the objects of the calling function are used for generating the checksum for the file name.
#' @param cachedir Path for saving the cache, i.e. prefixed to the generated name, remember to end with '/' to make a directory.
#' @return A generated cache file name.
#' @examples
#' # A function for demonstrating the using caching
#' fun <- function(x, y){
#' # Generate the cache name (no argument given, so both x and y is used)
#' # If the result is cached, then just return it
#' if(file.exists(nm)){ return(readRDS(nm)) }
#' # Do the calculation
#' res <- x^2 + y + 1
#' # Wait 1 sec
#' Sys.sleep(1)
#' # Save for cache
#' cache_save(res, nm)
#' # Return
#' return(res)
#' }
#'
#' # For this example use a temporary directory
#' # In real use this should not be temporary! (changes between R sessions with tempdir())
#' cachedir <- tempdir()
#' # Try changing the arguments (x,y) and run again
#'
#' # See the cache file(s)
#'
#' # Demonstrate how cache_name() is functioning
#' # Cache using the all objects given in the function calling, i.e. both x and y
#' fun <- function(x,y){
#' x^2 + y + 1
#' return(cache_name())
#' }
#' # These are the same (same values)
#' fun(x=1,y=2)
#' fun(1,2)
#' fun(y=2,x=1)
#' # But this one is different
#' fun(x=2,y=1)
#'
#' # Test: cache using the values specified in the cache_name call
#' fun2 <- function(x,y){
#' x^2 + y + 1
#' return(cache_name(x))
#' }
#'
#' # So now its only the x value that change the name
#' fun2(1,2)
#' fun2(1,3)
#' # But this one is different
#' fun2(3,3)
#' # And the function named changed the name
#'
#' @export
cache_name <- function(..., cachedir = "cache"){
# Get the name, definition and arguments of the function from which cache_name was called
funname <- strsplit(deparse(sys.calls()[[sys.nframe()-1]]), "\\(")[[1]][1]
# Find the function in the nearest environment in the stack (i.e. parent calls)
## for(i in rev(sys.parents())){
## browser()
## if(funname %in% ls(parent.frame(i+1))){
## val <- mget(funname, parent.frame(i+1))
## break
## }
## }
## fundef <- digest::digest(attr(eval(val[[funname]]), "srcref"))
# Somehow the above stopped working, don't know why! just take it, this should do the same I guess
fundef <- try(get(funname), silent=TRUE)
fundef <- digest::digest(fundef)
# if no arguments were given, then use the arguments function from which cache_name was called
if(length(list(...)) == 0){
funargs <- digest::digest(as.list( match.call(definition = sys.function( -1 ), call = sys.call(-1)))[-1])