0

对于我的一个脚本,我想编写一个 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但我无法成功。

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

如果一个已经实现它的函数存在,我想知道,但我真正感兴趣的是理解为什么我的代码不能按预期工作。

4

2 回答 2

3

扩展使用建议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 那里得到了一些有用的答案,这澄清了(我希望)这个问题。在此过程中,我想知道您对这个答案的抵制是否是因为这个函数的名称设置的期望应该发生替换,但没有发生看起来像“替换”的事情。我现在回想起来,这种期望似乎完全合理。我认为该函数的正确名称可能是: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

没有“努力”来检查第一个参数中任何符号的值,除非它在第二个参数中有一个命名项(名为env.)

于 2016-08-12T16:15:42.823 回答
-2

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

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

于 2016-08-12T16:22:04.247 回答