R函数安装丢失的包

R function to install missing packages

对于我的一个脚本,我想编写一个 R 函数来检查是否已经安装了一个包:如果是这样,它应该使用 library() 将它导入到命名空间中,否则它应该安装并导入它。

我假设 pkgname 是一个字符串,并尝试编写如下内容:

ensure_library <- function(pkgname) {
  if (!require(pkgname)) {
    install.packages(pkgname, dependencies = TRUE)
  }
  require(pkgname)
}

很简单,这个功能不起作用。 如果我尝试 运行 它像 ensure_library("dplyr") 它会安装包 dplyr 但它会失败,因为它试图在命名空间中导入 pkgname 而不是 dplyr

ensure_library("dplyr")
Loading required package: pkgname
Installing package into ‘/home/luca/R-dev’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/src/contrib/dplyr_0.5.0.tar.gz'
Content type 'application/x-gzip' length 708476 bytes (691 KB)
==================================================
downloaded 691 KB

* installing *source* package ‘dplyr’ ...
** package ‘dplyr’ successfully unpacked and MD5 sums checked
** libs

.... a lot of compiling here....

installing to /home/luca/R-dev/dplyr/libs
** R
** data
*** moving datasets to lazyload DB
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded
* DONE (dplyr)

The downloaded source packages are in
    ‘/tmp/Rtmpfd2Lep/downloaded_packages’
Loading required package: pkgname
Warning messages:
1: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
  there is no package called ‘pkgname’
2: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
  there is no package called ‘pkgname’

此外,如果我现在重新运行它,它将再次安装dplyr

我意识到这可能是由于 R 非标准评估,我尝试了 eval/substitute/quote 的几种组合以使其与 require 一起使用,但我没有成功。

有人可以帮助我了解发生了什么以及是否有一些简单的解决方法吗?

我想知道是否存在已实现此功能的函数,但我真正感兴趣的是了解为什么我的代码无法按预期工作。

扩展使用 character.only=TRUE 的建议:如果您查看 require 的代码,您会发现第一步仅在默认值为 'character.only' 时执行(= FALSE) 持有:

> require
function (package, lib.loc = NULL, quietly = FALSE, warn.conflicts = TRUE, 
    character.only = FALSE) 
{
    if (!character.only) 
        package <- as.character(substitute(package))
    loaded <- paste("package", package, sep = ":") %in% search()
    if (!loaded) {
        if (!quietly) 
            packageStartupMessage(gettextf("Loading required package: %s", 
                package), domain = NA)
        value <- tryCatch(library(package, lib.loc = lib.loc, 
            character.only = TRUE, logical.return = TRUE, warn.conflicts = warn.conflicts, 

# snipped rest of code

因此保留默认值 character.only 会强制函数将符号 pkgname 转换为字符值。

  as.character(substitute(pkgname))
 [1] "pkgname"

并且由于 'character.only' 也是 library 逻辑的一部分,并且需要调用 library,您可以使用 library.

进一步评论:您发布了 Rhelp 的跟进并从 Duncan Murdoch 和 Peter Dalgaard 那里得到了一些有用的答案,这些答案澄清了(我希望)这个问题。在这个过程中,我想知道你对这个答案的抵制是否是因为这个函数的名称设置的期望 substitution 应该发生但是没有发生看起来像 "substitution".现在回想起来,这种期望似乎是完全合理的。我认为该函数的正确名称可能是:substitute_but_only_on_the_basis_of_the_local_environment_or_second_argument。 substitute 更常见的用法是带有两个参数:

   y_val=45; a_val=99
   substitute( x + y == z + a , list( y= y_val, a = a_val)
   x + 45 == z + 99

没有'effort'检查第一个参数中任何符号的值除非它在第二个参数中有一个命名项(名为env.)

上面的建议已经很好了,可以解决你的问题。尽管如此,你还是在重新发明轮子。

如果你想分发 R 代码,文档对外部包有要求并且可能需要适当的测试,我建议你用它制作一个包。安装包时,会自动确保所有依赖项都可用。此外,您还有文档和测试脚本的位置。它将一切都很好地保存在一个地方,并同时进行版本控制。