11

I have a package that I wrote while learning R and its dependency list is quite long. I'm trying to trim it down, for two cases:

  1. I switched to other approaches, and packages listed in Suggests simply aren't used at all.
  2. Only one function out of my whole package relies on a given dependency, and I'd like to switch to an approach where it is loaded only when needed.

Is there an automated way to track down these two cases? I can think of two crude approaches (download the list of functions in all the dependent packages and automate a text search for them through my package's code, or load the package functions without loading the required packages and execute until there's an error), but neither seems particularly elegant or foolproof....

Community
  • 1
  • 1
Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
  • 1
    I'd love to know this too! You can always cull the entire dependency list and run `R CMD check` to see what "unstated dependencies" it complains about, but this is not ideal either. – mathematical.coffee Mar 22 '12 at 02:28
  • I suspect I'll wind up doing something like that, but holding out hope for a more elegant solution :-) – Ari B. Friedman Mar 22 '12 at 03:10
  • 2
    One quick way of checking function dependancy is to byte compile them because if you don't give the namespaces for commands that come from packages it will complain that it's not available at a global scope. – Hansi Mar 22 '12 at 10:13
  • @Hansi Interesting. Is there a way to force byte-compiling of a whole package? – Ari B. Friedman Mar 22 '12 at 12:11
  • Here is one way of doing it: http://ideone.com/D1c34 Basically takes all .R/.r files in C:/Somelibrary and loads them into an environment and then compiles them and attaches the enviroment. Sort of faking a package include any function in the folder that doesn't clarify functions for none base packages will issue a note on compiling. E.g. using na.locf from zoo would need to be written as zoo::na.locf in any function that uses it otherwise it will issue a notice. – Hansi Mar 22 '12 at 12:54
  • Fascinating. Want to post as an answer? – Ari B. Friedman Mar 22 '12 at 12:58

1 Answers1

1

One way to check dependancies in all functions is to use the byte compiler because that will check for functions being available in the global workspace and issue a notice if it does not find said function.

So if you as an example use the na.locf function from the zoo package in any of your functions and then byte compile your function you will get a message like this:

Note: no visible global function definition for 'na.locf' 

To correctly address it for byte compiling you would have to write it as zoo::na.locf

So a quick way to test all R functions in a library/package you could do something like this (assuming you didn't write the calls to other functions with the namespace):

Assuming your R files with the functions are in C:\SomeLibrary\ or subfolders there of and then you define a sourceing file as C:\SomeLibrary.r or similar containing:

if (!(as.numeric(R.Version()$major) >=2 && as.numeric(R.Version()$minor) >= 14.0)) {
        stop("SomeLibrary needs version 2.14.0 or greater.")
}

if ("SomeLibrary" %in% search()) {
        detach("SomeLibrary")
}

currentlyInWorkspace <- ls()

SomeLibrary <- new.env(parent=globalenv())

require("compiler",quietly=TRUE)

pathToLoad <- "C:/SomeLibraryFiles"

filesToSource <- file.path(pathToLoad,dir(pathToLoad,recursive=TRUE)[grepl(".*[\\.R|\\.r].*",dir(pathToLoad,recursive=TRUE))])

for (filename in filesToSource) {

        tryCatch({
                suppressWarnings(sys.source(filename, envir=SomeLibrary))
        },error=function(ex) {
                cat("Failed to source: ",filename,"\n")
                print(ex)
        })
}

for(SomeLibraryFunction in ls(SomeLibrary)) {
        if (class(get(SomeLibraryFunction,envir=SomeLibrary))=="function") {
                outText <- capture.output(with(SomeLibrary,assign(SomeLibraryFunction,cmpfun(get(SomeLibraryFunction)))))
                if(length(outText)>0){
                        cat("The function ",SomeLibraryFunction," produced the following compile note(s):\n")
                        cat(outText,sep="\n")
                        cat("\n")
                }
        }
}

attach(SomeLibrary)

rm(list=ls()[!ls() %in% currentlyInWorkspace])

invisible(gc(verbose=FALSE,reset=TRUE))

Then start up R with no preloaded packages and source in C:\SomeLibrary.r

And then you should get notes from cmpfun for any call to a function in a package that's not part of the base packages and doesn't have a fully qualified namespace defined.

Hansi
  • 2,566
  • 1
  • 15
  • 19