DBDelve
Dive deep into your data. A fast, native, multi-engine database client written in Rust. Free and open source, no telemetry.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A framework for creating function decorators in R.
A decorator wraps a function to add behaviour such as logging, timing or
caching, without changing the function itself. adorn applies decorators with an
infix operator, %@%, which reads top to bottom:
library(adorn)
shout <- decorator(function(f, ...) toupper(f(...)))
greet <- shout %@% function(who) paste("hello", who)
greet("world")
#> [1] "HELLO WORLD"
The point of adorn is that writing your own decorator is easy. adorn
ships no decorators of its own; it is the framework for making them. The
examples below use two small decorators, logged and timed, defined in
Using decorators.
vignette("writing-decorators") builds more, such as memoize, once and
retry, with the public API.
adorn is in early development, so the API may still change.
# install.packages("pak")
pak::pak("dyfanjones/adorn")
First, two basic decorators (see Writing your own decorator for how they work):
logged <- decorator(function(f, ...) {
name <- decorator_context()$name
message("-> ", name)
on.exit(message("<- ", name))
f(...)
})
timed <- decorator(function(f, ..., digits = 1) {
name <- decorator_context()$name
start <- Sys.time()
on.exit({
secs <- round(as.numeric(Sys.time() - start, units = "secs"), digits)
message(name, " took ", secs, " s")
})
f(...)
})
Apply one with %@%:
slow_add <- timed %@% function(x, y = 1) {
Sys.sleep(0.1)
x + y
}
slow_add(2)
#> slow_add took 0.1 s
#> [1] 3
Stack decorators with more %@%; the one on the left is the outermost.
decorators() lists the stack and undecorate() returns the original function.
tracked <- logged %@% timed(digits = 2) %@% function(x) x * 2
tracked(21)
#> -> tracked
#> tracked took 0 s
#> <- tracked
#> [1] 42
decorators(tracked) # "logged" "timed"
undecorate(tracked)(5) # 10, the original function
Decorators can be combined into a reusable bundle before they are applied:
logged_timed <- logged %@% timed
f <- logged_timed %@% function(x) x + 1
A decorator is named from how you write it next to %@%: timed %@% f and
timed(digits = 2) %@% f both give "timed". That is the name decorators()
reports. Pass name to decorator() to set it yourself. Inside a decorator,
decorator_context()$name is the name the decorated function was called by
(fib(10) gives "fib"); calls with no usable name, such as lapply(x, f),
fall back to the name of the decorated function, or "<anonymous>".
A decorated function keeps the formal arguments of the original, so argument
matching, defaults, missing(), lazy evaluation and formals() behave as
before.
A decorator is an ordinary function whose first argument is the function being
decorated. decorator() turns it into a decorator. There are two styles,
chosen by whether your function has a ... argument.
The first argument always receives the function to decorate, whatever you name
it, and it can't have a default. Decorator parameters go after it. adorn can't
check the name, so a signature like function(bob, f) is accepted but treats
bob as the function.
Call style runs on every call. Arguments after ... are parameters, set by
calling the decorator.
require_positive <- decorator(function(f, ..., arg = "x") {
args <- list(...)
if (any(args[[arg]] <= 0)) stop(arg, " must be positive", call. = FALSE)
f(...)
})
root <- require_positive(arg = "x") %@% function(x) sqrt(x)
root(16) # 4
root(-1) # Error: x must be positive
Factory style has no .... Your function runs once, when the function
is decorated, and returns the replacement, so each decorated function gets its
own state.
counted <- decorator(function(f) {
n <- 0
function(...) {
n <<- n + 1
message(decorator_context()$name, " call #", n)
f(...)
}
})
ping <- counted %@% function() "pong"
ping()
#> ping call #1
#> [1] "pong"
| You want | Write |
|---|---|
| Code on every call | decorator(function(f, ...) { ...; f(...) }) |
| State per decorated function | decorator(function(f) { state <- ...; function(...) { ...; f(...) } }) |
| Options | Arguments after ... (call style) or after f (factory style) |
| The function's name | decorator_context()$name |
If a decorator's own code fails, the error is reported against the decorator,
for example Error in logged(f, ...).
vignette("writing-decorators") has fuller examples, including memoize,
once and retry.
vignette("designing-decorators") covers choosing between the two styles, what
a decorated call costs, and the mistakes that are easy to make.
vignette("partial-decorators") shows how a factory can change the decorated
function's signature with formals = "replace", for partial application.
decorate()%@% is for functions you write. decorate() is for code that already
exists, and is the only way to reach a method that lives inside a generic or
class. It is an S7 generic that dispatches on the target:
以上为 README 的开头部分。其余内容请阅读原文。 查看完整 README ↗