Aquí hay un trazador de líneas que lo hace. Aquí PackageFuncA
es stats::acf
y PackageFuncB
es stats:::plot.acf
que queremos reemplazar con my.plot.acf
. my.plot.acf
imprime "Hello"
y luego llama al stats:::plot.acf
real.
# we want this to run in place of stats:::plot.acf
my.plot.acf <- function(x, ...) { cat("Hello\n"); stats:::plot.acf(x, ...) }
# this does it
library(proto)
acf <- with(proto(environment(acf), acf = stats::acf, plot.acf = my.plot.acf), acf)
# test
acf(1:10)
Un objeto proto es un entorno tal que cualquier función insertado en el objeto a través de la función proto
tiene su entorno restablecer automáticamente a ese objeto. El primer arg de proto()
es el elemento primario del objeto proto.
En el ejemplo anterior, se ha configurado para que la variable acf
se refiera a la versión de acf
que se insertó en el objeto proto (que es igual que el original, excepto que su entorno se ha modificado para ser el objeto proto) Cuando se ejecuta la nueva función acf
plot.acf
es una variable libre (es decir, no se define en acf
) por lo que se busca en el padre acf
y ese es el entorno en el objeto proto donde encuentra el nuevo plot.acf
. acf
podría tener otras variables libres, pero en esos casos, dado que no se encuentran en el objeto proto, se ve en el elemento primario del objeto proto que es el entorno original del documento original acf
. En términos de diagramas tenemos aquí donde <-
significa lado izquierdo es el padre del lado derecho:
environment(stats::acf) <- proto object <- revised acf
y objeto proto contiene tanto el plot.acf
y la acf
revisada.
También hemos establecido el entorno del nuevo plot.acf
en el objeto proto. Podemos o no haber necesitado hacer esto. En muchos casos, no importará. Si fuera importante no establecer el entorno de la nueva plot.acf
entonces se llevaría a cabo de esta manera porque proto nunca se pone el medio ambiente de las funciones insertadas usando [[...]]
:
acf <- with(p <- proto(environment(acf), acf = stats::acf), acf)
p[["plot.acf"]] <- my.plot.acf
En este ejemplo, ambos enfoques de trabajo.
Sería posible hacer todo esto con entornos de civil a costa de tener que utilizar varias líneas de código:
# create new environment whose parent is the original acf's parent
e <- new.env(parent = environment(stats::acf))
# the next statement is only need to overwrite any acf you already might have from
# trying other code. If you were sure there was no revised acf already defined
# then the next line could be omitted. Its a bit safer to include it.
acf <- stats::acf
# This sets the environment of the new acf. If there were no acf already here
# then it would copy it from stats::acf .
environment(acf) <- e
# may or may not need next statement. In this case it doesn't matter.
environment(my.plot.acf) <- e
e$plot.acf <- my.plot.acf
acf(1:10)
En este caso no hemos colocado la acf
revisada en e
como en el proto ejemplo pero solo establece su padre. De hecho, colocar el acf
revisado en e
o el objeto proto no es estrictamente necesario, pero solo se hizo en el caso de proto porque proto tiene el efecto secundario de restablecer el entorno y fue ese efecto secundario que buscamos.Por otro lado, es necesario poner el plot.acf
revisado en e
o el objeto proto para que se encuentre antes del original.
Es posible que desee leer este paper y, en particular, la sección sobre Proxies que comienza en la página 21, ya que la técnica que se muestra aquí es un ejemplo de un objeto proxy.
¿Sería más fácil crear su propia PackageFunA y modificar la llamada a PackageFunB para que llame a su función? – joran
Ver '? AssignInNamespace' – Andrie
joran - Prefiero no mantener mi propia versión de PackageFuncA, especialmente porque es más que unas pocas líneas de código. – SFun28