如何让R的R6类initialize方法从create_person继承Roxygen2参数?
R6类initialize方法参数注释继承失败的解决办法
问题重现
我定义了Person R6类,同时写了包装Person$new()的create_person()函数,两者参数完全一致。想让Person$initialize的参数注释从create_person继承,但执行devtools::document()时触发如下报错:
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中写参数注释,让create_person继承,无效。 - 自定义函数提取参数注释:分别尝试从R源码文件和生成的man文件提取注释插入Roxygen,均失败。相关代码如下:
- 从R文件提取参数的函数:
对应的Roxygen注释片段: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") }#' @description Initialize a Person Object (Class Init) #' `r inherit_params("R/Person.R", "create_person")` initialize = function(name, age) { - 从man文件提取参数的函数:
对应的Roxygen注释片段: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)] }#' @description Initialize a Person Object (Class Init) #' `r inherit_params_man("create_person")` initialize = function(name, age) {
- 从R文件提取参数的函数:
原代码
Person类与create_person函数
#' 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 #' @inheritParams create_person initialize = function(name, age) { 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) }
原因分析
Roxygen的@inheritParams机制对R6类方法的支持有限:R6类的文档主题和普通函数的文档主题是分离的,直接在initialize方法的注释中引用普通函数的参数注释会被Roxygen识别为无效操作,因为它无法跨主题继承参数描述。
解决方案
方案1:反向继承(推荐)
让create_person继承Person类的参数注释(更合理,因为类的初始化方法是参数的源头),具体代码如下:
#' Person example class #' #' @export #' @return a new Person object #' @examples #' Person$new("John", 30) 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 name of the person #' @param age age of the person initialize = function(name, age) { self$name <- name self$age <- age } ) ) #' Creates a new Person #' #' @export #' @inheritParams Person #' @inherit Person return examples create_person <- function(name, age) { Person$new(name, age) }
执行devtools::document()即可正常生成文档,参数注释会从Person类的initialize方法继承到create_person函数,同时Person类的初始化参数也有明确的注释。
方案2:类主注释继承参数
如果坚持要让Person类继承create_person的参数注释,可以在类的主注释中添加@inheritParams create_person,并在initialize方法中保留空的@param标签:
#' Person example class #' #' @export #' @inherit create_person return examples #' @inheritParams create_person 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 #' @param age initialize = function(name, age) { 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) }
这样Roxygen会将类主注释中的参数描述关联到initialize方法的参数上,避免报错。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

