Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Roxygen2 R6 inherit params for initialize from other function

Tags:

r

roxygen2

r6

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.

What I've tried so far

  1. Write the parameters into Person$initialize and inherit in create_person(), also didnt work.
  2. Write a custom function that extracts the parameters from the source code and uses inline code in Roxygen. Also fails.

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) {
    

like image 572
David Avatar asked Dec 16 '25 21:12

David


1 Answers

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.

like image 73
jslth Avatar answered Dec 19 '25 13:12

jslth