📦
Building tidy tools

Day 1 Session 2: 🏷️Documentation - Minimal

Emma Rand and Ian Lyttle

Invalid Date

🏷️ Document your package

Learning Objectives

At the end of this section you will be able to:

  • Describe the different levels of package documentation
  • Describe what is in the DESCRIPTION file and know what to edit manually and which parts devtools will edit automagically
  • Document a function with Roxygen comments and use the devtools workflow to convert to “R documentation” format .Rd
  • Use some of the most common Roxygen tags
  • Add a package level help file
  • Describe, and document your package with, the common types of package dependencies
  • Add a citation file in Citation File Format (CFF)

Overview

Levels of package documentation

  • Metadata: The DESCRIPTION file – “what’s in this package?”

  • Object documentation: for functions and data

  • Package-level documentation

  • Vignettes: Long form documentation

DESCRIPTION

Sample DESCRIPTION

🎬 Take a look at the DESCRIPTION for the following packages. What’s common? What’s different?

Metadata in DESCRIPTION

  • Title: One line, title case, with no period. Fewer than 65 characters.

  • Version

  • for release: MAJOR.MINOR.PATCH version.

  • for development version: MAJOR.MINOR.PATCH.9000

  • Authors@R:

  • “aut” means author, “cre” means creator, “ctb” means contributor.

Update DESCRIPTION

🎬 Edit the title


🎬 You should find that your information as an author is already included because you edited your .RProfile at the start of the session

Update DESCRIPTION

Package: ussie
Title: Work with European Football League Data
Version: 0.0.0.9000
Authors@R: 
    person("Emma", "Rand", , "emma.rand@york.ac.uk", role = c("aut", "cre"),
           comment = c(ORCID = "0000-0002-1358-8275"))
Description: What the package does (one paragraph).
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.0

Metadata in DESCRIPTION

  • Description: One paragraph describing what the package does. Keep the width of the paragraph to 80 characters; indent subsequent lines with 4 spaces.

  • License

  • Encoding: How to encode text, use UTF-8 encoding.

  • LazyData: Use true to lazy-load data sets in the package.

Update DESCRIPTION

🎬 Edit the description

Description: This is a demo package for the "Building Tidy Tools" workshop at 
    at rstudio::conf(2022L). It allows you to work with European football 
    league data supplied by the engsoccerdata package (Curley 2016).

👀 The full stop matters!

Commit and push

Now would be a good time to commit your changes and push them to GitHub.


Or just commit

Git iconGitHub icon

Object documentation

Object documentation

  • Object documentation is what you see when you use ? or help()

🎬 Try this now:

?uss_make_matches
  • Files are written in a special “R documentation” format: .Rd

  • .Rd resembles LaTeX,

man/uss_make_matches.Rd

man/uss_make_matches.Rd


% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/matches.R
\name{uss_make_matches}
\alias{uss_make_matches}
\title{Make a standard league-play tibble}
\usage{
uss_make_matches(data_engsoc, country)
}
\arguments{
\item{data_engsoc}{obtained from {engsoccerdata}.}

\item{country}{\code{character} scalar, specifies the league.}
}
\value{
a tibble with columns \code{country}, \code{date}, \code{season}, \code{tier}, \code{home},
\code{visitor}, \code{goals_home}, \code{goals_visitor}.
}
\description{
Given a league-play data frame from {engsoccer}, returns a tibble with
standardised column-names and types, e.g. \code{date} is a \code{Date}.
}
\examples{
uss_make_matches(engsoccerdata::spain, "Spain")
}

Object documentation

🥳 We don’t have to write it!!

  • We write “roxygen comments” in the .R files

  • These get turned into .Rd format

  • Functions from roxygen2 (Wickham et al. 2022) do the work but we can use devtools functions to call them

Roxygen comments

#' Make a standard league-play tibble
#'
#' Given a league-play data frame from {engsoccer}, returns a tibble with
#' standardised column-names and types, e.g. `date` is a `Date`.
#'
#' @param data_engsoc  obtained from {engsoccerdata}.
#' @param country `character` scalar, specifies the league.
#'
#' @return a tibble with columns `country`, `date`, `season`, `tier`, `home`,
#'    `visitor`, `goals_home`, `goals_visitor`.
#' @export
#'
#' @examples
#' uss_make_matches(engsoccerdata::spain, "Spain")
uss_make_matches <- function(data_engsoc, country) {
  result <-
    data_engsoc |>
    tibble::as_tibble() |>
    dplyr::transmute(
      country = as.character(country),
      tier = as.integer(tier),
      season = as.integer(Season),
      date = as.Date(Date),
      home = as.character(home),
      visitor = as.character(visitor),
      goals_home = as.integer(hgoal),
      goals_visitor = as.integer(vgoal)
    )
  result
}
  • the #' indicates it is a roxygen comment

Object documentation workflow

  • Add roxygen comments to your .R files.
  • Preview documentation with ?
  • Repeat until the documentation looks the way you want.

Document your function

🎬 Open matches.R

usethis::use_r("matches")


. . .

🎬 Put your cursor anywhere in the function and do Code | Insert Roxygen Documentation (Ctrl-Alt-Shift-R)

#' Title
#'
#' @param data_engsoc 
#' @param country 
#'
#' @return
#' @export
#'
#' @examples
uss_make_matches <- function(data_engsoc, country) {
  result <-
    data_engsoc |>
    tibble::as_tibble() |>
    dplyr::transmute(
      country = as.character(country),
      tier = as.integer(tier),
      season = as.integer(Season),
      date = as.Date(Date),
      home = as.character(home),
      visitor = as.character(visitor),
      goals_home = as.integer(hgoal),
      goals_visitor = as.integer(vgoal)
    )
  result
}

Roxygen comments and tags

  • #' indicates it is a roxygen comment

  • @ indicates a roxygen tag

    • @param arg — describe the inputs
    • @examples— show how the function works
    • @seealso — point out related functions
    • @return — describe the outputs
    • @export — is this a user visible function

Document your function

🎬 Give your function a title and a brief description


🎬 Define the two parameters


🎬 Describe what the function returns

Our answer

#' Make a standard league-play tibble
#'
#' Given a league-play data frame from {engsoccer}, returns a tibble with
#' standardised column-names and types, e.g. `date` is a `Date`.
#'
#' @param data_engsoc  obtained from {engsoccerdata}.
#' @param country `character` scalar, specifies the league.
#'
#' @return a tibble with columns `country`, `date`, `season`, `tier`, `home`,
#'    `visitor`, `goals_home`, `goals_visitor`.
#' @export
#'
#' @examples


🎬 Save matches.R

Build documentation

🎬 Run devtools::document() to turn roxygen comments to .Rd

devtools::document()
ℹ Updating ussie documentation
ℹ Loading ussie
Writing NAMESPACE
Writing uss_make_matches.Rd
Warning message:
[matches.R:13] @examples requires a value 

We will that fix later!

Take a look 1

├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── man
│   └── uss_make_matches.Rd 
├── NAMESPACE
├── R
│   └── matches.R
└── ussie.Rproj
  • NAMESPACE now lists the exported function

  • man/uss_make_matches.Rd has been written

Take a look 2

🎬 Load the package : devtools::load_all()


🎬 Preview the documentation with:

?uss_make_matches


😮 🥳

Fix warning

Warning message:
[matches.R:13] @examples requires a value 

We need to add a usage example!

🎬 Under @examples, add one example for using your function

#' @examples
#' uss_make_matches(engsoccerdata::spain, "Spain")

Look again

🎬 Save matches.R, run devtools::document() followed by devtools::load_all()


🎬 Preview the documentation with ?uss_make_matches and edit if needed

Package-level help page

🎬 What happens if you do:

?ussie
No documentation for 'ussie' in specified packages and libraries:
you could try '??ussie'

Package-level help page

We can fix this with use_package_doc()

🎬 Add a package-level help page:

usethis::use_package_doc()


✔ Writing 'R/ussie-package.R'
• Modify 'R/ussie-package.R'


🎬 Run devtools::document() then devtools::load_all() followed by ?ussie

Commit and push

Now would be a good time to commit your changes and push them to GitHub

Git iconGitHub icon

devtools::check()

This is a good time to run R CMD check to ensure our package is in full working order.

🎬 Use devtools to run R CMD check

devtools::check()

── R CMD check results ─────────────────────────────────── ussie 0.0.0.9000 ────
Duration: 40.4s

❯ checking dependencies in R code ... WARNING
  '::' or ':::' imports not declared from:
    'dplyr' 'tibble'

❯ checking for unstated dependencies in examples ... WARNING
  '::' or ':::' import not declared from: 'engsoccerdata'

❯ checking R code for possible problems ... NOTE
  uss_make_matches: no visible binding for global variable 'tier'
  uss_make_matches: no visible binding for global variable 'Season'
  uss_make_matches: no visible binding for global variable 'Date'
  uss_make_matches: no visible binding for global variable 'home'
  uss_make_matches: no visible binding for global variable 'visitor'
  uss_make_matches: no visible binding for global variable 'hgoal'
  uss_make_matches: no visible binding for global variable 'vgoal'
  Undefined global functions or variables:
    Date Season hgoal home tier vgoal visitor

0 errors ✔ | 2 warnings ✖ | 1 note ✖


We’ve gained a warning!


Our warnings are about Package dependencies

Package dependencies

Package dependencies

Our warnings are because we have used packages that we have not declared officially.


We need to document our package dependencies


Our users, and the package installation machinery, need to know what our package depends on before installing

Package dependencies

Levels of dependency

  • Imports: must be installed for your package to work. If they’re not, they will get installed.
  • Suggests: used by your package, but not required. Might provide data for examples, to run tests, build vignettes.
  • Depends: Avoid where possible. When your package requires a specific version of R, e.g. Depends: R (>= 3.4.0). Think critically: downstream effects on packages that depend on your package.

❯ checking dependencies in R code ... WARNING
  '::' or ':::' imports not declared from:
    'dplyr' 'tibble'

❯ checking for unstated dependencies in examples ... WARNING
  '::' or ':::' import not declared from: 'engsoccerdata'

Package dependencies

usethis again!

use_package(package, type = "Imports")

  • Type – one of “Imports”, “Depends”, “Suggests”, “Enhances”, or “LinkingTo”
  • The default is “Imports”

usethis::use_package()

🎬 Use usethis::use_package() to add the dplyr package to Imports

usethis::use_package("dplyr")


✔ Adding 'dplyr' to Imports field in DESCRIPTION
• Refer to functions with `dplyr::fun()`


Look how your DESCRIPTION file changed!

usethis::use_package()

Note: we get reminded to “Refer to functions with dplyr::fun()

 

That is, we do NOT use library(dplyr) to make functions available to our package.

devtools::check()

🎬 Run devtools::check() on your package again

── R CMD check results ─────────── ussie 0.0.0.9000 ────
Duration: 24s

❯ checking dependencies in R code ... WARNING
  '::' or ':::' import not declared from: 'tibble'

❯ checking for unstated dependencies in examples ... WARNING
  '::' or ':::' import not declared from: 'engsoccerdata'

❯ checking R code for possible problems ... NOTE
  uss_make_matches: no visible binding for global variable 'tier'
  uss_make_matches: no visible binding for global variable 'Season'
  uss_make_matches: no visible binding for global variable 'Date'
  uss_make_matches: no visible binding for global variable 'home'
  uss_make_matches: no visible binding for global variable 'visitor'
  uss_make_matches: no visible binding for global variable 'hgoal'
  uss_make_matches: no visible binding for global variable 'vgoal'
  Undefined global functions or variables:
    Date Season hgoal home tier vgoal visitor

0 errors ✔ | 2 warnings ✖ | 1 note ✖

Imports

Three types, according to how much your are using the imported package.

If you are using….

  • a few functions from another package: put package name in the Imports: field of the DESCRIPTION file and call the function(s) explicitly using ::, e.g., pkg::fun().
  • a function repeatedly, uses you can avoid :: by importing the function with @importFrom pkg fun in ussie-package.R.
  • many functions from another package repeatedly: @import package. But beware, less transparent, higher likelihood of conflicting function names.

Imports

We will use tibble::tible() multiple times.

Instead of using:

usethis::use_package("tibble")

we can use

usethis::use_import_from("tibble", "tibble")

which will:

  • to add the package to the DESCRIPTION imports
  • add @importFrom tibble tibble to ussie-package.R and NAMESPACE
  • mean we can avoid ::

@importFrom pkg fun

🎬 Import tibble() from tibble:

usethis::use_import_from("tibble", "tibble")
✔ Adding 'tibble' to Imports field in DESCRIPTION
✔ Adding '@importFrom tibble tibble' to 'R/ussie-package.R'
✔ Writing 'NAMESPACE'
✔ Loading ussie

Suggests

  • Are used by your package, but not required for it to work

  • Might provide data for examples

In our case:

matches.R

#' @examples
#' uss_make_matches(engsoccerdata::spain, "Spain")

Suggests

🎬 Add engsoccerdata

usethis::use_package("engsoccerdata",
                     type = "Suggests")

 

✔ Adding 'engsoccerdata' to Suggests field in DESCRIPTION
• Use `requireNamespace("engsoccerdata", quietly = TRUE)` to test if package is installed
• Then directly refer to functions with `engsoccerdata::fun()`

Suggests

  • Packages listed in Suggests are not automatically installed along with your package.

  • This means that you can’t assume the package is available

CITATION.cff

The cffr (Hernangómez 2021) package will write a citation file in Citation File Format (CFF) (Druskat et al. 2021) from the description file.

🎬 Add a CFF file with:

cffr::cff_write()
CITATION.cff generated
Adding  CITATION.cff to .Rbuildignore

cff_validate results-----
Congratulations! This .cff file is valid

🏷️Yee haw! 🏷️
Your package has documentation!

Commit and push

Now would be a good time to commit your changes and push them to GitHub

Git iconGitHub icon

Summary

  • A package has metadata and object documentation (essential), vignettes and pkgdown sites (optional)
  • Metadata is in the DESCRIPTION
    • some fields need manual editing
    • some fields are appropriately edited by devtools workflow functions
  • Objects like functions and data are documented with roxygen comments then turned into documentation with devtools::document()
    • roxygen comments are indicated with #'
    • roxygen tags start with @

Summary continued

  • Package dependencies need to be documented
    • package dependencies are added with use_package()
    • functions from dependencies are called with pkg::function()
    • we don’t use library()
  • cffr::cff_write() will write a citation file from the description file.

References

Druskat, Stephan, Jurriaan H. Spaaks, Neil Chue Hong, Robert Haines, James Baker, Spencer Bliven, Egon Willighagen, David Pérez-Suárez, and Alexander Konovalov. 2021. “Citation File Format,” August. https://doi.org/10.5281/zenodo.5171937.
Hernangómez, Diego. 2021. “Cffr: Generate Citation File Format Metadata for r Packages” 6: 3900. https://doi.org/10.21105/joss.03900.
Horst, Allison Marie, Alison Presmanes Hill, and Kristen B Gorman. 2020. “Palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data.” https://allisonhorst.github.io/palmerpenguins/.
Wickham, Hadley. 2016. “Ggplot2: Elegant Graphics for Data Analysis.” https://ggplot2.tidyverse.org.
Wickham, Hadley, Peter Danenberg, Gábor Csárdi, and Manuel Eugster. 2022. “Roxygen2: In-Line Documentation for r.” https://CRAN.R-project.org/package=roxygen2.
Wickham, Hadley, Jay Hesselberth, and Maëlle Salmon. 2022. “Pkgdown: Make Static HTML Documentation for a Package.” https://CRAN.R-project.org/package=pkgdown.