Acknowledgement
Setting up an R package isn’t really intuitive as the developer needs a basic understanding of some package conventions and good practice methods. There are multiple packages in the R landscape that help doing exactly this. personalr
makes heavy usage of the most important package development helper package: usethis
. It has a ton of useful functions but the developer has to know which of them is needed for the individual purpose.
personalr
is more or less a wrapper around several usethis functions and completes the whole thing with some helper functions. The package setup that personalr creates is also based on the tidyverse
package.
Everything you need to know about R package development is perfectly summarized in Hadley Wickham’s book R Packages.
Usage
First setup
The main function of personalr
is setup_package()
. Handed a valid path, the desired package name and a vector or list of package names (the ‘core’ of the personal package that is about to be created) it does the following things:
- create the project with the intended package name
- create all basic package files like DESCRIPTION (including the Imports of the ‘core’ packages), NAMESPACE or the “R” directory
- create a basic Readme
- create all scripts and functions in the R directory that are required to attach the core packages
- add the pipe operator
magrittr::%>%()
to your exported functions so it is usable as soon as the package is loaded - document and install the package
- open the new package in a separate R session.
The following example creates the new package "mypackage"
with the core
packages dplyr, glue and purrr in a temporary directory.
library(personalr)
temp_directory <- tempdir()
setup_package(path = temp_directory, packagename = "mypackage", core = c("dplyr", "glue", "purrr"))
#> ✔ Creating '/tmp/RtmpSv9D1Z/mypackage/'
#> ✔ Setting active project to '/tmp/RtmpSv9D1Z/mypackage'
#> ✔ Creating 'R/'
#> ✔ Writing 'DESCRIPTION'
#> Package: mypackage
#> Title: What the Package Does (One Line, Title Case)
#> Version: 1.0.0
#> 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
#> Roxygen: list(markdown = TRUE)
#> RoxygenNote: 7.2.1
#> ✔ Writing 'NAMESPACE'
#> ✔ Setting active project to '<no active project>'
#> ✔ Setting active project to '/tmp/RtmpSv9D1Z/mypackage'
#> ✔ Writing 'R/mypackage-package.R'
#> ✔ Writing 'README.md'
#> ✔ Adding 'dplyr' to Imports field in DESCRIPTION
#> ✔ Adding 'glue' to Imports field in DESCRIPTION
#> ✔ Adding 'purrr' to Imports field in DESCRIPTION
#> ✔ Adding 'cli' to Imports field in DESCRIPTION
#> ✔ Adding 'crayon' to Imports field in DESCRIPTION
#> ✔ Adding 'rstudioapi' to Imports field in DESCRIPTION
#> ✔ Writing 'R/core.R'
#> ✔ Writing 'R/attach.R'
#> ✔ Writing 'R/conflicts.R'
#> ✔ Writing 'R/pipe.R'
#> ✔ Writing 'R/utils.R'
#> ✔ Writing 'R/zzz.R'
#> • Updating documentation and installing mypackage...
#> ℹ Loading mypackage
#> ── Attaching packages ─────────────────────────────────────── mypackage 1.0.0 ──
#>
#> ✔ dplyr 1.0.9 ✔ purrr 0.3.4
#> ✔ glue 1.6.2
#>
#> ──────────────────────────────────────────────────────────────── Ready to go! ──
#>
#> Writing 'NAMESPACE'
#> Writing 'NAMESPACE'
#> Writing 'mypackage-package.Rd'
#> Writing 'pipe.Rd'
#> Running /opt/R/4.2.1/lib/R/bin/R CMD INSTALL /tmp/RtmpSv9D1Z/mypackage \
#> --install-tests
#> * installing to library ‘/home/runner/work/_temp/Library’
#> * installing *source* package ‘mypackage’ ...
#> ** using staged installation
#> ** R
#> ** byte-compile and prepare package for lazy loading
#> ** help
#> *** installing help indices
#> ** building package indices
#> ** testing if installed package can be loaded from temporary location
#> ** testing if installed package can be loaded from final location
#> ** testing if installed package keeps a record of temporary installation path
#> * DONE (mypackage)
#> ✔ Setting active project to '<no active project>'
Once the setup is finished and the new package installed, the new package should be opened in a separate R session. It will show the following files and directories
#> /tmp/RtmpSv9D1Z/mypackage
#> ├── DESCRIPTION
#> ├── NAMESPACE
#> ├── R
#> │ ├── attach.R
#> │ ├── conflicts.R
#> │ ├── core.R
#> │ ├── mypackage-package.R
#> │ ├── pipe.R
#> │ ├── utils.R
#> │ └── zzz.R
#> ├── README.md
#> └── man
#> ├── mypackage-package.Rd
#> └── pipe.Rd
Update your package
There are basically two reasons why you want to update your personal package:
- You want to update the list of
core
packages - You want to add a helper function so you can call it when the package is loaded (i.e. ‘export’ a function)
Update your ‘core’ packages
There is a separate function in personalr
to update your list of core
packages: update_core()
. It can either append new packages to the existing core
or overwrite it completely (with the logical argument append
).
Assuming you have run the above code and have created the personal package "mypackage"
with the core
packages “dplyr”, “glue” and “purrr” you can add another package, e.g. “tibble” by running the following code (please note that the example uses temporary directories and if you run this on your machine it’s easier to open the project and set path = "."
).
update_core(path = temp_directory, packagename = "mypackage", core = "tibble", append = TRUE)
#> ✔ Setting active project to '/tmp/RtmpSv9D1Z/mypackage'
#> ✔ Adding 'tibble' to Imports field in DESCRIPTION
#> ℹ If you really want to update your core you'll have toconfirm the following dialogue...!
#> ✔ Leaving 'R/core.R' unchanged
#> ✔ Setting Version field in DESCRIPTION to '1.0.1'
#> • Updating documentation and installing mypackage...
#> ℹ Loading mypackage
#>
#> Running /opt/R/4.2.1/lib/R/bin/R CMD INSTALL /tmp/RtmpSv9D1Z/mypackage \
#> --install-tests
#> * installing to library ‘/home/runner/work/_temp/Library’
#> * installing *source* package ‘mypackage’ ...
#> ** using staged installation
#> ** R
#> ** byte-compile and prepare package for lazy loading
#> ** help
#> *** installing help indices
#> ** building package indices
#> ** testing if installed package can be loaded from temporary location
#> ** testing if installed package can be loaded from final location
#> ** testing if installed package keeps a record of temporary installation path
#> * DONE (mypackage)
#> ✔ Setting active project to '<no active project>'
Now "mypackage"
attaches “dplyr”, “glue”, “purrr” and “tibble” when it is loaded. If you want to overwrite the core (i.e. only use “tibble” and drop the other packages) just set append = FALSE
in the above code chunk.
Add your own exported helper function
One of the strengths of a package is that you are able to save your helper functions inside the package and make them available in your code without littering the Global Environment.
Let’s say you often use the negated version of %in%
to select values that are not in a vector. The typical way to do it is !value %in% vector
. This is somewhat annoying as it’s hard to read the code and see the exclamation mark at the beginning of the expression. So now we want to write and export our own little helper for the negated version of %in%
, and we call it %nin%
.
If you run this inside your project
usethis::use_r("nin")
it will create a new script "R/nin.R"
and open it directly. Add the code of your helper function and don’t forget to export it with #' @export
(this means the next time you document and install your package the new function will be exported and available for usage).
#' @export
'%nin%' <- Negate(`%in%`)
To update your package you should consider changing the package version to make more clear something changed by running
usethis::use_version()
and afterwards documenting and installing the new version by running