0

I am trying to write an Rscript from within R. Using quote() with the $wholeSrcref attribute works well when on its own. However, additional unwanted lines are written when used within a function. Details are as provided below.

My first attempt was to quote() the expression, followed by writing the quoted expression to file, that is,

expr <- quote({
  a <- 1 # comment 1
  b <- 2 # comment 2
})
writeLines(tail(as.character(expr), -1), file)

However, comments in the code are not written to file. A workaround would be to use the $wholeSrcref attribute, as given by this answer. My second attempt:

library(magrittr)
expr <- quote({
  a <- 1 # comment 1
  b <- 2 # comment 2
})
attributes(expr)$wholeSrcref %>% as.character() %>%
  tail(-1) %>%  # remove '{'
  head(-1) %>%  # remove '}'
writeLines(file)

This works well. However, when wrapping this within a function, part of the function's body is also prepended to the quoted expression. That is, given the following code,

library(magrittr)
f <- function(dir) {
  # change directory to dir
  # do stuff

  expr <- quote({
    a <- 1 # comment 1
    b <- 2 # comment 2
  })

  attributes(expr)$wholeSrcref %>% as.character() %>%
    tail(-1) %>%  # remove '{'
    head(-1) %>%  # remove '}'
  writeLines(file)

  # do more stuff
}
f(dir="")

The file would contain

  # change directory to dir 
  # do stuff 

  expr <- quote({
    a <- 1 # comment 1
    b <- 2 # comment 2

How can I write only the quoted expression to file?

bert
  • 332
  • 1
  • 9

2 Answers2

1

Well, the easiest approach would be to count the lines above the quote function and adjust the tail function to exclude these rows. Admittedly, it's not very elegant

f <- function(dir) {
  # change directory to dir
  # do stuff
  
  expr <- quote({
    a <- 1 # comment 1
    b <- 2 # comment 2
  })
  exclusion_line <- which(grepl("expr <- quote({",
                               attributes(expr)$wholeSrcref %>% as.character(),
                               fixed = TRUE))
  attributes(expr)$wholeSrcref %>% as.character() %>%
    tail(-exclusion_line) %>%  # remove '{'
    head(-1) %>%  # remove '}'
    writeLines(file)
  
  # do more stuff
}
f(dir="")

starja
  • 9,887
  • 1
  • 13
  • 28
  • 1
    Thanks, this actually turned out to be rather useful. Sure, it's not very elegant, but it got me started. Some of the modifications I made are (1)`which(grepl())` shortened to `grep()`, and (2) use a variable for `attributes(expr)$wholeSrcref %>% as.character()`. Now, the only unelegant part remaining is the hardcoded `"expr <- quote({"`. – bert Mar 02 '22 at 09:10
  • Found a way around that hardcoded search term. I've posted an answer. Once again, this was helpful :) – bert Mar 02 '22 at 17:16
1

One way to approach this, as user starja pointed out in his answer, is to find the start of the quoted expression. In the example given in the question, one can search for "expr <- quote({", as in:

  expr_ref <- attributes(expr)$wholeSrcref %>% as.character()
  exclusion_line <- grep("expr <- quote({", 
                         expr_ref, fixed = TRUE) 

  expr_ref %>%
    tail(-exclusion_line) %>%  # remove up till '{'
    head(-1) %>%  # remove '}'
    writeLines(file)

One caveat is the hard coded "expr <- quote({". What if we wanted to use another variable name other than "expr"?. We place the above code in a function and modify it with deparse(substitute(...)), ie

write_expr <- function(expr, file) {

  expr_name <- deparse(substitute(expr))
  expr_ref <- attr(expr, "wholeSrcref") %>% as.character()
  exclusion_line <- grep(paste0("^\\s*", expr_name, "\\s*<-"), expr_ref)

 expr_ref %>%
    tail(-exclusion_line) %>%  # remove up till '{'
    head(-1) %>%  # remove '}'
    writeLines(file)
}

and modify the f to become

f <- function(dir) {
  # change directory to dir
  # do stuff
  
  some_expr <- quote({
    a <- 1 # comment 1
    b <- 2 # comment 2
  })
  write_expr(some_expr, file)

  # do more stuff
}

Now, upon calling f(), the file contains

    a <- 1 # comment 1
    b <- 2 # comment 2

as desired.

bert
  • 332
  • 1
  • 9