2012-04-11 7 views
31

Sto aggiornando un vecchio pacchetto e abbreviando una serie di nomi di funzione veramente lunghi. Come faccio a far sapere a un utente che la vecchia funzione è stata deprecata? Ho documentato tutto con roxygen2 quindi mi chiedo se #' @alias è quello che dovrei usare? Pensieri?Esistono le pratiche consigliate/consigliate da seguire quando si rinomino le funzioni in una nuova versione di un pacchetto?

+7

vedere '? Deprecated' – GSee

+0

@alias consente solo all'utente di trovare la documentazione della funzione tramite? Help. È meglio definire sia in linea che esportare sia il vecchio che il nuovo. 'some_func <- new_func_name <- function (x)' e usa la direttiva @alias. Dovrai '@export some_func new_fund_name' se vuoi che siano entrambi nello spazio dei nomi. Vedi? Namespace_roclet. Per me non sembra che tu stia cambiando la funzione, cambiando solo il nome - quindi? Deprecato non sembra proprio applicarsi. –

+0

Grazie mille @BrandonBertelsen Ti suggerisco di postarlo come risposta, quindi è utile per gli altri. – Maiasaura

risposta

42

Anche se si stanno solo abbreviando i nomi delle funzioni, lo tratterei sempre con lo stesso fanfara di qualsiasi modifica all'API pubblica del pacchetto: con fasi di deprecazione/defunto alle vecchie funzioni quando vengono introdotte le nuove funzioni.

Nella prima fase, per ogni funzione che si desidera abbreviare il nome di (chiamiamolo transmute_my_carefully_crafted_data_structure_into_gold), si mantiene una funzione con quella firma, ma si sposta tutto il codice effettivo nella funzione appena nominata (chiamiamola alchemy).

Inizialmente:

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") 
} 

Prima versione con nuovi nomi:

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") 
} 

modo che transmute_my_carefully_crafted_data_structure_into_gold inizia come un sottile involucro intorno alchemy, con un ulteriore .Deprecated chiamata.

> 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" 

Se si apportano modifiche a alchemy, è ancora portato da transmute_my_carefully_crafted_data_structure_into_gold dal che chiama solo il primo. Tuttavia, non si modifica la firma di transmute_my_carefully_crafted_data_structure_into_gold anche se lo fa alchemy; in tal caso è necessario mappare, nel miglior modo possibile, i vecchi argomenti nei nuovi argomenti.

In una versione successiva, è possibile modificare .Deprecated in .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") 

Si noti che si tratta di un errore e si interrompe; non va avanti e chiama alchemy.

In alcune versioni successive, è possibile eliminare completamente questa funzione, ma lo lascerei in questo stato come un cartello.

Hai menzionato l'utilizzo di roxygen. Quando si effettua la prima transizione a deprecato, è possibile modificare @rdname in deprecato dal pacchetto, aggiungere una riga all'inizio della descrizione dicendo che è deprecato, aggiungere la nuova funzione a @seealso. Quando cambia in defunct, cambia il @rdname in package-defunct.

+5

+1 Questa è una grande risposta, degna di una generosità. – Andrie

+1

Grazie per il tempo dedicato a scrivere questa grande risposta. Saluti. – Maiasaura

3

In caso di conversione di nomi di funzione eccessivamente lunghi in versioni più brevi, si consiglia di esportare entrambi i nomi come la stessa funzione (vedere il commento di @ Brandon). Ciò consentirebbe al vecchio codice di continuare a funzionare offrendo ai nuovi utenti un'alternativa più conveniente.

Nella mia mente, l'unica ragione per taggare qualcosa come .Deprecated (vedi @GSEE) sarebbe se si pianificasse di modificare fondamentalmente la funzionalità o di smettere di supportare alcune funzionalità in una versione futura. In tal caso, è possibile utilizzare .Defunct o .Deprecated.

20

Immagino che la risposta "giusta" dipenda da ciò che si desidera.Dal mio punto di vista:

  1. Il problema con l'approccio di Jeff e Brandon è che l'indice indicherà entrambi i nomi di funzioni e non darà alcuna indicazione su quale sia il nome preferito. Inoltre, senza una sorta di chiamata .Deprecata, è ancora più improbabile che l'utente sappia quale sia il modo preferito per chiamare la funzione.
  2. Il problema con l'approccio di Brian era che il processo per elencare più di una funzione come deprecato non era chiaro per me.

Quindi, inserisci il mio esempio qui sotto. In un'altra posizione definisco le versioni "buone" delle funzioni (ad esempio alchimia, latinSquareDigram). Qui definisco tutte le vecchie versioni "cattive" di cui voglio produrre avvisi di deprecazione. Ho seguito l'approccio del pacchetto auto e ho modificato tutte le mie chiamate di funzione affinché la versione deprecata usasse ... come argomento. Questo mi ha aiutato a evitare un sacco di dichiarazioni @param disordinate. Ho anche usato le direttive @name e @docType per far apparire "yourPackageName-deprecato" nell'indice. Forse qualcuno ha un modo migliore di farlo?

Ora ognuna delle funzioni deprecate compare ancora nell'indice, ma dice "Funzionalità deprecata nel pacchetto yourPackageName" accanto a loro e qualsiasi chiamata a loro genera un avviso di deprecazione. Per rimuoverli dall'indice si potrebbe rilasciare la direttiva @aliases, ma in questo caso si avranno oggetti di codice non documentati a livello utente che, a mio avviso, sono di cattiva forma.

#' 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

perché non ha alcun upvotes ?! Lo adoro! –

+1

@ mathematical.coffee: Grazie! Probabilmente perché ho fornito la mia risposta 8 mesi dopo il vincitore della taglia. :) Ho provato il consiglio di cui sopra e non ero soddisfatto del risultato. Così, quando finalmente ho ottenuto un risultato, ero felice di aver postato la mia risposta. – russellpierce

+1

Ho trovato utile il vincitore della taglia, ma questo sicuramente lo aggiunge. Avevo bisogno di quel tocco in più di amore per roxygen2. –

2

Ho avuto questo problema per un po 'di tempo e non sono riuscito a trovare una buona soluzione. Quindi ho trovato questo. Tuttavia, le risposte di cui sopra sono eccessivamente complicate per il semplice caso in cui si vuole solo: 1) aggiungere un alias in modo che il vecchio codice non smetta di funzionare, 2) l'alias deve funzionare con la documentazione integrata e 3) dovrebbe essere fatto con roxygen2.

primo luogo, aggiungere una copia della funzione:

old_function_name = new_function_name 

Poi, in cui è definito new_function_name(), aggiungere alla roxygen2:

#' @export new_function_name old_function_name 
#' @aliases old_function_name 

Ora la vecchia funzione funziona perché è solo una copia della nuova funzione e la documentazione funziona perché si imposta l'alias. Anche la vecchia versione viene esportata perché è inclusa in @export.

Problemi correlati