install.packages(c('devtools', 'testthat', 'covr'))
Log into GitHub and create a new repository (click the plus sign in the top-right corner and choose New repository…)
Create file .Rbuildignore in the root directory of your project
(it contains a list of files which should be omitted during package build)
Fill it with:
^.*\.Rproj$
^\.Rproj\.user$
^.travis.yml$
Add a line *.Rproj to file .gitignore
(we don’t want to include our RStudio project file in the repository)
Initialize package skeleton
(this will generate an R directory and a DESCRIPTION file)
(we are using rstudio = FALSE parameter, because RStudio project files are already created)
devtools::setup(rstudio = FALSE)
Go to tab Build and click Check (or simply hit CTRL+SHIFT+E)
A lot of messages will be displayed but the final one should be R CMD check succeeded
Moreover you should see no more then one warning (the one we can expect is checking PDF version of manual … WARNING and is connected with the fact we do not have LaTeX installed on our computer)
Congratulations! You have just built your first R package (an empty one, but anyway)
Set up directory structure for tests (directory tests with some content will be created)
devtools::use_testthat()
Create file .travis.yml in the root directory of your project
Fill it with:
(adjust the notification email)
# http://docs.travis-ci.com/user/languages/r/
language: r
cache: packages
r:
- release
after_success:
- Rscript -e 'library(covr);coveralls()'
warnings_are_errors: false
notifications:
email:
- your@email
if your package depends on packages available on GitHub but not on CRAN, add a section:
r_github_packages:
- user1/repoName1
- user2/repoName2
Add Travis and Coveralls badges to your package README.md file:
(adjust your login and repository name in URLs) (you can also copy badges code from Travis/Coveralls web sites)
# sampleProject
[![Travis-CI Build Status](https://travis-ci.org/zozlak/sampleProject.png?branch=master)](https://travis-ci.org/zozlak/sampleProject)
[![Coverage Status](https://coveralls.io/repos/zozlak/sampleProject/badge.svg?branch=master&service=github)](https://coveralls.io/github/zozlak/sampleProject?branch=master)
Now lets create a simple function which will take two arguments and return average value of the first one grouped according to values of the second one
Create file myFunction.R in the R directory with a following content:
myFunction = function(values, groups){
result = data.frame(value = values, group = groups) %>%
group_by_('group') %>%
summarize_(avg = ~mean(value, na.rm = TRUE))
return(result)
}
Remarks:
We will use Roxygen syntax.
The easiest way to introduce it will be an example, so lets look at the myFunction.R after adding documentation in a Roxygen syntax:
#' Computes means by groups
#' @description
#' You can put extended description here
#' @details
#' If your function is complicated, you may consider adding a details section
#' @param values numeric vector of values
#' @param groups vector of groups
#' @return data.frame with groups names in first column and average values per group in the second one
#' @export
#' @import dplyr
myFunction = function(values, groups){
result = data.frame(value = values, group = groups) %>%
group_by(group) %>%
summarize(avg = mean(value, na.rm = TRUE))
return(result)
}
Remarks:
Run your function on sample data:
myFunction(1:10, rep(1:2, each = 5))
## Source: local data frame [2 x 2]
##
## group avg
## (int) (dbl)
## 1 1 3
## 2 2 8
Check automatically created documentation:
?myFunction
We will use the testthat library to prepare tests.
Create file tests/testthat/test-myFunction.R:
test_that('my first test', {
expect_equal(
myFunction(1:10, rep(1:2, each = 5)),
data.frame(group = c(1, 2), avg = c(3, 8))
)
})
Remarks:
You should get something like:
Loading sampleProject
Loading required package: testthat
Loading required package: dplyr
Attaching package: ‘dplyr’
Następujące obiekty zostały zakryte z ‘package:stats’:
filter, lag
Następujące obiekty zostały zakryte z ‘package:base’:
intersect, setdiff, setequal, union
Loading required package: ggplot2
Testing sampleProject
1
1. Failure (at test-myFunction.R#2): my first test -----------------------------
myFunction(1:10, rep(1:2, each = 5)) not equal to data.frame(group = c(1, 2), avg = c(3, 8))
Incompatible type for column group: x integer, y numeric
Lets fix our test according to the error message (by providing the group variable as an integer data type):
test_that('my first test', {
expect_equal(
myFunction(1:10, rep(1:2, each = 5)),
data.frame(group = c(1L, 2L), avg = c(3, 8))
)
})
Besides tests provided by you R can perform his own tests on your package code.
Among them there are as useful ones as checking for undefined variables and functions (a curse of R developers).
As these are more advanced topics and your package will still work even R package tests rise some NOTEs or even WARNINGs on it you can skip this section if you find it to difficult (but if you want to put your package in CRAN at some point you will have master them anyway).
Among check results you should find:
* checking R code for possible problems ... NOTE
myFunction: no visible binding for global variable ‘group’
myFunction: no visible binding for global variable ‘value’
This message is caused by the fact that we are trying to use undeclared variables group and value in our function.developing packages you should avoid non-standard evaluation and rather write your function like that:
#' Computes means by groups
#' @description
#' You can put extended description here
#' @details
#' If your function is complicated, you may consider adding a details section
#' @param values numeric vector of values
#' @param groups vector of groups
#' @return data.frame with groups names in first column and average values per group in the second one
#' @export
#' @import dplyr
myFunction = function(values, groups){
result = data.frame(value = values, group = groups) %>%
group_by_('group') %>%
summarize_(avg = ~mean(value, na.rm = TRUE))
return(result)
}
At the moment we should have an R project configured to work with Travis and Coveralls with a sample function and tests.
No lets try to see a continues integration at work.
Everybody can install your package:
devtools::install_github('yourLogin/yourRepository')