Ответ 1
Кроме того, я только что нашел новый пакет под названием cyclocomp (выпущен 2016). Проверьте это!
Цикломатическая сложность определяет, сколько возможных ветвей можно взять через функцию. Существует ли существующая функция/инструмент для вычисления ее для функций R? Если нет, предложения будут оценены наилучшим образом для записи.
Дешевое начало в этом направлении - подсчитать все вхождения if
, ifelse
или switch
внутри вашей функции. Чтобы получить реальный ответ, вам нужно понять, когда начинаются и заканчиваются ветки, что намного сложнее. Может быть, некоторые инструменты анализа R помогут нам начать?
Кроме того, я только что нашел новый пакет под названием cyclocomp (выпущен 2016). Проверьте это!
Вы можете использовать codetools::walkCode
для перехода к дереву кода. К сожалению, документация на кодеки довольно редкая. Здесь объяснение и образец, чтобы вы начали.
walkCode
принимает выражение и ходок кода. Кодовый ходок - это список, который вы создаете, который должен содержать три функции обратного вызова: handler
, call
и leaf
. (Вы можете использовать вспомогательную функцию makeCodeWalker
для обеспечения разумных реализаций по умолчанию каждого из них.) walkCode
просматривает дерево кода и делает вызовы в ходу кода по мере его прохождения.
call(e, w)
вызывается, когда встречается составное выражение. e
- выражение, а w
- сам хост кода. Реализация по умолчанию просто рекурсирует в дочерние узлы выражения (for (ee in as.list(e)) if (!missing(ee)) walkCode(ee, w)
).
leaf(e, w)
вызывается, когда встречается лист node в дереве. Опять же, e
- это выражение листа node, а w
- ходок кода. Реализация по умолчанию - это просто print(e)
.
handler(v, w)
вызывается для каждого составного выражения и может быть легко использован для альтернативного поведения для call
для определенных типов выражений. v
- это представление символьной строки родительского элемента составного выражения (немного сложно объяснить), но в основном <-
, если оно является выражением присваивания, {
, если оно является началом блока, if
, если оно if-statement и т.д.). Если обработчик возвращает NULL
, тогда call
вызывается, как обычно; если вместо этого вы возвращаете функцию, то вызываемое вместо функции.
Здесь представлен чрезвычайно упрощенный пример, который учитывает вхождения функции if
и ifelse
функции. Надеюсь, это поможет вам хотя бы начать!
library(codetools)
countBranches <- function(func) {
count <- 0
walkCode(body(func),
makeCodeWalker(
handler=function(v, w) {
if (v == 'if' || v == 'ifelse')
count <<- count + 1
NULL # allow normal recursion
},
leaf=function(e, w) NULL))
count
}