I tried to write a for loop to create getters and setters for slots of an S4 class.
A similar reprex with a smaller class and only methods for the getters is:
library(methods)
library(testthat)
get_slot <- function(slot) {
function(x) slot(x, slot)
}
setClass("TEST", slots = list(a = "character", b = "character"))
for (e in c("a", "b")) {
def <- eval(parse(text = sprintf("function(x) standardGeneric('%s')", e)))
setGeneric(e, def = def)
setMethod(e, "TEST", get_slot(e))
}
test_that("getters work", {
o <- new("TEST")
o@a <- "a"
o@b <- "b"
expect_equal(a(o), "a")
expect_equal(b(o), "b")
})
#> ── Failure ('<text>:20:3'): getters work ───────────────────────────────────────
#> a(o) not equal to "a".
#> 1/1 mismatches
#> x[1]: "b"
#> y[1]: "a"
#> Error in `reporter$stop_if_needed()`:
#> ! Test failed
#> Backtrace:
#> ▆
#> 1. └─testthat::test_that(...)
#> 2. └─withr (local) `<fn>`(`<env>`)
#> 3. ├─base::tryCatch(...)
#> 4. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#> 5. │ └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 6. │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#> 7. └─base::eval(handler$expr, handler$envir)
#> 8. └─base::eval(handler$expr, handler$envir)
#> 9. └─reporter$stop_if_needed()
#> 10. └─rlang::abort("Test failed") at testthat/R/reporter-stop.R:56:8
getMethod("a", signature = "TEST")
#> Method Definition:
#>
#> function (x)
#> slot(x, slot)
#> <environment: 0x55bb459bec98>
#>
#> Signatures:
#> x
#> target "TEST"
#> defined "TEST"
getMethod("b", signature = "TEST")
#> Method Definition:
#>
#> function (x)
#> slot(x, slot)
#> <bytecode: 0x55bb45b97558>
#> <environment: 0x55bb45ab1258>
#>
#> Signatures:
#> x
#> target "TEST"
#> defined "TEST"
Created on 2023-09-18 with reprex v2.0.2
I would expect that a(o) is equal to "a" and b(o) is equal to "b". I do not understand why the slot argument is wrong not correct for the first getter.
Not exactly sure what's going on, but if you
eval()andparse()the wholesetGeneric()andsetMethod()functions, it works. Generally people don't like eval-parse answers, but it does work here.Created on 2023-09-18 with reprex v2.0.2