--- title: "goodpractice" author: "Hannah Frick" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{goodpractice} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## What's it for? Building an R package is a great way of encapsulating code, documentation and data in a single testable and easily distributable unit. For a package to be distributed via CRAN, it needs to pass a set of checks implemented in `R CMD check`, such as: Is there minimal documentation, e.g., are all arguments of exported functions documented? Are all dependencies declared? These checks are helpful in developing a solid R package but they don't check for several other good practices. For example, a package does not need to contain any tests but is it good practice to include such. Following a coding standard helps readability. Avoiding overly complex functions reduces the risk of bugs. Including an URL for bug reports lets people more easily report bugs if they find any. Tools for automatically checking several of these aspects already exist and the **goodpractice** package bundles the checks from [**rcmdcheck**](https://cran.r-project.org/package=rcmdcheck) with code coverage through the [**covr**](https://cran.r-project.org/package=covr) package, source code linting via the [**lintr**](https://cran.r-project.org/package=lintr) package and cyclomatic complexity via the [**cyclocomp**](https://cran.r-project.org/package=cyclocomp) package and augments it with some further checks on good practice for R package development such as avoiding `T` and `F` in favour of `TRUE` and `FALSE`. It provides advice on which practices to follow and which to avoid. You can use **goodpractice** checks as a reminder for you and your colleagues - and if you have custom checks to run, you can make **goodpractice** run those as well! Please see the vignette "Custom Checks" for more details. ## Good practice out of the box ### Main function The main function is `goodpractice()` and has an alias `gp()` which takes the path to the source code of a package as its first argument. The **goodpractice** package contains the source for a simple package which violates some good practices. We'll use this for the examples. ```{r} library(goodpractice) # get path to example package pkg_path <- system.file("bad1", package = "goodpractice") # run gp() on it g <- gp(pkg_path) # show the result g ``` So with this package, we've done a few things in the DESCRIPTION file for which there are reasons not to do them, have unnecessary trailing semicolons in the code and used `T` and `F` for `TRUE` and `FALSE`. The output of `gp()` tells you what you did that isn't considered good practice and if it's in the R code, it points you the location of your faux-pas. In general, the messages are supposed to not only point out to you _what_ you might want to avoid but also _why_. The above example tries to run all 230 checks available, to see the full list use `all_checks()`. If you only want to run a subset of the checks, e.g., the one on the URL field in the DESCRIPTION, you can specify the checks by name: ```{r} # what is the name of the check? grep("url", all_checks(), value = TRUE) # run only this check g_url <- gp(pkg_path, checks = "description_url") g_url ``` ### Doing more than just printing Apart from printing a `goodPractice` object as returned by `gp()` to access the advice, you can also access which checks were carried out and which of those failed: ```{r} # which checks were carried out? checks(g_url) # which checks failed? failed_checks(g) ``` To access all the checks carried out with their results in a data frame, use `results()` on your `goodPractice` object. ```{r} # show the first 5 checks carried out and their results results(g)[1:5,] ``` Note that the code coverage could not be calculated. The corresponding check does not show up in the failed checks (because it was not carried out) and the result is `NA`. It is also possible to export the results to a JSON file with `export_json()`.