Reputation: 5601
I'm trying to instrument some functions in R, by replacing them with my own versions which record some information and then call the original versions. My trouble is, how do I construct the call such that it exactly replicates the original arguments.
First, we'll set up an environment
env <- new.env()
One way I could do this is by getting the call and modifying it. However, I don't know how to do this with a primitive function.
## Option 1: get the call and modify it
env$`[` <- function(x, i, j, ...) {
my.call <- match.call()
## This isn't allowed.
my.call[[1]] <- as.name(.Primitive("["))
record.some.things.about(i, j)
eval(my.call, envir = parent.frame())
}
Alternatively, I could just get the arguments and use do.call
. However, I haven't worked out how to extract the arguments correctly.
## Option 2: do a call with the arguments
env$`[` <- function(x, i, j, ...) {
## This outputs a list, so if 'i' is missing, then 'j' ends up in the 'i' position.
## If I could get an alist here instead, I could keep 'j' in the right position.
my.args <- match.call()[-1]
record.some.things.about(i, j)
do.call(
.Primitive("["),
my.args,
envir = parent.frame()
)
}
Then, if we've done things right, we can eval some expression which uses [
inside the enviroment we've constructed, and our instrumented function will be called instead:
## Should return data.frame(b = c(4, 5, 6))
evalq(
data.frame(a = c(1, 2, 3), b = c(4, 5, 6))[, "b"],
envir = env
)
Can anyone help/advise?
Upvotes: 1
Views: 222
Reputation: 132706
Use trace
:
trace(`[.data.frame`, quote({print("hello!")}), at = 1)
iris[1,]
#Tracing `[.data.frame`(iris, 1, ) step 1
#[1] "hello!"
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1 5.1 3.5 1.4 0.2 setosa
Upvotes: 4
Reputation: 970
Can't you just capture everything for original function args with triple dots arg, that gets passed on to the original function?
sum <- function(..., na.rm = TRUE) {
print("my sum") # here is where you can "record some info"
base::sum(..., na.rm = na.rm) # then call original function w/ ...
}
base::sum(5,5, NA)
##[1] NA
# your function
sum(5,5, NA)
##[1] "my sum"
##[1] 10
Upvotes: 0