-
Notifications
You must be signed in to change notification settings - Fork 2
/
README.Rmd
143 lines (109 loc) · 3.92 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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
---
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%"
)
```
# refactor
{refactor} helps you test your refactored code with real live data. It's
a complement to unit tests, useful in the dirtier stage of refactoring,
when we're not quite sure if our unit tests are good enough or if we don't want to
write them yet because there are too many things changing.
{refactor} lets you run both the original and refactored
version of your code and checks whether the output is the same and if it runs
as fast.
As you encounter failures you might improve your unit tests, and
when you're comfortable with your work you can remove the original version
## Installation
Install with:
``` r
remotes::install_github("moodymudskipper/refactor")
```
## Examples
```{r}
library(refactor)
```
`%refactor%` by default checks that the output value is consistent between
the original and refactored expressions.
They'll often be used on the body of a function but can be used on any expression.
Here I intend to correct an inefficient use of the `apply()` function,
but used `pmax` incorrectly:
```{r, error=TRUE}
fun1 <- function(data) {
apply(data, 1, max)
} %refactor% {
pmax(data)
}
fun1(cars)
```
Now using it correctly:
```{r}
fun2 <- function(data) {
apply(data, 1, max)
} %refactor% {
do.call(pmax, data)
}
fun2(cars)
```
We can use the option `refactor.env` to test that the local environment isn't
changed in different ways by the original and refactored expression.
```{r, error=TRUE}
options("refactor.env" = TRUE)
{
# original code
data <- cars
i <- 1
apply(data, i, max)
} %refactor% {
# refactored code
do.call(pmax, cars)
}
```
We can use the option `refactor.time` to test that the refactored solution is
faster.
```{r, error=TRUE}
# use bigger data so execution time differences are noticeable
cars2 <- do.call(rbind, replicate(1000,cars, F))
options("refactor.time" = TRUE)
fun3 <- function(data) {
do.call(pmax, data)
} %refactor% {
apply(data, 1, max)
}
fun3(cars2)
```
## Other functions
It's often easier to use the functions below:
* `%refactor_chunk%` behaves like `%refactor%` with `options(refactor.value = FALSE, refactor.env = TRUE, refactor.time = FALSE)`,
it's convenient to refactor chunks of code that modify the local environment.
* `%refactor_value%` behaves like `%refactor%` with `options(refactor.value = TRUE, refactor.env = FALSE, refactor.time = FALSE)`,
it's convenient to refactor the body of a function that returns a useful value.
* `%refactor_chunk_and_value%` behaves like `%refactor%` with `options(refactor.value = TRUE, refactor.env = TRUE, refactor.time = FALSE)`,
it's convenient to refactor the body of a function that returns a closure.
* `%refactor_chunk_efficiently%`, `%refactor_value_efficiently%` and `%refactor_chunk_and_value_efficiently%` are variants of the above
which also check the improved execution speed of the refactored solution
* `%ignore_original%` and `%ignore_refactored%` are useful when original and
refactored code give different results (possibly because one of them is wrong)
and we want to keep both codes around without commenting.
## Additional functions
We provide a few helper for refactoring tasks, check out the doc!
## Caveats
We don't control that side effects are the same on both sides, with the exception
of modifications to the local environment. This means
the following for instance might be different in your refactored code
and you won't be warned about it :
* modified environments (other than local)
* written files
* printed output
* messages
* warnings
* errors
We might be able to support some of those though.
More importantly since both side are run, side effects will be run twice and in some case
this might change the behavior of the program, so use cautiously.