25 Packages 101

title: “How to convert your functions to package(s)”

subtitle: “GC Lunch and Learn: R packages 101” author: Dmitry Gorodnichy and Joseph Stinziano gitlab: https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/packages101 date: “March -June 2021” Taken from: https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/packages101/-/blob/master/packages101.Rmd

25.1 Resources

25.1.3 How to contribute

  1. Anyone: Fork Packages101 repo - modify - commit changes - push - submit request to merge

  2. Members of r4gc group:

A token is generated to allow you to push/pull Packages101 repo.
Use this line to push/pull from Packages101 repo:

git clone --progress https://oauth2:tjxrg3GyUQJJDMaA6LfHA@gccode.ssc-spc.gc.ca/r4gc/gc-packages/packages101 r4gc_packages101

=======

25.1.4 * R script to start:

library(devtools)

devtools::create("rCanada") ## if you are  in /my_package
devtools::create("../../rCanada") ## will it erase it,if I lready have it?
> #or usethis::create_package("../r4gc/packages/rCanada2")

library(roxygen2)
## library(testthis).<- we dont use this!Dont confuse it with library(testthat) ??

library(testthat) ## do we need it?

library(usethis)
## https://github.com/r-lib/usethis

usethis::use_testthat()
## use_testthat()

use_news_md()

use_test("iviDT")

x <- 1
y <- 2
use_data(x, y)


use_vignette(name="my_vignettes") #
use_vignette(name="data_linking")


use_package("data.table")
## > use_package("data.table")
## √ Adding 'data.table' to Imports field in DESCRIPTION
## * Refer to functions with `data.table::fun()`


  
  

use_package("magrittr")
use_package("data.table")
use_package("lubridate", type="Imports")  ## how about order ?! lubridate must be after data.table !
use_package("stringr")

use_package("IVIM")

## To update .Rd files in ./man, run:
devtools::document()
## Warning: The existing 'NAMESPACE' file was not generated by roxygen2, and will not be overwritten.
## So delete it, and then it will be created

25.1.4.1 To be discussed

Q: When I Clean and Rebuid: ????! ** testing if installed package can be loaded from final location

?????? C:/Users/gxd006/DOWNLO1/R-401.2 /etc/Renviron.site ?? May 12 19:25:09 Warning: replacing previous import ‘data.table::month’ by ‘lubridate::month’ when loading ‘IVIM’

25.2 * Setup

This is what you already have:
- “Original”" folder, with no specific structure, with R and Rmd files that contain: a) functions that that you want to be re-used by others (and yourself many months later!).
- They are tested and test codes are included in if(F) or in separate .Rmd, or, even better, in interactive Shiny App (eg https://rCanada.shinyapp.io/covid) - Good idea to be have them in form that can be sourced: source("caCovid.R"); source("iviBase.R")

  1. functions and other codes that are not (yet) ready for re-use.

https://gccode.ssc-spc.gc.ca/r4gc/codes/tracking-covid-data - caCovid.R - iviBase.R - … common.R, plot.R, etc

This is what you want to get: - Package folder (or several folders). - GCCode/r4gc/packages/rCanada - GCCode/r4gc/packages/IVI https://gccode.ssc-spc.gc.ca/gorodnichy/rCanada

25.2.0.1 Ways to do it:

You can create it in two ways:

25.2.0.1.0.1 From New Project

Either way RStudio will initialize and launch your new project. In the second way, it also puts .gitignore

  1. In RStudio -> New Project -> New Direcory ->R package -> package name: caPSES

NB: there are many templates. Choose basic (“R package) and create in folder /my_packages NB: If you have .R codes that are already source-able, attached them with”Add"button (one at a time), or you can copy them into /R folder later

note from Hadley: https://r-pkgs.org/workflows101.html

Call usethis::create_package(“path/to/package/pkgname”). Or, In RStudio, do File > New Project > New Directory > R Package. This ultimately calls usethis::create_package(), so really there’s just one way.

Don’t use package.skeleton() to create a package. Because this function comes with R, you might be tempted to use it, but it creates a package that immediately throws errors with R CMD build.

25.2.0.1.0.2 From script
  1. Run from any R, Rmd window or R console the command below

NB: output from

> devtools::create("../r4gc/packages/rCanada")
> #or usethis::create_package("../r4gc/packages/rCanada2")

New project 'rCanada' is nested inside an existing project '../r4gc/packages/', which is rarely a good idea.
If this is unexpected, the here package has a function, `here::dr_here()` that reveals why '../r4gc/packages/' is regarded as a project.
Do you want to create anyway?

1: Yes
2: Absolutely not
3: Nope

Selection: 1
√ Creating '../r4gc/packages/rCanada/'
√ Setting active project to 'C:/Users/gxd006/Downloads/_CODES/GCCode/r4gc/packages/rCanada'
√ Creating 'R/'
√ Writing 'DESCRIPTION'
Package: rCanada
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
    * First Last <first.last@example.com> [aut, cre] (YOUR-ORCID-ID)
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
    pick a license
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
√ Writing 'NAMESPACE'
√ Writing 'rCanada.Rproj'
√ Adding '^rCanada\\.Rproj$' to '.Rbuildignore'
√ Adding '.Rproj.user' to '.gitignore'
√ Adding '^\\.Rproj\\.user$' to '.Rbuildignore'
√ Opening 'C:/Users/gxd006/Downloads/_CODES/GCCode/r4gc/packages/rCanada/' in new RStudio session
√ Setting active project to '<no active project>'

25.3 * Overall Workflow

25.3.0.1 .. Copy needed codes from MY_CODES to R directory

  • Copy a function
dt.replaceAwithB <- function(dt, col, a, b) {
  dt[get(col)==a, (col):=b]; 
}
  • Insert roxigen skeleton (from magic wand menu) and add description NB: you may need to manually insert @ import and @ export

25.3.1

no need to Load All? Always start from “Clean and rebuild” Then Check

25.4 * .Rbuildignore

^.*.Rproj$ ^.Rproj.user$ MY_CODES incorrect ^MY_CODES$ correct ^MY_DATASETS$ ^LICENSE.md$

25.5 * License: use_mit_license()

License: MIT + file LICENSE

25.6 * DESCRIPTION

25.7 * NAMESPACE

https://r-pkgs.org/namespace.html

use_package("data.table")
## > use_package("data.table")
## √ Adding 'data.table' to Imports field in DESCRIPTION
## * Refer to functions with `data.table::fun()`

However this does notchange NAMESPACE ! Who changes is it? is that devtools::document() ???

Generated by roxygen2: do not edit by hand

export()
export(addDerivatives)
export(extractMostInfectedToday)
export(readCovidUofT.csv)
importFrom(lubridate,dmy)
importFrom(stringr,str_replace)

I deleted NAMESPACE so that roxigen can generate it! then added manually there . Not sure that’s theway to do it !

import(data.table)
import(ggplot2)
import(lubridate)
import(magrittr)
import(IVIM)

It Worked !

If you are using just a few functions from another package, the recommended option is to note the package name in the Imports: field of the DESCRIPTION file and call the function(s) explicitly using ::, e.g., pkg::fun(). Alternatively, though no longer recommended due to its poorer readability, use @importFrom, e.g., @importFrom pgk fun, and call the function(s) without ::.

25.8 * Examples and tests

25.8.0.1 .. In main file in /R folder

#' @examples

Some could be such :

#' \dontrun{}

25.8.0.2 .. In /tests folder

> use_testthat()

√ Setting active project to 'C:/Users/gxd006/Downloads/_CODES/GCCode/r4gc/packages/IVIM'
√ Adding 'testthat' to Suggests field in DESCRIPTION
√ Setting Config/testthat/edition field in DESCRIPTION to '3'
√ Creating 'tests/testthat/'
√ Writing 'tests/testthat.R'
* Call `use_test()` to initialize a basic test file and open it for editing.
Warning messages:
1: In readLines(f, n) :
  incomplete final line found on 'C:/Users/gxd006/Downloads/_CODES/GCCode/r4gc/packages/IVIM/DESCRIPTION'
...
  incomplete final line found on 'C:/Users/gxd006/Downloads/_CODES/GCCode/r4gc/packages/IVIM/DESCRIPTION'
> use_vignette()
Error in check_vignette_name(name) : 
  argument "name" is missing, with no default

25.9 .. in MY_CODES

Provide as .R, Rmd or shiny

25.10 * testthat

https://testthat.r-lib.org/

25.11 * Documentation

devtools::document()

https://kbroman.org/pkg_primer/pages/docs.html

#' For more details see the help vignette:
#' \code{vignette("help", package = "mypkg")}

or 

\href{../doc/help.html}{\code{vignette("help", package = "mypkg")}}

25.12 * Vignettes

> use_vignette(name="my_vignettes")

√ Adding 'knitr' to Suggests field in DESCRIPTION
√ Setting VignetteBuilder field in DESCRIPTION to 'knitr'
√ Adding 'inst/doc' to '.gitignore'
√ Creating 'vignettes/'
√ Adding '*.html', '*.R' to 'vignettes/.gitignore'
√ Adding 'rmarkdown' to Suggests field in DESCRIPTION
√ Writing 'vignettes/my_vignettes.Rmd'
* Modify 'vignettes/my_vignettes.Rmd'

I later renamed my first vignette to intro.Rmd - manually

https://bookdown.org/yihui/rmarkdown-cookbook/package-vignette.html

25.13 Delivering package

  • [Easiest way] Put binary in package repo. Then you can install it simply using install.packages("IVIM", repos = "https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/IVIM/-/blob/master/versions/IVIM_0.0.0.9000.tar.gz")
    • this .tar ball is obtained by running devtools::build() or devtools::check() which will place it in “../yourRPackageProject” directory.
  • [CONFIRM THIS!] Put source in github. Then people will be able to install using devtools::install_github("https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/IVIM")

25.14 Packaging and publishing w. pkgdown

https://fanwangecon.github.io/R4Econ/support/development/fs_packaging.pdf

25.14.0.1 Appendix: Various possible Errors and problems

25.14.0.1.0.1 Errors in using usethis::use_testthat()

Problem:


> usethis::use_vignette(name="howtoCovid")
Error in read.dcf(con) : 
  Line starting 'analyze and visualiz ...' is malformed!
> 

Solution:
https://stackoverflow.com/questions/59303030/devtools-error-in-read-dcfpath-desc-line-starting-this-corresponds-to

Corrections from https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/IVIM/-/tree/useR-dev/

25.15 (optional) Rtools

NBL This is not required

https://cran.r-project.org/bin/windows/Rtools/

http://web.mit.edu/insong/www/pdf/rpackage_instructions.pdf

25.15.0.1 package_initialization_script.R


 ## package_initialization_script.R
 
 library(devtools)

devtools::create("rCanada") ## if you are  in /my_package
devtools::create("../../rCanada") ## will it erase it,if I lready have it?
> #or usethis::create_package("../r4gc/packages/rCanada2")

library(roxygen2)
## library(testthis). What's the difference from library(testthat) ??
library(testthat) ## do we need it?
## Attaching package: ‘testthat’
#
## The following object is masked from ‘package:devtools’:
#
##   test_file
#
## The following objects are masked from ‘package:magrittr’:
#
##   equals, is_less_than, not


usethis::use_testthat() ## from usethis, which is callsed from devtools


use_vignette(name="my_vignettes") #
use_vignette(name="data_linking")


use_package("data.table")
use_package("magrittr")
use_package("data.table")
use_package("lubridate", type="Imports")  ## how about order ?! lubridate must be after data.table !
use_package("stringr")