Overview
To help you get a feel for the kind of advice tblcheck provides, we’ve collected a few example exercises that use grade_this_table()
or grade_this_vector()
from tblcheck to grade a learnr exercise.
In the examples below, we’ll show the specific R chunks you’d need to prepare the exercise. Globally, we assume learnr and gradethis are already loaded, and we’ve made a few adjustments to the default gradethis options using gradethis::gradethis_setup()
:
```{r setup}
library(learnr)
library(gradethis)
library(tblcheck)
gradethis_setup(
pass.praise = TRUE,
fail.hint = TRUE,
fail.encourage = TRUE,
maybe_code_feedback.before = "\n\n"
)
```
Note that in all examples below we’re using either grade_this_table()
or grade_this_vector()
without any additional customizations. We’ve also made sure that each exercise contains a -solution
chunk. (Read more about how to set up an exercise for use with tblcheck.)
Create a Table
The first example repeats the example presented in the Get started article. The goal is for the learner to use the tibble::tibble()
function to create a table, but it takes them a few tries.
Prompt
Create atibble
with three columns:food
,vegetable
, andcolor
.
- In
food
, store “lettuce” and “tomato”.- In
vegetable
, store whether the food is a vegetable.- In
color
, store the color of the food.
tibble(
food = c("lettuce", "tomato"),
vegetable = c(TRUE, FALSE),
color = c("green", "red")
)
#> # A tibble: 2 × 3
#> food vegetable color
#> <chr> <lgl> <chr>
#> 1 lettuce TRUE green
#> 2 tomato FALSE red
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
list(
food = "lettuce",
fruit = "TRUE",
color = "green"
)
#> $food
#> [1] "lettuce"
#>
#> $fruit
#> [1] "TRUE"
#>
#> $color
#> [1] "green"
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
tibble(
food = "lettuce",
fruit = "TRUE",
color = "green"
)
#> # A tibble: 1 × 3
#> food fruit color
#> <chr> <chr> <chr>
#> 1 lettuce TRUE green
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
tibble(
food = "lettuce",
vegetable = "TRUE",
color = "green"
)
#> # A tibble: 1 × 3
#> food vegetable color
#> <chr> <chr> <chr>
#> 1 lettuce TRUE green
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
tibble(
food = c("lettuce", "tomato"),
vegetable = c("TRUE", "TRUE"),
color = c("green", "red")
)
#> # A tibble: 2 × 3
#> food vegetable color
#> <chr> <chr> <chr>
#> 1 lettuce TRUE green
#> 2 tomato TRUE red
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
tibble(
food = c("lettuce", "tomato"),
vegetable = c(TRUE, TRUE),
color = c("green", "red")
)
#> # A tibble: 2 × 3
#> food vegetable color
#> <chr> <lgl> <chr>
#> 1 lettuce TRUE green
#> 2 tomato TRUE red
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Transform a Table with transmute()
The first example shows all of the problems that tblcheck will discover. This example, however, is more realistic.
In this problem students are asked to use the dplyr::transmute()
function to transform the starwars
dataset.
Prompt
Consider thestarwars
dataset. Usetransmute()
to turn convertheight
from centimeters into inches andmass
from kilgrams into pounds, keeping only those columns.
The correct answer uses dplyr::transmute()
to divide the height
column by 2.54
(to convert height from cm to in) and to multiply the mass
column by 2.205
(to convert kg to lb). Note that transmute()
keeps only the columns named in its calculations, so our final table has only two columns.
In this example, the student uses dplyr::mutate()
, which is certainly a reasonable choice but not what was requested. As a result, their submission contains more columns than expected.
starwars %>%
mutate(
height = height / 2.54,
mass = mass * 2.205
)
#> # A tibble: 87 × 14
#> name height mass hair_color skin_color eye_color birth_year sex
#> <chr> <dbl> <dbl> <chr> <chr> <chr> <dbl> <chr>
#> 1 Luke… 67.7 170. blond fair blue 19 male
#> 2 C-3PO 65.7 165. NA gold yellow 112 none
#> 3 R2-D2 37.8 70.6 NA white, bl… red 33 none
#> 4 Dart… 79.5 300. none white yellow 41.9 male
#> 5 Leia… 59.1 108. brown light brown 19 fema…
#> 6 Owen… 70.1 265. brown, gr… light blue 52 male
#> 7 Beru… 65.0 165. brown light blue 47 fema…
#> 8 R5-D4 38.2 70.6 NA white, red red NA none
#> 9 Bigg… 72.0 185. black light brown 24 male
#> 10 Obi-… 71.7 170. auburn, w… fair blue-gray 57 male
#> # … with 77 more rows, and 6 more variables: gender <chr>,
#> # homeworld <chr>, species <chr>, films <list>, vehicles <list>,
#> # starships <list>
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Here the student has done more or less the right thing, but they specified the columns in the opposite order.
starwars %>%
transmute(
mass = mass * 2.205,
height = height / 2.54
)
#> # A tibble: 87 × 2
#> mass height
#> <dbl> <dbl>
#> 1 170. 67.7
#> 2 165. 65.7
#> 3 70.6 37.8
#> 4 300. 79.5
#> 5 108. 59.1
#> 6 265. 70.1
#> 7 165. 65.0
#> 8 70.6 38.2
#> 9 185. 72.0
#> 10 170. 71.7
#> # … with 77 more rows
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
If we decide we don’t mind if the columns aren’t in the right order, we could set check_column_order = FALSE
in the check code for this exercise.
If the student were to somehow create columns with an incorrect class, e.g. integer values where doubles were expected, tblcheck will alert them to their mistake.
starwars %>%
transmute(
mass = as.integer(mass * 2.205),
height = as.integer(height / 2.54)
)
#> # A tibble: 87 × 2
#> mass height
#> <int> <int>
#> 1 169 67
#> 2 165 65
#> 3 70 37
#> 4 299 79
#> 5 108 59
#> 6 264 70
#> 7 165 64
#> 8 70 38
#> 9 185 72
#> 10 169 71
#> # … with 77 more rows
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
If the values are completely wrong — here the student is multiplying height
by 2.54
rather than dividing — then tblcheck points out which column is incorrect and gives a hint about the expected values.
starwars %>%
transmute(
height = height * 2.54,
mass = mass * 2.205
)
#> # A tibble: 87 × 2
#> height mass
#> <dbl> <dbl>
#> 1 437. 170.
#> 2 424. 165.
#> 3 244. 70.6
#> 4 513. 300.
#> 5 381 108.
#> 6 452. 265.
#> 7 419. 165.
#> 8 246. 70.6
#> 9 465. 185.
#> 10 462. 170.
#> # … with 77 more rows
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Transform a Factor Column
This example comes from a lesson on factors
in R. Students have just learned about functions from the forcats package, and are now asked to practice using forcats::fct_reorder()
.
Prompt
Consider themarital_age
dataset. Usefct_reorder()
to turn themarital
column into a factor with levels ordered based onavg_age
.
We created a new table specifically for this exercise in the factor-setup
chunk, drawing from the data provided in forcats::gss_cat
.
```{r factor-setup}
library(dplyr)
library(forcats)
marital_age <- gss_cat %>%
mutate(marital = as.character(marital)) %>%
group_by(marital) %>%
summarize(avg_age = mean(age, na.rm = TRUE)) %>%
ungroup()
```
```{r factor, exercise=TRUE}
marital_age
```
```{r factor-solution}
marital_age %>%
mutate(marital = fct_reorder(marital, avg_age))
```
```{r factor-check}
grade_this_table()
```
Since students aren’t familiar with the marital_age
table, we’ve included the starter code so they can see the initial state of the table when they start the exercise.
marital_age
#> # A tibble: 6 × 2
#> marital avg_age
#> <chr> <dbl>
#> 1 Divorced 51.1
#> 2 Married 48.7
#> 3 Never married 33.9
#> 4 No answer 52.4
#> 5 Separated 45.3
#> 6 Widowed 71.7
In the expected solution, the student will use the forecats::fct_reorder()
function to transform the marital
column, reordering its factor levels by increasing avg_age
.
marital_age %>%
mutate(marital = fct_reorder(marital, avg_age))
#> # A tibble: 6 × 2
#> marital avg_age
#> <fct> <dbl>
#> 1 Divorced 51.1
#> 2 Married 48.7
#> 3 Never married 33.9
#> 4 No answer 52.4
#> 5 Separated 45.3
#> 6 Widowed 71.7
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Here the student forgets about the forcats::fct_reorder()
function and tries to use order()
to set the order of the factor levels in the marital
column.
marital_age %>%
mutate(marital = order(marital, avg_age))
#> # A tibble: 6 × 2
#> marital avg_age
#> <int> <dbl>
#> 1 1 51.1
#> 2 2 48.7
#> 3 3 33.9
#> 4 4 52.4
#> 5 5 45.3
#> 6 6 71.7
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
In this case the student remembers to use forecats::fct_reorder()
but incorrectly assigns the result to an unexpected column.
marital_age %>%
mutate(marital_fct = fct_reorder(marital, avg_age))
#> # A tibble: 6 × 3
#> marital avg_age marital_fct
#> <chr> <dbl> <fct>
#> 1 Divorced 51.1 Divorced
#> 2 Married 48.7 Married
#> 3 Never married 33.9 Never married
#> 4 No answer 52.4 No answer
#> 5 Separated 45.3 Separated
#> 6 Widowed 71.7 Widowed
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
In another case, the student uses forecats::fct_reorder()
but sets .desc = TRUE
, resulting in an unexpected ordering of the factor levels.
marital_age %>%
mutate(marital = fct_reorder(marital, avg_age, .desc = TRUE))
#> # A tibble: 6 × 2
#> marital avg_age
#> <fct> <dbl>
#> 1 Divorced 51.1
#> 2 Married 48.7
#> 3 Never married 33.9
#> 4 No answer 52.4
#> 5 Separated 45.3
#> 6 Widowed 71.7
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Subset a Vector with stringr
In addition to table-checking functions, tblcheck includes functions for checking vectors — after all, columns in a table are vectors!
Here’s an example exercise from a tutorial on string transformations with the stringr package. Students are asked to practice concepts they just discovered in the tutorial:
Prompt
Consider thefruit
data. Use a function from stringr to create a vector containing only the fruits with more than one word in their name.Hint: a fruit named with more than one word also has at least one space in its name.
In the exercise markdown, we call grade_this_vector()
in the string-check
chunk to automatically compare the result of the student’s submission with our string-solution
.
```{r string-setup}
library(dplyr)
library(stringr)
```
```{r string, exercise=TRUE}
```
```{r string-solution}
str_subset(fruit, " ")
```
```{r string-check}
grade_this_vector()
```
Note that fruit
is from stringr::fruit
, a vector containing 80 fruit names.
head(stringr::fruit, 20)
#> [1] "apple" "apricot" "avocado" "banana"
#> [5] "bell pepper" "bilberry" "blackberry" "blackcurrant"
#> [9] "blood orange" "blueberry" "boysenberry" "breadfruit"
#> [13] "canary melon" "cantaloupe" "cherimoya" "cherry"
#> [17] "chili pepper" "clementine" "cloudberry" "coconut"
11 of the 80 fruits have more than one word. What’s your favorite two-worded fruit name? (Mine is the purple mangosteen.)
str_subset(fruit, " ")
#> [1] "bell pepper" "blood orange" "canary melon"
#> [4] "chili pepper" "goji berry" "kiwi fruit"
#> [7] "purple mangosteen" "rock melon" "salal berry"
#> [10] "star fruit" "ugli fruit"
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
This student submission makes a potentially common mistake of hoping that stringr::str_which()
will return the fruit
which have pattern
. Instead, str_which()
follows the base R function which()
, and returns an integer
index indicating the items in fruit
where the pattern
is matched.
str_which(fruit, " ")
#> [1] 5 9 13 17 32 42 66 72 73 75 79
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
In another mistake example, this student probably expected stringr::str_extract()
to extract elements from the vector. However, str_extract()
instead extracts the pattern from each item, so it returns a vector with the same length as the input.
str_extract(fruit, " ")
#> [1] NA NA NA NA " " NA NA NA " " NA NA NA " " NA NA NA
#> [17] " " NA NA NA
#> [ reached getOption("max.print") -- omitted 60 entries ]
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found
Finally, a student might have chosen the right function, but they missed our hint and came up with a pattern that’s too clever. Here the student probably looked at the first 20 fruit names and took a guess at the answer.
str_subset(fruit, " (pepper|orange|melon|fruit)")
#> [1] "bell pepper" "blood orange" "canary melon" "chili pepper"
#> [5] "kiwi fruit" "rock melon" "star fruit" "ugli fruit"
#> #> (gradethis::grade_this({
#> #> pre_check <- get0(".__pre_check")
#> #> if (!is.null(pre_check)) {
#> #> rlang::eval_bare(pre_check)
#> #> }
#> #> if (isTRUE(get0(".__pass_if_equal", inherits = TRUE, ifnotfound = FALSE))) {
#> #> gradethis::pass_if_equal(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }
#> #> do.call(get(".__tblcheck_grader"), get(".__tblcheck_grader_args"))
#> #> post_check <- get0(".__post_check")
#> #> if (!is.null(post_check)) {
#> #> rlang::eval_bare(post_check)
#> #> }
#> #> gradethis::pass(message = get(".__correct"), praise = get(".__pass.praise"))
#> #> }))(check_env)
#> Error in get(".__tblcheck_grader_args"): object '.__tblcheck_grader_args' not found