Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to list all the functions signatures in an R file?

Tags:

r

Is there an R function that lists all the functions in an R script file along with their arguments?

i.e. an output of the form:

func1(var1, var2)
func2(var4, var10)
.
.
.
func10(varA, varB)
like image 551
user1971988 Avatar asked Dec 06 '22 04:12

user1971988


2 Answers

Using [sys.]source has the very undesirable side-effect of executing the source inside the file. At the worst this has security problems, but even “benign” code may simply have unintended side-effects when executed. At best it just takes unnecessary time (and potentially a lot).

It’s actually unnecessary to execute the code, though: it is enough to parse it, and then do some syntactical analysis.

The actual code is trivial:

file_parsed = parse(filename)
functions = Filter(is_function, file_parsed)
function_names = unlist(Map(function_name, functions))

And there you go, function_names contains a vector of function names. Extending this to also list the function arguments is left as an exercise to the reader. Hint: there are two approaches. One is to eval the function definition (now that we know it’s a function definition, this is safe); the other is to cheat and just get the list of arguments to the function call.

The implementation of the functions used above is also not particularly hard. There’s probably even something already in R core packages (utils has a lot of stuff) but since I’m not very familiar with this, I’ve just written them myself:

is_function = function (expr) {
    if (! is_assign(expr))
        return(FALSE)
    value = expr[[3]]
    is.call(value) && as.character(value[[1]]) == 'function'
}

function_name = function (expr)
    as.character(expr[[2]])

is_assign = function (expr)
    is.call(expr) && as.character(expr[[1]]) %in% c('=', '<-', 'assign')

This correctly recognises function declarations of the forms

  1. f = function (…) …
  2. f <- function (…) …
  3. assign('f', function (…) …)

It won’t work for more complex code, since assignments can be arbitrarily complex and in general are only resolvable by actually executing the code. However, the three forms above probably account for ≫ 99% of all named function definitions in practice.

like image 99
Konrad Rudolph Avatar answered Jan 09 '23 06:01

Konrad Rudolph


UPDATE: Please refer to the answer by @Konrad Rudolph instead

You can create a new environment, source your file in that environment and then list the functions in it using lsf.str() e.g.

test.env <- new.env()
sys.source("myfile.R", envir = test.env)
lsf.str(envir=test.env)
rm(test.env)

or if you want to wrap it as a function:

listFunctions <- function(filename) {
  temp.env <- new.env()
  sys.source(filename, envir = temp.env)
  functions <- lsf.str(envir=temp.env)
  rm(temp.env)
  return(functions)
}
like image 39
Alex Popov Avatar answered Jan 09 '23 05:01

Alex Popov