8 Best practices
R code is often organized in packages that can be installed from centralized repositories such as CRAN or GitHub. If you are new to writing R packages, this course cannot give a complete introduction into packages. It is still useful to embrace some very few concepts of R packages to gain access to a vast toolbox and also organize your code in a standardized way familiar to other users. With the first steps in place, the road to your first R package may become less steep.
- Create a
DESCRIPTION
file to declare dependencies and allow easy reloading of the functions you define - Store your functions in
.R
files in theR/
directory in your project- Scripts that you execute live in
script/
or a similar directory
- Scripts that you execute live in
- Use roxygen2 to document your functions close to the source
- Write tests for your functions, e.g. with testthat
See R packages for a more comprehensive treatment.
8.1 DESCRIPTION
Create and open a new RStudio project.
Then, create a DESCRIPTION
file with usethis::use_description()
:
# install.packages("usethis")
usethis::use_description()
Double-check success:
# install.packages("devtools")
devtools::load_all()
Declare that your project requires the tidyverse and the here package:
usethis::use_package("here")
# Currently doesn't work, add manually
# https://github.com/r-lib/usethis/issues/760
# usethis::use_package("tidyverse")
8.2 R
With a DESCRIPTION
file defined, create a new .R
file and save it in the R/
directory.
(Create this directory if it does not exist.)
Create a function in this file, save the file:
hi <- function(text = "Hello, world!") {
print(text)
invisible(text)
}
Do not source the file.
Restart R (with Ctrl + Shift + F10 in RStudio).
Run devtools::load_all()
again, you can use the shortcut Ctrl + Shift + L or Cmd + Shift + L in RStudio.
Check that you can run hi()
in the console:
hi()
## [1] "Hello, world!"
hi("Wow!")
## [1] "Wow!"
Edit the function:
hi <- function(text = "Wow!") {
print(text)
invisible(text)
}
Save the file, but do not source it.
Run devtools::load_all()
again, you can use the shortcut Ctrl + Shift + L or Cmd + Shift + L in RStudio.
Check that the new implementation of hi()
is active:
hi()
## [1] "Wow!"
All functions that are required for your project are stored in this directory.
Do not store executable scripts, use a script/
directory.
8.3 roxygen2
The following intuitive annotation syntax is a standard way to create documentation for your functions:
#' Print a welcome message
#'
#' This function prints "Wow!", or a custom text, on the console.
#'
#' @param text The text to print, "Wow!" by default.
#'
#' @return The `text` argument, invisibly.
#'
#' @examples
#' hi()
#' hi("Hello!")
hi <- function(text = "Wow!") {
print(text)
invisible(text)
}
This annotation can be rendered to a nicely looking HTML page with the roxygen2 and pkgdown packages. All you need to do is provide (and maintain) it.
8.4 testthat
Automated tests make sure that the functions you write today continue working tomorrow.
Create your first test with usethis::use_test()
:
# install.packages("testthat")
usethis::use_test("hi")
The file tests/testthat/test-hi.R
is created, with the following contents:
test_that("multiplication works", {
expect_equal(2 * 2, 4)
})
Replace this predefined text with a test that makes more sense for us:
test_that("hi() works", {
expect_output(hi(), "Wow")
expect_output(hi("Hello"), "Hello")
})
Run the new test with devtools::test()
, you can use the shortcut Ctrl + Shift + T or Cmd + Shift + T in RStudio.
Check that the test actually detects failures by modifying the implementation of hi()
and rerunning the test:
hi <- function(text = "Oops!") {
print(text)
invisible(text)
}
Run the new test with devtools::test()
, you can use the shortcut Ctrl + Shift + T or Cmd + Shift + T in RStudio.
One test should be failing now.