5

Let's say I have a R script, testScript.R

test <- function(){cat('Hello world')}
cat('Bye world')

In the R-console, I understand I can import the function, test() by

source('testScript.R')

However at the same time, it will also execute cat('Bye world'). Assuming it is not allowed to create/modify files, is there a way to import only the function, test() without executing cat('Bye world')?

Tarod
  • 6,732
  • 5
  • 44
  • 50
SeaSprite
  • 564
  • 8
  • 12

2 Answers2

4

First of all, let me say that this really isn't a good idea. R is a functional programming language so functions are just like regular objects. There's not a strong separation between calling a function and assigning a function. These are all pretty much the same thing

a <- function(a) a+1
a(6)
# [1] 7

assign("a", function(i) i+1)
a(6)
# [1] 7

`<-`(a, function(i) i+1)
a(6)
# [1] 7

There's no difference between defining a function and calling an assignment function. You never know what the code inside a function will do unless you run it; therefore it's not easy to tell which code creates "functions" and which does not. As @mdsumner pointed out, you would be better off manual separating the code you used to define functions and the code you use to run them.

That said, if you wanted to extract all the variable assignments where you use <- from a code file, you could do

cmds <- parse("fakeload.R")
assign.funs <- sapply(cmds, function(x) {
   if(x[[1]]=="<-") {
       if(x[[3]][[1]]=="function") {
           return(TRUE)
       }
   }
   return(FALSE)
})
eval(cmds[assign.funs])

This will evaluate all the function assignments of the "standard" form.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • Great answer. I was trying to follow the functional programming style of React where each module has a few functions and at the end of the module file you call that function and save the values in a variable. Your extraction method was very helpful in keeping that style in my R module files. – MGLondon Aug 10 '21 at 10:09
3

Oh man... that's interesting. I don't know of any way to do that without some atrocity like this:

# assume your two like script is stored in testScript.R
a <- readLines("testScript.R")
a <- paste(a, collapse="\n")
library(stringr)
func_string <- str_extract(a, "[a-z]+ <- function.+}")
test <- eval(parse(text=func_string))
> test()
Hello world

You will certainly need to work on the regex to extract your functions. And str_extract_all() will be helpful if there's more than one function. Good luck.

cory
  • 6,529
  • 3
  • 21
  • 41
  • Thanks for the neat solution. I totally agree on the regular expression part. If not designed carefully, the greedy nature of `.+` would unintentionally include the for loop bracket `}` – SeaSprite Mar 19 '15 at 15:34