Функция R для установки недостающих пакетов
Для одного из моих сценариев я хочу написать функцию 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 / replace/quote, чтобы заставить его работать с require
но я не смог добиться успеха.
Может ли кто-нибудь помочь мне понять, что происходит, и если есть какие-то легко исправить?
Если функция, уже реализующая это, существует, я хотел бы знать, но что меня действительно интересует, так это понимание того, почему мой код работает не так, как задумано.
2 ответа
Расширение предложения по использованию 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
,
Дальнейший комментарий: Вы опубликовали продолжение к Релпу и получили несколько полезных ответов от Дункана Мердока и Питера Далгаарда, которые прояснили (я надеюсь) этот вопрос. В процессе я задавался вопросом, происходит ли ваше сопротивление этому ответу из-за ожидания, заданного именем этой функции, что должно произойти замещение, но ничего не происходило, что выглядело как "замещение". Это ожидание кажется вполне обоснованным, и я вижу его с запозданием в ретроспективе. Я думаю, что правильное имя функции могло бы быть: 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
.)
Приведенные выше предложения уже хороши и могут решить вашу проблему. Тем не менее, вы заново изобретаете колесо.
Если вы хотите распространять код R с документацией, которая содержит требования к внешним пакетам и, возможно, нуждается в надлежащем тестировании, я бы посоветовал вам сделать пакет из него. Когда пакет устанавливается, он автоматически обеспечивает доступность всех зависимостей. Кроме того, у вас есть документация и место для ваших сценариев тестирования. Он хранит все в одном месте и в то же время поддерживается версия.