Find the source file containing R function definition
Asked Answered
J

2

15

I come from a python background and am trying to get up to speed with R, so please bear with me

I have an R file - util.R with the following lines:

util.add <- function(a,b) a + b
util.sub <- function(a,b) { a - b }

I source it as follows:

source('path/util.R')

I now have two function objects and want to write a function as follows:

getFilePath(util.add)

that would give me this result

[1] "path/util.R"

Jonme answered 23/9, 2015 at 18:49 Comment(3)
Maybe wait until your previous question is answered before posting another...Brighten
IMO the two questions are independentJonme
This might be difficult or somewhat hacky in R. If you describe in more detail why you might want to do this, perhaps some experienced R folks might be able to suggest a different approach.Bechler
B
13

Digging into the srcref attribute of one of the loaded functions appears to work, if you go deep enough ...

source("tmp/tmpsrc.R")
str(util.add)
## function (a, b)  
##  - attr(*, "srcref")=Class 'srcref'  atomic [1:8] 1 13 1 31 13 31 1 1
##   .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x8fffb18> 
srcfile <- attr(attr(util.add,"srcref"),"srcfile")
ls(srcfile)
## [1] "Enc"           "filename"      "fixedNewlines" "isFile"       
## [5] "lines"         "parseData"     "timestamp"     "wd"    
srcfile$filename
## [1] "tmp/tmpsrc.R"

Comments note that this only works out-of-the-box for interactive code, because ...

Rscript does not load srcrefs by default. A work-around is this code snippet: Rscript -e "options(keep.source = TRUE); source('your_main_file.R')" or set the option keep.source permanently in the .Rprofile file (see ?Startup for details)

Barmen answered 23/9, 2015 at 20:51 Comment(4)
Fantastic, there is even a srcfile$wd for the relative paths!Jonme
@Ben, this only seems to work in interactive mode. Not when I do R with -e option or Rscript. Any idea how to get it to work for the additional conditions? ThanksJonme
Don't know, offhand -- sorry. Maybe edit your code/offer a bounty to draw attention to this new issue? Or ask another question?Barmen
@Jonme Rscript does not load srcrefs by default. A work-around is this code snippet: Rscript -e "options(keep.source = TRUE); source('your_main_file.R')" or set the option keep.source permanently in the .Rprofile file (see ?Startup for details)Frottage
F
2

I know this was solved years ago, but I've just come across it and realised that there is a bit more to this if you use the body() function.

The raw function has only the one attribute, "srcref" which contains the code of the function, along with it's own attributes and class of "srcref" (which dictates how it'll get printed).

The body() of a function, such as body(util.add) has three attributes.

  • "srcref" which contains the body of the function stored as a list of expressions.
  • "srcfile" which contains the source file of the function (which is what you are looking for in this question)
  • "wholeSrcref" which points to the entire source file.

This gives you an alternative (although slightly slower) method to extract the source file name attr(body(util.add),"srcfile"), along with being able to see (although not interact with) the sibling functions (i.e. the other functions loaded in the same source file).

Not sure if it's useful, but it could be interesting.

Let's also not forget about the %@% infix operator for accessing attributes using the {purrr} package, with this we could use the more succinct (although again, slower) piece of code as: util.add%@%srcref%@%srcfile

Fulminant answered 3/8, 2020 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.