Source only part of a file

前端 未结 2 1000
小蘑菇
小蘑菇 2020-12-06 01:33

My R workflow is usually such that I have a file open into which I type R commands, and I’d like to execute those commands in a separately opened R shell.

The easies

相关标签:
2条回答
  • 2020-12-06 02:19

    Here's another way with just R:

    source2 <- function(file, start, end, ...) {
        file.lines <- scan(file, what=character(), skip=start-1, nlines=end-start+1, sep='\n')
        file.lines.collapsed <- paste(file.lines, collapse='\n')
        source(textConnection(file.lines.collapsed), ...)
    }
    
    0 讨论(0)
  • 2020-12-06 02:28

    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.

    0 讨论(0)
提交回复
热议问题