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.1 GC groups and repos
- Discussions:
- Codes:
- Packages101 repo: https://gccode.ssc-spc.gc.ca/r4gc/gc-packages/packages101
- Related codes and resources: https://gccode.ssc-spc.gc.ca/r4gc
25.1.3 How to contribute
Anyone: Fork Packages101 repo - modify - commit changes - push - submit request to merge
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)
::create("rCanada") ## if you are in /my_package
devtools::create("../../rCanada") ## will it erase it,if I lready have it?
devtools> #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
::use_testthat()
usethis## use_testthat()
use_news_md()
use_test("iviDT")
1
x <- 2
y <-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:
::document()
devtools## 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")
- 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
- 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
- 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
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()
ordevtools::check()
which will place it in “../yourRPackageProject” directory.
- this .tar ball is obtained by running
- [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!
>
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")