-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcode.qmd
253 lines (192 loc) · 9.7 KB
/
code.qmd
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# Code Style {#sec-code-style}
```{r}
#| eval: true
#| echo: false
#| include: false
source("_common.R")
```
```{r}
#| label: co_box_dev
#| echo: false
#| results: asis
#| eval: true
co_box(
color = "y",
header = "Caution",
contents = "The contents for section are being revised. Thank you for your patience."
)
```
:::: {.callout-tip collapse='true' appearance='default'}
## [Accessing applications]{style='font-weight: bold; font-size: 1.15em;'}
::: {style='font-size: 0.95em; color: #282b2d;'}
I've created the [`shinypak` R package](https://mjfrigaard.github.io/shinypak/) In an effort to make each section accessible and easy to follow:
Install `shinypak` using `pak` (or `remotes`):
```{r}
#| code-fold: false
#| message: false
#| warning: false
#| eval: false
# install.packages('pak')
pak::pak('mjfrigaard/shinypak')
```
Review the chapters in each section:
```{r}
#| code-fold: false
#| message: false
#| warning: false
#| collapse: true
library(shinypak)
list_apps(regex = '^21')
```
Launch an app with `launch()`
```{r}
#| code-fold: false
#| eval: false
launch(app = "21_style")
```
Download an app with `get_app()`
```{r}
#| code-fold: false
#| eval: false
get_app(app = "21_style")
```
:::
::::
> ["*We're in the business of keystrokes and neurons*"]{style="font-size: 1.25em; font-weight: bold; font-style: italic;"}
During development, it can be challenging to keep the code in your app-package clean and perfectly formatted. Fortunately, the R ecosystem has some excellent tools for making your code functional and easy to read.
## Code style and formatting
The [`lintr`](https://lintr.r-lib.org/) and [`styler`](https://styler.r-lib.org/) packages in R serve related but distinct purposes and have different focuses in their functionality. The primary difference between `lintr` and `styler` is that `styler` can automatically fix any stylistic issues it identifies in your code (rather than just reporting them).
```{r}
#| label: git_box_21_style
#| echo: false
#| results: asis
#| eval: true
git_margin_box(
contents = "launch",
fig_pw = '75%',
branch = "21_style",
repo = 'sap')
```
### `lintr` {#sec-lintr}
`lintr` is a static code analysis tool used to identify syntax errors, semantic issues, and violations of stylistic guidelines in your code. The package contains a list of 'linters' for various potential problems and can be customized according to your needs. lintr is designed to help improve your code's quality and readability by generating reports in the 'markers' pane. Running `lintr` won't automatically correct the identified issues (you'll need to fix the linting issues it reports manually).
### `styler` {#sec-code-style-styler}
On the other hand, the purpose of `styler` is to ensure consistency in the code formatting, which is crucial if you're working in a team or contributing to open-source projects (like `tidyverse` packages). The `styler` package will change your code's format according to specified style guidelines. These changes include indentation, spaces, and line breaks that adhere to your style guidelines.
While there is some overlap (both packages can help enforce coding style guidelines), `lintr` is a more general tool for code quality, spotting potential issues and bugs. At the same time, `styler` focuses on code formatting and can automatically apply fixes. Many developers find combining both can help catch potential issues and ensure a consistent, readable coding style.
## Checking your code
I've [previously mentioned](@sec-dev-check) running `devtools::check()` can be overkill for your app-package (especially if it's not destined for CRAN). A nice alternative to `check()` is the [`goodpractice` package.](https://mangothecat.github.io/goodpractice/).
`goodpractice::gp()` inspects your package and prints any areas that might need 'good practice' advice:
```{r}
#| eval: false
#| code-fold: false
library(goodpractice)
pkg_checks <- gp(path = ".")
pkg_checks
```
```{verbatim}
Preparing: description
Preparing: lintr
|====================================================================| 100%
Preparing: namespace
Preparing: rcmdcheck
── GP sap ───────────────────────────────────────────────────────
It is good practice to
✖ add a "URL" field to DESCRIPTION. It helps users find information about your
package online. If your package does not have a homepage, add an URL to
GitHub, or the CRAN package package page.
✖ add a "BugReports" field to DESCRIPTION, and point it to a bug tracker.
Many online code hosting services provide bug trackers for free,
https://github.com, https://gitlab.com, etc.
✖ avoid long code lines, it is bad for readability. Also, many people prefer
editor windows that are about 80 characters wide. Try make your lines
shorter than 80 characters
data-raw/tidy_movies.R:49:81
R/data.R:4:81
R/data.R:7:81
R/data.R:17:81
R/data.R:21:81
... and 13 more lines
✖ not import packages as a whole, as this can cause name clashes between the
imported packages. Instead, import only the specific functions you need.
✖ fix this R CMD check NOTE: display_type: no visible binding for global
variable
‘.rs.invokeShinyPaneViewer’ display_type: no visible binding for global
variable
‘.rs.invokeShinyWindowExternal’ display_type: no visible binding for global
variable
‘.rs.invokeShinyWindowViewer’ mod_scatter_display_server : <anonymous>: no
visible binding for global
variable ‘movies’ Undefined global functions or variables:
.rs.invokeShinyPaneViewer
.rs.invokeShinyWindowExternal
.rs.invokeShinyWindowViewer
movies
```
We can also check specific components of our package by looking up the available checks in `all_checks()`:
```{r}
#| eval: false
#| code-fold: false
grep("import", x = all_checks(), value = TRUE)
```
```{bash}
#| eval: false
#| code-fold: false
[1] "no_import_package_as_a_whole"
[2] "rcmdcheck_undeclared_imports"
[3] "rcmdcheck_imports_not_imported_from"
[4] "rcmdcheck_depends_not_imported_from"
[5] "rcmdcheck_triple_colon_imported_objects_exist"
[6] "rcmdcheck_unexported_base_objects_imported"
[7] "rcmdcheck_unexported_objects_imported"
[8] "rcmdcheck_empty_importfrom_in_namespace"
```
All of the checks with the `rcmdcheck_` prefix are part of the `R CMD check` diagnostic, but `goodpractice` comes with other checks that are good practices (even if you're not submitting your package to CRAN).
For example, `no_import_package_as_a_whole` checks the practice we covered in [managing imports](#sec-depends-imports). If we pass the `no_import_package_as_a_whole` check as a character vector to the `checks` argument:
```{r}
#| eval: false
#| code-fold: false
gp(path = ".", checks = 'no_import_package_as_a_whole')
```
Only this check is performed:
```{bash}
#| eval: false
#| code-fold: false
── GP sap ───────────────────────────────────────────────────
It is good practice to
✖ not import packages as a whole, as this can cause name clashes between
the imported packages. Instead, import only the specific functions you need.
───────────────────────────────────────────────────────────────────
```
## Recap
This chapter covered an introduction to some tools and practices for improving and maintaining the quality of the code in your app-package. Maintaining code style and standards (`lintr` and `styler`) and performing thorough checks to adhere to best practices (`goodpractice`) will ensure efficient and reliable development and deployment for your app.
```{r}
#| label: co_box_recap
#| echo: false
#| results: asis
#| eval: true
co_box(
color = "b",
header = "Code tools recap",
look = "default", hsize = "1.10", size = "1.05",
contents = "
This chapter covered:
**Code Linting and Styling**:
- `lintr` is used for checking the code for potential errors and style issues\n
- Can help in identifying syntactical and stylistic problems that might lead to code inefficiency or errors\n
- Linters are instrumental in enforcing coding standards and ensuring consistency across the codebase
- `styler` is used to automatically style the R code in your app-package\n
- `styler` will format R code according to specified style guidelines, ensuring that the code is not only consistent in its look but also adheres to best practices\n
- Automating styling can save time and reduces manual effort in code formatting\n
**Managing Dependencies**:
- The `attachment` package helps in managing these dependencies by automatically listing and updating the packages used in your app-package
- `att_amend_desc` scans the code and identifies all package dependencies\n
- managing dependencies ensures reproducibility and ease of package installation\n
- `desc` assists in handling the `DESCRIPTION` file in your app-package\n
- provides tools for reading, writing, and modifying the `DESCRIPTION` files
**Code Checks**:
- `goodpractice` is designed to help ensure best practices in R coding and package development are adhered to in your app-package\n
- `goodpractice::gp()` performs a comprehensive analysis of the code (beyond `devtools::check()`) and checks for various potential issues like code complexity, redundancy, adherence to coding standards, etc\n
- Offers suggestions for improvements, making it a helpful tool for quality assurance in package development\n
",
fold = FALSE
)
```