Поиск неиспользуемых / «потерянных» неэкспортируемых объектов во время разработки пакета

#r #devtools

#r #devtools

Вопрос:

Я занимаюсь рефакторингом пакета, содержащего множество неэкспортированных функций и других неэкспортированных объектов. Есть ли способ быстро идентифицировать все «потерянные» объекты, которые определены, но не экспортированы или не вызываются где-либо еще в пакете, кроме ручного полнотекстового поиска по имени каждой функции в пакете?

Дополнительная сложность заключается в том, что некоторые функции вызываются внутри glue строк в стиле f, поэтому могут быть случаи, когда вызываются функции, которые не могут быть проанализированы как выражения (вероятно, это не очень хороший шаблон проектирования).

Но я был бы удовлетворен методом только для функций и других объектов, которые никогда не отображаются как обычные выражения после определения.

Ответ №1:

Это даст вам частичный ответ (отредактированный из оригинала):

 pkg <- "testpkg"
library(pkg, character.only = TRUE)
ns <- getNamespace(pkg)
allnames <- ls(ns)
exports <- ls(paste0("package:", pkg))

nsInfo <- readRDS(system.file("Meta/nsInfo.rds", package = pkg))

if (!is.null(nsInfo$S3methods)) {
  S3methods <- with(nsInfo, paste(S3methods[,1], S3methods[,2], sep = "."))
} else
  S3methods <- NULL

locals <- setdiff(allnames, c(exports, S3methods))

used <- character()
newones <- c(exports, S3methods)
while (length(newones)) {
  mentioned <- unique(unlist(lapply(newones, function(n) {
      fun <- get(n, envir = ns)
      if (is.function(fun)) 
        codetools::findGlobals(fun)
        })))
  used <- c(used, newones)
  newones <- setdiff(intersect(mentioned, locals), used)
}
 
unused <- setdiff(locals, used)
unused
 

Это все еще не совсем правильно, но это должно помочь вам начать. Некоторые проблемы:

  • предполагается, что никакие функции не выполняют забавные вещи, такие как assign() , или возятся со средами и т. Д.
  • он не обнаруживает функции, которые полностью используются для создания других объектов в пакете.
  • он не обнаруживает странные методы S3, объявленные с нестандартным именем.

Комментарии:

1. Ограничение S3 — это облом, но, учитывая ограничения языка, мне непонятно, как вы могли бы его обойти.

2. «Ограничения языка»? Я не уверен, что вы имеете в виду под этим, мы говорим о R ;-). Я отредактирую свой ответ, чтобы включить и методы S3.

3. Поскольку R не является безопасным для типов, как можно узнать, какой метод S3 вызывается во время синтаксического анализа?

4. Я предполагаю, что если он объявлен как метод S3, он экспортируется, потому что он попадает в таблицу методов S3. Если вы объявите метод в локальном универсальном и никогда не вызовете его, то новый код будет ошибочно предполагать, что он может быть вызван.