Я обновляю старый пакет и сокращаю кучу действительно длинных имен функций. Как сообщить пользователю, что старая функция устарела? Я документирую все с помощью roxygen2
, поэтому мне интересно, что я должен использовать #' @alias
? Мысли?
Существуют ли лучшие/рекомендуемые методы для переименования функций в новой версии пакета?
Ответ 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.