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
Plus sur ce sujet lors du cours 6
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 packagesContient 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/.RData
R/sysdata.rda
inst/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 devtools
inst/
: 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
.
roxygen2
usethis
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".
#'
#' @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)
}
@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
, @inherit
Liste 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
devtools
En 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 ?