I have a Person R6 object class in R with an accompanying create_person() function that wraps Person$new(). Therefore, the two functioncs (create_person(), and Person$new()/initialize) have the exact same parameters.
How can I inherit the parameters for Person$new()/initialize from the function create_person()?
Interestingly, the inherit return and examples work from the class to the wrapper function.
#' Person example class, where the initialize parameters should be inherited from create_person
#'
#' @export
#' @inherit create_person return examples
Person <- R6::R6Class(
"Person",
public = list(
#' @field name The name of the person
name = NULL,
#' @field age The age of the person
age = NULL,
# TODO this fails below: ✖ In topic 'Person': @inheritParams failed. AND Must use one @param for each argument.
#' @description Initialize a Person Object
#' @inheritParams create_person
initialize = function(name, age) {
# do something
self$name <- name
self$age <- age
}
)
)
#' Creates a new Person
#'
#' @param name name of the person
#' @param age age of the person
#'
#' @return a new Person object
#' @export
#'
#' @examples
#' create_person("John", 30)
create_person <- function(name, age) {
Person$new(name, age)
}
Which results in
devtools::document()
#> ✖ Person.R:5: Must use one @param for each argument.
#> ✖ $initialize(name) is not documented
#> ✖ Person.R:5: Must use one @param for each argument.
#> ✖ $initialize(age) is not documented
#> ✖ In topic 'Chat': @inheritParams failed.
#> ℹ All parameters are already documented; none remain to be inherited.
#> ✖ In topic 'Person': @inheritParams failed.
#> ℹ All parameters are already documented; none remain to be inherited.
Person$initialize and inherit in create_person(), also didnt work.For the curious, this is what I had for approach 2.
# file <- "R/Person.R"
# func <- "create_person"
# extracts the parameters from the R/Person.R file and inserts them with roxygen formatting - fails
inherit_params <- function(file, func) {
x <- readLines(file)
is_func <- startsWith(trimws(x), func)
x_before <- x[cumsum(is_func) == 0]
is_not_comment_rev <- !startsWith(rev(x_before), "#'")
lines_with_comment <- rev(rev(x_before)[cumsum(is_not_comment_rev) == 0])
params <- lines_with_comment[grepl("@param", lines_with_comment)]
paste(gsub("#' ", "", c(params, "\n")), collapse = "\n")
}
# snippet from Person
#' @description Initialize a Person Object (Class Init)
#' `r inherit_params("R/Person.R", "create_person")`
initialize = function(name, age) {
# alternatively, try to extract the man/rd code directly
# extracts the arguments from the man/create_person.Rd file
inherit_params_man <- function(func) {
x <- readLines(sprintf("man/%s.Rd", func))
is_args <- which(startsWith(trimws(x), "\\arguments{"))
is_closing <- which(startsWith(trimws(x), "}"))
diff <- is_closing - is_args
diff <- diff[diff > 0]
nlines <- min(diff)
x[is_args:(is_args + nlines)]
}
# snippet from Person
#' @description Initialize a Person Object (Class Init)
#' `r inherit_params_man("create_person")`
initialize = function(name, age) {
Inheriting parameters does not currently be supported for R6 methods (see the respective Github issues here and here). The official recommendation is what you already tried: using inline code (see this Posit forum answer). I didn't quite manage to reproduce your attempt of creating inline code because your code is incomplete, but I created a minimal working example using global objects (inspired by the approach of the affiner package):
#' Person example class, where the initialize parameters should be inherited from create_person
#'
#' @export
#' @inherit create_person return examples
Person <- R6::R6Class(
"Person",
public = list(
#' @field name The name of the person
name = NULL,
#' @field age The age of the person
age = NULL,
#' @description Initialize a Person Object
#' @param name `r rd_arg_name`
#' @param age `r rd_arg_age`
initialize = function(name, age) {
# do something
self$name <- name
self$age <- age
}
)
)
#' Creates a new Person
#'
#' @param name `r rd_arg_name`
#' @param age `r rd_arg_age`
#'
#' @return a new Person object
#' @export
#'
#' @examples
#' create_person("John", 30)
create_person <- function(name, age) {
Person$new(name, age)
}
rd_arg_name <- "name of the person"
rd_arg_age <- "age of the person"
The idea is to define the documentation for each parameter in global variables and access these variables in the Roxygen inline code. The downside is that you still need to manually define which arguments should be inherited for each function/method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With