Reputation: 970
I'd like to create a function create_thresholds
that dynamically creates an R6 class and an instance object. The idea is to dynamically create a data structure that has read-only active fields that client-objects can access similar to the example illustrated by Wickham (https://adv-r.hadley.nz/r6.html - 16.3.2 Active fields). I've looked at dynamically add function to r6 class instance but I am looking for a solution that modifies the class definition, not add a function to an instance object.
The function create_thresholds
reads in a data.frame of var/val pairs, then creates an R6Class object on which it tries to set various private fields and create read-only active fields. The function terminates by creating a new instance of the Thresholds object.
As illustrated in the code below, calling the active methods appears to evaluate the method expressions in the incorrect environment.
library("R6")
create_thresholds <- function(df) {
require(glue)
Thresholds <- R6Class("Thresholds")
for (i in 1:nrow(df)){
e <- environment()
print(e)
Thresholds$set("private", glue(".{df$var[i]}"), df$val[i])
Thresholds$set("active", glue("{df$var[i]}"), function() {
eval(parse(text = glue("private$.{df$var[i]}")))
})
}
th <- Thresholds$new()
return(th)
}
df <- tibble::tribble(~var, ~val,
"min_units", 100,
"min_discount", 999)
th <- create_thresholds(df)
th$min_discount ## expect 999
th$min_units ## OOPS! expect 100
Upvotes: 2
Views: 475
Reputation: 970
The following solution entails dynamically creating a string form of the entire function/method definition, and then calling eval(parse())
on it.
library("R6")
df <- tibble::tribble(~var, ~val,
"min_units", 100,
"min_discount", 999)
create_thresholds <- function(df) {
Thresholds <- R6Class("Thresholds")
for (i in 1:nrow(df)){
mthd_name <- df$var[i]
mthd_def <- glue::glue("function() private$.{mthd_name}")
Thresholds$set("private", glue(".{mthd_name}"), df$val[i])
Thresholds$set("active", mthd_name, eval(parse(text = mthd_def)))
}
hh <- Thresholds$new()
return(hh)
}
hh <- create_thresholds(df)
hh$min_discount # expect 999!
hh$min_units #expect 100
Upvotes: 1