{"id":511,"date":"2016-03-29T19:09:51","date_gmt":"2016-03-29T17:09:51","guid":{"rendered":"http:\/\/perso.ens-lyon.fr\/lise.vaudor\/?p=511"},"modified":"2017-05-23T15:44:09","modified_gmt":"2017-05-23T13:44:09","slug":"creation-dun-package-r","status":"publish","type":"post","link":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/creation-dun-package-r\/","title":{"rendered":"Cr\u00e9ation d&rsquo;un package R"},"content":{"rendered":"<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/RMarkdown\/headband.png\" alt=\"plot of chunk\nheadband\" \/><\/p>\n<p>Ce document est un <strong>document de travail<\/strong> listant toutes les \u00e9tapes n\u00e9cessaires pour cr\u00e9er un package R. Je l&rsquo;ai construit pour pouvoir m&rsquo;y r\u00e9f\u00e9rer moi-m\u00eame la prochaine fois que je souhaiterai cr\u00e9er un package. Il s&rsquo;adresse donc \u00e0 un public certes exigeant (mon moi du futur!) mais avec des besoins bien sp\u00e9cifiques. Il ne se veut donc pas exhaustif, et les termes que j&rsquo;y emploie peuvent \u00eatre, si ce n&rsquo;est approximatifs, du moins imag\u00e9s. Cependant je le mets \u00e0 disposition de quiconque le souhaite car il a le m\u00e9rite de balayer l&rsquo;ensemble d&rsquo;un processus qui peut \u00eatre a priori assez intimidant!<\/p>\n<h2>Cr\u00e9er un package R, pour quoi faire?<\/h2>\n<ul>\n<li>\n<p><strong>pour soi-m\u00eame<\/strong>, parce que si l&rsquo;on en fait pas des packages on a tendance \u00e0 perdre les b\u00e9n\u00e9fices des fonctions que l&rsquo;on s&rsquo;\u00e9crit pour soi-m\u00eame: on oublie qu&rsquo;on les a faites\/on oublie o\u00f9 on les a mises\/ on oublie comment on s&rsquo;en sert etc.<\/p>\n<\/li>\n<li>\n<p><strong>pour les autres<\/strong>, parce que partager un package et la documentation associ\u00e9e, c&rsquo;est plus facile que de partager des scripts \u00e9pars, surtout si l&rsquo;on s&rsquo;adresse \u00e0 des utilisateurs de R qui ne sont pas eux-m\u00eames d\u00e9veloppeurs.<\/p>\n<\/li>\n<\/ul>\n<p>Voici deux liens o\u00f9 je suis all\u00e9e chercher des renseignements pour apprendre \u00e0 cr\u00e9er un package:<\/p>\n<ul>\n<li>\n<p>Pour d\u00e9buter: <a href=\"http:\/\/hilaryparker.com\/2014\/04\/29\/writing-an-r-package-from-scratch\/\">Writing an R package from scratch, Hilary Parker<\/a><\/p>\n<\/li>\n<li>\n<p>Plus long et d\u00e9taill\u00e9: <a href=\"http:\/\/kbroman.org\/pkg_primer\/\">R package primer, Karl Broman<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>Cr\u00e9ation et organisation d&rsquo;un d\u00e9p\u00f4t local pour le package<\/h2>\n<h3>Cr\u00e9ation du d\u00e9p\u00f4t local et de son squelette<\/h3>\n<p>Par exemple on peut cr\u00e9er un dossier <code>monpackage<\/code> sous l&#8217;emplacement par d\u00e9faut pour d\u00e9p\u00f4t sur GitHub:<\/p>\n<p><code>C:\\Users\\lvaudor\\Documents\\GitHub\\monpackage<\/code><\/p>\n<p>Pour l&rsquo;instant le dossier est vide. Pour cr\u00e9er l&rsquo;architecture d&rsquo;un package R (sous sa forme \u00ab\u00a0source\u00a0\u00bb)<\/p>\n<p>On aura besoin du package <strong>devtools<\/strong> (cr\u00e9ation et installation du package) et <strong>roxygen2<\/strong> (cr\u00e9ation de la documentation):<\/p>\n<pre><code>if(!require(devtools)){install.packages(\"devtools\")}\nif(!require(roxygen2)){devtools::install_github(\"klutometis\/roxygen\")}\n<\/code><\/pre>\n<p>La commande suivante cr\u00e9e<\/p>\n<ul>\n<li>\n<p>un fichier DESCRIPTION,<\/p>\n<\/li>\n<li>\n<p>un fichier NAMESPACE,<\/p>\n<\/li>\n<li>\n<p>un dossier R (qui contiendra les scripts contenant eux-m\u00eame les fonctions)<\/p>\n<\/li>\n<li>\n<p>les fichiers .gitignore, .Rbuildignore, et un projet Rstudio<\/p>\n<\/li>\n<\/ul>\n<p><!-- --><\/p>\n<pre><code>devtools::create(\"monpackage\")\n<\/code><\/pre>\n<h3>Modification du fichier DESCRIPTION<\/h3>\n<p>Le fichier <strong>DESCRIPTION<\/strong> doit \u00eatre modifi\u00e9. Il faut notamment pr\u00e9ciser:<\/p>\n<ul>\n<li>\n<p>le <strong>titre et la description<\/strong> du package (ce qu&rsquo;il fait)<\/p>\n<\/li>\n<li>\n<p>l&rsquo;<strong>auteur<\/strong> et les informations de contact<\/p>\n<\/li>\n<li>\n<p>les <strong>d\u00e9pendances<\/strong>: (\u00ab\u00a0Depends: \u00ab\u00a0) c&rsquo;est ici qu&rsquo;il faut pr\u00e9ciser quels autres packages doivent \u00eatre charg\u00e9s<\/p>\n<\/li>\n<\/ul>\n<h3>Ajout du dossier <code>inst<\/code><\/h3>\n<p>On peut si besoin cr\u00e9er ce dossier et y placer les dossiers de scripts, d&rsquo;images, ou tout autre fichier n\u00e9cessaire \u00e0 l&rsquo;execution des fonctions du package.<\/p>\n<p>Lors de l&rsquo;installation du package (transformation du dossier source en dossier \u00ab\u00a0librairie\u00a0\u00bb) les dossiers plac\u00e9s dans \u00ab\u00a0inst\u00a0\u00bb se retrouveront \u00e0 la racine du dossier \u00ab\u00a0librairie\u00a0\u00bb.<\/p>\n<p>Pour ma part j&rsquo;ai cr\u00e9\u00e9 une fonction <strong>findmypath<\/strong> qui permet de retrouver (une fois le package install\u00e9) facilement le chemin de tout fichier \u00ab\u00a0file\u00a0\u00bb plac\u00e9 initialement dans <code>inst\/dir\/<\/code>:<\/p>\n<pre><code>findmypath=function(dir,file){\n  path=system.file(dir,file,package=\"monpackage\")\n  return(path)\n}\n<\/code><\/pre>\n<p>Si j&rsquo;utilise les fonctions du package <em>sans l&rsquo;avoir install\u00e9 et charg\u00e9 au pr\u00e9alable<\/em> je dois alors utiliser une autre fonction findmypath.<\/p>\n<h3>Organisation des scripts<\/h3>\n<p>Il faut ensuite d\u00e9poser l&rsquo;ensemble des scripts contenant les <strong>fonctions du package<\/strong> sous le dossier <strong>R<\/strong>.<\/p>\n<p>On peut organiser les fonctions soit en les regroupant dans un script soit en faisant une fonction = un script.<\/p>\n<p>Pour l&rsquo;exemple on peut imaginer une fonction \u00ab\u00a0mafonction\u00a0\u00bb sauvegard\u00e9e dans un script <code>mafonction.R<\/code>:<\/p>\n<pre><code>mafonction &lt;- function(nom=\"toi\"){\n  print(paste0(\"Salut, \", nom, \"!\"))\n}\n<\/code><\/pre>\n<h2>Documentation<\/h2>\n<h3>Fichiers d&rsquo;aide associ\u00e9s aux fonctions<\/h3>\n<p>Il y a plusieurs mani\u00e8res de proc\u00e9der pour g\u00e9n\u00e9rer la documentation. Pour ma part je pr\u00e9f\u00e8re documenter les fonctions sous forme d&rsquo;ent\u00eates puis <strong>g\u00e9n\u00e9rer la documentation<\/strong> \u00e0 l&rsquo;aide des packages devtools+roxygen2.<\/p>\n<p>Reprenons l&rsquo;exemple de la fonction \u00ab\u00a0mafonction\u00a0\u00bb. Voici le genre d&rsquo;ent\u00eate qui permet de g\u00e9n\u00e9rer la documentation associ\u00e9e \u00e0 cette fonction:<\/p>\n<pre><code>#' Une fonction pour l'exemple\n#'\n#' Cette fonction ne sert a rien d'autre qu'a servir d'exemple.\n#' @param nom (par defaut, \"toi\")\n#' @keywords salutation\n#' @export\n#' @examples\n#' mafonction(\"mec\")\nmafonction &lt;- function(nom=\"toi\"){\n  print(paste0(\"Salut, \", nom, \"!\"))\n}\n<\/code><\/pre>\n<p>La commande suivante <strong>g\u00e9n\u00e8re les fichiers d&rsquo;aide \u00e0 partir des ent\u00eates<\/strong>:<\/p>\n<pre><code>devtools::document(\"monpackage\")\n<\/code><\/pre>\n<p>On peut r\u00e9executer cette fonction (puis r\u00e9installer le package) pour mettre \u00e0 jour la documentation si l&rsquo;on modifie les ent\u00eates par la suite.<\/p>\n<h3>Cr\u00e9ation d&rsquo;une vignette<\/h3>\n<p>Une <strong>vignette<\/strong> correspond \u00e0 la <strong>documentation \u00ab\u00a0informelle\u00a0\u00bb<\/strong> d&rsquo;un package (contrairement aux fichiers d&rsquo;aide li\u00e9s aux fonctions qui sont tr\u00e8s \u00ab\u00a0contraints\u00a0\u00bb d&rsquo;un point de vue formel). On peut g\u00e9n\u00e9rer la vignette de la mani\u00e8re suivante:<\/p>\n<pre><code>devtools::use_vignette(\"monpackage_vignette\",pkg=\"monpackage\")\n<\/code><\/pre>\n<p>On peut alors aller modifier le fichier <code>vignettes\/monpackage_vignette.Rmd<\/code> et y inclure les explications, la biblio, et les exemples d&rsquo;application du package.<\/p>\n<h2>Installation et utilisation du package en local:<\/h2>\n<p>Voici comment installer le package depuis le d\u00e9p\u00f4t local vers une librairie.<\/p>\n<pre><code>devtools::install(\"monpackage\")\n<\/code><\/pre>\n<p>Cette installation devrait cr\u00e9er un dossier <code>monpackage<\/code> dans vos librairies R. Chez moi, elle correspond \u00e0 la cr\u00e9ation d&rsquo;un dossier au chemin suivant: <code>C:\\Users\\lvaudor\\Documents\\R\\win-library\\3.2\\monpackage<\/code><\/p>\n<p>L&rsquo;architecture et les fichiers contenus dans ce dossier sont <em>diff\u00e9rents<\/em> de ceux du d\u00e9p\u00f4t local (ayant pour chemin, chez moi, <code>C:\\Users\\lvaudor\\Documents\\GitHub\\monpackage<\/code>)<\/p>\n<p>On peut d\u00e8s lors charger le package et utiliser ses fonctions:<\/p>\n<pre><code>require(monpackage)\nmafonction()\n<\/code><\/pre>\n<p>On a document\u00e9 mafonction, on peut donc afficher l&rsquo;aide associ\u00e9e:<\/p>\n<pre><code>help(mafonction)\n<\/code><\/pre>\n<h2>Dep\u00f4t du package sur GitHub<\/h2>\n<h3>Pour quoi faire?<\/h3>\n<ul>\n<li>\n<p>pour <strong>partager<\/strong> ses scripts en ligne<\/p>\n<\/li>\n<li>\n<p>pour <strong>g\u00e9rer les versions<\/strong> du package (le syst\u00e8me Git permet de garder trace de l&rsquo;historique du package: quand et pourquoi tel ou tel script a \u00e9t\u00e9 modifi\u00e9, et de quelle mani\u00e8re).<\/p>\n<\/li>\n<\/ul>\n<h3>Pr\u00e9alable<\/h3>\n<ul>\n<li>\n<p><strong>Cr\u00e9ation d&rsquo;un compte sur GitHub<\/strong> (le mien est visible ici: <a href=\"https:\/\/github.com\/lvaudor\">https:\/\/github.com\/lvaudor<\/a>)<\/p>\n<\/li>\n<li>\n<p><strong>Installation de Git<\/strong>: <a href=\"https:\/\/git-scm.com\/downloads\">https:\/\/git-scm.com\/downloads<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>Cr\u00e9ation d&rsquo;un d\u00e9p\u00f4t distant (\u00ab\u00a0repo\u00a0\u00bb) sur GitHub<\/h3>\n<p>On cr\u00e9e un <strong>repo<\/strong> (ou repository) sur GitHub qui sera un clone du d\u00e9p\u00f4t local.<\/p>\n<p>Il est utile d&rsquo;associer un fichier <strong><code>README.Rd<\/code><\/strong> \u00e0 ce repo de mani\u00e8re \u00e0 renseigner l&rsquo;utilisateur sur son contenu. Personnellement j&rsquo;y indique en quelques lignes la fonction du package et de quelle mani\u00e8re l&rsquo;utilisateur peut l&rsquo;installer sur sa machine.<\/p>\n<h3>Commandes Git<\/h3>\n<p>On peut alors envoyer les scripts depuis le d\u00e9p\u00f4t local vers le repo (d\u00e9p\u00f4t distant).<\/p>\n<p>On peut le faire soit depuis l&rsquo;application <strong>GitHub Desktop<\/strong>, soit par ligne de commande avec <strong>Git Shell<\/strong>. J&rsquo;utilise pour ma part Git Shell car je trouve que c&rsquo;est la m\u00e9thode la mieux document\u00e9e en ligne (et je d\u00e9bute en Git!).<\/p>\n<p>Je me place dans le dossier qui m&rsquo;int\u00e9resse (dossier local):<\/p>\n<pre><code>cd monpackage\n<\/code><\/pre>\n<p>Je <strong>cr\u00e9e le squelette git<\/strong> (un nouveau sous-dossier .git appara\u00eet dans le dossier):<\/p>\n<pre><code>git init\n<\/code><\/pre>\n<p>J&rsquo;ajoute l&rsquo;ensemble des fichiers dans le r\u00e9pertoire local \u00e0 la liste des fichiers \u00ab\u00a0\u00e0 suivre\u00a0\u00bb par Git:<\/p>\n<pre><code>git add .\n<\/code><\/pre>\n<p>Je <strong>consigne les changements<\/strong> en effectuant un \u00ab\u00a0commit\u00a0\u00bb:<\/p>\n<pre><code>git commit -m \"Premier commit\"\n<\/code><\/pre>\n<p>Il est n\u00e9cessaire d&rsquo;associer un court message (ici \u00ab\u00a0Premier commit\u00a0\u00bb) \u00e0 chaque fois pour que la commande soit effective.<\/p>\n<p>Je vais ensuite <strong>lier mon d\u00e9p\u00f4t local \u00e0 mon d\u00e9p\u00f4t distant<\/strong> (\u00ab\u00a0origin\u00a0\u00bb correspond \u00e0 un nom court auquel il me sera facile de faire r\u00e9f\u00e9rence par la suite):<\/p>\n<pre><code>git remote add origin https:\/\/github.com\/lvaudor\/monpackage\n<\/code><\/pre>\n<p>Je peux alors <strong>pousser<\/strong> mes fichiers depuis le d\u00e9p\u00f4t local vers le d\u00e9p\u00f4t distant (ici vers la branche <em>master<\/em>):<\/p>\n<pre><code>git push -u origin master\n<\/code><\/pre>\n<p><strong>Remarque:<\/strong><\/p>\n<p>Par la suite je pourrai utiliser davantage de fonctionnalit\u00e9s de Git, comme la possibilit\u00e9 de cr\u00e9er des branches.<\/p>\n<h3>Modifications ult\u00e9rieures<\/h3>\n<p>Si je veux mettre \u00e0 jour le d\u00e9p\u00f4t distant par la suite je n&rsquo;aurai pas besoin de r\u00e9effectuer toutes les t\u00e2ches list\u00e9es ci-dessus. Les lignes de commandes suivantes sont suffisantes:<\/p>\n<pre><code>cd monpackage\ngit add .\ngit commit -m \"nouveau commit\"\ngit push -u origin master\n<\/code><\/pre>\n<h3>Installation du package depuis GitHub (dev version)<\/h3>\n<p>D\u00e8s lors que les fichiers relatifs \u00e0 mon package ont \u00e9t\u00e9 \u00ab\u00a0pouss\u00e9s\u00a0\u00bb de ma machine vers mon repo GitHub, n&rsquo;importe qui peut installer le package depuis ce repo (cependant cela n\u00e9cessite d&rsquo;utiliser une fonction du package devtools):<\/p>\n<pre><code>if(!require(devtools)){install.packages(\"devtools\")}\ndevtools::install_github(\"lvaudor\/graphiT\")\n<\/code><\/pre>\n<p>Attention lorsque l&rsquo;on travaille sur une version qui n&rsquo;est pas la toute derni\u00e8re on peut avoir des difficult\u00e9s \u00e0 installer le package <code>devtools<\/code>.<\/p>\n<h2>D\u00e9p\u00f4t du package sous CRAN<\/h2>\n<p>En l&rsquo;\u00e9tat actuel des choses mes packages peuvent \u00eatre install\u00e9s depuis GitHub (gr\u00e2ce \u00e0 la fonction <code>install_github<\/code> du package devtools) et non par la commande habituelle <code>install_packages<\/code> (la plus simple pour installer un package).<\/p>\n<p>Le d\u00e9p\u00f4t d&rsquo;un package sur CRAN a pour int\u00e9r\u00eat de permettre l&rsquo;installation des packages par cette commande, et de garantir que le package est test\u00e9 sur divers syst\u00e8mes d&rsquo;exploitation.<\/p>\n<p>Le d\u00e9p\u00f4t sur CRAN est quelque chose que je n&rsquo;ai pour le moment pas encore test\u00e9&#8230; Document \u00e0 compl\u00e9ter donc&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ce document est un document de travail listant toutes les \u00e9tapes n\u00e9cessaires pour cr\u00e9er un package R. Je l&rsquo;ai construit pour pouvoir m&rsquo;y r\u00e9f\u00e9rer moi-m\u00eame la prochaine fois que je souhaiterai cr\u00e9er un package. Il s&rsquo;adresse donc \u00e0 un public certes exigeant (mon moi du futur!) mais avec des besoins bien sp\u00e9cifiques. Il ne se veut donc pas exhaustif, et les termes que j&rsquo;y emploie peuvent \u00eatre, si ce n&rsquo;est.. <a href=\"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/creation-dun-package-r\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-511","post","type-post","status-publish","format-standard","hentry","category-tous-les-posts"],"_links":{"self":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/comments?post=511"}],"version-history":[{"count":7,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/511\/revisions"}],"predecessor-version":[{"id":514,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/511\/revisions\/514"}],"wp:attachment":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/media?parent=511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/categories?post=511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/tags?post=511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}