The create_pkg, and its sister functions create_data_raw and create_vignette, are provided to build a package skeleton that I prefer. These functions are based on the devtools create, use_vignette and use_data_raw functions.
This vignette will provided a detailed explanation of the package structure and design I prefer for R package development.
This vignette only needs the qwraps2 namespace loaded and attached.
create_pkgThe basic package skeleton is created with the create_pkg function.
The path is a directory to use for the package. For the examples to follow we will use a temporary directory.
tmp_dir <- tempdir()
pkg_dir <- paste(tmp_dir, "eg.pkg", sep = "/")
pkg_dir
## [1] "/var/folders/76/c_58hkfs13g3rn64v707fdxh0000gp/T//RtmpNuKUOh/eg.pkg"
create_pkg(pkg_dir)
## Warning in normalizePath(path.expand(path)): path[1]="/var/folders/76/
## c_58hkfs13g3rn64v707fdxh0000gp/T//RtmpNuKUOh/eg.pkg": No such file or
## directoryLet’s look at the files and the skeleton created for the package. We’ll do this a few times so a tree function will be created and used:
tree <- function(pkg_dir) {
files <- list.files(pkg_dir,
all.files = TRUE,
full.names = TRUE,
recursive = TRUE,
include.dirs = TRUE)
files <- data.frame(filename = gsub(tmp_dir, "", files), file.info(files))
print(data.tree::as.Node(files, pathName = "filename"), "isdir")
}
tree(pkg_dir)
## levelName isdir
## 1 eg.pkg NA
## 2 ¦--.Rbuildignore FALSE
## 3 ¦--.gitignore FALSE
## 4 ¦--CONTRIBUTING.md FALSE
## 5 ¦--DESCRIPTION FALSE
## 6 ¦--NAMESPACE FALSE
## 7 ¦--NEWS.md FALSE
## 8 ¦--R TRUE
## 9 ¦--README.md FALSE
## 10 ¦--examples TRUE
## 11 °--makefile FALSEThere are two empty directories created, the R directory and the examples directory. The examples directory is expected to be used to store the examples for the documentation written, using roxygen2 markup, in the files within the R directory. More details are given in a later section.
The files populating the root directory of the package includes the needed DESCRIPTION file, which you, the package developer, will need to edit. Details on the metadata and what/how to edit it is found in the R packages book by Hadley Wickham.
cat(readLines(paste0(pkg_dir, "/DESCRIPTION")), sep = "\n")
## Package: eg.pkg
## Title: What the Package Does (one line, title case)
## Version: 0.0.0.9000
## Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
## Description: What the package does (one paragraph).
## License: What license is it under?
## Encoding: UTF-8
## LazyData: true
## VignetteBuilder: knitrThe NAMESPACE file is provided, but should not be edited by the end user, let devtools::document(), called via the makefile handle the edits to the NAMESPACE file. General package documentation in the form of a README.md, CONTRIBUTING.md, and NEWS.md are provided. The .Rbuildignore and .gitignore files are provided with commonly needed expressions. Lastly, the makefile is provided for building, checking, and installing the package. A help recipe has been provided in the makefile.
make help
The recipes in the makefile are:
This makefile is built to be useful for most R package development, it is copied into new R packages created by qwraps2::create_pkg, see vignette("create_pkg", package = "qwraps2").
usage: make [build-options] [check-options] [install-options] [targets]
| Target | Description |
|---|---|
| all | Build the man files, vignettes, and the <package>_<version>.tar.gz file |
| help | Display usage, targets, and options provided by the makefile |
| check | Run R CMD check |
| install | Install the R package via R CMD INSTALL |
| document | Construct raw data sets, if needed, and build/update man files. |
| vignettes |
| Options | Description |
|---|---|
| build-options |
If the rstudio option is used when calling create_pkg then a .Rproj file is added to the root directory.
The ci argument is used to add template files for either Travis CI or gitlab runners.
The use_data_raw option is used if raw data is to be part of the package. calling the create_data_raw function can be called later to create the directories and place the generic makefiles as needed to work with the makefile in the package root directory.
create_data_rawAdding the data-raw and data directories to the package, if not done on the initial construction, is done via
The updated package structure is:
tree(pkg_dir)
## levelName isdir
## 1 eg.pkg NA
## 2 ¦--.Rbuildignore FALSE
## 3 ¦--.gitignore FALSE
## 4 ¦--CONTRIBUTING.md FALSE
## 5 ¦--DESCRIPTION FALSE
## 6 ¦--NAMESPACE FALSE
## 7 ¦--NEWS.md FALSE
## 8 ¦--R TRUE
## 9 ¦--README.md FALSE
## 10 ¦--data TRUE
## 11 ¦--data-raw TRUE
## 12 ¦ °--makefile FALSE
## 13 ¦--examples TRUE
## 14 °--makefile FALSEThe makefile in the data-raw is generic such that any .R file will be evaluated. Noting that some scripts needed to create a data set might require a non-trivial amount of time to evaluate, the makefile creates, and then uses, md5sums for assessing if the .R file(s) needs to be re-evaluated instead of the standard file modified time stamp.
cat(readLines(paste0(pkg_dir, "/data-raw/makefile")), sep = "\n")
## SOURCES = $(wildcard *.R)
## TARGETS = $(addsuffix .Rout, $(basename $(SOURCES)))
##
## .PRECIOUS: %.md5
##
## all: $(TARGETS)
## find ../data -type f | gawk {'print substr($$1, 4)'} | gawk -F'[.]' '{print $$1}' > ../data/datalist
##
## %.Rout : %.R.md5
## @echo "Building: " $@
## R CMD BATCH --vanilla $(basename $<)
##
## %.md5 : %
## @echo "md5sum check: " $@
## @md5sum $< | cmp -s $@ -; if test $$? -ne 0; then md5sum $< > $@; fi
##
## clean:
## /bin/rm -f *.Routcreate_vignetteAuthoring vignettes is a great way to document your package. I have found that the parallel development of a ‘how to use this package’ vignette while writing and testing the package code has made development and documentation easier.
Developing the vignette and the code base can be painful. Consider a standard .Rmd or .Rnw file with with R code in individual chunks. Having to re-evaluate all the chunks can be time consuming and cumbersome depending on your IDE. An alternative method is to author .R files with the expectation of using knitr::spin to generate the .Rmd file that then gets processed into the vignette(s).
The create_vignette places a template vignette file and makefile into a vignettes directory.#’
create_vignette(name = "egVign.R", path = pkg_dir)
tree(pkg_dir)
## levelName isdir
## 1 eg.pkg NA
## 2 ¦--.Rbuildignore FALSE
## 3 ¦--.gitignore FALSE
## 4 ¦--CONTRIBUTING.md FALSE
## 5 ¦--DESCRIPTION FALSE
## 6 ¦--NAMESPACE FALSE
## 7 ¦--NEWS.md FALSE
## 8 ¦--R TRUE
## 9 ¦--README.md FALSE
## 10 ¦--data TRUE
## 11 ¦--data-raw TRUE
## 12 ¦ °--makefile FALSE
## 13 ¦--examples TRUE
## 14 ¦--makefile FALSE
## 15 °--vignettes TRUE
## 16 ¦--egVign.R FALSE
## 17 °--makefile FALSEIt is critically important that you do not use devtools::build_vignettes() as this will over write the .R file. If you need to build the vignettes without building the whole package use the makefile in the package root directory and call
make .vignettes.Rout
The best example for this style of package development is the qwraps2 package on github.
print(sessionInfo(), local = FALSE)
## R version 3.4.4 (2018-03-15)
## Platform: x86_64-apple-darwin17.3.0 (64-bit)
## Running under: macOS High Sierra 10.13.4
##
## Matrix products: default
## BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
## LAPACK: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] qwraps2_0.3.0 knitr_1.20
##
## loaded via a namespace (and not attached):
## [1] Rcpp_0.12.16 plyr_1.8.4 compiler_3.4.4
## [4] pillar_1.2.1 RColorBrewer_1.1-2 influenceR_0.1.0
## [7] bindr_0.1.1 viridis_0.5.1 tools_3.4.4
## [10] digest_0.6.15 jsonlite_1.5 viridisLite_0.3.0
## [13] gtable_0.2.0 evaluate_0.10.1 memoise_1.1.0
## [16] tibble_1.4.2 rgexf_0.15.3 pkgconfig_2.0.1
## [19] rlang_0.2.0.9001 igraph_1.2.1 rstudioapi_0.7
## [22] yaml_2.1.18 bindrcpp_0.2.2 gridExtra_2.3
## [25] downloader_0.4 withr_2.1.2 DiagrammeR_1.0.0
## [28] dplyr_0.7.4 stringr_1.3.0 htmlwidgets_1.0
## [31] devtools_1.13.5 hms_0.4.2 grid_3.4.4
## [34] rprojroot_1.3-2 data.tree_0.7.5 glue_1.2.0
## [37] R6_2.2.2 Rook_1.1-1 XML_3.98-1.10
## [40] rmarkdown_1.9 ggplot2_2.2.1.9000 tidyr_0.8.0
## [43] purrr_0.2.4 readr_1.1.1 magrittr_1.5
## [46] backports_1.1.2 scales_0.5.0.9000 htmltools_0.3.6
## [49] assertthat_0.2.0 colorspace_1.3-2 brew_1.0-6
## [52] stringi_1.1.7 visNetwork_2.0.3 lazyeval_0.2.1
## [55] munsell_0.4.3