Skip to content

Commit 20e4cb6

Browse files
authored
feat(exercise): Support exercise.pipe option (#804)
1 parent 58aa962 commit 20e4cb6

File tree

9 files changed

+100
-10
lines changed

9 files changed

+100
-10
lines changed

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
- Added a new quick restore option that restores both the last submitted exercise code and the output of that submission, if the output is available to be restored. This option is enabled by setting the global option `tutorial.quick_restore = 2` or the environment variable `TUTORIAL_QUICK_RESTORE=2`. This option augments the quick restore value when `TRUE` or `1`, wherein only the last submitted **code** is restored, such that users will need to click the "Submit" button to evaluate and see the output. (#794)
1010

11+
- A new `exercise.pipe` tutorial or exercise chunk option can now be used to determine which pipe operator is used for interactive exercises. The default is `"|>"` (the native R pipe) when the tutorial is rendered with R >= 4.1.0, or `"%>%"` otherwise (the magrittr pipe). You can set the pipe used for the tutorial using `tutorial_options()`, or you can use `exercise.pipe` as a knitr chunk option on an individual exercise chunk. (#804)
12+
1113
# learnr 0.11.4
1214

1315
- Moved curl from Imports to Suggests. curl is only required when using an external evaluator (#776).

R/knitr-hooks.R

+18-6
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,16 @@ tutorial_knitr_options <- function() {
374374
completion <- as.numeric(options$exercise.completion %||% 1 > 0)
375375
diagnostics <- as.numeric(options$exercise.diagnostics %||% 1 > 0)
376376
startover <- as.numeric(options$exercise.startover %||% 1 > 0)
377-
paste0('<div class="tutorial-', class,
378-
'" data-label="', options$label,
379-
'" data-completion="', completion,
380-
'" data-diagnostics="', diagnostics,
381-
'" data-startover="', startover,
382-
'" data-lines="', lines, '">')
377+
paste0(
378+
'<div class="tutorial-', class,
379+
'" data-label="', options$label,
380+
'" data-completion="', completion,
381+
'" data-diagnostics="', diagnostics,
382+
'" data-startover="', startover,
383+
'" data-lines="', lines,
384+
'" data-pipe="', htmltools::htmlEscape(exercise_option_pipe(options)),
385+
'">'
386+
)
383387
}
384388
# after exercise
385389
else {
@@ -575,3 +579,11 @@ verify_tutorial_chunk_label <- function() {
575579
)
576580
}
577581
}
582+
583+
exercise_option_pipe <- function(options = knitr::opts_chunk$get()) {
584+
if (!is.null(options[["exercise.pipe"]])) {
585+
return(options[["exercise.pipe"]])
586+
}
587+
588+
if (getRversion() < "4.1.0") "%>%" else "|>"
589+
}

R/options.R

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
#' (defaults to \code{30}).
1717
#' @param exercise.lines Lines of code for exercise editor (defaults to the
1818
#' number of lines in the code chunk).
19+
#' @param exercise.pipe The characters to enter when the user presses the
20+
#' "Insert Pipe" keyboard shortcut in the exercise editor
21+
#' (`Ctrl/Cmd + Shift + M`). This can be set at the tutorial level or for an
22+
#' individual exercise. If `NULL` (default), the base R pipe (`|>`) is used
23+
#' when the tutorial is rendered in R >= 4.1.0, otherwise the \pkg{magrittr}
24+
#' pipe (`%>%`) is used.
1925
#' @param exercise.blanks A regular expression to be used to identify blanks in
2026
#' submitted code that the user should fill in. If `TRUE` (default), blanks
2127
#' are three or more underscores in a row. If `FALSE`, blank checking is not
@@ -37,6 +43,7 @@ tutorial_options <- function(exercise.cap = NULL,
3743
exercise.eval = FALSE,
3844
exercise.timelimit = 30,
3945
exercise.lines = NULL,
46+
exercise.pipe = NULL,
4047
exercise.blanks = NULL,
4148
exercise.checker = NULL,
4249
exercise.error.check.code = NULL,
@@ -53,6 +60,7 @@ tutorial_options <- function(exercise.cap = NULL,
5360
eval(parse(text = sprintf(set_option_code, "exercise.eval")))
5461
eval(parse(text = sprintf(set_option_code, "exercise.timelimit")))
5562
eval(parse(text = sprintf(set_option_code, "exercise.lines")))
63+
eval(parse(text = sprintf(set_option_code, "exercise.pipe")))
5664
eval(parse(text = sprintf(set_option_code, "exercise.blanks")))
5765
eval(parse(text = sprintf(set_option_code, "exercise.checker")))
5866
eval(parse(text = sprintf(set_option_code, "exercise.error.check.code")))

inst/lib/tutorial/tutorial.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/lib/tutorial/tutorial.js.map

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

learnr-js/tutorial/tutorial.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,9 @@ Tutorial.prototype.$initializeExerciseEditors = function () {
10871087
}
10881088
})
10891089
}
1090-
bindInsertKey('insertPipe', 'Ctrl+Shift+M', { r: ' %>% ' })
1090+
1091+
const pipeCode = exercise.attr('data-pipe') || '%>%'
1092+
bindInsertKey('insertPipe', 'Ctrl+Shift+M', { r: ' ' + pipeCode })
10911093
bindInsertKey('insertArrow', 'Alt+-', { r: ' <- ', fallback: ' = ' })
10921094

10931095
// re-focus the editor on run button click

man/tutorial_options.Rd

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
title: "Exercise Pipe Option"
3+
output: learnr::tutorial
4+
runtime: shiny_prerendered
5+
---
6+
7+
```{r setup, include=FALSE}
8+
library(learnr)
9+
library(dplyr)
10+
knitr::opts_chunk$set(echo = FALSE)
11+
```
12+
13+
14+
## Ceci n'est pas une pipe
15+
16+
Qu'est-ce qu'une pipe, sinon l'idée d'une pipe?
17+
18+
You can set the characters used for the pipe shortcut at the tutorial level with
19+
20+
```r
21+
knitr::opts_chunk$set(exercise.pipe = "%>%")
22+
```
23+
24+
Or you can set the pipe option at the individual level using the `exercise.pipe` chunk option.
25+
26+
````{verbatim echo = TRUE}
27+
```{r base-pipe, exercise=TRUE, exercise.pipe="|>"}
28+
mtcars count(cyl)
29+
```
30+
````
31+
32+
By default, if not set otherwise set, learnr will use the base R pipe (`|>`) when the tutorial is rendered in R >= 4.1.0.
33+
34+
### Old school
35+
36+
In this next chunk, pressing `Ctrl/Cmd + Shift + M` enters the magrittr pipe: `%>%`.
37+
38+
```{r magrittr, exercise=TRUE, exercise.pipe="%>%"}
39+
mtcars count(cyl)
40+
```
41+
42+
### New school
43+
44+
In this next chunk, pressing `Ctrl/Cmd + Shift + M` enters the base R pipe: `|>`.
45+
46+
```{r pipe, exercise=TRUE, exercise.pipe="|>"}
47+
mtcars count(cyl)
48+
```
49+
50+
### Night school
51+
52+
In this next chunk, pressing `Ctrl/Cmd + Shift + M` enters the pipe that matches your R version. It's the base R pipe for R >= 4.1.
53+
54+
```{r auto, exercise=TRUE}
55+
mtcars count(cyl)
56+
```

vignettes/articles/exercises.Rmd

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ There are many options associated with tutorial exercises (all of which are desc
2222
+-----------------------------+-------------------------------------------------------------------------------------------------------------------------------------+
2323
| `exercise.lines` | Lines of code for exercise editor (default to size of code chunk). |
2424
+-----------------------------+-------------------------------------------------------------------------------------------------------------------------------------+
25+
| `exercise.pipe` | The code to insert when the user presses `Ctrl/Cmd + Shift + M` (defaults to `|>` for R >= 4.1.0, otherwise `%>%`). |
26+
+-----------------------------+-------------------------------------------------------------------------------------------------------------------------------------+
2527
| `exercise.timelimit` | Number of seconds to limit execution time to (defaults to 30). |
2628
+-----------------------------+-------------------------------------------------------------------------------------------------------------------------------------+
2729
| `exercise.checker` | Function used to check exercise answers (e.g., `gradethis::grade_learnr()`). |

0 commit comments

Comments
 (0)