Skip to content

Instantly share code, notes, and snippets.

@hadley
Created September 27, 2013 20:04
Show Gist options
  • Save hadley/6734404 to your computer and use it in GitHub Desktop.
Save hadley/6734404 to your computer and use it in GitHub Desktop.
# A tutorial navigates through a series of states, either manually, with
# nxt(), prv(), jmp() etc, or automatically, by using addTaskCallback() and
# checking that preconditions are met.
#
# Each state has:
# * a message
# * a next state (a function name)
# (eventually may have multiple next named states)
# * an auto test
#
# Questions:
#
# * how could you make it more interactive like a pick-a-path book?
# * would need to have multiple "next" tests
# * would it make sense to have a special file format? (json based?)
# * if running on web, how would you modify stuff outside of the cli?
# * how can you save state so you can start again later?
# * states should have setup functions that they can use to ensure that
# the environment is in the right state
# * should have the ability to run code and show output
# * need to be able to load/run "modules"
# * build simple web interface?
# * v. similar to command line, but sends json result
# * two components: script output, new instructions
library(stringr)
frndly <- new.env(parent = emptyenv())
frndly_out <- function(...) {
wrapped <- strwrap(str_c(..., sep = " "),
width = getOption("width") - 2)
message(str_c("| ", wrapped, collapse = "\n"))
}
hi <- function() {
addTaskCallback(auto_advance, name = "frndly")
jmp("start")
invisible()
}
bye <- function() {
frndly_out("All done! Use jmp('start') to restart.")
removeTaskCallback(which(getTaskCallbackNames() == "frndly"))
invisible()
}
jmp <- function(state) {
if (is.null(state)) return(bye())
state <- get(str_c(state, "_state"))
frndly$next_state <- state$next_state
# Only use auto-advance if the test isn't already true
if (!is.null(state$test) && !state$test()) {
frndly$test <- state$test
}
frndly_out(state$msg)
}
nxt <- function() {
jmp(frndly$next_state)
}
attr(nxt, "source") <- "| Hey you! To evaluate a function in R, you need to put () on the end."
auto_advance <- function(...) {
if (is.null(frndly$test)) return(TRUE)
# Auto-advance if test is true
if (frndly$test()) {
nxt()
}
return(TRUE)
}
new_state <- function(msg, next_state = NULL, test = NULL) {
structure(list(msg = msg, next_state = next_state, test = test),
class = "state")
}
is.state <- function(x) inherits(x, "state")
start_state <- new_state("Hi! I'm frndly, your friendly introduction to R. I'm
going to guide you through a quick introduction to R. You'll know it's me
talking whenever you see output that starts with |. Otherwise you'll
interacting with R in exactly the same way you will when I'm not around
Type nxt() to run your first R function and proceed with your introduction
to R", "assignment")
assignment_state <- new_state("In R, you create variables with the arrow: <-,
like a <- 1 or b <- 2. To continue, create a new variable called d with the
value 10, or type nxt()", "arith", function() {
exists("d", globalenv()) && get("d", globalenv()) == 10
})
arith_state <- new_state("Good work!", NULL)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment