Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a package function inherited by another package

I am trying to override the tidy.source function of the knitr package. The problem is that tidy.source is defined in the formatR package, which is imported by the knitr package. If I run:

get("tidy.source", envir=asNamespace("knitr"))

I get the original code. So I am tempted to override tidy.source with:

assignInNamespace ("tidy.source", function()print("My tidy.source"), "knitr"),

but I get:

Error in bindingIsLocked(x, ns) : no binding for "tidy.source".

In fact tidy.source is defined in formatR and inherited by knitr. With:

assignInNamespace ("tidy.source", function()print("My tidy.source"), "formatR")

everything is apparently smooth, but checking again get("tidy.source", envir=asNamespace("knitr")) shows that inside knitr nothing has changed.

Any help?

EDIT:

This question is partly obsolete due to the new development release of knitr/formatR. Many thanks to Yihui for noticing this discussion and for deciding to update his package. See:

https://github.com/yihui/formatR/commit/6f70360f359caa8d2bb33190a1c89530defb0e98

I can definitely switch from Sweave to knitr.

The general question concerning the overriding of an imported package function remains anyway open. Since it is not related to knitr/formatR package anymore, I restate it in more general terms.

Suppose you have a package main importing the package imp. If you load the former, "package:main" shows in the list of the attached packages and both "main" and "sub" show among the names of the loaded namespaces.

Assume that main imports the exported sub function exp.sub.func, which calls in turns the non-exported sub function prv.sub.func. If you want to change/customise exp.sub.func with your exp.sub.func.mod, you may think of using:

assign("exp.sub.func", exp.sub.func.mod, asNamespace ("sub"))

As a result, by running sub::exp.sub.func you will get your patched version (that is exp.sub.func.mod).
Unfortunately, as far as your exp.sub.func.mod keeps on relying on prv.sub.func, you get the error:

Error in [...] : object 'prv.sub.func' not found

In fact:

environment(sub::exp.sub.func) 

returns now: <environment: R_GlobalEnv> while it was <environment: namespace:sub> before patching.

The question is: how to move the patched function to the proper namespace?

To implement the problem above you can use whatever packages of course; in my case I used knitr and formatR as main and imported namespace and tidy.source() as patched function.

like image 454
antonio Avatar asked Nov 27 '12 23:11

antonio


2 Answers

Changing the function in the formatR namespace doesn't change what knitr uses because knitr is already loaded. So, you could unload and reload it.

assignInNamespace("tidy.source", function()print("My tidy.source"), "formatR")
detach('package:knitr', unload=TRUE)
library(knitr)
get("tidy.source", envir=asNamespace("knitr"))
#function()print("My tidy.source")
like image 192
GSee Avatar answered Nov 15 '22 08:11

GSee


If all you want is comments after function arguments, I have added the support in the development version, and you can install it from Github.

Normally it is a bad idea to modify packages using assignInNamespace(), as its documentation shows.

like image 2
Yihui Xie Avatar answered Nov 15 '22 08:11

Yihui Xie