--- title: "Teaching with livelink" vignette: > %\VignetteIndexEntry{Teaching with livelink} %\VignetteEngine{quarto::html} %\VignetteEncoding{UTF-8} format: html: embed-resources: true knitr: opts_chunk: collapse: true comment: '#>' --- ```{=html} ``` ```{r setup} #| include: false library(livelink) ``` The hardest part of teaching R is not R. It is the twenty minutes at the start of a workshop spent installing R, then RStudio, then a package that fails to compile on one student's laptop. livelink sidesteps that. A link opens a working R session in the browser, with your code already in the editor. Nothing to install, nothing to configure, and it works on a school Chromebook. ## Exercise and solution pairs `webr_repl_exercise()` is built for the most common teaching shape: give students a scaffold with the answer removed, and keep the worked solution behind a second link. ![One call returns two links. They differ by a single flag: the solution carries `a` for autorun and computes the answer on arrival, while the exercise waits.](../man/figures/exercise-light.svg){.ll-fig .ll-light} ![](../man/figures/exercise-dark.svg){.ll-fig .ll-dark aria-hidden="true"} ```{r} exercise <- " # Exercise: what is the mean mpg of the cars in mtcars? # Replace the 0 below with your answer. mean_mpg <- 0 print(mean_mpg) " solution <- " # Solution mean_mpg <- mean(mtcars$mpg) print(mean_mpg) " links <- webr_repl_exercise(exercise, solution, "mean_mpg") links ``` These are written as plain strings on purpose. An exercise is mostly its instructions, and those live in comments, so a braced `{ }` expression would drop them the moment these notes are knitted. [Links inside documents](links-in-documents.html#why-not-a-braced-expression) explains why. The two links differ in one deliberate way: the solution **autoruns** and the exercise does not. Students landing on the exercise see the code sitting there waiting for them. Students landing on the solution see the answer already computed. ```{r} links$exercise$autorun links$solution$autorun ``` Hand out the exercise link in class, and hold the solution link back until afterwards, or put it behind a collapsed callout in your notes. ```{r} repl_urls(links) ``` ## Choosing what students see A full webR session shows an editor, a plot pane, a file browser, and a terminal. For a first-year class that is a lot of surface area, and the terminal in particular invites students to wander off. `panels` controls which of them appear. ![webR has four panels. `panels` names the ones you want, and the rest never appear.](../man/figures/panels-light.svg){.ll-fig .ll-light} ![](../man/figures/panels-dark.svg){.ll-fig .ll-dark aria-hidden="true"} ```{r} # A focused exercise: just write code and see the plot webr_repl_link("plot(1:10)", panels = c("editor", "plot")) ``` ```{r} #| eval: false # The full environment, for a project week webr_repl_link(code, panels = c("editor", "plot", "files", "terminal")) ``` For a lecture demo, where students should see the *result* and not the machinery, combine `autorun` with a plot-only view: ```{r} webr_repl_link( "hist(rnorm(1000), col = 'steelblue', main = 'The central limit theorem, again')", autorun = TRUE, panels = "plot" ) ``` Only `.R` files can autorun. Ask for it on something else and livelink tells you rather than quietly producing a link that does nothing: ```{r} #| error: true webr_repl_link("some data", filename = "data.csv", autorun = TRUE) ``` ## A whole folder of scripts Course material tends to live as a directory of scripts, and livelink gives you two ways to turn that folder into links. Which you want comes down to a single question: are the scripts **independent**, or **parts of one thing**? `webr_repl_directory()` gives each script *its own* link. That is the right call for a folder of standalone exercises: one link per file, each opening just that script. ![Each script becomes its own link, named after the file. That is the mirror image of `webr_repl_project()`, which bundles a whole folder into one link.](../man/figures/course-light.svg){.ll-fig .ll-light} ![](../man/figures/course-dark.svg){.ll-fig .ll-dark aria-hidden="true"} ```{r} # A small course directory course <- file.path(tempdir(), "course") dir.create(course, showWarnings = FALSE) writeLines("plot(1:10)", file.path(course, "01-plotting.R")) writeLines("mean(mtcars$mpg)", file.path(course, "02-summaries.R")) writeLines("lm(mpg ~ wt, mtcars)", file.path(course, "03-models.R")) links <- webr_repl_directory(course, panels = c("editor", "plot")) links ``` The result is named by file, so it drops straight into a table of contents: ```{r} urls <- repl_urls(links) cat(sprintf("- [%s](%s)", names(urls), urls), sep = "\n") ``` Use `pattern` to pick out a subset, say the exercises but not the solutions: ```{r} webr_repl_directory(course, pattern = "^0[12]") ``` ### One link per file, or one link for the folder? `webr_repl_project()` is the other half of the pair. It packs several files into a *single* link, so a script that `source()`s its neighbour still finds it once webR unpacks them side by side. Reach for it when the files belong together rather than standing alone. The two are mirror images, and the table says which to reach for: | You want | Call | |---|---| | each script openable on its own | `webr_repl_directory(dir)` | | the whole folder bundled into one link | `webr_repl_directory(dir, single_link = TRUE)` | | a hand-picked set of files bundled into one link | `webr_repl_project(files)` | `single_link = TRUE` is the bridge between them: point it at a folder and it bundles the lot into one link, exactly as `webr_repl_project()` would, without your having to list the files by hand. ```{r} # the same course folder, as one bundled link instead of three webr_repl_directory(course, single_link = TRUE, panels = c("editor", "plot")) ``` ## Embedding links in your notes If you write course notes in Quarto or R Markdown, you do not have to build the link in one chunk and paste the URL into another. livelink plugs into knitr, so a chunk can carry its own link. ![A `livelink` chunk renders as the code plus a link that runs it, comments and all. A braced expression cannot manage that in a knitted document.](../man/figures/engine-light.svg){.ll-fig .ll-light} ![](../man/figures/engine-dark.svg){.ll-fig .ll-dark aria-hidden="true"} Add `livelink: true` to an ordinary `r` chunk. It runs as it always did, the plot appears in your notes, and a link is added underneath. Here it is, running in this very vignette: ```{r} #| livelink: true #| autorun: true #| panels: ["editor", "plot"] # Load the data data(mtcars) plot(mtcars$mpg, mtcars$wt) # a comment students will actually see ``` Students read the result *and* get to go and poke at it. Follow the link: the comments are still there, which they would not be had you written `webr_repl_link({ ... })`. For a folder of course notes, set it once and let every chunk carry a link: ```{r} #| eval: false knitr::opts_chunk$set(livelink = TRUE, autorun = TRUE) ``` [Links inside documents](links-in-documents.html) covers the rest: the engine, for code your notes should not run, every chunk option, and why `echo` is not what stands between you and a link. ## Collecting work back in Students send you links. `decode_webr_link()` accepts a vector of them and writes each into its own directory, so a stack of submissions becomes a folder you can grade. ```{r} submissions <- c( as.character(webr_repl_link("mean(mtcars$mpg)", filename = "student_a.R")), as.character(webr_repl_link("median(mtcars$mpg)", filename = "student_b.R")) ) decode_webr_link(submissions, output_dir = file.path(tempdir(), "submissions")) ``` If you would rather read the code than write it to disk, `preview_webr_link()` shows you a submission without touching your filesystem at all, which is the safer default when the code came from someone else.