library("adorn")
# A function
shout <- decorator(function(f, ...) toupper(f(...)))
greet <- decorate(function(who) paste("hello", who), shout)
greet("world")
#> [1] "HELLO WORLD"
# An existing S3 method
area <- function(x, ...) UseMethod("area")
area.square <- function(x, ...) x$side^2
decorate("area", shout, class = "square")
area(structure(list(side = 3), class = "square"))
#> [1] "9"
# An R6 method
if (requireNamespace("R6", quietly = TRUE)) {
Greeter <- R6::R6Class("Greeter", public = list(
hi = function(who) paste("hello", who)
))
decorate("hi", shout, class = Greeter)
Greeter$new()$hi("world")
}
#> [1] "HELLO WORLD"Decorate a function or an existing method
Description
decorate() applies a decorator to a target: a function, or a method that already exists on an S3, S4, S7 or R6 class. Use %@% to decorate a function you are defining, and decorate() for code you did not write.
Usage
decorate(target, decorator, ...)
decorate(target, signature) <- value
Arguments
target
|
What to decorate; see the table above. |
decorator
|
A decorator, or a stack of them built with %@%.
|
…
|
Arguments for specific kinds of target:
|
signature
|
For the replacement form, the S7 class, S4 signature, S3 class name, or R6 method name(s), as above. |
value
|
For the replacement form, the decorator to apply. |
Details
target
|
Example | Extra argument |
| a function |
decorate(fn, d), the same as d %@% fn
|
|
| the name of an S3 generic |
decorate(“print”, d, class = “money”)
|
class
|
| an S4 generic |
decorate(area, d, signature = “Square”)
|
signature
|
| an S7 generic |
decorate(speak, d, class = Dog)
|
class
|
| the name of an R6 method |
decorate(“add”, d, class = Counter)
|
class
|
For S3 and R6 the method is named by a string, and class gives the class or R6 generator. For S4 and S7 the generic is the target. The replacement form (see below) works for all four systems.
Value
For a function, the decorated function. For R6, the class generator, invisibly. For the others, the decorated method, invisibly; the method is replaced in place.
R6 classes
decorate(“name”, decorator, class = Generator) replaces the method in the generator, so objects created afterwards use it. Objects that already exist keep the old method, because R6 copies methods into each object when it is created. An inherited method is copied into Generator and decorated there; the parent class is unchanged. Give several names to decorate several methods.
Replacement form
decorate(target, class) <- decorator mirrors S7’s method(generic, class) <- fn and works for all four systems:
decorate(speak, Dog) <- shout # S7 decorate(area, "Square") <- shout # S4 decorate(print, "money") <- shout # S3, with the generic function decorate(Counter, "add") <- shout # R6, public methods
R does not allow a string as the target of a replacement call, so for S3 pass the generic function. Its name is read from its UseMethod() call, so the generic must call UseMethod() directly. For R6 the form reaches public methods only; use the explicit form for where.