从编译的二进制版本“反向工程”R 包

hok*_*bot 12 r r-package

我所在的组织拥有许多内部 R 包,这些包都是多年前编写的。这些文件存储为.zip在 R 3.x 下的 Windows 上构建的存档。它们无法在不重新构建的情况下加载到 Linux 或 macOS 或 R 4.y 下。不幸的是,我无权访问包源。他们输给了时间……

我想获取这些二进制文件,提取源代码,并根据当前的最佳实践(版本控制、roxygen2testthat等)重新打包它。最好的方法是什么?

我已经通过以下方式解决了其中一个二进制文件:

  1. 手动将加载的命名空间中的对象(导出和内部函数、数据集等)的源代码复制到新.R文件。
  2. 手动将 Roxygen 块添加到.R文件中,以便重现浏览器中显示的帮助页面。

我部分陷入(1),因为某些功能是 S4 通用的。dput(<name>)给出new("standardGeneric", ...)而不是简单的function定义。否则,这个过程相当简单,但非常耗时。

有没有办法以编程方式从 R 包二进制文件“反向工程”源文件,同时正确处理 S4 通用函数、类和方法?

在这个问题得到解决之前,组织中的每个人都将停留在 R 3.6 上。

Rom*_*man 9

检查这是否适用于R 3.6.

下面的脚本可以通过将所有函数源写入单独且适当命名的文件中来自动解决问题的至少一部分.R。该代码还将处理隐藏函数。

提取代码

# Use your package name
package_name <- "dplyr" 

# Extract all method names, including hidden
nms <- paste(lsf.str(paste0("package:", package_name), all.names = TRUE))

# Loop through the method names,
# extract head and body, and write them to R files
for (i in 1:length(nms)) {

    # Extract name
    nm <- nms[i]

    # Extract head
    hd_raw <- capture.output(args(nms[i]))
    # Collapse raw output, but drop trailing NULL
    hd <- paste0(hd_raw[-length(hd_raw)], collapse = "\n")

    # Extract body, collapse
    bd <- paste0(capture.output(body(nms[i])), collapse = "\n")
    
    # Write all to file
    write(paste0(hd, bd), file = paste0(nm, ".R"))
}
Run Code Online (Sandbox Code Playgroud)

提取帮助文件

要以类似的方式提取函数的帮助文本,您可以使用以下答案中的代码:

起点可能是这样的:

library(tools)
package_name <- "dplyr" 
db <- Rd_db(package_name)

# Extract all method names, including hidden
nms <- paste(lsf.str(paste0("package:", package_name), all.names = TRUE))

# Loop through the method names,
# extract Rd contents if they exist in this namespace, 
# and write them to new Rd files
for (i in 1:length(nms)) {
    
    # Extract name
    nm <- nms[i]
    
    rd_raw <- db[names(db) %in% paste0(nm, ".Rd")]
    if (length(rd_raw) > 0) {
        rd <- paste0(capture.output(rd_raw), collapse = "\n")
        # Write all to file
        write(rd, file = paste0(nm, ".Rd"))
    }
    
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这非常有帮助!我只需要稍微编辑帮助提取代码(“.rd”而不是“.Rd”)。现在我只需要弄清楚如何重新创建 S4 自定义通用... (3认同)