0

I got tired of starting my scripts with require(data.table); require(ggplot2) etc etc. I know that I could do something like lapply(c('data.table', 'ggplot2'), require, character.only=T), but it would just return a warning (not an error) for a missing package, plus I wanted my own function require_mult(...) to keep my scripts cleaner. So I wrote the function:

require_mult <- function(...){
  arg_list <- list(...)
  if(any(!sapply(arg_list, is.character)) ) stop('require_mult must have character arguments')
    check <- tryCatch({pkg_array <- unlist(arg_list)
                       loaded <- sapply(pkg_array, require, character.only=TRUE, quietly=TRUE)
                       message('Loaded packages: ',
                               paste(pkg_array, collapse=', ') ) },
                       warning = function(w) stop(w), # I want execution to halt if a package is missing
                       error = function(e) stop(e)
                       )
}

Which seems to work as desired (e.g., loads for require_mult('data.table','ggplot2'), errors for require_mult('data.table','ggplotfoo')), but I would like to make this require_mult(...) work for character.only=FALSE. I looked at the definition of require, which uses

if (!character.only) 
        package <- as.character(substitute(package))

But I can't figure out how to apply substitute across an unevaluated expression that's really a comma-delimited list.

I know this application is pretty pointless and academic, but it would enrich my understanding of R expression evaluation if there is in fact a way to write a require_mult that could be used for require_mult(data.table, ggplot2) etc.

An explanation of why this can't be done would also be acceptable.

C8H10N4O2
  • 18,312
  • 8
  • 98
  • 134
  • You don't want to use `require` here - you might find this article by Yihui Xie useful: http://yihui.name/en/2014/07/library-vs-require/ – TARehman Dec 18 '15 at 15:21
  • @TARehman I get that -- but can you figure out how to pass multiple package names to `library`? This doesn't work: `lapply(c('data.table','ggplot2'), library, character.only=T)` If you can provide a solution with `library` by all means please do so. – C8H10N4O2 Dec 18 '15 at 15:24
  • I believe that you just want `do.call`. Do you specifically need the list of packages being passed to be non-character? I could see writing a wrapper function for that. Or is it that it needs to raise an _error_, not a _warning_? – TARehman Dec 18 '15 at 15:26
  • @TARehman good point with `do.call`, but yes I'm specifically interested in whether it is possible to pass a non-character list of packages. Maybe I'll edit the title of the question accordingly. Also, I think that my change to how `require` responds to not-loaded packages (via `tryCatch`) might mitigate the pitfalls in that article, but that's a side issue. – C8H10N4O2 Dec 18 '15 at 15:27
  • This is actually interesting. I'll see if I can devise a way to do this. – TARehman Dec 18 '15 at 15:42
  • @TARehman thanks for your interest. Re: `do.call`, try `do.call(what= library, args = list("ggplot2", "thisisnotapackage"))` – C8H10N4O2 Dec 18 '15 at 15:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/98358/discussion-between-tarehman-and-c8h10n4o2). – TARehman Dec 18 '15 at 16:04
  • I think you may want to look at the *lack an* package's `p_load` function. – Tyler Rinker Dec 18 '15 at 19:17

1 Answers1

1

I learned something here today! You can use match.call to obtain the arguments passed in ... without evaluating them. (Presumably, you could do this with named arguments...? I need to experiment more on that.) I used this answer to build the very simple function below. As you can see, it breaks when reaching the package that does not exist.

I think you could use this to build further.

library_mult <- function(...) {
    args <- match.call(expand.dots = FALSE)$`...`
    for(x in args) {

        x <- as.character(substitute(x))
        library(x,character.only = TRUE)
    }
}

> library_mult(MASS,thisisnopack)

Error in library(x, character.only = TRUE) : 
  there is no package called ‘thisisnopack’
Community
  • 1
  • 1
TARehman
  • 6,659
  • 3
  • 33
  • 60
  • This is awesome. I really think you should post it to [R-devel](https://stat.ethz.ch/mailman/listinfo/r-devel) for inclusion in a future version of base R, because the default way of loading multiple libraries is tedious. Thanks! – C8H10N4O2 Dec 18 '15 at 16:49