Only Source Functions in a .R File

Only source functions in a .R file

This works without using regex. It's also probably less computationally efficient than regex solutions. It creates a new environment, sources the entire file, then returns only the functions back to the global environment.

SourceFunctions<-function(file) {
MyEnv<-new.env()
source(file=file,local=MyEnv)
list2env(Filter(f=is.function,x=as.list(MyEnv)),
envir=parent.env(environment()))
}

How to import only functions from .R file without executing the whole file

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.

R: source() and path to source files

If you are distributing a script to colleagues, you should really not be writing a script that sources other scripts. What if you want to rename or move functions.R in the future? What if you need to modify a function in functions.R, but wrapper.R relies on the older version of that function? It's a flimsy solution that will cause headache. I would recommend either of the following instead.

  1. Put everything needed into a single, self-contained script and distribute that.

  2. If you really want to separate code into different files, write a package. Might sound like overkill, but packages can actually be very simple and lightweight. In the simplest form a package is just a directory with a DESCRIPTION and NAMESPACE file along with an R/ directory. Hadley breaks this down nicely: https://r-pkgs.org/whole-game.html.

Define all functions in one .R file, call them from another .R file. How, if possible?

You can call source("abc.R") followed by source("xyz.R") (assuming that both these files are in your current working directory.

If abc.R is:

fooABC <- function(x) {
k <- x+1
return(k)
}

and xyz.R is:

fooXYZ <- function(x) {
k <- fooABC(x)+1
return(k)
}

then this will work:

> source("abc.R")
> source("xyz.R")
> fooXYZ(3)
[1] 5
>

Even if there are cyclical dependencies, this will work.

E.g. If abc.R is this:

fooABC <- function(x) {
k <- barXYZ(x)+1
return(k)
}

barABC <- function(x){
k <- x+30
return(k)
}

and xyz.R is this:

fooXYZ <- function(x) {
k <- fooABC(x)+1
return(k)
}

barXYZ <- function(x){
k <- barABC(x)+20
return(k)
}

then,

> source("abc.R")
> source("xyz.R")
> fooXYZ(3)
[1] 55
>

Source only part of a file

Using the right tool for the job …

As discussed in the comments, the real solution is to use an IDE that allows sourcing specific parts of a file. There are many existing solutions:

  • For Vim, there’s Nvim-R.

  • For Emacs, there’s ESS.

  • And of course there’s the excellent stand-alone RStudio IDE.

As a special point of note, all of the above solutions work both locally and on a server (accessed via an SSH connection, say). R can even be run on an HPC cluster — it can still communicate with the IDEs if set up properly.

… or … not.

If, for whatever reason, none of the solutions above work, here’s a small module[gist] that can do the job. I generally don’t recommend using it, though.1

#' (Re-)source parts of a file
#'
#' \code{rs} loads, parses and executes parts of a file as if entered into the R
#' console directly (but without implicit echoing).
#'
#' @param filename character string of the filename to read from. If missing,
#' use the last-read filename.
#' @param from first line to parse.
#' @param to last line to parse.
#' @return the value of the last evaluated expression in the source file.
#'
#' @details If both \code{from} and \code{to} are missing, the default is to
#' read the whole file.
rs = local({
last_file = NULL

function (filename, from, to = if (missing(from)) -1 else from) {
if (missing(filename)) filename = last_file

stopifnot(! is.null(filename))
stopifnot(is.character(filename))

force(to)
if (missing(from)) from = 1

source_lines = scan(filename, what = character(), sep = '\n',
skip = from - 1, n = to - from + 1,
encoding = 'UTF-8', quiet = TRUE)
result = withVisible(eval.parent(parse(text = source_lines)))

last_file <<- filename # Only save filename once successfully sourced.
if (result$visible) result$value else invisible(result$value)
}
})

Usage example:

# Source the whole file:
rs('some_file.r')
# Re-soure everything (same file):
rs()
# Re-source just the fifth line:
rs(from = 5)
# Re-source lines 5–10
rs(from = 5, to = 10)
# Re-source everything up until line 7:
rs(to = 7)

1 Funny story: I recently found myself on a cluster with a messed-up configuration that made it impossible to install the required software, but desperately needing to debug an R workflow due to a looming deadline. I literally had no choice but to copy and paste lines of R code into the console manually. This is a situation in which the above might come in handy. And yes, that actually happened.

R: Source function by name/Import subset of functions

It looks like your code will work with a slight change: define an empty object for the function you want to load first, then use insertSource.

mult <- function(x) {0}
insertSource("C:\\functions.R", functions="mult")
mult

Which gives:

Object of class "functionWithTrace", from source
function (x, y)
{
return(x * y)
}

## (to see original from package, look at object@original)

The mult object has some additional information that I suppose is related to the original application for insertSource, but you could get rid of them with mult <- mult@.Data, which will set mult to the actual function body only.

Also, you might be interested in the modules project on github, which is trying to implement a lightweight version of R's package system to facilitate code reuse. Seems like that might be relevant, although I think you would have to split your functions into separate files in different subdirectories.



Related Topics



Leave a reply



Submit