Un ‘package’ ou une ‘librairie’ rassemble du code, des données, de la documentation et des tests ensemble et est facile à partager.
Pour le développeur :
Pour l’utilisateur :


Github et Git
Voir cours n°2
Installer un package :
install.packages en R base, depuis le CRAN ou des sourcesremotes : librairie permettant l’installation depuis le CRAN et différents dépôt de code programmaticalement, tels que github, gitlab, bitbucket, ainsi que Bioconductor.pak : librairie pour l’installation interactive de packagestidyverse du développement de librairie.Utilisation interactive
usethis est un outil d’aide au développement : vous l’utiliserez toujours (ou presque) interactivement, en appelant les instructions dans la console R, et non par le biais de scripts !
Contient le code R du package.
build time ;run time.Pas de sous-dossier
Utilisez des préfixes “smthing-*.R” pour organiser les fichiers par thème
Contient le code R du package.
build time ;run time.Points de vigilance
source, library dans le code d’un packagepar, options, setwd …Contenu des fichiers
Rester cohérent et clair sur le contenu des fichiers - ni trop, ni pas assez. Dépend du contexte.
usethis
Voir usethis::use_data()
data/ au format .rda/.RDataR/sysdata.rdainst/extdata/Préserver la reproducibilité des datasets
Voir usethis::use_data_raw()
roxygen2 pour les générer automatiquement !roxygen2 est bien intégré au workflow devtoolsinst/ : pour les fichiers additionnels à inclure dans la librairie ;src/: pour stocker des fichiers sources et “header” C/C++/… et utiliser du code compilé dans un package R ;demo/, exec/, po/, tools/, …Plus d’informations
Voir le chapitre dédié dans R packages
Package: mynewpackage
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R:
person("First", "Last", , "first.last@example.com", role = c("aut", "cre"),
comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
Suggests:
testthat (>= 3.0.0)
Config/testthat/edition: 3
Title : Décrire en une phrase la librairieDescription : Décrire de manière plus détaillée l’intérêt et les fonctionnalités de la librairieAuthors@R : Les auteurs. Voir ?person().Version : Version du package. Important de le maintenir à jour, voir chapitre dédié dans R avancé.License : Quelle licence et quels droits d’utilisation ?Suggests, Imports, and others : Gestion des dépendances avec des librairies tierces.Plusieurs critères et questions à se poser :
Imports : Les packages listés ici doivent être présents et installés pour que votre librairie fonctionne.Suggests: Votre package peut utiliser ces dépendances, mais ne sont pas nécessaires à son fonctionnement. Par exemple, ces packages peuvent être utilisés dans les vignettes ou les tests.DESCRIPTION
Les dépendances déclarées dans le fichier DESCRIPTION aident R à valider la présence des packages nécessaires et à les installer lors de l’installation de votre package.
Quelle fonction here() est disponible dans l’environnement global ?
Que se passe-t-il lorsque l’on déclare une nouvelle fonction var ?
Cela est possible grâce au namespace du package stats où la fonction var du package stats est déjà référencée.
Exemple tiré du package remotes
# Generated by roxygen2: do not edit by hand
S3method(format,bioc_git2r_remote)
S3method(format,bioc_xgit_remote)
...
export(add_metadata)
export(available_packages)
...
importFrom(stats,update)
importFrom(tools,file_ext)
roxygen2
Une bonne pratique aujourd’hui est d’utiliser roxygen2 pour générer automatiquement le fichier NAMESPACE
importFrom : importe un objet (fonction) d’une dépendanceimport : importe tous les objets exportésS3method : pour exporter une méthode S3export : pour exporter une fonction (rendre une fonction publique)Autres instructions
Plus rares : useDynLib(), exportPattern(), exportClasses(), exportMethods(), importClassesFrom(), importMethodsFrom()
Création d’un squelette de package :

RStudio initialise un nouveau projet.
Nouveau projet
En utilisant l’interface graphique, il est possible de créer des projets avec des templates, dont des packages. Ceci utilise in fine usethis.
roxygen2usethis
usethis::use_r pour créer un fichier .R dans le répertoire R/, ou naviguer dans celui-ci dans RStudio.
Resultats ?
Résultats :
#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean",
#' "min", "max".
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean",
#' "min", "max".
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean",
#' "min", "max".
#'
#' @export
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean",
#' "min", "max".
#'
#' @export
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}#' A Function to Compute Group Statistics
#'
#' @description This function is designed for example only and is not really usefull..
#'
#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean", "min", "max".
#' @return A named vector statistics, of size `length(unique(data[[col]]))`
#'
#' @export
#' @examples
#' compute_stats_by_levels(mtcars, "mpg", "cyl", "mean")
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}#' A Function to Compute Group Statistics
#'
#' @description This function is designed for example only and is not really usefull..
#'
#' @param data A data.frame
#' @param col A string, the column name for which we compute the stats
#' @param by A string, the column name by which we group
#' @param stats A string, the name of the function. Must be one of "mean", "min", "max".
#' @return A named vector statistics, of size `length(unique(data[[col]]))`
#'
#' @export
#' @examples
#' compute_stats_by_levels(mtcars, "mpg", "cyl", "mean")
compute_stats_by_levels <- function(
data, col, by, stats
) {
if (stats %in% c("mean", "max", "min")) {
res <- tapply(data[[col]], data[[by]], stats)
} else {
stop("wrong stats")
}
return(res)
}@title, @description, @detail : pour présenter et détailler sa fonction. Peuvent être implicites.@param : pour documenter les paramètres de la fonction@return : quel est l’output de la fonction@examples : suite d’examples@export : pour exposer la fonction dans le NAMESPACE@importFrom : quand la fonction importe une fonction depuis une librairie tierce@noRd : pour documenter la fonction mais ne pas exposer la documentation publiquement@describe, @rdname, @inheritParams, @inheritSection, @inheritListe des balises
https://roxygen2.r-lib.org/articles/rd.html pour le processus de base https://roxygen2.r-lib.org/reference/tags-rd.html pour la liste exhaustive
devtoolsEn développement logiciel (donc quand vous développez une librairie / des fonctions en R) :
Framework dominant pour l’écriture de tests en R.
# from dplyr test suite
# https://github.com/tidyverse/dplyr/blob/2af5c86112c697a8abf114eb5dc323e5116777bc/tests/testthat/test-bind-cols.R#L33
test_that("bind_cols() handles all-NULL values (#2303)", {
expect_identical(bind_cols(list(a = NULL, b = NULL)), tibble())
expect_identical(bind_cols(NULL), tibble())
})Dans R/
Dans tests/testthat/test-myfunction.R
expect_equal() expect_identical()expect_type() expect_s3_class()expect_length()expect_true() expect_false()expect_error() expect_warning() expect_message() expect_condition()Liste exhaustive ici
usethis::use_testthat() et ?usethis::use_test())?devtools::load_all()devtools::document() permet de générer et mettre à jour automatiquement les différents documents (.Rd, NAMESPACE).devtools::test() qui exécutera la suite de test de la librairie en développement.devtools::check() si vous voulez tester la compatibilité avec le CRAN.pkgdown et des vignettes détaillées.
Comment testez-vous une fonction ?