Search code examples
rfunctionroxygen2r6

creating Rd documentation files for R6 classes not in a package


I am trying to create the documentation of a few scripts that have some R6 classes in it. As an example I use the R6Class named "Person" from here: https://www.tidyverse.org/blog/2019/11/roxygen2-7-0-0/

I am using this function https://stackoverflow.com/a/59073260/12166017 to create the documentation without the need of creating a package. Is it also possible to use this for R6Classes or is there maybe another way to achieve this? With the mentioned function I always get an Error R6 Class (Person) without source references.

The solution of the official tidyverse blog https://www.tidyverse.org/blog/2019/11/roxygen2-7-0-0/ to write Roxygen: list(r6 = FALSE) in the DESCRIPTION file does not work because I don't have a package and so no DESCRIPTION file.


Solution

  • One way to do this is to hijack some of roxygen2's unexported functions to create the block object for the documented R6 class and write an Rd file. This can then be parsed and written to html using the tools package.

    This is a very rough proof-of-concept, requiring your R6 definition to be in a standalone file, and not taking any arguments to allow saving to specific locations, etc, but it could be adapted and expanded to suit:

    document_R6 <- function(R_file)
    {
      blocks  <- lapply(roxygen2:::tokenize_file(R_file), roxygen2:::block_set_env,
                        env = .GlobalEnv)
      blocks  <- roxygen2:::order_blocks(blocks)
      roclet  <- roxygen2:::roclet("rd")
      my_rd   <- suppressWarnings(roxygen2:::roclet_process(roclet, blocks))
      my_rd   <- my_rd[[1]]$format()
      rd_file <- tempfile()
      writeLines(my_rd, rd_file)
      tools::Rd2HTML(tools::parse_Rd(rd_file), 
                     gsub("\\.R$", ".html", R_file))
    }
    

    So if we have the following file, taken from your link:

    Person.R

    #' R6 Class representing a person
    #'
    #' A person has a name and a hair color.
    Person <- R6::R6Class("Person",
      public = list(
        #' @field name First or full name of the person.
        name = NULL,
    
        #' @field hair Hair color of the person.
        hair = NULL,
    
        #' @description
        #' Create a new person object.
        #' @param name Name.
        #' @param hair Hair color.
        #' @return A new `Person` object.
        initialize = function(name = NA, hair = NA) {
          self$name <- name
          self$hair <- hair
          self$greet()
        },
    
        #' @description
        #' Change hair color.
        #' @param val New hair color.
        #' @examples
        #' P <- Person("Ann", "black")
        #' P$hair
        #' P$set_hair("red")
        #' P$hair
        set_hair = function(val) {
          self$hair <- val
        },
    
        #' @description
        #' Say hi.
        greet = function() {
          cat(paste0("Hello, my name is ", self$name, ".\n"))
        }
      )
    )
    

    Then we can do:

    document_R6("Person.R")
    

    The following is a screenshot of the resulting rendered "Person.html" file, found in the same directory as "Person.R":


    enter image description here