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_pkg
The 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
## directory
Let’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 FALSE
There 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: knitr
The 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_raw
Adding 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 FALSE
The 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 *.Rout
create_vignette
Authoring 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 FALSE
It 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