Подтвердить что ты не робот

Существуют ли лучшие/рекомендуемые методы для переименования функций в новой версии пакета?

Я обновляю старый пакет и сокращаю кучу действительно длинных имен функций. Как сообщить пользователю, что старая функция устарела? Я документирую все с помощью roxygen2, поэтому мне интересно, что я должен использовать #' @alias? Мысли?

4b9b3361

Ответ 1

Несмотря на то, что вы просто сокращаете имена функций, я все равно буду относиться к ним с той же фанфарой, что и любое изменение общедоступного API пакета: с устаревшими/несуществующими этапами до старых функций при вводе новых функций.

В первой фазе для каждой функции вы хотите укоротить имя (позвоните на него transmute_my_carefully_crafted_data_structure_into_gold), вы сохраните функцию с этой сигнатурой, но переместите весь фактический код в свою новую функцию (позвольте ей позвонить 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_gold начинается как тонкая оболочка вокруг alchemy, с дополнительным вызовом .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 на отказ от пакетов, добавить строку в начале описания, говоря, что она устарела, добавить новую функцию в @seealso. Когда он изменится на несуществующий, измените @rdname на отсутствие пакетов.

Ответ 2

Я думаю, что "правильный" ответ зависит от того, что вы хотите. С моей точки зрения:

  • Проблема с подходом Джеффа и Брэндона заключается в том, что ваш индекс будет перечислять имена обеих функций и не указывать, какое имя является предпочтительным. Более того, без какого-либо недопустимого вызова пользователь еще более маловероятен, чтобы узнать, какой предпочтительный способ вызвать функцию.
  • Проблема с подходом Брайана заключалась в том, что процесс для перечисления более чем одной функции как устаревшей был для меня неясным.

Итак, введите мой пример ниже. В другом месте я определяю "хорошие" версии функций (например, алхимия, latinSquareDigram). Здесь я определяю все старые "плохие" версии, для которых я хочу написать предупреждения об устаревании. Я следил за приближением пакета автомобилей и менял все мои вызовы функций для использования устаревшей версии... в качестве аргумента. Это помогло мне избежать множества суматошных операторов @param. Я также использовал директивы @name и @docType, чтобы в индексе отображалось "yourPackageName-устарело". Может быть, у кого-то есть лучший способ сделать это?

Теперь каждая из устаревших функций по-прежнему отображается в индексе, но рядом с ними "Устаревшие функции в пакете 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

Ответ 3

В случае преобразования слишком длинных имен функций в более короткие версии я бы рекомендовал просто экспортировать оба имени в одну и ту же функцию (см. комментарий @Brandon). Это позволит старым кодам продолжить работу, предлагая новым пользователям более удобную альтернативу.

На мой взгляд, единственная причина пометить что-то как .Deprecated (см. @GSEE) будет, если вы планируете принципиально изменить функциональность или прекратить поддерживать какую-либо функцию в будущей версии. Если это так, вы можете использовать .Defunct или .Deprecated.

Ответ 4

У меня была эта проблема в течение некоторого времени и я не смог найти хорошее решение. Тогда я нашел это. Тем не менее, приведенные выше ответы слишком сложны для простого случая, когда нужно просто: 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.