Skip to content

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 a tibble with three columns: food, vegetable, and color.

  • In food, store “lettuce” and “tomato”.
  • In vegetable, store whether the food is a vegetable.
  • In color, store the color of the food.
```{r tomato-setup}
library(tibble)
```

```{r tomato, exercise=TRUE}

```

```{r tomato-solution}
tibble(
  food = c("lettuce", "tomato"),
  vegetable = c(TRUE, FALSE),
  color = c("green", "red")
)
```

```{r tomato-check}
grade_this_table()
```
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
A problem occurred with the grading code for this exercise.
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
A problem occurred with the grading code for this exercise.
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
A problem occurred with the grading code for this exercise.
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
A problem occurred with the grading code for this exercise.
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
A problem occurred with the grading code for this exercise.
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
A problem occurred with the grading code for this exercise.

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 the starwars dataset. Use transmute() to turn convert height from centimeters into inches and mass from kilgrams into pounds, keeping only those columns.

```{r starwars-setup}
library(dplyr)
```

```{r starwars, exercise=TRUE}

```

```{r starwars-solution}
starwars %>%
  transmute(
    height = height / 2.54, 
    mass = mass * 2.205
  )
```

```{r starwars-check}
grade_this_table(check_column_order = TRUE)
```

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.

starwars %>%
  transmute(
    height = height / 2.54, 
    mass = mass * 2.205
  )
#> # A tibble: 87 × 2
#>    height  mass
#>     <dbl> <dbl>
#>  1   67.7 170. 
#>  2   65.7 165. 
#>  3   37.8  70.6
#>  4   79.5 300. 
#>  5   59.1 108. 
#>  6   70.1 265. 
#>  7   65.0 165. 
#>  8   38.2  70.6
#>  9   72.0 185. 
#> 10   71.7 170. 
#> # … with 77 more rows

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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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.

```{r starwars-check}
grade_this_table(check_column_order = FALSE)
```
A problem occurred with the grading 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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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 the marital_age dataset. Use fct_reorder() to turn the marital column into a factor with levels ordered based on avg_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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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 the fruit 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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.

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
A problem occurred with the grading code for this exercise.