R6 and Magrittr

222 Views Asked by At

I have an R6 class, which contains a family of helper functions for conducting routine checks. These functions exist in the public list, usually take a single argument, conduct some checks on the value passed to the single argument, and if nothing is wrong, returns the value. It is common for me to use multiple checks quite frequently.

I would like to use magrittr to make chaining these tests together easy, is it possible to use the with function to further shorten the code

library(magrittr)
library(R6)

test = R6::R6Class("Test",inherit=NULL,
  public = list(
    initialize = function(){

    },
    fA = function(x){
      writeLines("Called FA")
      x
    },
    fB = function(x){
      writeLines("Called FB")
      x
    },

    #Enable Chaining by Returning Invisible copy of the R6 Instance
    fC = function(x){
      writeLines("Called FC")
      invisible(self)
    },
    fD = function(x){
      writeLines("Called FD")
      invisible(self)
    }
  )
)

#Works as expected
x = test$new()
y <- 1 %>% x$fA() %>% x$fB()
y

#This is also possible, but it loses the desired return value, and the value of the argument
#needs to be explicitly passed through to each function.
x$fC(1)$fD(1)

#I Would Like to do something like this:
y <- with(x,1 %>% fA() %>% fB()) #ERROR, could not find function "%>%"

#Trying to resolve the above, I also tried this, which doesn't work.
y <- with(x,1 magrittr::`%>%` fA() magrittr::`%>%` fB()) #ERROR

How can I get the %>% operator to get recognised within the with function?

1

There are 1 best solutions below

0
On

I posted a similar solution here. The issue is that with runs your code using x as an environment in which the only defined functions are the methods of x. One way to access the pipe would be to define it as an additional method (which is tricky), but alternatively you can set .GlobalEnv as a temporary parent environment for x, meaning you'll get to use other functions as normal within with:

parent.env(x) <- .GlobalEnv
with(x, 1 %>% fA() %>% fB())
parent.env(x) <- emptyenv() # removes the parent environment

You could also wrap this in a function so you don't have to manually set and reset the parent environment every time:

with_global <- function(object, task_expr) {
  task_expr <- substitute(task_expr)
  parent.env(object) <- rlang::current_env()
  with(object, eval(task_expr))