library("adorn")
# Call style: runs on every call
shout <- decorator(function(f, ...) toupper(f(...)))
# Call style with a parameter
repeated <- decorator(function(f, ..., times = 2) {
rep(f(...), times)
})
# Factory style: keeps state between calls
counted <- decorator(function(f) {
n <- 0
function(...) {
n <<- n + 1
message("call ", n)
f(...)
}
})
greet <- shout %@% function(who) paste("hello", who)
greet("world")
#> [1] "HELLO WORLD"
ones <- repeated(times = 3) %@% function() 1
ones()
#> [1] 1 1 1Create a decorator
Description
decorator() turns an ordinary function into a decorator. The first argument of wrapper receives the function being decorated. There are two styles, chosen by whether wrapper has a … argument:
Usage
decorator(wrapper, name = NULL)
Arguments
wrapper
|
A function, as described above. |
name
|
Name shown when printing the decorator and in decorators(). By default it is taken from how the decorator is written when applied with %@% (timed %@% f gives “timed”, and retry(times = 5) %@% f gives “retry”). Set it to override that; “decorator” is the last resort.
|
Details
-
Call style,
function(f, …, <params>): the body runs on every call.…holds the arguments of that call; forward them withf(…). -
Factory style,
function(f, <params>): the body runs once, when the function is decorated, and returns the replacement function. Use this when the decorator needs state, such as a cache.
Arguments after … (call style) or after f (factory style) are decorator parameters. Set them by calling the decorator: retry(times = 5), for a decorator named retry.
If your decorator stores the result of f(…) before returning it, use withVisible() to keep functions that return invisible() quiet.
Whatever the style, the decorated function keeps the formal arguments of the original, so argument matching, missing(), defaults and introspection all behave as before.
Value
A decorator: a function that decorates a function when called with one, and returns a configured decorator when called with parameters.