Search code examples
rlazy-evaluation

Pass arguments to function which uses substitute


I want to create a small wrapper to reprex that passes input code to reprex::reprex(). As reprex uses substitute() on its x argument, I need to somehow escape it.

MWE

A minimal working example is this, where internal_foo() acts as a surrogate for reprex(). The expected result is that both the call to internal_foo(...) as well as to the wrapper(...) return the identical output.

internal_foo <- function(x) {
  res <- substitute(x)
  res
}

# the expected output! ------
internal_foo({
  a <- 1:10
  b <- rnorm(10)
  plot(a, b)
})
#> {
#>   a <- 1:10
#>   b <- rnorm(10)
#>   plot(a, b)
#> }

wrapper <- function(x = NULL) {
  # pass x to internal_foo in such a way that it has the same output as calling internal_foo directly
  internal_foo(deparse(x))
}
wrapper({
  a <- 1:10
  b <- rnorm(10)
  plot(a, b)
})
#> deparse(x)
# clearly not equal to the expected output ----

Due to Rs lazy evaluation, x is not handed trough to internal_foo() the way I intend it to.

I have played around with eval, deparse, and substitute but I cannot find the right combination.

The more complicated reprex example

The actual target is this reprex wrapper.

wrapper2 <- function(x, input = NULL) {
  reprex::reprex(x = x, input = input, venue = "r", html_preview = FALSE)
}
wrapper2({
    a <- 1:10
    b <- rnorm(10)
    plot(a, b)
})

wrapper2 renders the reprex and copies it to clipboard but shows Error in eval object x not found.


Solution

  • You could do

    wrapper2 <- function(..., input = NULL) {
      reprex::reprex(..., 
                     input = input, 
                     venue = "r", 
                     html_preview = FALSE)
    }
    
    wrapper2({
      a <- 1:10
      b <- rnorm(10)
      plot(a, b)
    })
    
    #> i Rendering reprex...
    #> √ Reprex output is on the clipboard.
    

    Which outputs:

    a <- 1:10
    b <- rnorm(10)
    plot(a, b)
    
    #' ![](agile-pike_reprex_files/figure-gfm/unnamed-chunk-2-1.png)