danioyuan
danioyuan

Reputation: 1328

How to get R script file name when a function in it is called?

I have several R script files, such as f1.R, f2.R, f3.R.

I have another function called AddSignal(signal), which adds a signal vector to a list. Functions in f1.R, f2.R, etc. may call this AddSignal() function.

Now what I want is that, in function AddSignal(), besides doing the add signal part, it also records which function in which R file made the call. For example, I'd like to know function ff1() in f1.R added signal sig1.

Is there a way to do that?

In fact, using sys.call(), I can know which function (for example, ff1()) called AddSignal(). But I don't know which R file that ff1() is in. I can see a hard way of doing it, is to scan all .R files and then store a mapping of file names and function names. But I'd like to see whether there is an easier way of doing it.

Thanks.

Upvotes: 4

Views: 5837

Answers (3)

Xiangnan
Xiangnan

Reputation: 21

fn <- commandArgs()[4]

filename <- strsplit(fn, "=")[[1]][2]

cat(filename)

Upvotes: 0

xm1
xm1

Reputation: 1765

you could modify AddSignal(signal) to

AddSignal(signal, filename=NULL){
  ...
  ...
  return(list(signal=signal,filename=filename))}

Upvotes: 0

Paul Hiemstra
Paul Hiemstra

Reputation: 60964

What I would do is create a lookup table which maps a function to the .R file it is in. You have to recreate this table every time you add, remove, or move a function, but I think it would be preferable to regenerating the table every time you want to find the source file of a function. So here is my take on create such a table:

library(plyr)

functionsFromRfile = function(filename) {
# Get all functions from a source file. Create new enviroment
# source the functions into them and use ls() to extract names.
  e = new.env()
  source(filename, local = e)
  return(ls(envir = e))
}

# This assumes you are in the directory with your R code,
# and that all files need to be included. You can also
# make this list manually ofcourse
Rfiles = list.files(".", pattern = ".R")
# Get a list of functions for each .R file
lutFunc2sourcefile = ldply(Rfiles, function(x) {
  return(data.frame(fname = x, func = functionsFromRfile(x)))
})

For one of my own packages this leads to:

> head(lutFunc2sourcefile)
               fname                func
1 autofitVariogram.r    autofitVariogram
2     autoKrige.cv.r        autoKrige.cv
3     autoKrige.cv.r checkIfautokrige.cv
4     autoKrige.cv.r          compare.cv
5     autoKrige.cv.r   cv.compare.bubble
6     autoKrige.cv.r   cv.compare.ggplot

You can use the lookup table to performing the mapping using the function name obtained from sys.call.

EDIT: In view of your comment on non-function code, this code uses parse, which does not evaluate the code. It searches through the output of parse, and weeds out the functions, and should not evaluate any code or return code that is not a function. I haven't tested it exhaustively, give it a try.

library(plyr)

Rfiles = list.files(".", pattern = "(.R|.r)")
lutFunc2sourcefile = ldply(Rfiles, function(fname) {
   f = parse(fname)
   functions = sapply(strsplit(as.character(f), "="), function(l) {
     if(grepl("^function", sub(' ', '', l[2]))) {
       return(l[1])
     } else {
       return(NA)
     }
    })
   return(data.frame(fname, func = functions))  
})
# Remove lines with func = NA
lutFunc2sourcefile = lutFunc2sourcefile[!is.na(lutFunc2sourcefile$func),]

Upvotes: 7

Related Questions