knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
We are happy to announce that version 0.11.0
of learnr has arrived at a CRAN mirror near you.
This release collects many large and small improvements to the learnr package,
all with the goal of making it easier to create interactive tutorials for teaching programming concepts and skills.
Read on for an overview of the changes in version 0.11.0
,
or review the changelog for a full list of updates.
Use install.packages()
to install the latest version of learnr,
which includes demonstrations of many of the new features.
install.packages("learnr")
learnr tutorials are a great way to teach others R: it's in the package name, after all. And thanks to R Markdown's flexibility, learnr is a great way to teach other programming languages as well, using the spoken language of your choice!
learnr now allows tutorial authors to choose the words or language used for learnr's UI elements
using the language
argument of the tutorial
format.
We are very grateful for the contributions of a number of community members
to allow learnr to include out-of-the-box support for the following languages:
```{=html}
You can choose one of the above via the `language` setting in your tutorial's YAML frontmatter:
output: learnr::tutorial: language: es runtime: shinyrmd
The language chosen for the tutorial is passed to the R session used to evaluate exercise code, so that translatable messages from R will also be presented in the specified language (thanks [Alex Rossell Hayes](https://github.com/rossellhayes)). In addition, you can customize the words displayed on specific UI elements using a named list. For example, the default text used on the "Run Code" button in Spanish is *Ejecutar código*. You can use the Spanish language translation and modify this particular translation using a named list: ``` --- output: learnr::tutorial: language: es: button: runcode: Ejecutar runtime: shinyrmd ---
You can learn more about internationalization features and the full syntax for customizing the language used by learnr in the internationalization vignette.
We would love to support more languages and would happily welcome your contribution.
In addition to spoken languages,
learnr is now better at running code in programming languages other than R.
The biggest improvement is for SQL exercises,
where learners can execute SQL queries on a database.
This was previously possible,
but now tutorial authors can use grading packages like gradethis
to grade the tables returned by the student's queries.
You can see this in action using
run_tutorial("sql-exercise", "learnr")
(SQL demo online version).
learnr also includes UI improvements in the interactive exercise component for other languages,
including syntax highlighting and basic auto-completion for exercise code
in languages such as Python, JavaScript, Julia and SQL.
Try
run_tutorial("polyglot", "learnr")
(polyglot online version)
to see several programming languages in use in the same tutorial.
```{=html} <img src = "images/r-python-exercise.png" alt="One R and one Python interactive exercise component, with the same source code but which evaluates differently in each language. The code is:
x = 5 x <- 10 print(x)" />
For exercise checking, learnr communicates the exercise engine to exercise-checking functions via a new `engine` argument that should be included in the exercise checker function signature. ## Exercises Beyond expanded language support, interactive exercises and questions in learnr tutorials have received a number of updates and improvements. ### Setup chunk chaining Thanks to [Nischal Shrestha](https://github.com/nischalshrestha), exercises can now be chained together via chained setup chunks such that the setup of one exercise may depend on other exercises[^1], including the setup chunks of other exercises in the tutorial. This makes it easier for the author to progressively work through a problem with a series of interactive exercises that build on each other. [^1]: Note that with chained setup chunks, an exercise only ever uses the code as written in the chunks in the source document. Exercises are still completely independent of each other when viewed by a user. An exercise chunk — an R chunk with `exercise = TRUE` — can specify its setup chunk using the `{label}-chunk` naming convention or with the `exercise.setup` chunk option. Any chunk being used as a setup chunk may also include an `execise.setup` option specifying its own parent chunk. Try `run_tutorial("setup-chunks", "learnr")` ([setup-chunks online version](https://learnr-examples.shinyapps.io/setup-chunks/)) to see chained setup chunks in action. ### Catching common code issues When teaching new programming concepts, it can be helpful to provide learners with some scaffolding in an exercise to focus their attention on skills they just recently learned. For example, if you are explaining the difference between the `names_from` and `values_from` arguments in `tidyr::pivot_wider()`, you might want to ask students to practice using the arguments without distracting them with writing code to set up a transformation. It's common to use underscores or other patterns to indicate that students should fill in a missing piece. ```r library(tidyverse) us_rent_income %>% select(name = NAME, variable, estimate) %>% pivot_wider(names_from = ____, values_from = ____)
If students submit code containing blanks,
learnr will warn the student that they should replace the ____
with valid code.
```{=html}
Blanks are detected using regular expressions (since blanks may make the code unparsable), and learnr's default pattern is to detect three or more consecutive underscores. Authors can choose the pattern for detecting blanks with the `exercise.blanks` chunk option. Setting `exercise.blanks = "[.]{2}[a-z]+[.]{2}"`, for example, would allow the author to use valid R syntax for blanks. The warning message shown to students calls out the blanks they need to fill in. ```{=html} <img src="images/blanks-warning-custom.png" alt="A learnr exercise box with the feedback from submitting the example code with a custom exercise.blanks pattern. A red callout says "This exercise contains 2 blanks. Please replace '..names..' and '..values..' with valid code."" />
Another common problem in code involves character conversions when a student copies code from an application with automatic formatting and pastes the text into a learnr tutorial. We frequently see problems with quotation marks in code samples being converted to Unicode-formatted quotation marks (curly quotes). In general, these kinds of conversions make the R code unparsable. Now learnr will detect these mistakes and suggest a replacement.
```{=html} <img src="images/fancy-quotes-warning.png" alt="A learnr exercise box where the student's code contains curly quotes. The feedback message reads
It looks like your R code contains specially formatted quotation marks or "curly" quotes (“) around character strings, making your code invalid. R requires character values to be contained in straight quotation marks (" or ').
1: c(“hello”, “world”)
Don't worry, this is a common source of errors when you copy code from another app that applies its own formatting to text. You can try replacing the code on that line with the following. There may be other places that need to be fixed, too.
c("hello", "world") " />
Finally, if the learner submits code that isn't parsable -- and not for any of the above reasons -- learnr now returns a generic, but helpful, feedback message with guidance about common syntax errors. ```{=html} <img src="images/syntax-warning.png" alt="A learnr exercise box where the student's code contains invalid R code. The feedback message reads: It looks like this might not be valid R code. R cannot determine how to turn your text into a complete command. You may have forgotten to fill in a blank, to remove an underscore, to include a comma between arguments, or to close an opening ", ', ( or { with a matching ", ', ) or }." />
In all of the above cases, the actual R output, often an error message, is always shown to the learner. This helps students acclimate to the error messages they would see in their console if encountered in their every-day usage of R.
Keyboard navigation and shortcuts for the interactive exercise code editor has been improved. Previously, the editor would trap keyboard focus because the Tab key is used for indentation in the editor. Now, users can press Escape when the editor has focus to temporarily disable using Tab for indentation, making it possible to move to the next or previous element in the tutorial.
```{=html}
The exercise editor also supports a few additional keyboard shortcuts: * The (magrittr) pipe `%>%` with <kbd>Cmd</kbd> / <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> * The assignment arrow, `<-` with <kbd>Opt</kbd> / <kbd>Alt</kbd> + <kbd>-</kbd> * <kbd>Cmd</kbd> / <kbd>Ctrl</kbd> + <kbd>Enter</kbd> runs the selected code ### The `data` directory When users submit code as part of an exercise, learnr evaluates their code in a temporary directory that's used just for the evaluation of their submission. This helps ensure that every submission returns the same value, but it makes it harder for authors to write exercises that use files, such as `.csv` or other files, as inputs for the user's code. To remedy this, thanks to work by [Alex Rossell Hayes](https://github.com/rossellhayes), learnr now treats a `data/` directory, stored adjacent to the tutorial, as special. Authors can reference files in the `data/` directory in the static content of tutorials, and the files are also made available for student use in the exercises. Each exercise evaluation copies the directory into the exercise's temporary directory so that subsequent submissions work even if the student accidentally overwrites or deletes the files. In all cases, files in `data/` can be referenced using the same relative path, e.g. `"data/estimates.csv"`. ### Error checking It is now possible to provide customized feedback when a learner's exercise submission produces an evaluation error. The `exercise.error.checker` option of `tutorial_options()` allows authors to define an error-checking function that is applied when an error is thrown by a user's code. You may also use `exercise.error.check.code` to define the default error checking code that would normally be written in an `-error-check` chunk. An excellent default error checker is `gradethis::gradethis_error_checker()`, which is enabled by default if [gradethis] is loaded in a learnr tutorial. The gradethis error checker automatically provides the student with a hint when an error is encountered, by comparing the submitted code with the expected solution. ```{=html} <img src="images/error-checker.png" alt="A learnr exercise box where the student's code results in an error. The submitted code is 'runif(max = 10)' and the feedback message reads Your call to 'runif()' should include "n" as one of its arguments. You may have misspelled an argument name, or left out an important argument. That's okay: you learn more from mistakes than successes. Let's do it one more time." />
This release of learnr includes a new question type, question_numeric()
.
The numeric question type is a complement to question_text()
when a numeric answer is required.
{=html}
<img src="images/question-numeric.png" alt="A learnr question input asking "What is pi rounded to 2 digits?" followed by an input box with the text "3.14"" />
In general, question answers are specified with the answer()
function,
but these answers can only be a single value,
which has limited applicability in text and numeric questions.
Now, authors can use answer_fn()
to provide a single-argument function
that takes the student's submitted answer
and determines if their submission is correct.
This allows authors to check a range of values or answers at once.
We are hugely thankful for the 101 community members who have contributed pull requests, submitted translations, or reported issues since our last release. There are many more contributions and updates to this version of learnr that aren't covered in this post; be sure to check out the full list of changes.
Thank you also to the previous maintainer of learnr, Barrett Schloerke! (learnr is now maintained by me, Garrick Aden-Buie.)
🙏 Big thank you to all of our contributors:
@acarzfr, @acastleman, @adisarid, @agmath, @AlbertLeeUCSF, @andysouth, @annafergusson, @assignUser, @batpigandme, @bbitarello, @beatrizmilz, @bhogan-mitre, @bjornerstedt, @blaiseli, @Brunox13, @C4caesar, @caievelyn, @cderv, @chendaniely, @choonghyunryu, @chrisaberson, @coatless, @ColinFay, @cpsievert, @cswclui, @czucca, @davidkane9, @dcossyleon, @ddauber, @deepanshu88, @dfailing, @dmenne, @dputhier, @DrAtzi, @drmowinckels, @dtkaplan, @elimillera, @elmstedt, @emarsh25, @enoches, @ericemc3, @ethelpruss, @gadenbuie, @gaelso, @garrettgman, @gdkrmr, @gtritchie, @gvwilson, @helix84, @hyigit2, @ijlyttle, @indenkun, @jakub-jedrusiak, @jcheng5, @jennybc, @jhk0530, @joe-chelladurai, @johnbde, @jooyoungseo, @jtelleriar, @jtransue, @kaisamng, @KatherineCox, @kendavidn, @kevinushey, @lorenzwalthert, @ltl-manabi, @MAGALLANESJoseManuel, @MaralDorri, @markwsac, @MayaGans, @meatballhat, @mikelmadina, @mine-cetinkaya-rundel, @mpjashby, @mstackhouse, @mutlusun, @NinaCorrelAid, @nischalshrestha, @NuoWenLei, @petzi53, @plukethep, @profandyfield, @psads-git, @pseudorational, @RaymondBalise, @rossellhayes, @rundel, @schloerke, @shalom-lab, @shalutiwari, @siebrenf, @SilasK, @stragu, @themfrees, @tombeesley, @trestletech, @tvedebrink, @vnijs, @wch, and @yabellini.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.