2

My R script has evolved over many months with many additions and subtractions. It is long and rambling and I would like to find out which packages I am actually using in the code so I can start deleting library() references. Is there a way of finding redundant dependencies in my R script?

I saw this question so I tried:

library(mvbutils)
library(MyPackage)
library(dplyr)
foodweb( funs=find.funs( asNamespace( 'EndoMineR')), where= 
             asNamespace( 'EndoMineR'), prune='filter') 

But that really tells me where I am using a function from a package whereas I don't necessarily remember which functions I have used from which package.

I tried packrat but this is looking for projects whereas mine is a directory of scripts I am trying to build into a package.

Sebastian Zeki
  • 6,690
  • 11
  • 60
  • 125
  • 2
    Unless you have hundreds, I'd comment out (`#`) your library calls, run the script and see where you get an error, add the required library back in, rinse and repeat. – Phil Aug 31 '17 at 08:55
  • But I have about 50 functions. Surely there's a better way.... – Sebastian Zeki Aug 31 '17 at 11:13
  • One way to help with this in the future is to include calls to the requisite libraries inside of your functions. This way, each function is more self contained and there is no affect if the library is already loaded. – lmo Aug 31 '17 at 11:51

1 Answers1

0

To do this you first parse your file and then use getAnywhere to check for each terminal token in which namespace it is defined. Compare the result with the searchpath and you will have the answer. I compiled a function that takes a filename as argument and returns the packages which are used in the file. Note that it can only find packages that are loaded when the function is executed, so be sure to load all "candidates" first.

findUsedPackages <- function(sourcefile) {

  ## get parse tree
  parse_data <- getParseData(parse(sourcefile))

  ## extract terminal tokens
  terminal_tokens <- parse_data[parse_data$terminal == TRUE, "text"]

  ## get loaded packages/namespaces
  search_path <- search()

  ## helper function to find the package a token belongs to
  findPackage <- function(token) {

    ## get info where the token is defined
    token_info <- getAnywhere(token)

    ##return the package the comes first in the search path
    token_info$where[which.min(match(token_info$where, search_path))]
  }

  packages <- lapply(unique(terminal_tokens), findPackage)

  ##remove elements that do not belong to a loaded namespace
  packages <- packages[sapply(packages, length) > 0]

  packages <- do.call(c, packages)
  packages <- unique(packages)

  ##do not return base and .GlobalEnv
  packages[-which(packages %in% c("package:base", ".GlobalEnv"))]
}
AEF
  • 5,408
  • 1
  • 16
  • 30