-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME.Rmd
118 lines (86 loc) · 3.28 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# :eyes: assert
<!-- badges: start -->
[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/assert)](https://cran.r-project.org/package=assert)
![R-CMD-check](https://github.com/OlivierBinette/assert/workflows/R-CMD-check/badge.svg)
<!-- badges: end -->
Lightweight validation tool for checking function arguments and data analysis scripts. This is an alternative to stopifnot() from the 'base' package and to assert_that() from the 'assertthat' package. It provides more informative error messages and facilitates debugging.
<img src="gif.gif" width="700">
## Installation
You can install the released version of assert from [CRAN](https://CRAN.R-project.org) with:
``` r
install.packages("assert")
```
And the development version from [GitHub](https://github.com/) with:
``` r
# install.packages("devtools")
devtools::install_github("OlivierBinette/assert")
```
## Examples
Assertions throughout a data analysis workflow:
```{r data-analysis}
library(assert)
attach(ChickWeight)
# Passing assertions
assert(is.numeric(weight),
all(weight > 0))
```
```{r, eval=FALSE}
# Failing assertions
assert(all(Diet > 0),
is.numeric(Times))
#> Error in assert(all(Diet > 0), is.numeric(Times)) :
#> Failed checks:
#> all(Diet > 0) (NA)
#> is.numeric(Times) (object 'Times' not found)
```
Validate function arguments:
```{r argument-validation}
# Sample from a multivariate normal distribution
rmultinorm <- function(k, mu, sigma) {
assert(is.numeric(k),
length(k) == 1,
k > 0,
msg = "Number of samples `k` should be a positive integer")
assert(is.numeric(mu),
is.matrix(sigma),
all(length(mu) == dim(sigma)),
msg = "Mean vector should match the covariance matrix dimensions.")
p <- length(mu)
t(chol(sigma)) %*% matrix(rnorm(p*k, 0, 1), nrow=p) + mu
}
mu <- c(0,10)
sigma <- matrix(c(2,1,1,2), nrow=2)
rmultinorm(3, mu, sigma)
```
```{r, eval=FALSE}
rmultinorm(mu, 3, sigma)
#> Error: in rmultinorm(k = mu, mu = 3, sigma = sigma)
#> Failed checks:
#> length(k) == 1
#> k > 0 (c(FALSE, TRUE))
#>
#> Number of samples `k` should be a positive integer
```
## Philosophy
Function argument checks should throw errors as early as possible and at the *function* level. When `assert` is used within a function, all assertions are executed within `tryCatch` statements, error messages are recovered, and a single error is thrown from `assert`. This ensures that "object not found" errors and assertion execution errors are also caught as part of argument checks. The function signature and call are also included as part of error messages to facilitate debugging.
## Performance
Because `assert` executes each assertion inside of a tryCatch() statement and recovers error messages, it is not quite as efficient as `stopifnot` (which sequentially executes assertions without catching potential errors). `assertthat::assert_that` has the most overhead.
```{r}
library(assertthat)
bench::mark(assert(TRUE),
assert_that(TRUE),
stopifnot(TRUE),
check=FALSE)
```