Skip to content

jankowtf/cachefun

Repository files navigation

cachefun

The goal of cachefun is to make caching fun ;-)

It let's you define "cache-aware functions" (cafuns or cafs): functions that have an internal/built-in cache.

Whether or not you want this cache to be updated upon every execuction of the function or not is completely up to you (see .refresh_default argument of caf_create):

  • When setting .refresh_default = TRUE the caf would behave just as any regular R function unless you tell it otherwise by setting .refresh = FALSE when calling your caf
  • When setting .refresh_default = FALSE, then it's the other way around: you would always get the value of the internal cache unless you explicitly request the cache to be updated by setting .refresh = TRUE when calling your caf.

You are also able to define reactive dependencies that directly leverage the reactivity functionality of {shiny}. Thus, internal cache values are automatically invalidated if the cache value of one of your function's dependencies changes.

The main use case I had in mind when developping this package was offering effortless ("built-in") and flexible (sometimes I don't want the cache result, sometimes I do") iternal caching for functions that take a long time to run (e.g. loading data, tidying data, etc.).

Installation

require("devtools")
devtools::install_github("rappster/cachefun")

Examples

Introduction

library(cachefun)
# Define a regular function that you'd like to make "cache-aware"
fun <- function() Sys.time()

# Turn this function into a cache-aware function
caf <- caf_create(fun = fun)

str(caf)
#> function (..., .fun = function () 
#> Sys.time(), .refresh = TRUE, .reset = FALSE)
# Note that default value for arg '.refresh = TRUE' >> by default, the inner
# function is always executed (internal cache is always updated). This implies
# that the function behaves like any regular R function unless you explicitly
# tell it to return the internal cache in a particular call by setting '.refresh
# = FALSE'.

caf() # Inner function executed, result is cached
#> [1] "2018-02-06 11:05:07 CET"
Sys.sleep(1)
caf() # Inner function executed, result is cached
#> [1] "2018-02-06 11:05:08 CET"
Sys.sleep(1)
caf(.refresh = FALSE) # Inner function NOT executed, internal cache returned
#> [1] "2018-02-06 11:05:08 CET"
Sys.sleep(1)
caf(.refresh = FALSE) # Inner function NOT executed, internal cache returned
#> [1] "2018-02-06 11:05:08 CET"
Sys.sleep(1)
caf() # Inner function executed, result is cached
#> [1] "2018-02-06 11:05:11 CET"
Sys.sleep(1)
caf(.refresh = FALSE) # Inner function NOT executed, internal cache returned
#> [1] "2018-02-06 11:05:11 CET"

Change the default value of args

library(cachefun)
fun <- function() Sys.time()
caf <- caf_create(fun = fun, .refresh_default = FALSE)

str(caf)
#> function (..., .fun = function () 
#> Sys.time(), .refresh = FALSE, .reset = FALSE)
# Note that default value for arg '.refresh = FALSE' >> you reversed the
# pre-configured default settings. This implies that the function will always
# return the internal cache value unless you explicitly tell it not to by
# setting `.refresh = TRUE` in a particular call

caf() # Inner function is INITIALLY executed (as cache is still empty),
#> [1] "2018-02-06 11:05:45 CET"
        # result is cached
caf() # Inner function NOT executed, internal cache returned
#> [1] "2018-02-06 11:05:45 CET"
caf(.refresh = TRUE) # Explicit refresh request:
#> [1] "2018-02-06 11:05:45 CET"
                      # Inner function executed, result is cached
caf() # Inner function NOT executed, internal cache returned
#> [1] "2018-02-06 11:05:45 CET"

Inner function with argumeents

library(cachefun)
fun <- function(x) Sys.time() + x

caf <- caf_create(fun = fun)

caf(x = 3600) # Inner function executed, result is cached
#> [1] "2018-02-05 10:13:44 CET"
caf(x = 3600 * 5, .refresh = FALSE) # Inner function NOT executed, internal cache returned
#> [1] "2018-02-05 10:13:44 CET"
caf(x = 3600 * 5) # Inner function executed, result is cached
#> [1] "2018-02-05 14:13:44 CET"

Reset internal cache

library(cachefun)
fun <- function(x) rnorm(x)

caf <- caf_create(fun = fun)

res <- caf(x = 1000)

caf_reset(caf = caf)

Reactive dependencies

library(cachefun)

# Define 'caf_1' that 'caf_2' will depend on
fun_1 <- function(x) x
caf_1 <- caf_create(fun = fun_1)

# Define 'caf_2' that depends on 'caf_1'
fun_2 <- function(x, caf_1) {
  caf_1(.refresh = FALSE) + x
}
caf_2 <- caf_create(fun = fun_2, caf_1 = caf_1)
# Note that we state the dependency by relying on the internal cache of 'caf_1'
# ('.refresh = FALSE'). Behind the scenes, 'caf_create' takes care of turning 
# dependencies that are defined as args of the inner function into 
# **reactive** ones (directly leveraging shiny's reactive capabilities). This
# means that 'caf_2' will be re-evaluated whenever the cached return value of
# dependency 'caf_1' is updated. In shiny terms, the cache of 'caf_2' is
# autmatically invalidated when it needs to be and you never run the risk of
# being "out-of-sync" with dependencies

caf_1(x = 10)
#> [1] 10
caf_2(x = 50)
#> [1] 60

caf_1(x = 100)
#> [1] 100
caf_2(x = 50, .refresh = FALSE)
#> [1] 150
# Note that even though we explicitly requested that 'caf_2' should return the
# internally cached value of the previous execution (60), the inner function was
# instead re-evaluated. This is because the cached value of 'caf_1' has changed
# which automatically invalidates all reactive components that depend on it
# (i.e. the cache value of 'caf_2'). This way you can be sure that even though
# you might like to use cached values, you still never run the risk of being
# out-of-sync regarding your function's dependencies

caf_2(x = 200)
#> [1] 300

About

No description or website provided.

Topics

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE
MIT
LICENSE.md

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages