Once you know how to do it, creating your own R package is a snip – and it’s well worth the effort as it protects your ‘helper’ functions from your cleaning instinct … i myself am over-prone to:
rm(list=ls())
Which also cleans out the functions that live in the global environment. The solution? Stuff said functions into a namespace, so they do not get cleaned out when you clean up.
To create an R package, we will spend a little time in R setting up the package (R commands will be preceded by `R>`), and a little time in the shell (I use BASH; BASH commands will be preceded by `$`).
Our package will be very simple: we will package our combined head and tail method (described here, improved with thanks to stackoverflow) and quicker-quit (described here).
So, here we go (set the timer):
1/ fire up R …
2/ load the functions you want to put into the package into your R session. I’m going to assume that you will type them in – but you might source() them from some file (see below for to do that):
R> ht <- function(d, m=5, n=m){ # print the head and tail together list=NULL list[[paste0('HEAD #', m)]] <- head(d,m) list[[paste0('TAIL #', n)]] <- tail(d,n) return(list) } R> qw <- function(save='no', ...){ # quit without saving the workspace quit(save=save, ...) }
If you have the functions in a separate file (a good idea if you are going to grow this package), you’d save your fingers and load the functions using the source command:
R> source("~/R/RAhelper.r")
3/ Tell R that you want to put these functions into a package – using the `package.skeleton` function. At this point, you must pick the name of your package (i’m going for ‘RApack’) and specify the path (if you don’t have an ‘~/R/wd/raRlibrary/’ folder this will fail … create one, or change the destination to something that suits you better … such as “~/R/suitsMeBetter/”).
R> package.skeleton(name='RApack', list=c('ht', 'qw'), path='~/R/wd/raRlibrary/')
If you have a clean R session with just these functions in it, there is a neat trick that will save your fingers. You are probably aware that `ls()` returns all the objects in the specified environment – there is an equivalent that returns only functions, it is `lsf.str()`.
If you have been following along, the only functions in your environment will be `ht` and `qw` – so we can just dump all the functions into the build.
Like the source() trick above, this will trick will reward you when you have a larger package – as you can use this command to put all the functions loaded via the source command (and any others in the environment) into your package:
package.skeleton(name='RApack', list=lsf.str(), path='~/R/wd/raRlibrary')
If all has gone well, it’ll return:
Creating directories …
Creating DESCRIPTION …
Creating NAMESPACE …
Creating Read-and-delete-me …
Saving functions and data …
Making help files …
Done.
Further steps are described in ‘~/R/wd/raRlibrary/RApack/Read-and-delete-me’.
4/ Now we edit the documentation. If you are *REALLY* in a rush, you can get around this step by deleting a few files … but even though they are your own functions, I recommend that you document them (what’s obvious now may not be in a few years time).
If you want to delete them, do the following:
$ cd ~/R/wd/raRlibrary/RApack $ rm man Read-and-delete-me
I think you should document your work … so do the following:
$ cd ~/R/wd/raRlibrary/RApack $ vi Read-and-delete-me $ rm Read-and-delete-me
okay, read it? now you can delete it.
We will follow the instructions step-by-step … (If you don’t know how to get out of vi, type `:q!`, and see this vi/vim intro, because I’m going to assume you can edit using vim)
a/ editing ‘man’:
$ cd man $ vi Read-and-delete-me
Now edit is so that it looks something like this (note, I’ve shown the tabs and carriage-return markers):
\name{RApack-package} \alias{RApack-package} \alias{RApack} \docType{package} \title{ a home for miscellanious R functions } \description{ A head+tail method; qwick quitting; and later I'll add some POSIXct helpers ... } \details{ \tabular{ll}{ Package: \tab RApack\cr Type: \tab Package\cr Version: \tab 0.1\cr Date: \tab 2012-07-22\cr License: \tab GPL (>=3)\cr } } \author{ Maintainer: Ricardo <ricardianambivalence@gmail.com> } \references{ ~~ i didn't invent any of this - except the bugs, they are all mine. }
Next, edit the function docs. First we’ll edit `ht`:
$ vi ht.Rd
make it look something like this:
\name{ht} \alias{ht} \title{ A function to reveal the top and bottom of a data-set } \description{ ==> returns head(d,m) + tail(d,n) -- plus some formatting. } \usage{ ht(d, m = 5, n=m) } \arguments{ \item{d}{ the data you want to inspect } \item{m}{ the number of rows to use in head(d,m): defaults to m=5 if unspecified. } \item{n}{ the number of rows to use in tail(d,n): defaults to n=m if unspecified. } } \value{ the return value is a list containing the head and tail, with HEAD #m and TAIL #n the slot names. } \references{ https://www.stackoverflow.com/questions/11600391/combining-head-and-tail-methods-in-r } \examples{ x <- 1:100 ht(x, m=4, n=2) ## The function is currently defined as: function (d, m = 5, n = m) { list >- NULL list[[paste0('HEAD #', m)]] <- head(d,m) list[[paste0('TAIL #', n)]] <- tail(d,n) return(list) } } % Add one or more standard keywords, see file 'KEYWORDS' in the % R documentation directory. \keyword{ utilities } \keyword{ misc }
Finally, we’ll edit `qw`:
$ vi qw.Rd
make it look something like this:
\name{qw} \alias{qw} \title{ qwick quit - without saving the workspace } \description{ wrapper for quit('no') } \usage{ qw(save = "no", ...) } \arguments{ \item{save}{ argument to save workspace - defaults to 'no' } \item{\dots}{ ... } } \value{ quits R without saving the workspace - OR asking if you'd like it saved. } \references{ } \author{ Ricardo } \note{ careful with that qwick-quit - it WILL delete you workspace! } \examples{ # exit R without saving your workspace qw() } % Add one or more standard keywords, see file 'KEYWORDS' in the % R documentation directory. \keyword{ misc } \keyword{ utilities }% __ONLY ONE__ keyword per line
and you are done editing ‘man’.
so go back up one directory
$ cd ..
b/ edit NAMESPACE:
you can probably skip this, but it’s worth covering.
$ vi NAMESPACE
when vi opens, you’ll see:
exportPattern("^[[:alpha:]]+")
What does this mean? It means export all functions that have names beginning with a letter. To see this, do the following in R:
R> lLn <- c(letters, LETTERS, 1:26) R> grep("^[[:alpha:]]+", lLn, value=TRUE)
Note that lLn is 78 elements long, and but that the `grep` command returns only the first 52 items (as the final 26 are not of type `alpha`).
if you only wanted to export a subset of the functions, or felt like typing them all out, you’d replace the regex with:
R> export('ht', 'qw')
finally, we must edit the DESCRIPTION file.
$ vi DESCRIPTION
I made mine look like this:
Package: RApack Type: Package Title: Misc utility functions Version: 0.1 Date: 2012-07-22 Author: Ricardo Maintainer: Ricardo <ricardianambivalence@gmail.com> Description: qwick-quit, head_tail License: GPL-3
c/ we don’t have any C/C++/Fortran code …
d/ we have not compiled our code, so we can leave useDynLib() out.
e/ running R CMD build (note we invoke –vanilla, to stop your tweaks from loading and messing things up):
I’m told that we cannot direct the output of this step, so we need to move to our desired location before we build.
$ cd ~/R/wd/raRpackages $ R --vanilla CMD build ~/R/wd/raRlibrary/RApack
which should return the following:
* checking for file ‘~/R/wd/raRlibrary/RApack/DESCRIPTION’ … OK
* preparing ‘RApack’:
* checking DESCRIPTION meta-information … OK
* checking for LF line-endings in source and make files
* checking for empty or unneeded directories
* building ‘RApack_0.1.tar.gz’
and drop a .tar.gz file in your current working directory (you can check with `$ ls`).
f/ R CMD check(ing): note, you require latex for this step.
$ R --vanilla CMD check RApack_0.1.tar.gz
This will output lots of tests, each of which should be followed with … OK
Now for the good bit — we install our package:
$ R CMD INSTALL -l ~/R/wd/raRpackages ~/R/wd/raRpackages/RApack_0.1.tar.gz
See R CMD INSTALL –help for details: the logic is R CMD [destination] … you can install it somewhere else as follows
$ R CMD INSTALL -l ~/R/otherdir/ ~/R/wd/raRpackages/RApack_0.1.tar.gz
or from R:
R> install.packages(pkgs='~/R/wd/raRpackages/RApack_0.1.tar.gz', type='source', repos=NULL)
now you should be able to load R and attach your package. If not, you may need to add the folder you R CMD INSTALLed into to your library path.
I’ll assume we need to do so, then attach with `require(RApack)` and finally check that it’s on the search path with search()
R> .libPaths("~/R/wd/raRpackages/") R> require(RApack) R> search()
… you should see “package:RApack” amongst the returned packages on the search-path. Try typing in then names of the function, without brackets, to check that their definitions copied across faithfully
R> qw function (save = 'no', ...) { quit(save = save, ...) } <environment: namespace:RApack>
And now they won’t go away when you rm(list=ls()) …
To get rid of it, try:
R> detach(name=package:RApack)