I am starting to built a "user-friendly" R6 class and want to make a function does most of the work of my class. This is my structure so far
x <- X$new()
veggie_cubes <- veggie %>% x$cubesX(ID)
veggie_slices <- veggie %>% x$sliceX(ID)
My question is now if it is possible to rewrite the code such that:
x <- X$new()
veggie_cubes <- veggie %>% x$cutX(cubesX, ID)
veggie_slices <- veggie %>% x$cutX(sliceX, ID)
The function header should somehow look like: cut(.data, FUN, KEY)
So far my idea was to write cut
like:
cutX= function(.data, FUN, KEY)
{
.data %>%
FUN({{ KEY }}) %>%
base::return()
}
The only way this works was by calling veggie %>% x$cutX(x$cubesX, ID)
which I would not really prefer as "user-friendly" solution, I also do not really like to use strings for that. Is there a way to write it without the x$
?
here is the simplified R6 class:
X <- R6::R6Class(
classname = "X",
public = base::list(
cubesX = function(.data, KEY)
{
.data %>%
dplyr::select(!{{ KEY }}) %>%
base::return()
},
sliceX = function(.data, KEY)
{
.data %>%
dplyr::select({{ KEY }}) %>%
base::return()
},
cutX = function(.data, FUN, KEY)
{
.data %>%
FUN( {{ KEY}}) %>%
base::return()
}
)
)
running examples:
x <- X$new()
iris %>% x$sliceX(Species)
iris %>% x$cubesX(Species)
# with FUN
iris %>% x$cutX(x$sliceX, Species)
iris %>% x$cutX(x$cubesX, Species)
not running:
iris %>% x$cutX(sliceX, Species)
iris %>% x$cutX(cubesX, Species)
Thanks in Advance :-)
The following implementation will allow you to call your functions via any of your three methods. It works by using non-standard evaluation to figure out whether FUN
is in the format x$func
or just a bare func
. In either case it takes the bare function name and builds a call to turn it into self$func
. Then it just evaluates that function.
The following R6 class therefore works as expected on all your test examples:
X <- R6::R6Class(
classname = "X",
public = base::list(
cubesX = function(.data, KEY)
{
.data %>%
dplyr::select(!{{ KEY }}) %>%
base::return()
},
sliceX = function(.data, KEY)
{
.data %>%
dplyr::select({{ KEY }}) %>%
base::return()
},
cutX = function(.data, FUN, KEY)
{
if(is.call(substitute(FUN))) {
FUN <- substitute(FUN)
FUN[[2]] <- quote(self)
}
else
FUN <- as.call(list(quote(`$`), quote(self), substitute(FUN)))
eval(as.call(list(FUN, quote(.data), substitute(KEY))))
}
)
)
So, for example:
x <- X$new()
iris %>% x$cutX(sliceX, Species)
#> Species
#> 1 setosa
#> 2 setosa
#> 3 setosa
#> 4 setosa
#> 5 setosa
#> 6 setosa
#> 7 setosa
#> 8 setosa
#> 9 setosa
#> 10 setosa
#> 11 setosa
#> 12 setosa
#> 13 setosa
#> 14 setosa
#> 15 setosa
#> 16 setosa
#> 17 setosa
#> 18 setosa
#> 19 setosa
#> 20 setosa
#> ...etc