2013-05-10 5 views
6

Angenommen, ich ersetze eine Funktion eines Pakets, z. B. knitr:::sub_ext. (Hinweis: Ich bin besonders interessiert, wo es eine interne Funktion ist, d. H. Nur zugänglich durch ::: im Gegensatz zu ::, aber die gleiche Antwort kann für beide funktionieren).rufen Sie die ursprüngliche Version der Paketfunktion ab, selbst wenn sie überzugewiesen wurde

library(knitr) 
my.sub_ext <- function (x, ext) { 
    return("I'm in your package stealing your functions D:") 
} 
# replace knitr:::sub_ext with my.sub_ext 
knitr <- asNamespace('knitr') 
unlockBinding('sub_ext', knitr) 
assign('sub_ext', my.sub_ext, knitr) 
lockBinding('sub_ext', knitr) 

Frage: Gibt es eine Möglichkeit, die ursprünglichenknitr:::sub_ext abzurufen, nachdem ich das getan habe? Vorzugsweise ohne das Paket neu zu laden?


(Ich kenne einige Leute wollen wissen, warum ich das wollen würde, dies zu tun, hier ist es. Nicht für die Frage Pflichtlektüre). Ich habe wie so einige Funktionen in Paketen Patchen (nicht eigentlich die sub_ext Funktion ...):

original.sub_ext <- knitr:::sub_ext 
new.sub_ext <- function (x, ext) { 
    # some extra code that does something first, e.g. 
    x <- do.something.with(x) 
    # now call the original knitr:::sub_ext 
    original.sub_ext(x, ext) 
} 
# now set knitr:::sub_ext to new.sub_ext like before. 

Ich stimme dies nicht generell eine gute Idee ist (in den meisten Fällen handelt es sich schnelle Lösungen, bis Änderungen vornehmen ihren Weg in CRAN, oder sie sind "Feature Requests", die nie genehmigt werden würden, weil sie etwas fallspezifisch sind.

Das Problem mit dem oben genannten ist, wenn ich es versehentlich zweimal ausführen (z realknitr:::sub_ext, so bekomme ich unendliche Rekursion.

Da sub_ext eine interne Funktion (ich würde es nicht direkt aufrufen, sondern Funktionen von knitr wie knit es nennen intern), kann ich nicht alle Funktionen zu ändern, hoffen, dass sub_ext rufen new.sub_ext manuell aufrufen , daher der Ansatz, die Definition im Paket-Namespace zu ersetzen.

Antwort

4

Wenn Sie assign('sub_ext', my.sub_ext, knitr) ausführen, überschreiben Sie den zuvor mit sub_ext verknüpften Wert unwiderruflich mit dem Wert my.sub_ext. Wenn Sie zum ersten Mal den ursprünglichen Wert bunkern, aber es ist nicht schwer, es zurückgesetzt, wenn Sie fertig sind:

library(knitr) 
knitr <- asNamespace("knitr") 

## Store the original value of sub_ext 
.sub_ext <- get("sub_ext", envir = knitr) 

## Overwrite it with your own function 
my.sub_ext <- function (x, ext) "I'm in your package stealing your functions D:" 
assignInNamespace('sub_ext', my.sub_ext, knitr) 
knitr:::sub_ext("eg.csv", "pdf") 
# [1] "I'm in your package stealing your functions D:" 

## Reset when you're done 
assignInNamespace('sub_ext', .sub_ext, knitr) 
knitr:::sub_ext("eg.csv", "pdf") 
# [1] "eg.pdf" 

Alternativ, solange Sie nur Codezeilen hinzugefügt, was bereits vorhanden ist, können Sie Fügen Sie diesen Code mit trace() hinzu. Was ist trace() schön ist, dass, wenn Sie fertig sind, können Sie untrace() verwenden die Funktion des Körpers in seine ursprüngliche Form zurückzukehren:

trace(what = "mean.default", 
     tracer = quote({ 
      a <- 1 
      b <- 2 
      x <- x*(a+b) 
     }), 
     at = 1) 
mean(1:2) 
# Tracing mean.default(1:2) step 1 
# [1] 4.5 
untrace("mean.default") 
# Untracing function "mean.default" in package "base" 
mean(1:2) 
# [1] 1.5 

Beachten Sie, dass, wenn die Funktion, die Sie Ablaufverfolgung in einem Namensraum ist, werden Sie wollen Verwenden Sie das trace() Argument where, übergeben Sie den Namen einer anderen (exportierten) Funktion, die den Namespace der zu verfolgenden Funktion teilt. Um also eine nicht exportierte Funktion in Knitr 's Namensraum zu verfolgen, könnten Sie where=knit

+0

AHh, vermutete ich so viel (unwiderruflich überschreiben den Wert). Ich hatte gehofft, man könnte so etwas wie "Knitr" in einer privaten/"frischen" Umgebung nachladen und den Wert von dort abrufen. Ich bin jedoch sehr glücklich darüber, dass ich den Wert zurücksetzen kann, wenn ich fertig bin (warum habe ich nicht daran gedacht ?!) und der Fall, der die Frage inspirierte, ist in der Tat ein Fall von Add-In-Codezeilen zu der existierenden Funktion, so kann ich sogar die "trace" -Methode verwenden (nett btw! nie wirklich 'trace' vorher verwendet). –

+0

@ mathematic.coffee - Ich denke, Sie könnten immer so etwas tun, einen Systemaufruf verwenden, um die Definition der Funktion aus einer frischen R-Sitzung abzurufen: 'x <- system2 (" Rscript ", c (" - e ", shQuote) ('dput (knitr ::: sub_ext)')), stdout = TRUE); xx <- source (textConnection (x)) $ value; Umgebung (xx) <- asNamespace ("knitr"); assignInNamespace ("sub_ext", xx, asNamespace ("knitr")) '. Aber das scheint ziemlich lächerlich zu sein, oder ?! –

+0

Danke, dass du mich mit 'trace' bekannt gemacht hast! – isomorphismes

Verwandte Themen