在 RStudio 中记录 R 包中的 R6 类和方法 [英] Documenting R6 classes and methods within R package in RStudio

查看:63
本文介绍了在 RStudio 中记录 R 包中的 R6 类和方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力处理 R6 类及其方法的文档.我的目标是在 RStudio 中获得方法的自动完成.目前,我只得到了方法的名称,但没有得到我通常使用 roxygen2 记录带有参数等的函数的帮助信息.

I am struggling with the documentation of an R6 class and its methods. My goal is to get the autocompletion in RStudio for the methods. At the moment, I only get the name of the method but no the help information I normally get using roxygen2 documenting a function with parameters etc.

目前,这是我的班级:

#' @importFrom R6 R6Class
MQParameters <- R6::R6Class(
  'MQParameters',
  public=list(
    initialize=function(file_path=NA) {
      private$location <- file_path
      mq_parameters <- read.delim(file_path, stringsAsFactors=FALSE)
      mq_parameters <-
        setNames(mq_parameters$Value, mq_parameters$Parameter)
      private$mq_version <- unname(mq_parameters['Version'])
      private$fasta_file <-
        gsub('\\\\', '/', strsplit(mq_parameters['Fasta file'], ';')[[1]])
    },
    # this method returns the version
    getVersion=function() {
      private$mq_version
    },
    # this methods returns the fastafile.
    # @param new_param it is possible to rewrite the basedir.
    getFastaFile=function(new_basedir=NA) {
      if(is.na(new_basedir)) {
        private$fasta_file
      } else {
        file.path(new_basedir, basename(private$fasta_file))
      }
    }
  ),
  private=list(
    location=NULL,
    mq_version=NULL,
    fasta_file=NULL
  )
)

如果你有兴趣测试这个类,这里​​有一个可重现的小例子:

If you are interested to test this class, here is a little reproducible example:

df <- data.frame(Parameter=c('Version', 'Fasta file'),
                 Value=c('1.5.2.8','c:\\a\\b.fasta'))
write.table(df, 'jnk.txt', sep='\t', row.names=F)

p <- MQParameters$new('jnk.txt')
p$getVersion()
# [1] "1.5.2.8"
p$getFastaFile()
# [1] "c:/a/b.fasta"
p$getFastaFile(new_basedir='.')
# [1] "./b.fasta"

我不知道如何记录参数,因为参数实际上属于创建者而不是类.函数内其他方法的参数呢?
使用类的方法记录类的首选方式是什么?

I don't know how to document parameters, because the parameters are actually belong to the creator but not to the class. What about the parameters to other methods within the function?
What is the preferred way to document a class with it's methods?

我很想从 RStudio 获得正常"功能,比如点击 F1 直接进入帮助页面.

I would love to get the "normal" functionality from RStudio, like hitting F1 to get directly to the help page.

通过在互联网上搜索,我已经在 Github 上看到了一些关于此主题的报告,但它们已经超过一年了.

By searching the internet, I saw already some reports on Github about this topic, but they more than a year old.

感谢 mikeck 的回答,我现在有一个很好的类及其方法的文档.但是我仍然缺乏的是获得函数/方法及其参数的提示的可能性,如此屏幕截图中的通用函数:

Thanks to the answer of mikeck I now have a nice documentation for the class and it's methods. But what I am still lacking is the possibility to get the hint of function/method and its arguments like in this screenshot for a common function:

我想知道我是否可以以某种方式手动注册我的函数,但由于它没有特定名称(它始终与用于对象的变量 objectname 相关联 OBJECTNAME$methodeCall()) 我不知道该怎么做.

I am wondering if I can somehow register my function manually, but since it doesn't have a specific name (it is always coupled with the variable objectname you use for the object OBJECTNAME$methodeCall()) I don't know how to do this.

推荐答案

我的理解是,用与您的 @name 相同的 @name 记录一个 NULL 对象是最容易的类,因为这提供了最大的灵活性.我在我的一个包中使用了 R6 类;您可以在此处查看 roxygen.我在下面包含了一个小样本:

My understanding is that it is easiest to document a NULL object with the same @name as your class, as this provides maximum flexibility. I use an R6 class in one of my packages; you can view the roxygen here. I've included a small sample below:

#' Python Environment
#' 
#' The Python Environment Class. Provides an interface to a Python process.
#' 
#' 
#' @section Usage:
#' \preformatted{py = PythonEnv$new(port, path)
#'
#' py$start()
#' 
#' py$running
#' 
#' py$exec(..., file = NULL)
#' py$stop(force = FALSE)
#' 
#' }
#'
#' @section Arguments:
#' \code{port} The port to use for communication with Python.
#' 
#' \code{path} The path to the Python executable.
#' 
#' \code{...} Commands to run or named variables to set in the Python process.
#'
#' \code{file} File containing Python code to execute.
#' 
#' \code{force} If \code{TRUE}, force the Python process to terminate
#'   using a sytem call.
#' 
#' @section Methods:
#' \code{$new()} Initialize a Python interface. The Python process is not 
#'   started automatically.
#'   
#' \code{$start()} Start the Python process. The Python process runs 
#'   asynchronously.
#'
#' \code{$running} Check if the Python process is running.
#'   
#' \code{$exec()} Execute the specified Python 
#'   commands and invisibly return printed Python output (if any).
#'   Alternatively, the \code{file} argument can be used to specify
#'   a file containing Python code. Note that there will be no return 
#'   value unless an explicit Python \code{print} statement is executed.
#' 
#' \code{$stop()} Stop the Python process by sending a request to the 
#'   Python process. If \code{force = TRUE}, the process will be 
#'   terminated using a system call instead.
#'
#' @name PythonEnv
#' @examples
#' pypath = Sys.which('python')
#' if(nchar(pypath) > 0) { 
#'   py = PythonEnv$new(path = pypath, port = 6011)
#'   py$start()
#'   py$running
#'   py$stop(force = TRUE)
#' } else 
#' message("No Python distribution found!")
NULL

#' @export
PythonEnv = R6::R6Class("PythonEnv", cloneable = FALSE,
  # actual class definition...

还有其他替代(但类似)的实现;本示例使用@docType类 可能更适合您:

There are other alternative (but similar) implementations; this example uses @docType class which might suit you better:

#' Class providing object with methods for communication with lightning-viz server
#'
#' @docType class
#' @importFrom R6 R6Class
#' @importFrom RCurl postForm
#' @importFrom RJSONIO fromJSON toJSON
#' @importFrom httr POST
#' @export
#' @keywords data
#' @return Object of \code{\link{R6Class}} with methods for communication with lightning-viz server.
#' @format \code{\link{R6Class}} object.
#' @examples
#' Lightning$new("http://localhost:3000/")
#' Lightning$new("http://your-lightning.herokuapp.com/")
#' @field serveraddress Stores address of your lightning server.
#' @field sessionid Stores id of your current session on the server.
#' @field url Stores url of the last visualization created by this object.
#' @field autoopen Checks if the server is automatically opening the visualizations.
#' @field notebook Checks if the server is in the jupyter notebook mode.
#' #' @section Methods:
#' \describe{
#'   \item{Documentation}{For full documentation of each method go to https://github.com/lightning-viz/lightining-r/}
#'   \item{\code{new(serveraddress)}}{This method is used to create object of this class with \code{serveraddress} as address of the server object is connecting to.}
#'
#'   \item{\code{sethost(serveraddress)}}{This method changes server that you are contacting with to \code{serveraddress}.}
#'   \item{\code{createsession(sessionname = "")}}{This method creates new session on the server with optionally given name in \code{sessionname}.}
#'   \item{\code{usesession(sessionid)}}{This method changes currently used session on the server to the one with id given in \code{sessionid} parameter.}
#'   \item{\code{openviz(vizid = NA)}}{This method by default opens most recently created by this object visualization. If \code{vizid} parameter is given, it opens a visualization with given id instead.}
#'   \item{\code{enableautoopening()}}{This method enables auto opening of every visualisation that you create since that moment. Disabled by default.}
#'   \item{\code{disableautoopening()}}{This method disables auto opening of every visualisation that you create since that moment. Disabled by default.}
#'   \item{\code{line(series, index = NA, color = NA, label = NA, size = NA, xaxis = NA, yaxis = NA, logScaleX = "false", logScaleY = "false")}}{This method creates a line visualization for vector/matrix with each row representing a line, given in \code{series}.}
#'   \item{\code{scatter(x, y, color = NA, label = NA, size = NA, alpha = NA, xaxis = NA, yaxis = NA)}}{This method creates a scatterplot for points with coordinates given in vectors \code{x, y}.}
#'   \item{\code{linestacked(series, color = NA, label = NA, size = NA)}}{This method creates a plot of multiple lines given in matrix \code{series}, with an ability to hide and show every one of them.}
#'   \item{\code{force(matrix, color = NA, label = NA, size = NA)}}{This method creates a force plot for matrix given in \code{matrix}.}
#'   \item{\code{graph(x, y, matrix, color = NA, label = NA, size = NA)}}{This method creates a graph of points with coordinates given in \code{x, y} vectors, with connection given in \code{matrix} connectivity matrix.}
#'   \item{\code{map(regions, weights, colormap)}}{This method creates a world (or USA) map, marking regions given as a vector of abbreviations (3-char for countries, 2-char for states) in \code{regions} with weights given in \code{weights} vector and with \code{colormap} color (string from colorbrewer).}
#'   \item{\code{graphbundled(x, y, matrix, color = NA, label = NA, size = NA)}}{This method creates a bundled graph of points with coordinates given in \code{x, y} vectors, with connection given in \code{matrix} connectivity matrix. Lines on this graph are stacked a bit more than in the \code{graph} function.}
#'   \item{\code{matrix(matrix, colormap)}}{This method creates a visualization of matrix given in \code{matrix} parameter, with its contents used as weights for the colormap given in \code{colormap} (string from colorbrewer).}
#'   \item{\code{adjacency(matrix, label = NA)}}{This method creates a visualization for adjacency matrix given in \code{matrix} parameter.}
#'   \item{\code{scatterline(x, y, t, color = NA, label = NA, size = NA)}}{This method creates a scatterplot for coordinates in vectors \code{x, y} and assignes a line plot to every point on that plot. Each line is given as a row in \code{t} matrix.}
#'   \item{\code{scatter3(x, y, z, color = NA, label = NA, size = NA, alpha = NA)}}{This method creates a 3D scatterplot for coordinates given in vectors \code{x, y, z}.}
#'   \item{\code{image(imgpath)}}{This method uploads image from file \code{imgpath} to the server and creates a visualisation of it.}
#'   \item{\code{gallery(imgpathvector)}}{This method uploads images from vector of file paths \code{imgpathvector} to the server and creates a gallery of these images.}}


Lightning <- R6Class("Lightning",
...
)

编辑

如果您正在寻找一种在尝试使用类方法时显示 RStudio 工具提示的方法...不幸的是,我认为您不会找到不需要以某种方式对类进行编码的解决方案这消除了 R6 类的便利性和功能性.

If you are looking for a way to get the RStudio tooltips to show up when trying to use a class method... unfortunately I don't think you will find a solution that doesn't require coding your classes in a way that eliminates the convenience and functionality of R6 classes.

@f-privé 提供了一个可以做你想做的事情的答案——只需将该逻辑扩展到所有方法.例如,myclass$my_method

@f-privé has provided an answer that will do what you want---just extend that logic to ALL methods. For example, myclass$my_method is instead accessed by

my_method = function(r6obj) {
  r6obj$my_method()
}
obj$my_method()
my_method(obj)      # equivalent

换句话说,您需要为每个方法创建一个包装器.这显然比仅使用 obj$my_method() 更不方便编程,并且可能首先扼杀了使用 R6 类的用处.

In other words, you would need to create a wrapper for each method. This obviously is less convenient to program than just using the obj$my_method(), and probably kills the usefulness of using an R6 class in the first place.

这里的问题实际上是 RStudio.IDE 没有通过分析代码来识别 R6 类的好方法,并且无法区分已定义类的方法和列表或环境的元素.此外,RStudio 无法提供有关任意函数的帮助,例如:

The issue here is really RStudio. The IDE doesn't have a good way of identifying R6 classes by analyzing the code, and can't distinguish between methods of a defined class and elements of a list or environment. Furthermore, RStudio can't provide help on arbitrary functions, like:

na.omit()         # tooltip shows up when cursor is within the parentheses
foo = na.omit
foo()             # no tooltip

这非常类似于调用特定 R6 对象的方法.

which is fairly analogous to calling methods of a particular R6 object.

这篇关于在 RStudio 中记录 R 包中的 R6 类和方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆