+ - 0:00:00
Notes for current slide
Notes for next slide

Everything you need to know
to create your own package

Earo Wang

May 24, 2018
slides at http://slides.earo.me/rladies-pkg

1 / 35

This page has been intentionally left blank.

2 / 35

Why write a 📦?

3 / 35

Why write a 📦?






3 / 35

Tools to automate the 📦 development

  • RStudio

  • available: Check if the Title of a Package is Available, Appropriate and Interesting

  • usethis: Automate Package and Project Setup

  • devtools: Tools to Make Developing R Packages Easier

  • testthat: Unit Testing for R

  • covr: Test Coverage for Packages

  • pkgdown: Make Static HTML Documentation for a Package

4 / 35

Today's mission

Create an package to query the Zomato API

5 / 35

Step 0: come up with a catchy 📦 name

  • Unique & googleable

  • Describes what the package does (for example, knitr is neater than Sweave)

  • Only contains letters, numbers, and dots

  • Begins with a letter, and not end with a period

6 / 35

Step 0: come up with a catchy 📦 name

  • Unique & googleable

  • Describes what the package does (for example, knitr is neater than Sweave)

  • Only contains letters, numbers, and dots

  • Begins with a letter, and not end with a period

Good practices

  • Avoid capitalisation for less memorisation and less typing
6 / 35

Step 0: come up with a catchy 📦 name

7 / 35

Step 0: come up with a catchy 📦 name

available::available() makes sure that the package name is valid and unique.

7 / 35

Step 0: come up with a catchy 📦 name

available::available() makes sure that the package name is valid and unique.

available::available("romato", browse = FALSE)
#> ── romato ─────────────────────────────────────────────────────────────────
#> Name valid: ✔
#> Available on CRAN: ✔
#> Available on Bioconductor: ✔
#> Available on GitHub: ✖
#> Bad Words: ✔
#> Abbreviations: http://www.abbreviations.com/romato
#> Wikipedia: https://en.wikipedia.org/wiki/romato
#> Wiktionary: https://en.wiktionary.org/wiki/romato
#> Urban Dictionary:
#> Not found.
#> Sentiment:???
7 / 35

Step 1: setup 📦

8 / 35

Step 1: setup 📦

usethis::create_package() initialises the basic components of a package.

8 / 35

Step 1: setup 📦

usethis::create_package() initialises the basic components of a package.

usethis::create_package("~/Rpkg/romato")
#> Changing active project to romato
#> ✔ Creating 'R/'
#> ✔ Creating 'man/'
#> ✔ Writing 'DESCRIPTION'
#> ✔ Writing 'NAMESPACE'
#> ✔ Writing 'romato.Rproj'
#> ✔ Adding '.Rproj.user' to './.gitignore'
#> ✔ Adding '^romato\\.Rproj$', '^\\.Rproj\\.user$' to '.Rbuildignore'
#> ✔ Opening project in RStudio
  • R/: the R code

  • man/: the documentation (generated by roxygen2: do not edit by hand)

  • DESCRIPTION: the metadata of the package

  • NAMESPACE: how the package interacts with R and with other packages (do not edit by hand)

8 / 35

Step 1: setup 📦

9 / 35

Step 2: edit DESCRIPTION

Package: romato
Version: 0.0.0.9000
Title: What the Package Does (One Line, Title Case)
Description: What the package does (one paragraph).
Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
License: What license is it under?
Encoding: UTF-8
LazyData: true
ByteCompile: true
10 / 35

Step 2: edit DESCRIPTION

Package: romato
Version: 0.0.0.9000
Title: What the Package Does (One Line, Title Case)
Description: What the package does (one paragraph).
Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
License: What license is it under?
Encoding: UTF-8
LazyData: true
ByteCompile: true

Version numbering convention

  • major.minor.patch.dev: 0.0.0.9000
10 / 35

Step 3: choose a license

  • MIT License use_mit_license(): free for anyone to do anything with.

  • GPLv3 use_gpl3_license(): changes and bundles must also be GPL.

  • CC0 use_cc0_license(): dedicated to public domain, best for data packages.

11 / 35

Step 3: choose a license

  • MIT License use_mit_license(): free for anyone to do anything with.

  • GPLv3 use_gpl3_license(): changes and bundles must also be GPL.

  • CC0 use_cc0_license(): dedicated to public domain, best for data packages.

usethis::use_mit_license("Earo Wang")
✔ Setting License field in DESCRIPTION to 'MIT + file LICENSE'
✔ Writing 'LICENSE.md'
✔ Adding '^LICENSE\\.md$' to '.Rbuildignore'
✔ Writing 'LICENSE'

more about license: choose a license

11 / 35

Step 4: 📦-oriented functions

We are going to write some Zomato API wrappers.

usethis::use_r("zomato-api")
● Modify 'zomato-api.R'
12 / 35

Non 📦-oriented functions in a script

library(httr)
library(jsonlite)
zomato_search <- function(api_key = NULL, query) {
# URL to Zomato API
url <- modify_url(
url = "https://developers.zomato.com" ,
path = "/api/v2.1/search"
)
# request URL
resp <- GET(
url = url,
config = add_headers("user-key" = api_key),
query = list(q = query)
)
# read the JSON file
parsed <- fromJSON(
content(
resp, as = "text", type = "application/json", encoding = "UTF-8"
),
flatten = TRUE
)
# return results
parsed$restaurants
}
ur_key <- "your-api-key"
zomato_search(ur_key, query = "Brother Budan Baba Melbourne")
13 / 35

Step 4: 📦-oriented functions

In the R/ folder of a package:

  • 🚫 library() or require(): dependencies are managed in the NAMESPACE file.

  • 🚫 source()

  • 🚫 options() or par()

  • 🚫 setwd()

14 / 35

15 / 35

Click me to download the R scripts for this workshop.

16 / 35

Step 5: use 📦::fun()

usethis::use_package("httr")
#> ✔ Adding 'httr' to Imports field in DESCRIPTION
#> ● Refer to functions with `httr::fun()`
usethis::use_package("jsonlite")
#> ✔ Adding 'jsonlite' to Imports field in DESCRIPTION
#> ● Refer to functions with `jsonlite::fun()`
17 / 35

Step 5: use 📦::fun()

usethis::use_package("httr")
#> ✔ Adding 'httr' to Imports field in DESCRIPTION
#> ● Refer to functions with `httr::fun()`
usethis::use_package("jsonlite")
#> ✔ Adding 'jsonlite' to Imports field in DESCRIPTION
#> ● Refer to functions with `jsonlite::fun()`

one way

httr::fun
`%>%` <- magrittr::`%>%`

alternative

#' @importFrom httr fun
#' @import httr
#' @importFrom magrittr %>%
17 / 35

Step 6: explore in console write code

In RStudio, Cmd/Ctrl + Shift + L loads all the functions into the environment.

devtools::load_all(".")
#> Loading romato
18 / 35

Step 7: document

  • Enable markdown support in roxygen
usethis::use_roxygen_md()
#> ✔ Setting Roxygen field in DESCRIPTION to 'list(markdown = TRUE)'
#> ✔ Setting RoxygenNote field in DESCRIPTION to '6.0.1'
#> ● Re-document
19 / 35

Step 7: document

  • Cmd/Ctrl + Opt/Alt + Shift + R inserts roxygen skeleton
#' Title
#'
#' @param api_key
#' @param query
#'
#' @return
#' @export
#'
#' @examples
zomato_search <- function(api_key = NULL, query) {
...
}
20 / 35

Step 7: document

  • Cmd/Ctrl + Opt/Alt + Shift + R inserts roxygen skeleton
#' Title
#'
#' @param api_key
#' @param query
#'
#' @return
#' @export
#'
#' @examples
zomato_search <- function(api_key = NULL, query) {
...
}

Each roxygen comment is preceded by #'.

  • @param: inputs of the function, followed by a description
  • @return: what the function returns
  • @export: make the function visible/accessible to users
  • @examples: examples of how to use the function

To know the list of parameters: browseVignettes("roxygen2").

20 / 35

Step 7: document

  • Cmd/Ctrl + Shift + D to generate /man files (*.Rd)
==> devtools::document(roclets=c('rd', 'collate', 'namespace'))
Updating romato documentation
Loading romato
Writing NAMESPACE
Documentation completed

?zomato_search to preview the man page

21 / 35

Step 8: install 📦

  • Cmd/Ctrl + Shift + B to build the package
==> R CMD INSTALL --no-multiarch --with-keep.source romato
installing to library ‘/Library/Frameworks/R.framework/Versions/3.5/Resources/library’
installing *source* package ‘romato’ ...
* R
* byte-compile and prepare package for lazy loading
* help
** installing help indices
* building package indices
* testing if installed package can be loaded
DONE (romato)
22 / 35

Step 9: R CMD check

  • Cmd/Ctrl + Shift + E to perform R CMD check
Status: OK
R CMD check results
0 errors | 0 warnings | 0 notes
R CMD check succeeded
23 / 35

🎉

Create an package to query the Zomato API

24 / 35

Good practices

Build a 📦 that sustains

25 / 35

Unit tests

Catch bugs before they happen, and guarantee the validity of the code.

26 / 35

Unit tests

Catch bugs before they happen, and guarantee the validity of the code.

usethis::use_test("api")
#> ✔ Adding 'testthat' to Suggests field in DESCRIPTION
#> ✔ Creating 'tests/testthat/'
#> ✔ Writing 'tests/testthat.R'
#> ✔ Writing 'tests/testthat/test-api.R'
#> ● Modify 'test-api.R'
26 / 35

Unit tests

Catch bugs before they happen, and guarantee the validity of the code.

usethis::use_test("api")
#> ✔ Adding 'testthat' to Suggests field in DESCRIPTION
#> ✔ Creating 'tests/testthat/'
#> ✔ Writing 'tests/testthat.R'
#> ✔ Writing 'tests/testthat/test-api.R'
#> ● Modify 'test-api.R'

For example in the test-api.R

context("Zomato API")
test_that("invalid input", {
expect_error(zomato_search(api_key = NULL), "Please provide an API key.")
})
  • Cmd/Ctrl + Shift + T to perform tests
26 / 35

Unit tests





27 / 35

Code coverage

Code coverage is the % of code that is covered by unit tests.

covr::package_coverage()

tsibble-coverage

covr::report() displays covr results in a standalone report.

28 / 35

README

usethis::use_readme_rmd()
✔ Writing 'README.Rmd'
✔ Adding '^README\\.Rmd$' to '.Rbuildignore'
● Modify 'README.Rmd'
29 / 35

README

usethis::use_readme_rmd()
✔ Writing 'README.Rmd'
✔ Adding '^README\\.Rmd$' to '.Rbuildignore'
● Modify 'README.Rmd'

A README file should include:

  • A brief overview of the package

  • instructions on how to install

  • A few examples

29 / 35

Vignette

usethis::use_vignette("intro-romato")
#> ✔ Adding 'knitr' to Suggests field in DESCRIPTION
#> ✔ Setting VignetteBuilder field in DESCRIPTION to 'knitr'
#> ✔ Adding 'rmarkdown' to Suggests field in DESCRIPTION
#> ✔ Creating 'vignettes/'
#> ✔ Adding '*.html', '*.R' to 'vignettes/.gitignore'
#> ✔ Adding 'inst/doc' to './.gitignore'
#> ✔ Creating 'vignettes/intro-romato.Rmd'
#> ● Modify 'intro-romato.Rmd'
30 / 35

Vignette

usethis::use_vignette("intro-romato")
#> ✔ Adding 'knitr' to Suggests field in DESCRIPTION
#> ✔ Setting VignetteBuilder field in DESCRIPTION to 'knitr'
#> ✔ Adding 'rmarkdown' to Suggests field in DESCRIPTION
#> ✔ Creating 'vignettes/'
#> ✔ Adding '*.html', '*.R' to 'vignettes/.gitignore'
#> ✔ Adding 'inst/doc' to './.gitignore'
#> ✔ Creating 'vignettes/intro-romato.Rmd'
#> ● Modify 'intro-romato.Rmd'

Rmarkdown + metadata

---
title: "Vignette Title"
author: "Vignette Author"
date: "2018-05-24"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Vignette Title}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
30 / 35

Website

Build a website for your 📦 in 2 minutes.

31 / 35

Website

Build a website for your 📦 in 2 minutes.

pkgdown::build_site()

pkgdown

31 / 35

Release

  • Creates cran-comments.md, a template for your communications with CRAN when submitting a package.
usethis::use_cran_comments()
#> ✔ Writing 'cran-comments.md'
#> ✔ Adding '^cran-comments\\.md$' to '.Rbuildignore'
#> ● Modify 'cran-comments.md'
devtools::release(spelling = "en_GB")
32 / 35

More

33 / 35

More

Version control (Git & Github)

33 / 35

More

Version control (Git & Github)

Continuous integration

33 / 35

More

Version control (Git & Github)

Continuous integration

Track changes in NEWS

33 / 35

More

Version control (Git & Github)

Continuous integration

Track changes in NEWS

S3, S4, R6, Reference class

33 / 35

More

Version control (Git & Github)

Continuous integration

Track changes in NEWS

S3, S4, R6, Reference class

...

33 / 35

More

Version control (Git & Github)

Continuous integration

Track changes in NEWS

S3, S4, R6, Reference class

...

Keep calm

and write unit tests!

33 / 35

References

34 / 35

References

Resources

34 / 35

35 / 35


Made with

35 / 35


Made with

Slides created via xaringan ⚔️ http://slides.earo.me/rladies-pkg

35 / 35


Made with

Slides created via xaringan ⚔️ http://slides.earo.me/rladies-pkg

Open source https://github.com/earowang/rladies-pkg

35 / 35


Made with

Slides created via xaringan ⚔️ http://slides.earo.me/rladies-pkg

Open source https://github.com/earowang/rladies-pkg

This work is under licensed BY-NC 4.0.

35 / 35


Made with

Slides created via xaringan ⚔️ http://slides.earo.me/rladies-pkg

Open source https://github.com/earowang/rladies-pkg

This work is under licensed BY-NC 4.0.

Thank you!

35 / 35

This page has been intentionally left blank.

2 / 35
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow