在新版本的软件包中重命名函数时,是否有最佳/推荐的做法?

时间:2012-04-11 02:39:34

标签: r roxygen

我正在更新旧包并缩短一堆非常长的函数名称。如何让用户知道旧函数已被弃用?我用roxygen2记录了所有内容,所以我想知道#' @alias是否应该使用?想法?

4 个答案:

答案 0 :(得分:47)

即使您只是缩短功能名称,我仍然会像对包的公共API的任何更改一样对待它:随着新功能的引入,旧功能的弃用/废弃阶段。< / p>

在第一阶段,对于你想要缩短名称(让我们称之为transmute_my_carefully_crafted_data_structure_into_gold)的每个函数,你保留一个带有该签名的函数,但是将所有实际代码移动到你新命名的函数中(let's称之为alchemy)。

最初:

transmute_my_carefully_crafted_data_structure_into_gold <- function(lead, alpha=NULL, beta=3) {
  # TODO: figure out how to create gold
  # look like we are doing something
  Sys.sleep(10)
  return("gold")
}

首次发布新名称:

transmute_my_carefully_crafted_data_structure_into_gold <- function(lead, alpha=NULL, beta=3) {
  .Deprecated("alchemy") #include a package argument, too
  alchemy(lead=lead, alpha=alpha, beta=beta)
}

alchemy <- function(lead, alpha=NULL, beta=3) {
  # TODO: figure out how to create gold
  # look like we are doing something
  Sys.sleep(10)
  return("gold")
}

因此transmute_my_carefully_crafted_data_structure_into_goldalchemy周围的精简包装形式开始,并进行额外的.Deprecated调用。

> transmute_my_carefully_crafted_data_structure_into_gold()
[1] "gold"
Warning message:
'transmute_my_carefully_crafted_data_structure_into_gold' is deprecated.
Use 'alchemy' instead.
See help("Deprecated") 
> alchemy()
[1] "gold"

如果您对alchemy进行了更改,它仍由transmute_my_carefully_crafted_data_structure_into_gold承载,因为它只调用前者。但是,即使transmute_my_carefully_crafted_data_structure_into_gold发生,您也不会更改alchemy的签名;在这种情况下,您需要将旧参数尽可能映射到新参数中。

在以后的版本中,您可以将.Deprecated更改为.Defunct

> transmute_my_carefully_crafted_data_structure_into_gold()
Error: 'transmute_my_carefully_crafted_data_structure_into_gold' is defunct.
Use 'alchemy' instead.
See help("Defunct")

请注意,这是一个错误并停止;它不会继续并致电alchemy

在稍后的某个版本中,您可以完全删除此功能,但我会将其置于此状态作为路标。

你提到过使用roxygen。当您将第一个转换为不推荐使用时,可以将@rdname更改为package-deprecated,在描述的开头添加一行表示不推荐使用,将新函数添加到@seealso。当它变为已失效时,请将@rdname更改为package-defunct。

答案 1 :(得分:22)

我猜“正确”的答案取决于你想要什么。从我的观点来看:

  1. Jeff和Brandon的方法存在的问题是,您的索引将列出两个函数名称,并且不会指出哪个是首选名称。此外,如果没有某种.Deprecated调用,用户更不可能知道调用该函数的首选方式是什么。
  2. Brian的方法存在的问题是,我不清楚将多个函数列为已弃用的过程。
  3. 所以,请在下面输入我的示例。在另一个位置,我定义了函数的“好”版本(例如alchemy,latinSquareDigram)。在这里,我定义了我想要为其生成弃用警告的所有旧“坏”版本。我按照汽车包的方法,改变了我所有的函数调用,使用不推荐的版本作为参数。这有助于我避免一堆混乱的@param语句。我还使用了@name和@docType指令使“yourPackageName-deprecated”出现在索引中。也许有人有更好的方法来做到这一点?

    现在每个已弃用的函数仍显示在索引中,但它们旁边显示“yourPackageName包中的不推荐使用的函数”,并且对它们的任何调用都会产生弃用警告。要从索引中删除它们,可以删除@aliases指令,但是你会得到用户级的未记录的代码对象,我认为它们是不好的形式。

    #' Deprecated function(s) in the yourPackageName package
    #' 
    #' These functions are provided for compatibility with older version of
    #' the yourPackageName package.  They may eventually be completely
    #' removed.
    #' @rdname yourPackageName-deprecated
    #' @name yourPackageName-deprecated
    #' @param ... Parameters to be passed to the modern version of the function
    #' @docType package
    #' @export  latinsquare.digram Conv3Dto2D Conv2Dto3D dist3D.l
    #' @aliases latinsquare.digram Conv3Dto2D Conv2Dto3D dist3D.l
    #' @section Details:
    #' \tabular{rl}{
    #'   \code{latinsquare.digram} \tab now a synonym for \code{\link{latinSquareDigram}}\cr
    #'   \code{Conv3Dto2D} \tab now a synonym for \code{\link{conv3Dto2D}}\cr
    #'   \code{Conv2Dto3D} \tab now a synonym for \code{\link{conv2Dto3D}}\cr
    #'   \code{dist3D.l} \tab now a synonym for \code{\link{dist3D}}\cr
    #' }
    #'  
    latinsquare.digram <- function(...) {
      .Deprecated("latinSquareDigram",package="yourPackageName")
      latinSquareDigram(...)
    }
    Conv3Dto2D <- function(...) {
      .Deprecated("conv3Dto2D",package="yourPackageName")
      conv3Dto2D(...)
    }
    Conv2Dto3D <- function(...) {
      .Deprecated("conv2Dto3D",package="yourPackageName")
      conv2Dto3D(...)
    }
    dist3D.l <- function(...) {
      .Deprecated("dist3D",package="yourPackageName")
      dist3D(...)
    }
    NULL
    

答案 2 :(得分:3)

在将过长的函数名称转换为较短版本的情况下,我建议只将两个名称导出为相同的函数(请参阅@Brandon的注释)。这将允许旧代码继续工作,同时为新用户提供更方便的替代方案。

在我看来,将标记为.Deprecated(参见@GSEE)的唯一原因是,如果您计划从根本上更改功能或停止在将来的版本中支持某些功能。如果是这种情况,您可以使用.Defunct.Deprecated

答案 3 :(得分:3)

我有这个问题已经有一段时间了,无法找到一个好的解决方案。然后我发现了这个。但是,对于简单的情况,上面的答案过于复杂,人们只想:1)添加别名,以便旧代码不会停止工作,2)别名必须使用内置文档,3)它应该用roxygen2来完成。

首先,添加函数的副本:

old_function_name = new_function_name

然后,在定义new_function_name()的地方,添加到roxygen2:

#' @export new_function_name old_function_name
#' @aliases old_function_name

现在旧函数有效,因为它只是新函数的副本,并且文档可以正常工作,因为您设置了别名。旧版本也会导出,因为它包含在@export中。