2  Build your first R package

2.1 Create new R package

2.1.1 Steps

  • Go to Files > New Project…

  • Select New Directory > R Package

  • Fill in Package name

  • Tick Create a git repository

  • Click Create Project

A typical R package structure

Demo: create new package

2.1.2 Post creation

  • Install usethis and devtools

  • Generate a license for your package:

    • Open-source: run usethis::use_mit_license(copyright_holder=NULL) in RStudio Console

    • Proprietary: usethis::use_proprietary_license(copyright_holder) in RStudio Console

    • Other license options

  • Generate a read me file: run usethis::use_readme_rmd() in RStudio Console

  • (optional) Update information inside the DESCRIPTION file. Some fields of interest:

    • Title: what the package does

    • Description: more detailed information about the package (in one paragraph)

    • Depends: list of package’s dependencies for core functions (your package require these external packages to work)

    • Suggest: list of package’s dependencies for development tasks or optional functions (for example: packages used for testing)

    • Authors: list of package’s authors. Read Author section for the format.

  • (optional) Upload to Github

    • Create a new repository on Github

    • Open Terminal (To open Terminal in R studio, click Tools > Terminal > New Terminal )

    • Run the following snippet in RStudio Terminal (replace {link to repo} with your repo link)

      git add .
      git commit -m "Initial commit"
      git remote add origin {link to repo}                        
      git branch -M main
      git push -u origin main
    • Demo upload github

2.2 Writing the first function

2.2.1 Write it

  • Create a file to place your function into. The file must be created in R folder with the naming convention: function_name.R. To create the file, there are 2 options:
    • Use RStudio to navigate to R folder and click New Blank File > R Script
    • Run usethis::use_r("filename") in Console
  • Define a function

Example: Create a square.R that contains the following snippet

square <- function(x) {
  return(x * x)
}

2.2.2 Document it

  • Install roxygen2

  • Generate and update the roxygen documentation on top of the function. (Refer to demo video)

  • Run roxygen2::roxygenise() or devtools::document() to generate documents.

#' Square a number 
#' 
#' Takes a number x and returns its square, x * x. 
#' 
#' @param x A numeric value to be squared. 
#' @return The square of x. 
#' @examples 
#' square(2) 
#' square(-5.7) 
#' 
#' @export 
square <- function(x) { 
  return(x * x) 
}

Demo: how to generate roxygen skeleton

Trouble shooting NAMESPACE

If roxygen2::roxygenise() prints out the following message

✖ Skipping NAMESPACE It already exists and was not generated by roxygen2.

delete the current NAMESPACE file and rerun the command

2.2.3 Caveat (ノ◕ヮ◕)ノ*:・゚✧

Reuse built-in function names instead of creating new ones

Some reusable function names: plot, print, toString

To reuse function name:

  • Modify original function to add class to it

  • Write a custom function for your class

Example: overriding plot function for class square

square <- function(x) {
  out <- x * x 
  class(out) <- "square" # tell R that ouptut is of class "square"
  return(out)
}

# --- Override plot function
plot.square <- function(x, ...) {
  plot(c(1:length(x)), x, xlab = "x", ylab = "Square of x", ...)
}

# --- Test the new plot function 
y <- square(c(1,2,3,4,5,6,7,8,9,10))
plot(y)

2.3 Set up quality control

2.3.1 Unit testing

Makes sure your functions work as expected.

  • Install devtools, usethis

  • Create a test: run usethis::use_test("test_name") in RStudio Console. This would create a file named "test-test_name.R" under tests/testthat folder

Example: unit test for square function

library(testthat)
test_that("square(3) returns 9", {
  # --- Define expected output
  expected <- 9
  class(expected) <- "square" 
  # --- Test function
  actual <-  square(3)
  expect_equal(actual, expected)
})
Test passed 🥇
Tip

Run devtools::test() in R to run all tests in package

2.3.2 Code coverage

View coverage report locally

  • Install covr

  • Run covr::report()

Show your test coverage on Github

  • Import devtools and covr

  • Push your package to GitHub

  • Run use_coverage(type = c("codecov"))

  • Run use_github_action("test-coverage")

  • Login http://codecov.io and get your repo’s token

  • Run codecov(token = "YOUR_TOKEN_HERE")

2.3.3 Automatic R CMD check

Test your package locally

Run devtools::check() in R console to test the package

Ensure your changes doesn’t cause the package to failed to build.

  • Re-knit readme: devtools::build_readme()

  • Run:

    usethis::use_github_action_check_standard(
      save_as = "R-CMD-check.yaml",
      ref = NULL, ignore = TRUE, open = FALSE)

2.4 Package down

Share your package with the world 🌎.

  • Install pkgdown

  • Run usethis::use_pkgdown()

  • Run usethis::use_pkgdown_github_pages()

  • Create an empty branch for hosting your page.

    • Run the following snippet in Terminal
    • To open Terminal in R studio, click Tools > Terminal > New Terminal
git checkout --orphan gh-pages     
git rm -rf .     
git commit --allow-empty -m 'Initial gh-pages commit'    
git push origin gh-pages     
git checkout master

2.5 Additional materials

2.5.1 Cheatsheet

2.6 R package with STAN

2.6.1 Quick start

  • Install rstantools and rstan packages

  • Run one of the following commands:

    • rstantools::rstan_create_package(path = "pkgname") to create new package with STAN functionality

    • rstantools::use_rstan() to add STAN functionality to existing package

  • Store your STAN models (.stan files) under inst/ folder

  • Run rstan::config() after adding STAN models (make sure to do this after adding or updating STAN model)

  • Run devtools::document() to compile STAN models. You should find the translated C++ files under src/ folder

  • Write your R function under R/ folder just like normal, and your STAN models is accessible via stanmodels$model_name

2.6.2 Additional material

Warnings on Mac

Mac users may encounter WARNING during devtools::check() with the following message

checking top-level files ... WARNING A complete check needs the 'checkbashisms' script. See section ‘Configure and cleanup’ in the ‘Writing R Extensions’ manual.

that may persists even after installing checkbashisms via terminal. This may be caused by RStudio using different $PATH. To resolve this, there are 3 options:

  • Change PATH manually

  • Remove configure, configure.win which are the files that need to be checked (not recommended)

  • Or simply ignore the message since CRAN check system will have checkbashisms anyways

2.7 Releasing to CRAN

2.7.1 Release workflow

The most concrete expression of the release process is the checklist produced by usethis::use_release_issue(), which opens a GitHub issue containing a list of todo’s.

The generated checklist would include the following

First release:

  •  usethis::use_news_md()

  •  usethis::use_cran_comments()

  •  Update (aspirational) install instructions in README

  •  Proofread Title: and Description:

  •  Check that all exported functions have @return and @examples

  •  Check that Authors@R: includes a copyright holder (role ‘cph’)

  •  Check licensing of included files

  •  Review https://github.com/DavisVaughan/extrachecks

Prepare for release:

  •  git pull

  •  urlchecker::url_check()

  •  devtools::build_readme()

  •  devtools::check(remote = TRUE, manual = TRUE)

  •  devtools::check_win_devel()

  •  git push

Submit to CRAN:

  •  usethis::use_version('patch')

  •  devtools::submit_cran()

  •  Approve email

Wait for CRAN...

  •  Accepted 🎉

  •  usethis::use_github_release()

  •  usethis::use_dev_version(push = TRUE)

  •  usethis::use_news_md()

But to summarize the process, there are 3 stages for the submission process

Local checks

  • Run devtools::check() and resolve any ERRORs, WARNINGs, and try to not have any NOTEs if possible (as CRAN will not allow some specific NOTEs). After resolving all issues, copy and paste the check result to cran-comments.md (generated by usethis::use_cran_comment())

  • If you find some NOTEs are un-resolvable, make sure to also include the NOTEs and explanation in cran-comments.md

  • Make sure to double check documentations following the checklist

Run check on servers

There are several R functions to check package compatibility on other OS

  • Run devtools::check_win_devel() to check your package on a Windows server

  • Run devtools::check_mac_release() to check your package on a MacOS server

If there are any OS-specific issues, make sure to note that in cran-comments.md as well

Submission

  • Call usethis::use_version() to update your package version number then submit to cran with devtools::submit_cran()

  • Wait for CRAN email, but be prepared for several rejections before your package is finally approved

  • Once you received the approval email, generate a github release using  usethis::use_github_release() and update version to development mode using  usethis::use_dev_version(push = TRUE)

2.7.2 Common issues and how to resolve them

  • devtools::check() don’t like tidyverse syntax (NOTE: no visible binding for global variable … ) This can be ignored but make sure to include explanation for this NOTE in cran-comments.md

  • Note regarding package size (checking installed package size … NOTE). Similarly, this NOTE can be ignored but require a explanation in cran-comments.md

2.7.3 Things that needed to be double check before submission

  • Include contributors, references: make sure that you include authors of any code you copied for your package, and any reference for your methodology
  • Document your code properly: make sure your roxygen all include @return tag and explain the returned result

2.7.4 Caveats

About DESCRIPTION file

  • Author list: if part of your code is derived, copied from other sources, the authors of such code must be included in Author field with ‘ctb’ (contributor) role

  • Description section:

    • When functions are mentioned, make sure it follows the format function_name()

    • When packages or software names are mentioned, make sure to place them in single quotes ('package_name')

    • When refer to publication titles, make sure to place them in double quotes ("publication title")

About LICENSE file

  • Github vs CRAN LICENSE file: since LICENSE file for Github and CRAN follows different formats, a work around is to have a LICENSE.md file for Github and a LICENSE file for CRAN (make sure LICENSE.md is in included in .Rbuildignore). This is usually automatically handled when LICENSE is generated by usethis::use_{license_name}_license()

    LICENSE format for Github
    # MIT License
    
    Copyright (c) 2024 demoPkg authors
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.

    </details>

    LICENSE format for CRAN
    YEAR: 2024
    COPYRIGHT HOLDER: demoPkg authors

    </details>

2.8 Example package

The package used for this tutorial is available at Github

2.9 Resources

A sample R package: https://thinhong.github.io/denim/

Popular R packages: https://tidyverse.tidyverse.org/

Thorough guide to R package development: https://r-pkgs.org

“Advanced R” book: https://adv-r.hadley.nz/”

“R for data science” book : https://r4ds.had.co.nz/

Explore syntax for function documentation: https://roxygen2.r-lib.org/articles/roxygen2.html