diff --git a/NAMESPACE b/NAMESPACE index b3b8488d7..795c0d3d8 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -40,6 +40,7 @@ export(question_ui_initialize) export(question_ui_try_again) export(quiz) export(random_encouragement) +export(random_phrases_add) export(random_praise) export(run_tutorial) export(safe) diff --git a/R/exercise.R b/R/exercise.R index 06c360935..0e189460d 100644 --- a/R/exercise.R +++ b/R/exercise.R @@ -1,4 +1,4 @@ -current_exercise_version <- "2" +current_exercise_version <- "3" # run an exercise and return HTML UI setup_exercise_handler <- function(exercise_rx, session) { @@ -24,7 +24,8 @@ setup_exercise_handler <- function(exercise_rx, session) { tutorial_id = read_request(session, "tutorial.tutorial_id"), tutorial_version = read_request(session, "tutorial.tutorial_version"), user_id = read_request(session, "tutorial.user_id"), - learnr_version = as.character(utils::packageVersion("learnr")) + learnr_version = as.character(utils::packageVersion("learnr")), + language = read_request(session, "tutorial.language") ) # short circuit for restore (we restore some outputs like errors so that @@ -210,6 +211,7 @@ upgrade_exercise <- function(exercise, require_items = NULL) { current_version <- as.numeric(current_exercise_version) if (exercise$version == 1) { + # upgrade from version 1 to version 2 # exercise version 2 added $tutorial information exercise$tutorial <- list( tutorial_id = "tutorial_id:UPGRADE learnr", @@ -217,10 +219,16 @@ upgrade_exercise <- function(exercise, require_items = NULL) { user_id = "user_id:UPGRADE learnr" ) exercise$version <- 2 - exercise } - # Future logic to upgrade an exercise from version 2 to version N goes here... + if (exercise$version == 2) { + # upgrade from version 2 to version 3 + # => add language $tutorial information + exercise$tutorial$language <- i18n_get_language_option() + exercise$version <- 3 + } + + # Future logic to upgrade an exercise from version 3 to version N goes here... if (identical(exercise$version, current_version)) { return(exercise) @@ -283,6 +291,8 @@ evaluate_exercise <- function(exercise, envir, evaluate_global_setup = FALSE) { require_items = if (evaluate_global_setup) "global_setup" ) + i18n_set_language_option(exercise$tutorial$language) + # return immediately and clear visible results # do not consider this an exercise submission if (!nzchar(str_trim(paste0(exercise$code, collapse = "\n")))) { @@ -436,12 +446,10 @@ render_exercise <- function(exercise, envir) { # Put the exercise in a minimal HTML doc output_format_exercise <- function(user = FALSE) { # start constructing knitr_options for the output format - knitr_options <- rmarkdown::knitr_options_html( - fig_width = exercise$options$fig.width, - fig_height = exercise$options$fig.height, - fig_retina = exercise$options$fig.retina, - keep_md = FALSE - ) + knitr_options <- exercise$options + # Recreate the logic of `rmarkdown::knitr_options_html()` by setting these options + knitr_options$opts_chunk$dev <- "png" + knitr_options$opts_chunk$dpi <- 96 if (isTRUE(user)) { knitr_options$knit_hooks$evaluate <- function( @@ -624,7 +632,11 @@ exercise_code_chunks_prep <- function(exercise) { } exercise_code_chunks_user <- function(exercise) { - exercise_code_chunks(exercise_get_chunks(exercise, "user")) + # chunk options on the user chunk just duplicate the exercise$options + # which are set globally for the exercise + user_chunk <- exercise_get_chunks(exercise, "user") + user_chunk[[1]]$opts <- NULL + exercise_code_chunks(user_chunk) } exercise_code_chunks <- function(chunks) { diff --git a/R/i18n.R b/R/i18n.R index c67eb84ae..319b22a9b 100644 --- a/R/i18n.R +++ b/R/i18n.R @@ -129,5 +129,59 @@ i18n_span <- function(key, ..., opts = NULL) { } i18n_translations <- function() { - readRDS(system.file("i18n_translations", package = "learnr")) + readRDS(system.file("internals", "i18n_translations.rds", package = "learnr")) +} + +i18n_set_language_option <- function(language = NULL) { + # Sets a knitr option for `tutorial.language` using language found in this order + # 1. `language` provided + # 2. From read_request() + # 3. Default + + current <- knitr::opts_knit$get("tutorial.language") + if (is.null(language)) { + session <- shiny::getDefaultReactiveDomain() + language <- + if (!is.null(session)) { + read_request(session, "tutorial.language", default_language()) + } else { + default_language() + } + } + + knitr::opts_knit$set(tutorial.language = language) + + invisible(current) +} + +i18n_get_language_option <- function() { + # 1. knitr option + lang_knit_opt <- knitr::opts_knit$get("tutorial.language") + if (!is.null(lang_knit_opt)) { + return(lang_knit_opt) + } + + # 2. Shiny current language session as last reported if available + session <- shiny::getDefaultReactiveDomain() + lang_session <- if (!is.null(session)) { + read_request(session, "tutorial.language", NULL) + } + if (!is.null(lang_session)) { + return(lang_session) + } + + # 3. R option + lang_r_opt <- getOption("tutorial.language") + if (!is.null(lang_r_opt)) { + return(lang_r_opt) + } + + # 4. final default + default_language() +} + +i18n_observe_tutorial_language <- function(input, session) { + shiny::observeEvent(input[['__tutorial_language']], { + write_request(session, 'tutorial.language', input[['__tutorial_language']]) + }) } diff --git a/R/identifiers.R b/R/identifiers.R index fef6e5b9c..a08f51760 100644 --- a/R/identifiers.R +++ b/R/identifiers.R @@ -10,7 +10,7 @@ initialize_session_state <- function(session, metadata, location, request) { } # function to initialize an identifier (read from http header or take default) - initialize_identifer <- function(identifier, default) { + initialize_identifier <- function(identifier, default) { # determine whether a custom header provides the value (fallback to default) header <- as_rook_header(getOption(sprintf("tutorial.http_header_%s", identifier))) @@ -34,15 +34,16 @@ initialize_session_state <- function(session, metadata, location, request) { # initialize and return identifiers list( - tutorial_id = initialize_identifer( + tutorial_id = initialize_identifier( "tutorial_id", default = default_tutorial_id(metadata$id, location, pkg) ), - tutorial_version = initialize_identifer( + tutorial_version = initialize_identifier( "tutorial_version", default = default_tutorial_version(metadata$version, pkg) ), - user_id = initialize_identifer("user_id", default = default_user_id()) + user_id = initialize_identifier("user_id", default = default_user_id()), + language = initialize_identifier("language", default = default_language()) ) } @@ -98,6 +99,12 @@ default_user_id <- function() { unname(Sys.info()["user"]) } +default_language <- function() { + # knitr option > R global option > default + knitr::opts_knit$get("tutorial.language") %||% + getOption("tutorial.language", "en") +} + read_request <- function(session, name, default = NULL) { if (!is.null(name)) { if (exists(name, envir = session$request)) diff --git a/R/initialize.R b/R/initialize.R index e2bae0ba9..0f066b78d 100644 --- a/R/initialize.R +++ b/R/initialize.R @@ -40,6 +40,12 @@ initialize_tutorial <- function() { singleton = TRUE ) + # record tutorial language in session object + rmarkdown::shiny_prerendered_chunk( + "server", + "learnr:::i18n_observe_tutorial_language(input, session)" + ) + # Register session stop handler rmarkdown::shiny_prerendered_chunk( 'server', diff --git a/R/praise.R b/R/praise.R index 85cb0ee87..fb731dc08 100644 --- a/R/praise.R +++ b/R/praise.R @@ -1,71 +1,170 @@ -random_praises <- c( - "Absolutely fabulous!", - "Amazing!", - "Awesome!", - "Beautiful!", - "Bravo!", - "Cool job!", - "Delightful!", - "Excellent!", - "Fantastic!", - "Great work!", - "I couldn't have done it better myself.", - "Impressive work!", - "Lovely job!", - "Magnificent!", - "Nice job!", - "Out of this world!", - "Resplendent!", - "Smashing!", - "Someone knows what they're doing :)", - "Spectacular job!", - "Splendid!", - "Success!", - "Super job!", - "Superb work!", - "Swell job!", - "Terrific!", - "That's a first-class answer!", - "That's glorious!", - "That's marvelous!", - "Very good!", - "Well done!", - "What first-rate work!", - "Wicked smaht!", - "Wonderful!", - "You aced it!", - "You rock!", - "You should be proud.", - ":)" -) - -random_encouragements <- c( - "Please try again.", - "Give it another try.", - "Let's try it again.", - "Try it again; next time's the charm!", - "Don't give up now, try it one more time.", - "But no need to fret, try it again.", - "Try it again. I have a good feeling about this.", - "Try it again. You get better each time.", - "Try it again. Perseverence is the key to success.", - "That's okay: you learn more from mistakes than successes. Let's do it one more time." -) - - #' Random praise and encouragement #' -#' Random praises and encouragements sayings to compliment your question and quiz experience. +#' Random praises and encouragements sayings to compliment your question and +#' quiz experience. +#' +#' @param language The language for the random phrase. The currently supported +#' languages include: `en` and `debug` (static phrases). #' #' @return Character string with a random saying #' @export #' @rdname random_praise -random_praise <- function() { - sample(random_praises, 1) +random_praise <- function(language = NULL) { + sample(random_phrases("praise", language), 1) } + #' @export #' @rdname random_praise -random_encouragement <- function() { - sample(random_encouragements, 1) +random_encouragement <- function(language = NULL) { + sample(random_phrases("encouragement", language), 1) +} + +read_random_phrases <- function() { + readRDS(system.file("internals", "i18n_random_phrases.rds", package = "learnr")) +} + +random_phrases_languages <- function() { + rp <- read_random_phrases() + sort(Reduce(lapply(rp, names), f = union)) +} + +random_phrases <- function(type, language = NULL) { + .random_phrases <- merge_random_phrases() + + if (!type %in% names(.random_phrases)) { + stop.( + "`type` should be one of ", + knitr::combine_words(paste0("'", names(.random_phrases), "'"), and = " or ") + ) + } + + warn_unsupported_language <- function(language, default = "en") { + if (is.null(language)) { + return(warn_unsupported_language(default)) + } + if (!language %in% names(.random_phrases[[type]])) { + warning( + "learnr doesn't know how to provide ", type, " in the language '", language, "'", + call. = FALSE + ) + return(warn_unsupported_language(default)) + } + language + } + + language <- warn_unsupported_language(language, i18n_get_language_option()) + + .random_phrases[[type]][[language]] +} + +#' Add Phrases to the bank of random phrases +#' +#' Augment the random phrases available in [random_praise()] and +#' [random_encouragement()] with phrases of your own. Note that these phrases +#' are added to the existing phrases, rather than overwriting them. +#' +#' @section Usage in learnr tutorials: +#' +#' To add random phrases in a learnr tutorial, you can either include one or +#' more calls to `random_phrases_add()` in your global setup chunk: +#' +#' ```` +#' ```{r setup, include = FALSE}`r ''` +#' library(learnr) +#' random_phrases_add( +#' language = "en", +#' praise = "Great work!", +#' encouragement = "I believe in you." +#' ) +#' ``` +#' ```` +#' +#' Alternatively, you can call `random_phrases_add()` in a separate, standard +#' R chunk (with `echo = FALSE`): +#' +#' ```` +#' ```{r setup-phrases, echo = FALSE}`r ''` +#' random_phrases_add( +#' language = "en", +#' praise = c("Great work!", "You're awesome!"), +#' encouragement = c("I believe in you.", "Yes we can!") +#' ) +#' ``` +#' ```` +#' +#' @examples +#' random_phrases_add("demo", praise = "Great!", encouragement = "Try again.") +#' random_praise(language = "demo") +#' random_encouragement(language = "demo") +#' +#' +#' @param language The language of the phrases to be added. +#' @param praise,encouragement A vector of praising or encouraging phrases, +#' including final punctuation. +#' +#' @return Returns the previous custom phrases invisibly when called in the +#' global setup chunk or interactively. Otherwise, it returns a shiny pre- +#' rendered chunk. +#' +#' @export +random_phrases_add <- function(language = "en", praise = NULL, encouragement = NULL) { + phrases <- list() + if (!is.null(praise)) { + stopifnot(is.character(praise)) + phrases$praise <- list() + phrases$praise[[language]] <- praise + } + if (!is.null(encouragement)) { + stopifnot(is.character(encouragement)) + phrases$encouragement <- list() + phrases$encouragement[[language]] <- encouragement + } + if ( + isTRUE(getOption('knitr.in.progress')) + ) { + if (!identical(knitr::opts_current$get("label"), "setup")) { + rmarkdown::shiny_prerendered_chunk( + context = "server-start", + singleton = TRUE, + sprintf( + "learnr:::update_custom_random_phrases(%s)", + dput_to_string(phrases) + ) + ) + } + } else { + update_custom_random_phrases(phrases) + } +} + +update_custom_random_phrases <- function(x) { + custom_phrases <- knitr::opts_chunk$get("tutorial.random_phrases") + if (is.null(custom_phrases)) { + knitr::opts_chunk$set("tutorial.random_phrases" = x) + return(invisible(custom_phrases)) + } + + new_phrases <- merge_random_phrases(x, custom_phrases) + + knitr::opts_chunk$set("tutorial.random_phrases" = new_phrases) + invisible(custom_phrases) } + +merge_random_phrases <- function( + new = knitr::opts_chunk$get("tutorial.random_phrases"), + current = read_random_phrases() +) { + if (is.null(new)) { + return(current) + } + for (type in names(new)) { + for (lang in names(new[[type]])) { + current[[type]][[lang]] <- c( + current[[type]][[lang]], + new[[type]][[lang]] + ) + } + } + current +} \ No newline at end of file diff --git a/data-raw/i18n_random-phrases.yml b/data-raw/i18n_random-phrases.yml new file mode 100644 index 000000000..13b54bc59 --- /dev/null +++ b/data-raw/i18n_random-phrases.yml @@ -0,0 +1,71 @@ +praise: + testing: + - RANDOM PRAISE. + en: + - Absolutely fabulous! + - Amazing! + - Awesome! + - Beautiful! + - Bravo! + - Cool job! + - Delightful! + - Excellent! + - Fantastic! + - Great work! + - I couldn't have done it better myself. + - Impressive work! + - Lovely job! + - Magnificent! + - Nice job! + - Out of this world! + - Resplendent! + - Smashing! + - Someone knows what they're doing :) + - Spectacular job! + - Splendid! + - Success! + - Super job! + - Superb work! + - Swell job! + - Terrific! + - That's a first-class answer! + - That's glorious! + - That's marvelous! + - Very good! + - Well done! + - What first-rate work! + - Wicked smaht! + - Wonderful! + - You aced it! + - You rock! + - You should be proud. + emo: + - ๐Ÿ˜€ + - ๐Ÿ˜ + - ๐Ÿ˜‡ + - ๐Ÿฅณ + - ๐Ÿ˜ป + - ๐Ÿ˜Ž + - ๐Ÿฅ‡ + - ๐ŸŽ‰ + - ๐Ÿ’ฏ +encouragement: + testing: + - RANDOM ENCOURAGEMENT. + en: + - Please try again. + - Give it another try. + - Let's try it again. + - Try it again; next time's the charm! + - Don't give up now, try it one more time. + - But no need to fret, try it again. + - Try it again. I have a good feeling about this. + - Try it again. You get better each time. + - Try it again. Perseverence is the key to success. + - "That's okay: you learn more from mistakes than successes. Let's do it one more time." + emo: + - ๐Ÿค— + - ๐Ÿค˜ + - ๐Ÿ’ช + - ๐Ÿคž + - ๐Ÿ™Œ diff --git a/data-raw/i18n_translations.R b/data-raw/i18n_translations.R index 6652d0cb4..adc9e9743 100644 --- a/data-raw/i18n_translations.R +++ b/data-raw/i18n_translations.R @@ -35,7 +35,7 @@ reencode_utf8 <- function(x) { USE.NAMES = FALSE, FUN = function(x) { - bytes_nz <- x[x > 0] + bytes_nz <- x[min(which(x > 0)):length(x)] if (length(bytes_nz) > 2) { out <- paste("\\U", paste(as.hexmode(x), collapse = ""), sep = "") @@ -90,4 +90,12 @@ translations_list <- # Drop null keys again map_depth(3, compact) -saveRDS(translations_list, file = here("inst/i18n_translations"), version = 2) +saveRDS(translations_list, file = here("inst", "internals", "i18n_translations.rds"), version = 2) + +i18n_random_phrases <- + here("data-raw", "i18n_random-phrases.yml") %>% + yaml::read_yaml() %>% + map_depth(3, reencode_utf8) %>% + map_depth(2, map_chr, stri_unescape_unicode) + +saveRDS(i18n_random_phrases, file = here("inst", "internals", "i18n_random_phrases.rds"), version = 2) diff --git a/inst/internals/i18n_random_phrases.rds b/inst/internals/i18n_random_phrases.rds new file mode 100644 index 000000000..56a0e1cf6 Binary files /dev/null and b/inst/internals/i18n_random_phrases.rds differ diff --git a/inst/i18n_translations b/inst/internals/i18n_translations.rds similarity index 100% rename from inst/i18n_translations rename to inst/internals/i18n_translations.rds diff --git a/inst/lib/i18n/tutorial-i18n-init.js b/inst/lib/i18n/tutorial-i18n-init.js index 716933742..6b973de74 100644 --- a/inst/lib/i18n/tutorial-i18n-init.js +++ b/inst/lib/i18n/tutorial-i18n-init.js @@ -71,15 +71,18 @@ $(document).on("shiny:sessioninitialized", function () { return $.includes(this.dataset, "i18n"); }); + // tell the shiny process that the language was changed + Shiny.setInputValue("__tutorial_language", i18next.language) + if (!$els.length) { - // console.error('No elements found for localization with selector ' + selector); + // No elements found for localization with selector return; } $els.each(function (idx) { var optsItem = $.extend({}, opts); // Note: `this.dataset.i18nOpts` maps directly to the DOM element attribute `data-i18n-opts` - // And `this.dataset.i18nAttrVALUE` to element attribute `data-i18n-attr-VALUE` + // And `this.dataset.i18nAttrVALUE` to element attribute `data-i18n-attr-VALUE` // Link: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes // Reference: // > To get a data attribute through the dataset object, get the property diff --git a/man/random_phrases_add.Rd b/man/random_phrases_add.Rd new file mode 100644 index 000000000..a93b614cf --- /dev/null +++ b/man/random_phrases_add.Rd @@ -0,0 +1,56 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/praise.R +\name{random_phrases_add} +\alias{random_phrases_add} +\title{Add Phrases to the bank of random phrases} +\usage{ +random_phrases_add(language = "en", praise = NULL, encouragement = NULL) +} +\arguments{ +\item{language}{The language of the phrases to be added.} + +\item{praise, encouragement}{A vector of praising or encouraging phrases, +including final punctuation.} +} +\value{ +Returns the previous custom phrases invisibly when called in the +global setup chunk or interactively. Otherwise, it returns a shiny pre- +rendered chunk. +} +\description{ +Augment the random phrases available in \code{\link[=random_praise]{random_praise()}} and +\code{\link[=random_encouragement]{random_encouragement()}} with phrases of your own. Note that these phrases +are added to the existing phrases, rather than overwriting them. +} +\section{Usage in learnr tutorials}{ + + +To add random phrases in a learnr tutorial, you can either include one or +more calls to \code{random_phrases_add()} in your global setup chunk:\preformatted{```\{r setup, include = FALSE\}`r ''` +library(learnr) +random_phrases_add( + language = "en", + praise = "Great work!", + encouragement = "I believe in you." +) +``` +} + +Alternatively, you can call \code{random_phrases_add()} in a separate, standard +R chunk (with \code{echo = FALSE}):\preformatted{```\{r setup-phrases, echo = FALSE\}`r ''` +random_phrases_add( + language = "en", + praise = c("Great work!", "You're awesome!"), + encouragement = c("I believe in you.", "Yes we can!") +) +``` +} +} + +\examples{ +random_phrases_add("demo", praise = "Great!", encouragement = "Try again.") +random_praise(language = "demo") +random_encouragement(language = "demo") + + +} diff --git a/man/random_praise.Rd b/man/random_praise.Rd index c160c770d..7bd632780 100644 --- a/man/random_praise.Rd +++ b/man/random_praise.Rd @@ -5,13 +5,18 @@ \alias{random_encouragement} \title{Random praise and encouragement} \usage{ -random_praise() +random_praise(language = NULL) -random_encouragement() +random_encouragement(language = NULL) +} +\arguments{ +\item{language}{The language for the random phrase. The currently supported +languages include: \code{en} and \code{debug} (static phrases).} } \value{ Character string with a random saying } \description{ -Random praises and encouragements sayings to compliment your question and quiz experience. +Random praises and encouragements sayings to compliment your question and +quiz experience. } diff --git a/sandbox/multilang.Rmd b/sandbox/multilang.Rmd index 69a1a8f20..52497b413 100644 --- a/sandbox/multilang.Rmd +++ b/sandbox/multilang.Rmd @@ -46,13 +46,13 @@ jsonlite::write_json( ) ``` - ```{r setup, include=FALSE} library(learnr) library(nycflights13) options(tutorial.event_recorder = function(...) { message(capture.output(learnr:::debug_event_recorder(...))) }) +random_phrases_add("es", "Buen trabajo!", "Intentalo de nuevo.") tutorial_options( exercise.eval = FALSE, exercise.checker = function(label, user_code, envir_result, ...) { @@ -67,6 +67,12 @@ tutorial_options( ) ``` + +```{r echo=FALSE} +random_phrases_add("es", "Que bueno!", "Una vez mรกs, por favor.") +``` + + ## intro This is the intro to the whole ball of wax. diff --git a/tests/testthat/helpers-exercise.R b/tests/testthat/helpers-exercise.R index 7e9ac94e7..a073bc7c3 100644 --- a/tests/testthat/helpers-exercise.R +++ b/tests/testthat/helpers-exercise.R @@ -79,13 +79,16 @@ mock_exercise <- function( version = version ) - if (!is.null(version) && version == "2") { + if (!is.null(version) && version %in% c("2", "3")) { ex$tutorial <- list( id = "mock_tutorial_id", version = "9.9.9", user_id = "the_learnr", learnr_version = as.character(utils::packageVersion("learnr")) ) + if (version == "3") { + ex$tutorial$language <- "en" + } return(ex) } diff --git a/tests/testthat/test-exercise.R b/tests/testthat/test-exercise.R index 7fd6612dc..b97188b22 100644 --- a/tests/testthat/test-exercise.R +++ b/tests/testthat/test-exercise.R @@ -444,12 +444,24 @@ test_that("exercise versions upgrade correctly", { expect_match(ex_1_upgraded$tutorial$tutorial_id, "UPGRADE") expect_match(ex_1_upgraded$tutorial$tutorial_version, "-1") expect_match(ex_1_upgraded$tutorial$user_id, "UPGRADE") - expect_equal(paste(ex_1_upgraded$version), "2") + expect_equal(paste(ex_1_upgraded$version), "3") ex_2 <- mock_exercise(version = "2") expect_type(ex_2$tutorial, "list") + ex_2$tutorial$language <- "en" expect_identical(ex_2$tutorial, upgrade_exercise(ex_2)$tutorial) + i18n_set_language_option("foo") + ex_2 <- mock_exercise(version = "2") + expect_type(ex_2$tutorial, "list") + ex_2$tutorial$language <- "foo" + expect_identical(ex_2$tutorial, upgrade_exercise(ex_2)$tutorial) + knitr::opts_knit$set("tutorial.language" = NULL) + + ex_3 <- mock_exercise(version = "3") + expect_type(ex_3$tutorial, "list") + expect_identical(ex_3$tutorial, upgrade_exercise(ex_3)$tutorial) + # future versions ex_99 <- mock_exercise(version = 99) expect_equal( diff --git a/tests/testthat/test-praise.R b/tests/testthat/test-praise.R new file mode 100644 index 000000000..c7047620a --- /dev/null +++ b/tests/testthat/test-praise.R @@ -0,0 +1,31 @@ +test_that("random_phrases()", { + expect_error(random_phrases("foo"), "should be one of") + expect_warning( + expect_equal(random_phrases("praise", "foo"), random_phrases("praise", "en")) + ) + + knitr::opts_knit$set("tutorial.language" = "en") + expect_equal(random_phrases("praise"), random_phrases("praise", "en")) + expect_equal(random_phrases("encouragement"), random_phrases("encouragement", "en")) + knitr::opts_knit$set("tutorial.language" = NULL) + + expect_equal(random_phrases("praise", "testing"), "RANDOM PRAISE.") + expect_equal(random_phrases("encouragement", "testing"), "RANDOM ENCOURAGEMENT.") +}) + +test_that("random_phrases_add()", { + random_phrases_add( + language = "bogus", + praise = "Praise here!", + encouragement = c("Go 1", "Go 2") + ) + + expect_equal(random_phrases("praise", "bogus"), "Praise here!") + expect_equal(random_phrases("encouragement", "bogus"), c("Go 1", "Go 2")) + + random_phrases_add("bogus", encouragement = "Go 3") + expect_equal(random_phrases("encouragement", "bogus"), c("Go 1", "Go 2", "Go 3")) + + expect_error(random_phrases_add("bogus", list("bad"))) + expect_error(random_phrases_add("bogus", 1:4)) +})