From a195fa3b92d1e10c7e6c5bfcf9394af198f4cfd2 Mon Sep 17 00:00:00 2001 From: Daniel Chen Date: Mon, 26 Aug 2019 10:03:35 -0400 Subject: [PATCH] fix gradethis demo (#70) --- inst/tutorials/grading-demo/grading-demo.Rmd | 249 +++++++++---------- 1 file changed, 112 insertions(+), 137 deletions(-) diff --git a/inst/tutorials/grading-demo/grading-demo.Rmd b/inst/tutorials/grading-demo/grading-demo.Rmd index 4a53cea3..c30bcb30 100644 --- a/inst/tutorials/grading-demo/grading-demo.Rmd +++ b/inst/tutorials/grading-demo/grading-demo.Rmd @@ -1,5 +1,5 @@ --- -title: "Grading demo" +title: "Gradethis demo" output: learnr::tutorial runtime: shiny_prerendered # editor_options: @@ -10,43 +10,43 @@ runtime: shiny_prerendered library(learnr) library(gradethis) -tutorial_options(exercise.timelimit = 60, exercise.checker = grade_learnr) +tutorial_options(exercise.timelimit = 60, exercise.checker = gradethis::grade_learnr) knitr::opts_chunk$set(echo = FALSE) ``` -## Grading Types - -### Check Exercise Result +## Grade Exercise Result `gradethis` can check for the final returned value. -This grading approach does not inspect the code. It only inspects the final result. +This grading approach does not inspect the code. +It only inspects the final result. + +The final result submitted by the "student" is captured with the `.result` value. See `?grade_result` for more information. Example code written below: ````markdown -`r ''````{r result, exercise = TRUE} +`r ''````{r grade_result, exercise = TRUE} 3 ``` -`r ''````{r result-hint-1} +`r ''````{r grade_result-hint-1} "Is it an even number" ``` -`r ''````{r result-hint-2} +`r ''````{r grade_result-hint-2} "Enter an even number below 5" ``` -`r ''````{r result-check} +`r ''````{r grade_result-check} grade_result( - results( - result(1, "Custom message for value 1."), - result(2, "Custom message for value 2.", correct = TRUE), - result(3, "Custom message for value 3."), - result(4, "Custom message for value 4.", correct = TRUE) - ) + fail_if(~ identical(.result, 1), "Custom message for value 1."), + pass_if(~ identical(.result, 2), "Custom message for value 2."), + fail_if(~ identical(.result, 3), "Custom message for value 3."), + pass_if(~ identical(.result %% 2, 0) && (.result < 5), + "Even number below 5") ) ``` ```` @@ -55,198 +55,175 @@ grade_result( * Enter an small even number, then click Submit Answer. -```{r result, exercise = TRUE} +```{r grade_result, exercise = TRUE} 3 ``` -```{r result-hint-1} +```{r grade_result-hint-1} "Is it an even number" ``` -```{r result-hint-2} +```{r grade_result-hint-2} "Enter an even number below 5" ``` -```{r result-check} +```{r grade_result-check} grade_result( - result(1, "Custom message for value 1."), - result(2, "Custom message for value 2.", correct = TRUE), - result(3, "Custom message for value 3."), - result(4, "Custom message for value 4.", correct = TRUE) + fail_if(~ identical(.result, 1), "Custom message for value 1."), + pass_if(~ identical(.result, 2), "Custom message for value 2."), + fail_if(~ identical(.result, 3), "Custom message for value 3."), + pass_if(~ identical(.result %% 2, 0) && (.result < 5), + "Even number below 5") ) ``` -### Test Exercise Result +## Grade Exercise Code -`gradethis` can test against for the final returned value. This grading approach does not inspect the code. It only inspects the final result. +`gradethis` can test against an exact code match. +This grading approach does not inspect the computed result. -Writers can include as many testing functions as they would like. The test functions should accept a single result value to test against. If any test fails, it should throw an error. This error message will be returned back to the user by default. See `?grade_conditions` for more information. +This check method requires a `*-solution` code chunk containing the solution to compare. +Only the last solution expression and last user expression will be matched. + +See `?grade_code` for more information. Example code written below: ````markdown -`r ''````{r grade_conditions, exercise = TRUE} -function(x) { - sqrt(log(x)) -} +`r ''````{r grade_code, exercise = TRUE} +sqrt(exp(3)) ``` -`r ''````{r grade_conditions-hint-1} -"function(x) { - sqrt(...) -}" +`r ''```{r grade_code-hint-1} +"You can take the log with `log()`" ``` -`r ''````{r grade_conditions-hint-2} -"function(x) { - sqrt(log(...)) -}" +`r ''```{r grade_code-hint-2} +"You can take the square root with `sqrt()`" ``` -`r ''````{r grade_conditions-check} -grade_conditions( - tests( - function(your_answer) { - checkmate::expect_function(your_answer, args = c("x")) - }, - test( - # use a custom error message - "Make sure your function returns a number!", - function(your_answer) { - checkmate::expect_number(your_answer(1)) - } - ), - function(your_answer) { - testthat::expect_equal(your_answer(0), NaN) - }, - function(your_answer) { - testthat::expect_equal(your_answer(1:10), sqrt(log(1:10))) - } - ) -) +`r ''````{r grade_code-solution} +sqrt(log(2)) +``` + +`r ''```{r grade_code-check} +grade_code("Good job. Don't worry, things will soon get harder.") ``` ```` ---------------------------- + +--------------------------- -Please make a function in the exercise space below. It should: +Here is a number. You can do great things with it, like this: -* Take a single `x` argument -* Take the `log` of `x` -* Take the `sqrt` of the logged value. +* Take the square root of the log of the number `2`. Then click Submit Answer. -```{r grade_conditions, exercise = TRUE} -function(x) { - sqrt(log(x)) -} +```{r grade_code, exercise = TRUE} +sqrt(exp(3)) ``` -```{r grade_conditions-hint-1} -"function(x) { - sqrt(...) -}" +```{r grade_code-hint-1} +"You can take the log with `log()`" ``` -```{r grade_conditions-hint-2} -"function(x) { - sqrt(log(...)) -}" +```{r grade_code-hint-2} +"You can take the square root with `sqrt()`" ``` -```{r grade_conditions-check} -grade_conditions( - tests( - function(your_answer) { - checkmate::expect_function(your_answer, args = c("x")) - }, - test( - # use a custom error message - "Make sure your function returns a number!", - function(your_answer) { - checkmate::expect_number(your_answer(1)) - } - ), - function(your_answer) { - testthat::expect_equal(your_answer(0), NaN) - }, - function(your_answer) { - testthat::expect_equal(your_answer(1:10), sqrt(log(1:10))) - } - ) -) +```{r grade_code-solution} +sqrt(log(2)) +``` + +```{r grade_code-check} +grade_code("Good job. Don't worry, things will soon get harder.") ``` -### Check Exercise Code +## Grade Exercise Conditions -`gradethis` can test against an exact code match. This grading approach does not inspect the computed result. +`gradethis` can create multiple tests against for the final returned value. +This grading approach does not inspect the code. +It only inspects the final result against all conditions. -This check method requires a `*-solution` code chunk containing the solution to compare. Only the last solution expression and last user expression will be matched. +This method is analogous to creating unit tests that all need to pass. -See `?grade_code` for more information. +See `?grade_conditions` for more information. Example code written below: ````markdown -`r ''````{r strict, exercise = TRUE} -2 -``` - -`r ''````{r strict-hint-1} -"You can take the log with `log()`" +`r ''````{r grade_conditions, exercise = TRUE} +function(x) { + # solution is x + 1L + x + 1 +} ``` -`r ''````{r strict-hint-2} -"You can take the square root with `sqrt()`" +`r ''````{r grade_conditions-hint-1} +"Function should add an integer 1" ``` -`r ''````{r strict-solution} -sqrt(log(2)) +`r ''````{r grade_conditions-hint-2} +"Integers are created by adding a L to the number, e.g., 10L" ``` -`r ''````{r strict-check} -grade_code("Good job. Don't worry, things will soon get harder.") +`r ''````{r grade_conditions-check} +grade_conditions( + pass_if(~ .result(3) == 4), + pass_if(~ identical(.result(0), 1)), + pass_if(~ identical(sapply(1:10, .result), 2:11)), + pass_if(~ sapply(1:10, .result) == 2:11), + pass_if(~ all.equal(sapply(1:10, .result), 2:11)), + pass_if(~ checkmate::test_function(.result, args = c("x"))) +) ``` ```` --------------------------- -Here is a number. You can do great things with it, like this: -* Take the square root of the log of the number `2`. +Please make a function in the exercise space below. It should: -Then click Submit Answer. +* Take a single `x` argument +* Add the integer `1` to the `x` value. -```{r strict, exercise = TRUE} -2 -``` +Then click Submit Answer. -```{r strict-hint-1} -"You can take the log with `log()`" +```{r grade_conditions, exercise = TRUE} +function(x) { + # solution is x + 1L + x + 1 +} ``` -```{r strict-hint-2} -"You can take the square root with `sqrt()`" +```{r grade_conditions-hint-1} +"Function should add an integer 1" ``` -```{r strict-solution} -sqrt(log(2)) +```{r grade_conditions-hint-2} +"Integers are created by adding a L to the number, e.g., 10L" ``` -```{r strict-check} -grade_code("Good job. Don't worry, things will soon get harder.") +```{r grade_conditions-check} +grade_conditions( + pass_if(~ .result(3) == 4), + pass_if(~ identical(.result(0), 1)), + pass_if(~ identical(sapply(1:10, .result), 2:11)), + pass_if(~ sapply(1:10, .result) == 2:11), + pass_if(~ all.equal(sapply(1:10, .result), 2:11)), + pass_if(~ checkmate::test_function(.result, args = c("x"))) +) ``` - - - - ## Custom Checking Code -`gradethis` can accept any checking method that returns a `gradethis::result` object. The example below returns a correct/incorrect answer with 50/50 probability. +`gradethis` can accept any checking method that returns a `gradethis::graded` object. +The example below returns a correct/incorrect answer with 50/50 probability. ````markdown @@ -262,8 +239,7 @@ fifty_fifty_checker <- function( user ) { is_correct <- (runif(1) < 0.5) - gradethis::result( - x = user, + gradethis::graded( correct = is_correct, message = ifelse(is_correct, correct, incorrect) ) @@ -290,8 +266,7 @@ fifty_fifty_checker <- function( user ) { is_correct <- (runif(1) < 0.5) - gradethis::result( - x = user, + gradethis::graded( correct = is_correct, message = ifelse(is_correct, correct, incorrect) )