Reputation: 32426
Is it possible to go from compiled R code found in packages back to R source code? I would like to get the source code for various functions from packages installed from CRAN or other sources. I know I can download the full source via separate downloads.
Upvotes: 1
Views: 2030
Reputation: 78
Andrie's answer above has been hugely helpful for me. I had to use a package that is not on CRAN or git, and was only distributed as a compiled package built for R 3.0.1. Obviously when I tried to use it with R 4 it didn't work, and I didn't want to keep switching back and forth between R versions, so I had to decompile the package, rebuild the source, and reinstall.
However, Andrie's code example has a few shortcomings, most importantly that it only decompiles exported functions, not internal ones. Obviously this post is pretty old, but I'm posting my updates here in case it's helpful for anyone else trying to do the same thing.
packagename <- "ggplot2" #input package name here
pkg <- asNamespace(packagename) # importing as namespace rather than package accesses internals
allfuns <- ls(name = pkg)
for(f in allfuns){
# Andrie's [1] subset didn't work if the function arguments were more than one line long
args <- head(capture.output(print(args(getFromNamespace(f, packagename)))), -1)
body <- paste(capture.output(print(body(getFromNamespace(f, packagename)))),
collapse = "\n")
# This now writes directly to an R code file, rather than the console, to avoid copy/paste
# You could tweak this to create a separate file for each function, if desired.
cat(sprintf("%s <- %s\n%s\n\n", f, args, body),
file = paste(packagename, "functions.R"),
append = TRUE)
}
Upvotes: 1
Reputation: 179448
You can extract the text of functions in a package using args()
and body()
. To list all the objects in a package you can use ls()
and specify the package environment.
Caveat: The approach below will give you the source code, but not the NAMESPACE
or DESCRIPTION
.
For example, to print the source code of everything in ggplot2
, try this:
library(ggplot2)
pkg <- as.environment("package:ggplot2")
allfuns <- ls(envir = pkg)
for(f in allfuns[1:2]){
args <- capture.output(print(args(f)))[1]
body <- paste(capture.output(print(body(f))), collapse = "\n")
cat(sprintf("%s <- %s\n%s\n\n", f, args, body))
}
This will give you:
%+% <- function (e1, e2)
{
e2name <- deparse(substitute(e2))
if (is.theme(e1))
add_theme(e1, e2, e2name)
else if (is.ggplot(e1))
add_ggplot(e1, e2, e2name)
}
%+replace% <- function (e1, e2)
{
if (!is.theme(e1) || !is.theme(e2)) {
stop("%+replace% requires two theme objects", call. = FALSE)
}
e1[names(e2)] <- e2
e1
}
Upvotes: 3