Я рефакторинг пакета, содержащего множество неэкспортируемых функций и других неэкспортируемых объектов. Есть ли способ быстро идентифицировать все "осиротевшие" объекты, которые определены, но не экспортированы или не вызваны где-либо еще в пакете, кроме ручного полнотекстового поиска имени каждой функции в пакете?
Дополнительная сложность заключается в том, что некоторые функции вызываются внутри строк glue
f-стиля, поэтому могут быть случаи, когда вызываются функции, которые не анализируются как выражения (вероятно, это не очень хороший шаблон проектирования).
Но меня удовлетворил бы метод только для функций и других объектов, которые после определения никогда не появляются как нормальные выражения.
Это даст вам частичный ответ (отредактированный из оригинала):
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()
, или возятся
с окружением и т.д."Ограничения языка"? Я не уверен, что вы имеете в виду, мы говорим о R ;-). Я отредактирую свой ответ, включив в него и методы S3.
Поскольку R не является типобезопасным, как можно узнать, какой метод S3 вызывается во время синтаксического анализа?
Я предполагаю, что если он объявлен как метод S3, он экспортируется, потому что он попадает в таблицу методов S3. Если вы объявите метод в локальном универсальном объекте и никогда его не вызовете, новый код будет ошибочно предполагать, что его можно вызвать.
Ограничение S3 - это облом, но, учитывая ограничения языка, мне не ясно, как его обойти.