{fusen} v0.4 – 14 trucs et astuces de développeurs

banner with sticker logo of fusen package
Author : Sébastien Rochette
Tags : développement, astuces, fusen, package, Rmarkdown
Date :

Si vous pensez que {fusen} n’est pas pour vous parce que vous avez créé des packages R toute votre vie sans en avoir besoin, il est temps de l’essayer ! Référez-vous aux nouveaux trucs et astuces dans la vignette dédiée au cas où vous auriez besoin de fonctionnalités supplémentaires : il y a de fortes chances que je les ai déjà implémentées….

Retournez à l’article précédent pour savoir comment commencer avec {fusen} : https://rtask.thinkr.fr/fr/fusen-v0-3-de-meilleurs-modeles-de-projets-des-fonctions-groupees-et-de-nombreuses-autres-ameliorations/

En dessous des Nouveautés, vous trouverez le contenu de la vignette ‘Tips & Tricks’ de {fusen} 0.4, pour aller plus loin dans la construction de vos packages avec {fusen}.

Nouveautés dans {fusen} v.0.4

Nouvelles fonctionnalités

  • inflate() gonfle le fichier “flat” actuellement ouvert si l’argument flat_file est vide (#138)
  • Ajout d’un modèle rmarkdown pour un fichier plat supplémentaire dans RStudio.
  • Ajout de raccourcis autour de add_flat_template() pour les développeurs paresseux : add_additional(), add_full(), add_minimal().
  • Affiche l’origine du “flat_template” dans les fichiers générés par {fusen} pour pouvoir retrouver les sources facilement (@ALanguillaume)
  • Permet inflate(vignette_name = c("Super title" = "01-Super Slug")) pour un beau Titre différent de “Vignette Entry” (#87)

Résolution de Bugs

  • Lire le fichier DESCRIPTION pour le nom du package quand il est disponible (#144 @VincentGuyader)
  • Lire nyc_squirrels avec l’encodage correct pour éviter les problèmes d’encodage avec use_data().
  • Autorise les fichiers “flat” avec tests seulement
  • Simplifie le “flat_teaching” pour la formation avec une fonction simple et unique
  • Corrige asciify_name() pour tenir compte des diacritiques (@ALanguillaume)
  • Améliorer le modèle ‘full’ pour l’utilisation des données internes.
  • Fixe les tests quand git n’existe pas
hex log of fusen package

Trucs et astuces de développeur.euses

1. Puis-je être fainéant dans les noms de chunk utilisés ?

  • Les noms courts de “chunk” sont possibles :
    • function peut être nommée fun- ou fun_ ou fun-mon_nom_de_fonction.
    • example peut être nommé ex- ou ex_ ou ex-mon_nom_de_fonction.
    • tests peut être nommé test- ou test-mon_nom_de_fonction.
    • development peut être nommé dev- ou dev_ ou dev-mon_nom_de_fonction.
  • Il existe des raccourcis autour de add_flat_template() pour les développeurs paresseux : add_additional(), add_full(), add_minimal().

2. Puis-je tricoter le contenu du modèle “flat” ?

Oui. Bien que ce ne soit pas le but réel, le modèle “flat” peut être rempli et exécuté comme tout autre fichier Rmarkdown.
Cependant, vous devez garder à l’esprit qu’il sera transformé en paquet R, ce qui nécessite une attention particulière.

  • Utilisez un chunk development au début de votre “flat template” pour déclarer tous les packages dont vous aurez besoin pour explorer votre code
```{r dev}
library(glue)
library(stringi)
```

Notez que ceci ne sera utilisé nulle part dans le paquet. Un chunk development n’est là que pour l’exploration du code, pendant le développement.

  • Rappelez-vous que dans la structure du paquet, les exemples et le code des tests seront exécutés indépendamment. Ainsi, les morceaux examples et tests doivent contenir tout le code nécessaire à leur exécution indépendante.
  • Le chunk development qui contient l’appel inflate() doit avoir le paramètre eval=FALSE pour éviter les effets secondaires si vous tricotez le fichier plat.

3. Comment déclarer les paquets avec library() pour la future vignette ?

Si vous utilisez un chunk classique, sans nom spécifique, il sera copié tel quel dans la vignette.

```{r}
library(glue)
library(stringi)
```

4. Comment inclure des exemples qui ne peuvent pas être exécutés ?

J’ai créé un chunk example mais je ne veux pas que l’exemple soit exécuté dans la fonction example et je ne veux pas qu’il soit exécuté dans la vignette.

  • Utilisez eval=FALSE dans les options du chunk, pour qu’il ne soit pas exécuté dans la vignette.
  • Utilisez la syntaxe #' \dontrun{}, avec #' devant pour que les exemples de la fonction exemple ne soient pas exécutés
```{r function-myfunction}
myfunction <- function(x) {x}
```

```{r example-myfunction, eval=FALSE}
# Will be run in example but not in vignette
myfunction(10)
# Will not be run in example
#' \dontrun{
myfunction(12)
#' }
#' \dontrun{
#' myfunction(12)
#' }
```

5. Documenter vos jeux de données internes dans un chunk function comme d’habitude

Pour documenter des jeux de données, pkgdoc, des fichiers R spéciaux, vous pouvez les écrire tels quels dans le chunk function.
Si {fusen} ne détecte pas le mot-clé function() ou R6Class() dans le code du chunk function, alors le chunk est copié tel quel dans un fichier “R/”.

```{r function-cars}
#' cars
#'
#' data in 'datasets'.
#'
#' @format A data frame with 50 rows and 2 variables:
#' \describe{
#'   \item{ speed }{  numeric }
#'   \item{ dist }{  numeric }
#' }
#' @source Ezekiel, M. (1930) Methods of Correlation Analysis. Wiley.
"cars"
```

6. Comment ignorer certains chunks ?

Tous les chunks nommés dev ou development ne seront pas utilisés dans le paquet.
Utilisez-les pour votre exploration que vous ne voulez pas garder à la fin du processus.
Cela n’affectera pas votre paquet.

```{r dev}
# Some code exploration
```

7. Comment créer une vignette avec un titre et une entrée d’index différents ?

Vous pouvez utiliser inflate(vignette_name = c("Super title" = "01-Super Slug")) pour créer une vignette dont le titre est différent de “Vignette Entry”.

inflate(vignette_name = c("Super title" = "01-Super Vignette Index Entry"))

8. Comment ne pas créer une vignette ?

  • Si je ne construis que des fonctions internes, je n’ai peut-être pas envie de gonfler le fichier plat comme une vignette.
  • Le fichier plat est la documentation du développeur et cela peut être suffisant.
inflate(vignette_name = NA)

9. Comment obtenir un modèle pré-rempli pour un nom de fonction spécifique ?

Si c’est la première fonction du modèle plat :

  • vous pouvez créer le modèle avec add_flat_template("minimal", flat_name = "my_function_name"). Dans ce cas, le modèle sera pré-rempli avec le nom de votre fonction : noms de chunk, appels de fonction.
  • Vous pouvez également utiliser l’extension RStudio “Add {fusen} flat template” pour créer un nouveau modèle dans votre répertoire “dev/”. Vous serez invité à saisir le type de modèle et le nom de la fonction.

Si c’est la deuxième fonction à l’intérieur d’un modèle existant :

  • Positionnez votre invite à l’endroit où vous voulez ajouter la nouvelle fonction et utilisez l’Addin RStudio : “Add {fusen} chunks”. Le nom de la fonction vous sera demandé.
  • L’Addin utilise add_fusen_chunks("ma_fonction_nom").

10. Comment pré-remplir plusieurs fonctions dans un template

Ceci peut être ajouté dans le fichier “dev_history.Rmd”, et remplacera un emplacement dans votre fichier plat rmd (HERE dans ce cas) avec des morceaux de fusen appropriés pour toutes vos futures fonctions.

  • Ajoutez une ligne avec HERE dans votre fichier flat
# Path of the flat file
path_flat_rmd <- here::here("dev/flat_minimal.Rmd")
# Name of future functions to add - example
fun_nms <- c(
  "get_contract_by_country_of",
  "get_contract_subsidies_of",
  "get_contract_effort_of",
  "get_contract_fees_of",
  "get_contract_target_countries_of",
  "get_contract_all_info_of"
)

# Create content
l_chunks <- purrr::map_chr(fun_nms, fusen:::build_fusen_chunks)
chunks <- paste(l_chunks, collapse = "")

# Add in the flat file
flat_rmd <- readLines(path_flat_rmd)
flat_rmd <- sub("^HERE$", chunks, flat_rmd)
writeLines(flat_rmd, path_flat_rmd)

11. Comment gonfler plusieurs fichiers plats ?

  • Ajoutez une entrée dans votre fichier principal “dev_history.Rmd”.
fusen::inflate("dev/flat_file1.Rmd")
fusen::inflate("dev/flat_file2.Rmd")
fusen::inflate("dev/flat_file3.Rmd")

Si le fichier principal “dev_history.Rmd” n’existe pas, vous pouvez le créer avec add_flat_template(“dev_history”).

12. Comment stocker plusieurs fonctions dans un seul fichier R ?

Il y a plusieurs façons de le faire. Choisissez l’une d’entre elles : utiliser la structure de titre de section, utiliser les balises roxygen ou utiliser le paramètre chunk.

Toutes les fonctions sous une même section de titre

Utilisez deux fois l’ensemble de trois morceaux (fun, example, test) sous la même section de titre du Rmd.

# One title for both groups of chunk

The code and tests for the first function
```{r function-fun1}
```
```{r example-fun1}
```
```{r test-fun1}
```

The code and tests for the second function
```{r function-fun2}
```
```{r example-fun2}
```
```{r test-fun2}
```

Utiliser le même @rdname dans le “roxygen” de la fonction

# Title 1 for function 1

```{r function-fun_rdname1}
#' My fun_rdname1
#'
#' @param x Vector of Numeric values
#' @inheritParams stats::median
#'
#' @rdname same_rdname
#' @return
#' Median of vector x
#' @export
#'
#' @examples
#' my_fun_rdname1(2:20)
my_fun_rdname1 <- function(x, na.rm = TRUE) {
  if (!is.numeric(x)) {stop("x should be numeric")}
  stats::median(x, na.rm = na.rm)
}
```

# Title  2 for function 2

```{r function-fun_rdname2}
#' My fun_rdname2
#'
#' @param x Vector of Numeric values
#' @inheritParams stats::median
#'
#' @rdname same_rdname
#' @return
#' Median of vector x
#' @export
#'
#' @examples
#' my_fun_rdname2(2:20)
my_fun_rdname2 <- function(x, na.rm = TRUE) {
  if (!is.numeric(x)) {stop("x should be numeric")}
  stats::median(x, na.rm = na.rm)
}
```

Utiliser le même @filename dans le “roxygen” de la fonction

@filename n’est reconnu que par {fusen} comme un tag roxygen approprié pour fusionner plusieurs fonctions dans les mêmes fichiers “R/” et “tests/”.
Cette ligne de code est supprimée dans les fichiers “R/” résultants pour éviter toute interférence avec Roxygenize.

# Title 1 for function 1

```{r function-fun_filename1}
#' My fun_filename1
#'
#' @param x Vector of Numeric values
#' @inheritParams stats::median
#'
#' @filename same_filename
#' @return
#' Median of vector x
#' @export
#'
#' @examples
#' my_fun_filename1(2:20)
my_fun_filename1 <- function(x, na.rm = TRUE) {
  if (!is.numeric(x)) {stop("x should be numeric")}
  stats::median(x, na.rm = na.rm)
}
```

# Title  2 for function 2

```{r function-fun_filename2}
#' My fun_filename2
#'
#' @param x Vector of Numeric values
#' @inheritParams stats::median
#'
#' @filename same_filename
#' @return
#' Median of vector x
#' @export
#'
#' @examples
#' my_fun_filename2(2:20)
my_fun_filename2 <- function(x, na.rm = TRUE) {
  if (!is.numeric(x)) {stop("x should be numeric")}
  stats::median(x, na.rm = na.rm)
}
```

Utiliser le paramètre du chunk filename = "le_fichier_commun".

Ajoutez-le uniquement dans le chunk function.

# Title 1 for function 1

```{r function-fun_chunk1, filename = "fun_chunk1"}
#' The code of your function 1
```
```{r example-fun_chunk1}
```
```{r test-fun_chunk1}
```

# Title 2 for function 2

```{r function-fun_chunk2, filename = "fun_chunk1"}
#' The code of your function 2
```
```{r example-fun_chunk2}
```
```{r test-fun_chunk2}
```

13. Comment lire le jeu de données que je place habituellement dans “tests/testthat/” pour mes tests unitaires ?

Vous devrez écrire deux façons de lire les données :

  • Une à utiliser à la demande dans le fichier plat, qui doit être commentée.
  • Une autre à utiliser dans le futur fichier de test
# The code that you will run manually in the flat file if needed during development

# > This needs to be commented
# my_file <- read.csv("tests/testthat/my_file.csv")

# The code that will be used in the inflated test file
# This needs to be uncommented
my_file <- read.csv("my_file.csv")

14. Et vous, quels sont vos trucs et astuces ?

Quels sont vos trucs et astuces avec {fusen} ?
Partagez-les avec nous sur Twitter avec @thinkR_fr


À propos de l'auteur

Sébastien Rochette

Sébastien Rochette

Expert du langage R – Défenseur du 'Rmd first', joueur de cartographies


Comments


Also read

{golem} 0.3.2

2022-03-11 / Colin Fay