Chapter 5 A Practical Guide

Disclaimer: This book is by no mean a legal book and should not be used as such. This book aims at helping you decipher the complexity of open source licenses, but if you have legal concerns and questions about open source licenses, please refer to a professional lawyer.

So now that you’ve got a good grasp of the different licenses, how do you add these information to your package / R code?

5.1 Filling the DESCRIPTION file

The most common way to share R code is to bundle it into a package. A package is a collection of R function, that comes with a DESCRIPTION file. This file contains the metadata about your package, which includes the license and the authors from the package.

5.1.1 Adding licenses with {usethis}

If you are building a package, {usethis} comes handy when it comes to licenses: this package has a series of functions that help you add licenses, by adding the license name to the DESCRIPTION, but also by adding external file is necessary.

For example, the MIT license needs to come with a file LICENSE, that contains the following:

YEAR:
COPYRIGHT HOLDER: 

You can add it with:

usethis::use_mit_license("NAME")

Note that if you want to add your name automatically, you can define options(usethis.full_name = "My name") in your .Rprofile.

For example, here’s mine:

readLines("~/.Rprofile") %>%
  glue::as_glue()
## options(
##   usethis.description = list(
##     `Authors@R` = 'person("Colin", "Fay", 
##         email = "contact@colinfay.me", 
##         role = c("aut", "cre"),
##         comment = c(ORCID = "0000-0001-7343-1846"))',
##     License = "MIT + file LICENSE"
##   )
## )
## 
## options(
##   usethis.full_name = "Colin Fay"
## )

Here are all the available licenses you can set with {usethis}:

library(usethis)
 ls( "package:usethis", pattern = "license")
## [1] "use_apl2_license" "use_cc0_license"  "use_ccby_license"
## [4] "use_gpl3_license" "use_lgpl_license" "use_mit_license"

5.1.2 Adding external contributors

If you are integrating someone else code inside your package, you need to state that in your package documentation. That’s for example what is done in {shiny}:

readLines(
  system.file("LICENSE", package = "shiny")
)[1:23] %>%
  glue::as_glue()
## The shiny package as a whole is distributed under GPL-3 (GNU GENERAL PUBLIC
## LICENSE version 3).
## 
## The shiny package includes other open source software components. The following
## is a list of these components (full copies of the license agreements used by
## these components are included below):
## 
## - jQuery, https://github.com/jquery/jquery
## - jQuery UI (some components), https://github.com/jquery/jquery-ui
## - Bootstrap, https://github.com/twbs/bootstrap
## - html5shiv, https://github.com/aFarkas/html5shiv
## - Respond.js, https://github.com/scottjehl/Respond
## - bootstrap-datepicker, https://github.com/eternicode/bootstrap-datepicker
## - Font Awesome, https://github.com/FortAwesome/Font-Awesome
## - selectize.js, https://github.com/selectize/selectize.js
## - es5-shim, https://github.com/es-shims/es5-shim
## - ion.rangeSlider, https://github.com/IonDen/ion.rangeSlider
## - strftime for Javascript, https://github.com/samsonjs/strftime
## - DataTables, https://github.com/DataTables/DataTables
## - showdown.js, https://github.com/showdownjs/showdown
## - highlight.js, https://github.com/isagalaev/highlight.js
## - tar implementation from R, http://www.r-project.org/

A good practice is also to include the author from these external libraries to your list of Authors@R in your DESCRIPTION, in the following form:

person("Name", "Last Name", 
        role = c("ctb", "cph"),
        comment = "Author of library XXX")

Like what is done in {shiny}:

read.dcf(
  system.file("DESCRIPTION", package = "shiny")
)[5] %>%
  glue::as_glue()
## c(
## person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"),
## person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
## person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"),
## person("Yihui", "Xie", role = "aut", email = "yihui@rstudio.com"),
## person("Jonathan", "McPherson", role = "aut", email = "jonathan@rstudio.com"),
## person(family = "RStudio", role = "cph"),
## person(family = "jQuery Foundation", role = "cph",
## comment = "jQuery library and jQuery UI library"),
## person(family = "jQuery contributors", role = c("ctb", "cph"),
## comment = "jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt"),
## person(family = "jQuery UI contributors", role = c("ctb", "cph"),
## comment = "jQuery UI library; authors listed in inst/www/shared/jqueryui/AUTHORS.txt"),
## person("Mark", "Otto", role = "ctb",
## comment = "Bootstrap library"),
## person("Jacob", "Thornton", role = "ctb",
## comment = "Bootstrap library"),
## person(family = "Bootstrap contributors", role = "ctb",
## comment = "Bootstrap library"),
## person(family = "Twitter, Inc", role = "cph",
## comment = "Bootstrap library"),
## person("Alexander", "Farkas", role = c("ctb", "cph"),
## comment = "html5shiv library"),
## person("Scott", "Jehl", role = c("ctb", "cph"),
## comment = "Respond.js library"),
## person("Stefan", "Petre", role = c("ctb", "cph"),
## comment = "Bootstrap-datepicker library"),
## person("Andrew", "Rowls", role = c("ctb", "cph"),
## comment = "Bootstrap-datepicker library"),
## person("Dave", "Gandy", role = c("ctb", "cph"),
## comment = "Font-Awesome font"),
## person("Brian", "Reavis", role = c("ctb", "cph"),
## comment = "selectize.js library"),
## person("Kristopher Michael", "Kowal", role = c("ctb", "cph"),
## comment = "es5-shim library"),
## person(family = "es5-shim contributors", role = c("ctb", "cph"),
## comment = "es5-shim library"),
## person("Denis", "Ineshin", role = c("ctb", "cph"),
## comment = "ion.rangeSlider library"),
## person("Sami", "Samhuri", role = c("ctb", "cph"),
## comment = "Javascript strftime library"),
## person(family = "SpryMedia Limited", role = c("ctb", "cph"),
## comment = "DataTables library"),
## person("John", "Fraser", role = c("ctb", "cph"),
## comment = "showdown.js library"),
## person("John", "Gruber", role = c("ctb", "cph"),
## comment = "showdown.js library"),
## person("Ivan", "Sagalaev", role = c("ctb", "cph"),
## comment = "highlight.js library"),
## person(family = "R Core Team", role = c("ctb", "cph"),
## comment = "tar implementation from R")
## )

Other packages have a different, but still valid approach:

read.dcf(
  system.file("DESCRIPTION", package = "tripack")
)[4] %>%
  glue::as_glue()
## Fortran code by R. J. Renka.
## R functions by Albrecht Gebhardt <albrecht.gebhardt@aau.at>.
## With contributions from Stephen Eglen <stephen@anc.ed.ac.uk>,
## Sergei Zuyev <sergei@stams.strath.ac.uk> and
## Denis White <white.denis@epamail.epa.gov>

5.2 Dependencies exploration

One thing you might want to do when building a package is analyse its dependencies and whether or not they might impact yours. To do that, here is a little suggestion, based on {pkgnet}.

  1. Download the CRAN package database:
pkgdb <- tools::CRAN_package_db()
  1. Then, we’ll use the {pkgnet} package to extract dependencies recursively.
get_deps <- function(pkg){
  DependencyReporter$new()$set_package(pkg)$nodes$node
}

gol <- get_deps("golem")
## INFO [2019-09-26 21:50:11] Checking installed packages...
## INFO [2019-09-26 21:50:11] Found 'golem' in installed packages.
## INFO [2019-09-26 21:50:11] Constructing dependency network for golem
## INFO [2019-09-26 21:50:11] ...done constructing dependency network.
extract_from_cran_db <- function(deps, pkgdb){
  pkgdb %>%
    as_tibble(.name_repair = "universal") %>%
    filter(Package %in% deps) 
}

deps <- extract_from_cran_db(gol, pkgdb)
## New names:
## * MD5sum -> MD5sum...14
## * `Authors@R` -> Authors.R
## * `Classification/ACM` -> Classification.ACM
## * `Classification/ACM-2012` -> Classification.ACM.2012
## * `Classification/JEL` -> Classification.JEL
## * … and 9 more problems
deps %>%
  count(
    License
  )
deps %>%
  summarize(
    any(License_restricts_use, na.rm = TRUE)
  )
## Warning in any(License_restricts_use, na.rm = TRUE): coercing argument of
## type 'character' to logical