-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constructors: Using rlang::inject
with new_object()
#497
Comments
As an aside, is there a way to access the property names for an object within the constructor function?
penguins_properties <- access_prop_names(prop_names_from_penguin_object_properties) Instead of relying on referencing an external object (the |
Thanks for reporting! I agree we'll want to enable this use case. Just so you're not blocked, here is an approach you can use with the current release: library(S7)
library(rlang)
library(purrr, warn.conflicts = FALSE)
my_penguin <- as.list(palmerpenguins::penguins[1, ])
Penguin <- new_class(
"Penguin",
properties = list(
species = class_factor,
island = class_factor,
bill_length_mm = class_double,
bill_depth_mm = class_double,
flipper_length_mm = class_integer,
body_mass_g = class_integer,
sex = class_factor,
year = class_integer
),
constructor = function(x) {
Penguin <- sys.function() # Get reference to Self / Class
prop_vals <- map(set_names(names(Penguin@properties)),
function(prop_name) pluck(x, prop_name))
# hack to enable using `new_object()` with NSE.
constructor <- function() {}
body(constructor) <- inject(quote(new_object(S7_object(), !!!prop_vals)))
attributes(constructor) <- attributes(sys.function())
constructor()
}
)
Penguin(my_penguin)
#> <Penguin>
#> @ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1
#> @ island : Factor w/ 3 levels "Biscoe","Dream",..: 3
#> @ bill_length_mm : num 39.1
#> @ bill_depth_mm : num 18.7
#> @ flipper_length_mm: int 181
#> @ body_mass_g : int 3750
#> @ sex : Factor w/ 2 levels "female","male": 2
#> @ year : int 2007 Created on 2024-11-19 with reprex v2.1.1 |
Thanks for the workaround! I was able to apply it to my real use case. Just for reference to anyone else reading this, here's what you'd do if you still want to rely on referencing an external object (the library(S7)
library(rlang)
library(purrr)
library(palmerpenguins)
my_penguin <- as.list(penguins[1,])
penguin <- new_class(
"penguin",
properties = list(
species = class_factor,
island = class_factor,
bill_length_mm = class_double,
bill_depth_mm = class_double,
flipper_length_mm = class_integer,
body_mass_g = class_integer,
sex = class_factor,
year = class_integer
),
constructor = function(x) {
props <- set_names(colnames(penguins)) # Get prop names from `penguins` tbl
prop_vals <- map(props, function(prop_name) pluck(x, prop_name))
# hack to enable using `new_object()` with NSE.
constructor <- function() {}
body(constructor) <- inject(quote(new_object(S7_object(), !!!prop_vals)))
attributes(constructor) <- attributes(sys.function())
constructor()
}
)
penguin(my_penguin)
#> <penguin>
#> @ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1
#> @ island : Factor w/ 3 levels "Biscoe","Dream",..: 3
#> @ bill_length_mm : num 39.1
#> @ bill_depth_mm : num 18.7
#> @ flipper_length_mm: int 181
#> @ body_mass_g : int 3750
#> @ sex : Factor w/ 2 levels "female","male": 2
#> @ year : int 2007 Created on 2024-11-19 with reprex v2.1.1 |
Is there a way to use
rlang::inject
(or something similar) withnew_object
? It currently throws an error thatnew_object()
must be called from within a constructor. Here's a reprex:Created on 2024-11-18 with reprex v2.1.1
The text was updated successfully, but these errors were encountered: