Skip to content

Commit

Permalink
Use tutorial, round 2 (#645)
Browse files Browse the repository at this point in the history
* copy readme template as tutorial template

* Add use_tutorial function and tutorial template

* Add tests for use_tutorial (more to come...)

* Clean up test

* Test titles

* Include edits from code review in #584

* Remove stray comma

* No full stop here, as per style guide

* Work on docs

* Fix test

* Add NEWS bullet

* Necessary for us to test this (and bypass the check via a mock)

* Make suggested mocking strategy actually work

* Moved scoped_temporary_package() inside with_mock()

* No need to check this twice

* Lower case the name
  • Loading branch information
angela-li authored and jennybc committed Mar 15, 2019
1 parent 3ee26ef commit 8fa45c0
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 2 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export(use_tidy_support)
export(use_tidy_thanks)
export(use_tidy_versions)
export(use_travis)
export(use_tutorial)
export(use_usethis)
export(use_version)
export(use_vignette)
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## New features

* `use_tutorial()` creates a new interactive R Markdown tutorial, as implemented
by the [`learnr` package](https://rstudio.github.io/learnr/index.html)
(@angela-li, #645).

* `git_protocol()` + `use_git_protocol()` and `git2r_credentials()` + `use_git2r_credentials()` are new helpers to summon or set git transport protocol (SSH or HTTPS) or git2r credentials, respectively. These functions are primarily for internal use. Most users can rely on default behaviour, but these helpers can be used to intervene if git2r isn't discovering the right credentials (#653).

* `use_github()` tries harder but also fails earlier, with more informative messages, making it less likely to leave the repo partially configured (#221).
Expand Down
2 changes: 1 addition & 1 deletion R/helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use_dependency <- function(package, type, min_version = NULL) {
stopifnot(is_string(package))
stopifnot(is_string(type))

if (package != "R" && !requireNamespace(package, quietly = TRUE)) {
if (package != "R" && !is_installed(package)) {
ui_stop(c(
"{ui_value(package)} must be installed before you can ",
"take a dependency on it."
Expand Down
49 changes: 49 additions & 0 deletions R/tutorial.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#' Create a learnr tutorial
#'
#' Creates a new tutorial below `inst/tutorials/`. Tutorials are interactive R
#' Markdown documents built with the [`learnr`
#' package](https://rstudio.github.io/learnr/index.html). `use_tutorial()` does
#' this setup:
#' * Adds learnr to Suggests in `DESCRIPTION`.
#' * Gitignores `inst/tutorials/*.html` so you don't accidentally track
#' rendered tutorials.
#' * Creates a new `.Rmd` tutorial from a template and, optionally, opens it
#' for editing.
#' * Adds new `.Rmd` to `.Rbuildignore`.
#'
#' @param name Base for file name to use for new `.Rmd` tutorial. Should consist
#' only of numbers, letters, `_` and `-`. We recommend using lower case.
#' @param title The human-facing title of the tutorial.
#' @inheritParams use_template
#' @seealso The [learnr package
#' documentation](https://rstudio.github.io/learnr/index.html).
#' @export
#' @examples
#' \dontrun{
#' use_tutorial("learn-to-do-stuff", "Learn to do stuff")
#' }
use_tutorial <- function(name, title, open = interactive()) {
stopifnot(is_string(name))
stopifnot(is_string(title))

dir_path <- path("inst", "tutorials")

use_directory(dir_path)
use_git_ignore("*.html", directory = dir_path)
use_dependency("learnr", "Suggests")

path <- path(dir_path, asciify(name), ext = "Rmd")

data <- project_data()
data$tutorial_title <- title

new <- use_template(
"tutorial-template.Rmd",
save_as = path,
data = data,
ignore = TRUE,
open = open
)

invisible(new)
}
6 changes: 5 additions & 1 deletion R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ compact <- function(x) {
"%||%" <- function(a, b) if (!is.null(a)) a else b

check_installed <- function(pkg) {
if (!requireNamespace(pkg, quietly = TRUE)) {
if (!is_installed(pkg)) {
ui_stop("Package {ui_value(pkg)} required. Please install before re-trying.")
}
}

is_installed <- function(pkg) {
requireNamespace(pkg, quietly = TRUE)
}

## mimimalist, type-specific purrr::pluck()'s
pluck_chr <- function(l, what) vapply(l, `[[`, character(1), what)

Expand Down
75 changes: 75 additions & 0 deletions inst/templates/tutorial-template.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "{{{ tutorial_title }}}"
output: learnr::tutorial
runtime: shiny_prerendered
---

```{r setup, include=FALSE}
library(learnr)
knitr::opts_chunk$set(echo = FALSE)
```


## Topic 1

### Exercise

*Here's a simple exercise with an empty code chunk provided for entering the answer.*

Write the R code required to add two plus two:

```{r two-plus-two, exercise=TRUE}
```

### Exercise with Code

*Here's an exercise with some prepopulated code as well as `exercise.lines = 5` to provide a bit more initial room to work.*

Now write a function that adds any two numbers and then call it:

```{r add-function, exercise=TRUE, exercise.lines = 5}
add <- function() {
}
```

## Topic 2

### Exercise with Hint

*Here's an exercise where the chunk is pre-evaulated via the `exercise.eval` option (so the user can see the default output we'd like them to customize). We also add a "hint" to the correct solution via the chunk immediate below labeled `print-limit-hint`.*

Modify the following code to limit the number of rows printed to 5:

```{r print-limit, exercise=TRUE, exercise.eval=TRUE}
mtcars
```

```{r print-limit-hint}
head(mtcars)
```

### Quiz

*You can include any number of single or multiple choice questions as a quiz. Use the `question` function to define a question and the `quiz` function for grouping multiple questions together.*

Some questions to verify that you understand the purposes of various base and recommended R packages:

```{r quiz}
quiz(
question("Which package contains functions for installing other R packages?",
answer("base"),
answer("tools"),
answer("utils", correct = TRUE),
answer("codetools")
),
question("Which of the R packages listed below are used to create plots?",
answer("lattice", correct = TRUE),
answer("tools"),
answer("stats"),
answer("grid", correct = TRUE)
)
)
```

38 changes: 38 additions & 0 deletions man/use_tutorial.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions tests/testthat/test-use-tutorial.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
context("test-use-tutorial")

test_that("use_tutorial() checks its inputs", {
skip_if_not_installed("rmarkdown")

scoped_temporary_package()
expect_error(use_tutorial(), "no default")
expect_error(use_tutorial(name = "tutorial-file"), "no default")
})

test_that("use_tutorial() creates a tutorial", {
skip_if(getRversion() < 3.2) ## mock doesn't seem to work on 3.1

with_mock(
## need to pass the check re: whether learnr is installed
`usethis:::is_installed` = function(pkg) TRUE, {
scoped_temporary_package()
use_tutorial(name = "aaa", title = "bbb")
tute_file <- path("inst", "tutorials", "aaa", ext = "Rmd")
expect_proj_file(tute_file)
expect_equal(rmarkdown::yaml_front_matter(tute_file)$title, "bbb")
}
)
})

0 comments on commit 8fa45c0

Please # to comment.