2 R packages
As I said before, R package is a very convenient 5 way to share code with others and, more importantly, myself. I create a template, minir, with the intention to minimize (no function, no data), but it still becomes a bit overwhelm for beginners. Anyhow, I will explain how to use it in great detail, especially why I choose one way instead of the other.
2.1 basics
- dependency
- All needed packages should be listed in
Imports
(we don’t useDepends
). Remotes
only specifies where to find a package listed inImports
, if not from CRAN.
- All needed packages should be listed in
- testthat
- If you want to run arbitrary code, add
testthat::expect_true(T)
to prevent it from being skipped. testthat::test_dir()
dictate at least onetest-*.R
thoughdevtools::test()
only requirestests/testthat/
.- use
tolower(Sys.getenv('CI')) == 'true')
to selectively run some tests on Travis.
- If you want to run arbitrary code, add
- vignette
- You should show things happened after your package is installed, which means
library(pkg)
andsystem.file(package = 'pkg')
. Counter-intuitive as it seems when you are developing a package, it’s the most natural way for the user.
- You should show things happened after your package is installed, which means
- documentation
- Build panel =>
More
=>Configure Build Tools...
=>Configure...
=> check Build & Reload 6. - use
foobar()
rather thanpkg::foobar()
in@examples
, since there is an unspoken rule convention to assumelibrary(pkg)
and it makes testing examples very convenient (More
=>Load All
). @export
means everywhere,@noRd
means nowhere,@keywords internal
means?foobar
but not listed in index.
- Build panel =>
- pkgdown
- data
devtools::ues_data()
store each object with its name in separate.rds
file underdata/
.devtools::ues_data(internal=TURE)
store all the internal data in a single file,R/sysdata.rda
.- refer to rGEO.data for how I cache data
- others
2.2 namespace
Usually, @importFrom
should appear at the function using it (multiple times is okay, roxygen2 handles that).
But some (too) common things are put into R/aaa.R
:
#' @importFrom magrittr %>%
#' @export
::`%>%` magrittr
- Here we import
%>%
, sincedevtools::test()
won’t help us, even if we use%>%
in our function without importing it. Actually, when tests are executed, testthat is loaded, even worse, it exports%>%
(seetestthat::`%>%`
&?`%>%`
). - Exporting
%>%
makes it easier to write tests & examples. Althougth you can live without it 8, users would be confusing when run the examples, since the basic assumption is that they havelibrary()
your package.
Opionally, you can also import other pipes:
#' @importFrom magrittr %T>%
#'
NULL
NULL
is necessary, otherwise the command would be ignored.
2.3 Rcpp
- set up
create a package (copy
minir
)usethis::use_rcpp()
create a
.cpp
file insrc/
set up appropriate
src/Makevars
, like:PKG_CXXFLAGS = -std=c++17
You should make it as portable as possible. For example,
CXX = clang++
is a bad idea here, since others may haven’t install it and your code shouldn’t depend on certain complier.add to
zzz.R
function (libpath) { .onUnload <-library.dynam.unload("mypackage", libpath) }
- best practice
- use
Build
orLoad All
intead of sourcing individual.cpp
file. 9 .cpp
file in a package shouldn’t contain// [[Rcpp::plugins(cpp17)]]
, that’s the job ofsrc/Makevars
- use
- exporting & importing C++ code
2.4 documentation template
#' @title A sentence in one line.
#'
#' @description A paragraph which briefly describe what the function does,
#' usually supplements the title.
#'
#' @param name class. One sentence or paragraph.
#' @param name1 integer scalar. When the length must be 1, add 'scalar'.
#' @param name2 string. Means _character scalar_, consistent with C++.
#' @param ... passed onto [foo::bar()].
#'
#' @return list
#'
#' 1. x: string. name.
#'
#' 1. y: numeric. height.
#'
#' @details A (often long) section which goes into details about how the
#' function works.
#'
#' Many paragraphs is ok.
#'
#' @seealso [foobar2]
#'
#' @examples
#' foobar(1:5)
#'
#' \donotrun {
#' foobar("You're a doubi.")
#' }
#'
#' @section Other points: One or many paragraphs.
#'
#' @export
function(...) {
foobar <- }
multiple functions example
Maybe Python is more convenient, anyhow, I learned R first.↩︎
The option is saved in
.Rproj.user/***/build_options
,***
is a hash string like6AA761D1
to distinguish users.↩︎I used to put it
inst/
, but I realized I have no interest in building site from CRAN source package.↩︎Again, testthat exports %>%. Even if you use
%>%
in tests without exporting it, no one warns you.↩︎Actually, writing a pakcage is the standard solution when you want to use more than one
.cpp
file.↩︎