class: left, center, middle, inverse, title-slide # Creating packages ## with devtools and usethis ###
Lluís Revilla Sancho
Slides:
### IDIBAPS, CIBEREHD ### 2021-09-04
(updated: 2021-12-27)
--- # About .left[**myself** I'm [Lluís Revilla Sancho](https://llrs.dev), a bioinformatician working on a research center of a hospital. Three packages on repositories: [BioCor](https://bioconductor.org/packages/BioCor/), [BaseSet](https://cran.r-project.org/package=BaseSet) and [experDesign](https://cran.r-project.org/package=experDesign). I have reviewed some packages on [rOpenSci](https://ropensci.org) and informally at [Bioconductor](https://bioconductor.org). ] .center[**you** - ... know how to use R and write functions. - ... are using [RStudio IDE](https://www.rstudio.com/products/rstudio/download/). - ... have not created a package. - ... are using a computer with the latest [devtools](https://cran.r-project.org/package=devtools) installed. ] If you want to be sure run this code: ```r if (!require("devtools", character.only = TRUE, quietly = TRUE)) { install.packages("devtools") } if (!require("covr", character.only = TRUE, quietly = TRUE)) { install.packages("covr") } ``` ??? [devtools](https://cran.r-project.org/package=devtools) is a package to help develop packages. Currently many actions are done via [usethis](https://cran.r-project.org/package=usethis). If you see something like `usethis::function` it means we call the `function` from usethis package. --- name:resources # Resources - [R extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html "Offical complete instructions"): Official documentation, everything is answered here - [R packages](https://r-pkgs.org/ "R pakages"): A book more digestible and using other packages and tools to create packages. - [Package primer](https://kbroman.org/pkg_primer/ "R package primer a minimal tutorial"): Website explaining different aspects of creating a package. - [Creating R packages from scratch](https://hilaryparker.com/2014/04/29/writing-an-r-package-from-scratch/ "Creating a cats package"): Very easy to follow blog post. - [Updated version by Tomas Westlake](https://r-mageddon.netlify.app/post/writing-an-r-package-from-scratch/ "Creating a cats package with usethis"): Similar to the post above but updated with more modern tools. - [rOpenSci](https://devguide.ropensci.org/): A book about writing packages and maintaining them on good shape. - [Video](https://www.youtube.com/watch?v=IlWMkz769B4) with a similar workshop showing live the code used. Many resources! You can also find help online (always check the etiquette) - Asking your local community - [Asking on Twitter #rstats](https://www.t4rstats.com/) - [Asking on Stack Overflow](https://stackoverflow.com/questions/5963269) - [Asking on Rstudio forum](https://community.rstudio.com/) ??? Resources used to create this workshop [Maëlle post](https://masalmon.eu/2017/12/11/goodrpackages/): how to write good packages is also recommended. --- ## Example .left-column[ <img src="images/tidyverse_dtplyr.png" title="Tree view of the dtplyr package repository on 2021/08/06." alt="Tree view of the dtplyr package repository on 2021/08/06." width="100%" /> ] .right-column[ - `.github` folder: Files specific to GitHub (this isn't necessary/[Advanced content](#advanced)) - A `R` folder with [*.R files](#r-files): your code. - A `man` folder with [*.rd files](#rd-files): your documentation. - A `tests` folder: [Check the code](#tests) of the package. - A [`vignette` folder](#vignettes): Long documentation; not just examples. - A `.Rbuildignore`: A file describing what to omit when building the package. - A [`DESCRIPTION` file](#description): Summary and description of the package. - A [`LICENSE` file](#licenses): The conditions under the package is released. - A [`NAMESPACE` file](#namespace): What this package shares and needs. - A [`NEWS` file](#news): What has changed since last release. - A [`README`](#readme): How to install and why this packages is needed and some basic examples. ] --- ## Template .pull-left[ ```r create_package("dogs") ``` It will create a dogs project within the directory and will open a new Rstudio window. ] .pull-right[ - Creates DESCRIPTION file - Creates R files - Creates documentation files - Creates NAMESPACE file ] -- .pull-left[ Suggestions for packages: - fruits - cats - food - sports - ... ] .pull-right[ ![:scale 70% "Ghana market with cattle"](https://live.staticflickr.com/4041/4584360223_5ab315bfa4_b.jpg) ]
01
:
30
--- name: description ## DESCRIPTION .pull-left[ ``` Package: BaseSet Title: Short Descriptiono in Title Case Version: 0.0.9000 Authors@R: c(person(given = "Lluís", family = "Revilla Sancho", role = c("aut", "cre", "cph"), email = "lluis.revilla@gmail.com"), ...) Description: A long description of the pacakge License: MIT + file LICENSE Depends: R (>= 4.0.0) Imports: dplyr (>= 1.0.0), methods Suggests: covr, knitr, rmarkdown, spelling, testthat (>= 2.1.0) VignetteBuilder: knitr Encoding: UTF-8 Language: en-US Roxygen: list(markdown = TRUE) RoxygenNote: 7.1.1 ``` ] ??? Name of the package, description of the package, maintainer, relationships with other packages... Language does not need to be on English, it can be in other languages -- .pull-right[ Modify the DESCRIPTION of your package. - Add a good title. - Add a Description. - Add yourself as an author.
03
:
00
] --- name:r-files ## Add R files On the new package R console run: ```r usethis::use_r("dog_functions") ``` It will create a `dog_functions.R` file inside the R folder (and it will open it). .center[ ![:scale 50% "GIF of hadly wickham saying just typing R code"](https://c.tenor.com/pnK2MIoEAccAAAAC/hadley-wickham.gif) ] --- ## Add R files 1. Only valid R code: functions, objects, environments that don't depend on previous code executed. 2. If a function uses a function of an other package use `package::function` 3. Add that package to the appropriate site on [Description](#description) 4. add a `#' @importFrom package function` (See next slide) ```r meow <- function() { message("meow") } ```
03
:
00
--- name:namespace ## NAMESPACE Import code of other packages and export code of your package: ```r import(dplyr) importFrom(methods, is) export(meow) ``` -- If using roxygen2 you can use: ```r #' @import dplyr #' @importFrom methods is is_meow <- function(x){ methods(x, "meow") } #' @export # To make it available to others meow <- function() { message("meow") } ``` Which will be written to the NAMESPACE file when [updating the documentation](#rd-files) ??? Important file! --- name:readme ## Documentation ### README First page people might read if on Github or on a computer. ```r usethis::use_readme_rmd() # build_readme() ``` Example README: <img src="images/data.table_README.png" width="2531" /> -- Modify README:
03
:
00
--- name:rd-files ## Documentation ### Function documentation .pull-left[ Using [roxygen2](https://cran.r-project.org/package=roxygen2), example: ```r #' Title #' #' Description #' @param x #' #' @return Values returned #' @export #' #' @examples #' a("hi") a <- function(x) { print(x) } ``` ] .pull-right[ Convert this specials comments into *.Rd files with: ```r document() ``` ] ??? In Rstudio you can insert the skeleton with <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>R</kbd> . In Rstudio you can convert the special comments into documentation with <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> . -- .center[Write your own documentation]
03
:
00
--- name: vignettes ## Documentation ### Vignettes Long form of documentation, how multiple functions work together (It can use functions of other packages) ```r usethis::use_vignette(name = "intro") ``` -- Write your own vignette: - Fruits growing - Dogs/cats exploring the house or the neighborhood - A match of your sport - ...
03
:
00
--- name: tests ## Tests Make sure that what you think it happens it really stays that way: Can be quite complicated ```r use_testthat() use_test("meow") ``` .pull-left[ Change from: ```r test_that("multiplication works", { expect_equal(2 * 2, 4) }) ``` ] .pull-right[ To (**If** you used the [meow function](#namespace)): ```r test_that("mewo works", { expect_message(meow(), "meow") }) ``` ] --
03
:
00
--- name:licenses ## Licenses If sharing the package what can people do with your package? - **Permissive** licenses: Code with a permissive license can be freely copied, modified, and published, and the only restriction is that the license must be preserved. - **Copyleft** licenses: if you publish modified versions or bundle with other code, the modified version or complete bundle must also be licensed with the same license. ```r usethis::use_mit_license() # Permissive usethis::use_gpl_license() # Copyleft usethis::use_proprietary_license() # Own license ``` .right[<sup>[Source](https://r-pkgs.org/license.html)</sup>] ??? --- name: news ## NEWS Sharing what changed between releases ```r usethis::use_news_md() ``` The file has this structure: ```raw # dogs 0.0.0.9000 * Added a `NEWS.md` file to track changes to the package. ``` Version of the package Text describing changes on the packages. It is a good place to acknowledge minor contributions ??? Modify to explain the changes. Good idea to use - (#issue, `@user`) --
03
:
00
--- ## Finishing and checking Check if everything works well! It can take some time. ```r check() ``` It should pass without Warnings or Errors. If not (most probable) fix the problems found ??? Automatically runs the test and checks the package compilance with common quality standards --- ## That's all .center[ ![:scale 60% "That's all folks"](https://media.giphy.com/media/lD76yTC5zxZPG/giphy.gif) ] --- ## Developing your package - [Modify or add](#r-files) more *.R files to the R folder - [Add or change function's documentation](#rd-files) and [vignettes](#vignettes) and update it (`document()`) - Check the package (`check()`) - Repeat. --- ## Questions, doubts, comments? - It is normal to not succeed on the first 5-10 attempts!! - Search, ask whenever you need. Thanks for following through it. ![:scale 40% ""](https://media1.giphy.com/media/f2HiQKaEkaKwo/giphy.gif?cid=ecf05e475uwtpser5kqd7t5pwoz8vdrrkbp817x708vdb4ci&rid=giphy.gif&ct=g) ??? --- name:advanced # Advanced ## Git Set up git as a control version system. This allows to share on [GitHub](https://github.com). To set it up use: ```r usethis::use_git() ``` ??? Version controls helps you to modify code securely and interact with others (and receive their suggestions). --- # Advanced ## Github Share the package on Github: ```r usethis::use_github() ``` Add checks ```r usethis::use_github_action_check_release() ``` Use the git panel of Rstudio to commit and push updates on the package. ??? Having a package public on github can help on your CV and to get users. --- # Advanced ## Code coverage Report how much of the package is tested. ```r usethis::use_coverage() ``` It can be done offline on your computer `covr::report()` but usually also reported online. ??? Aim to have high code coverage (above 75%). High code coverage prevents your users (and yourself) to push changes that do not work. --- # Advanced ## Pkgdown website Now that the package is working and public, a website makes it easier for users to find documentation. ```r usethis::use_pkgdown() usethis::use_pkgdown_github_pages() ``` ??? It is also great for publicity, so others can read and learn about your package without installing it.