diff --git a/vignettes/basic_chunks.Rmd b/vignettes/basic_chunks.Rmd
index afb64005..261e73b6 100644
--- a/vignettes/basic_chunks.Rmd
+++ b/vignettes/basic_chunks.Rmd
@@ -11,72 +11,65 @@ vignette: >
# The chunks container
-The main concept behind the code chunks is the chunks container. This container consists of two elements:
+The main concept behind code reproducibility in teal is the chunks container object. This object consists of two elements:
1. A stack of quoted R expressions, each called a "chunk"
-2. An environment carrying variable values
+2. An environment carrying variables and their values
-Each chunk can be evaluated inside the current environment. To evaluate all chunks inside the same environment, the `chunks` R6 object was created in `teal.code`. We refer to this object as "chunks container". It internally has a stack of `chunk` objects and the environment where they will get evaluated.
+The chunks container object allows the evaluation of all expressions it contains in its own isolated environment, thus having no side effects on the surrounding environment.
The next sections will explain what a chunk is and how it is evaluated.
# What is a chunk?
-A quoted R expression is a necessary step to create a **chunk** object, which is an R6 object of class `chunk_call`. Quoted R expressions can be created in three different ways:
+A quoted R expression is a necessary step to create a **chunk** object, which is an R6 object of class `chunk_call`. Quoted R expressions can be created in many different ways, four of which will be described:
```{r}
a <- 3
# Creating a chunk by quote ------------------------------
expr_a <- quote(sum(a, a))
print(expr_a)
-print(class(expr_a))
-
-# Creating a chunk by bquote ------------------------------
-expr_b <- bquote(b <- sum(a, a))
+# Creating a chunk by substitute ------------------------------
+expr_b <- substitute(b <- sum(a, a))
print(expr_b)
-print(class(expr_b))
# Creating a chunk by call -------------------------------
expr_c <- call("sum", a, a)
print(expr_c)
-print(class(expr_c))
+
+# Creating a chunk by rlang::expr -------------------------------
+expr_d <- rlang::expr(sum(a, a))
+print(expr_d)
```
-To evaluate the expressions of class `call` or an assignment given by class `<-` above, R uses the `eval` function. This function evaluates each single `call` inside the current environment, in case no other environment is given. In the example code you can see what happens upon evaluating the expressions:
+To evaluate the expressions of class `call` or an assignment given by class `<-` above, R uses the `eval` function. This function evaluates each single `call` inside the current environment by default, but it does contain a parameter to input a specific environment argument to execute the expression in.
```{r}
a <- 3
expr_a <- quote(sum(a, a))
-expr_b <- bquote(b <- a + a)
-expr_c <- call("sum", a, a)
+expr_b <- substitute(b <- a + a)
eval(expr_a)
eval(expr_b)
print(b)
-eval(expr_c)
```
-Now `chunk` objects can be created and evaluated using the expressions above as follows:
-```{r}
-a <- 3
-expr_a <- quote(sum(a, a))
-expr_b <- bquote(b <- a + a)
-expr_c <- call("sum", a, a)
+`chunk` objects can be created and evaluated using the expressions above as follows:
+```{r}
chunk_1 <- teal.code::chunk$new(expression = expr_a)
chunk_1$eval()
chunk_2 <- teal.code::chunk$new(expression = expr_b)
chunk_2$eval()
print(b)
-
-chunk_3 <- teal.code::chunk$new(expression = expr_c)
-chunk_3$eval()
```
+
Note that `teal.code::chunk` is merely an alias for `teal.code::chunk_call`. And so the following code is the same as the above code:
+
```{r}
chunk_1 <- teal.code::chunk_call$new(expression = expr_a)
chunk_1$eval()
@@ -84,9 +77,6 @@ chunk_1$eval()
chunk_2 <- teal.code::chunk_call$new(expression = expr_b)
chunk_2$eval()
print(b)
-
-chunk_3 <- teal.code::chunk_call$new(expression = expr_c)
-chunk_3$eval()
```
## Motivation for the chunk (chunk_call) object
@@ -107,177 +97,152 @@ chunk_err$eval()
chunk_err$get_errors()
```
-Internally, the `chunks` container will convert quoted R expressions into `chunk` objects as they are pushed in.
+Internally, the `chunks` container will convert quoted base R expressions into `chunk` objects as they are pushed in.
+## Creation of a chunks container object
-The next sections will tell in a step by step guide which features are provided by the `chunks` container object.
+A chunks container may be initialized as an empty container.
-# Step by step to understand chunks container
+```{r}
+# initializing code chunks -------------------------------------------
+chunks_container_empty <- teal.code::chunks$new()
+```
-## General information
+However, it can also be initialized with a specific environment.
-Normally as a module developer the chunks container will be used within the `server` function of a shiny/teal module. This enables storing the chunks container inside the shiny session. For simplicity reasons this feature will be used in the tutorial. To store a container inside the shiny session simply use the call `init_chunks()` and the `chunks` R6 object will be stored in `session$userData$$chunks`. After using `init_chunks()`, the functions dealing with chunks container can be used. Those are recommended. If for any reasons you want to use your own chunks container, it is possible. Please see the last section of this article for more information. So for now, we just call `teal.code::init_chunks()`.
+```{r}
+# initializing code chunks -------------------------------------------
+env <- new.env()
+env$var_to_be_erased <- "some_value"
+env$x <- 0
+chunks_container <- teal.code::chunks$new(envir = env)
-As a simulation of the teal environment the `init_session` function is provided:
+# method to list all variables in the chunks environment
+chunks_container$ls()
-```{r}
-# pseudo code simulating a shiny session ----------------------------
-init_session <- function() {
- session <- new.env()
- session$userData <- new.env() # nolint
- session$ns <- function(x) paste0("x-", x)
- return(session)
-}
+# function to add a chunk to a chunks container object
+teal.code::chunks_push(quote(print(x)), chunks = chunks_container)
-# initializing code chunks -------------------------------------------
-session <- init_session()
-teal.code::init_chunks(session = session)
+# function to get all expressions from a chunks container code stack
+teal.code::chunks_get_rcode(chunks_container)
```
-## Feature 1: Reset (initialize the environment)
+
-Normally reproducible code will be used inside a `renderPlot` or `renderTable` call of a shiny module. For simplicity reasons we just use the *pseudo* shiny session defined above in this tutorial. As a first step the chunks container should be handed over an analysis dataset (`anl`) and two variables `x = "abc"`, `y = 5`. Therefore you need to use the `teal.code::chunks_reset` function. It not only empties all current chunks inside the container, but also hands over all variables from the current environment to the container environment.
+At any point, a chunks container can be reset. Resetting means that all expressions in its code stack will be emptied and its environment will be overridden by the inputted environment, which defaults to the parent environment.
-To check that it worked as expected the function `teal.code::chunks_get_var` will be used and check that the values inside the chunks container are equal to the values from the environment.
+```{r}
+env <- new.env()
+env$anl <- data.frame(left = c(1, 2, 3), right = c(4, 5, 6))
+env$x <- "abc"
+env$y <- 5
-You can use this code snippet:
+teal.code::chunks_reset(envir = env, chunks = chunks_container)
-```{r}
-# Adding variables to the chunks container -------------------------------------
-anl <- data.frame(left = c(1, 2, 3), right = c(4, 5, 6))
-x <- "abc"
-y <- 5
+# note that the variable var_to_be_erased is removed
+chunks_container$ls()
-teal.code::chunks_reset()
+# this function is used to extract values of variables in a chunks container environment
+# note that the variable x is overriden
+teal.code::chunks_get_var("x", chunks = chunks_container)
-# Double check variables were handed over-----------------------------
-all.equal(x, teal.code::chunks_get_var("x"))
+# note that the code stack has been emptied
+teal.code::chunks_get_rcode(chunks_container)
```
-
-## Feature 2: Push - adding code snippets
-
-To populate the chunks container, a chunk can be added using the `teal.code::chunks_push` function. Here two code snippets will be added:
+As mentioned above, the `teal.code::chunks_push` function is used to push expressions into the chunks container.
```{r}
-teal.code::chunks_push(bquote(y <- y + 1))
-teal.code::chunks_push(bquote(x <- paste0(x, y)))
+teal.code::chunks_push(substitute(y <- y + 1), chunks = chunks_container)
+teal.code::chunks_push(substitute(x <- paste0(x, y)), chunks = chunks_container)
```
-## Feature 3: Get R code - showing the chunks container code
-
-To reproduce what was done inside the chunks container, it is necessary to render the R code inside them. Therefore the chunks container can display all its code by calling `teal.code::chunks_get_rcode`. You can run this example to see the code:
+As mentioned above, the `teal.code::chunks_get_rcode` function is used to get all expressions pushed into the chunks container.
```{r}
-teal.code::chunks_get_rcode()
+teal.code::chunks_get_rcode(chunks_container)
```
-## Feature 4: `eval` - evaluating the code
-
-The `eval` function is responsible to run the code inside the chunks container. The `eval` function of a chunks container is called `teal.code::chunks_safe_eval`. It evaluates all chunks inside the container in the order they were pushed. It is not possible to change the order or run just pieces of the code.
+## Executing the code stored in the stack
-The `teal.code::chunks_safe_eval` will always return the value of the last evaluation. By `teal.code::chunks_get_var` it is possible to retrieve specific variables after evaluation.
+The chunks container also has an `eval` method which runs all code inside the chunks container. This method is wrapped inside the function `teal.code::chunks_safe_eval`. It evaluates all chunks inside the container in the order they were pushed and returns the value of the last evaluated expression. It is not possible to change the order or run just some of the expressions.
```{r}
-teal.code::chunks_safe_eval()
-teal.code::chunks_get_var("x")
-teal.code::chunks_get_var("y")
+teal.code::chunks_safe_eval(chunks_container)
+teal.code::chunks_get_var("x", chunks = chunks_container)
+teal.code::chunks_get_var("y", chunks = chunks_container)
```
-## Feature 5: Is ok - check for errors and warnings
-
-A chunks container object also has its own `eval` method. The function `teal.code::chunks_safe_eval` is merely a wrapper of this method. It is named `"safe_eval"` because it performs an additional step to handle errors by calling another method of the chunks container object, `validate_is_ok`. If any error occurs during the evaluation of expressions pushed into the chunks container, the error is handled and stored in the `chunk` object that contains the expression, and thus no error is thrown to the calling environment.
+It is still possible to push more code expressions into a chunks container that has already been evaluated. These newly added expressions may also modify the environment.
-The most important function to check if everything went fine is `teal.code::chunks_is_ok`. It will return `TRUE` in the case where everything was fine.
-
-`teal.code::chunks_validate_is_ok` returns a useful `validate(need(...))` message inside the shiny app in case something went wrong.
-
-```{r, error=TRUE}
-teal.code::chunks_is_ok()
-teal.code::chunks_validate_is_ok()
-
-# Trying an error inside a chunk ------------------------
-teal.code::chunks_push(quote(stop("ERROR")))
-teal.code::chunks_safe_eval()
-
-teal.code::chunks_is_ok()
+```{r}
+teal.code::chunks_push(quote(z <- 10), chunks = chunks_container)
+teal.code::chunks_get_rcode(chunks_container)
-teal.code::chunks_validate_is_ok()
+teal.code::chunks_safe_eval(chunks_container)
+chunks_container$ls()
+teal.code::chunks_get_var("z", chunks = chunks_container)
```
-
-
-The use of the `teal.code::chunks_safe_eval` is extremely important in a reactive context, such as inside the server function of a shiny app. Since errors are not thrown to the environment calling the chunks container, it will not crash the shiny app, which is a good thing. However, the shiny app will also not know that an error has occurred. Calling `teal.code::chunks_safe_eval` instead of the `eval` method of the chunks container ensures that a validation step occurs.
+Note that code that have already been evaluated will not be re-evaluated when newly added code is evaluated.
-## Tutorial Summary
+```{r}
+teal.code::chunks_push(quote(print("I will only be evaluated once")), chunks = chunks_container)
+teal.code::chunks_safe_eval(chunks_container)
-In summary:
+teal.code::chunks_push(quote(rm(z)), chunks = chunks_container)
-1. chunks containers host code snippets
-2. chunks containers host their own environment
-3. chunks containers are initialized inside shiny/teal using `teal.code::init_chunks`
-4. chunks container can be accessed to retrieve variables from the environment using `teal.code::chunks_get_var`
-5. chunks can be added to the chunks container by `teal.code::chunks_push`
-6. All chunks inside a container can be executed by `teal.code::chunks_safe_eval`
-7. `teal.code::chunks_validate_is_ok` and `teal.code::chunks_is_ok` allow checking for execution errors
+# note that the string "I will only be evaluated once" is not printed again
+teal.code::chunks_safe_eval(chunks_container)
-The whole implementation of this tutorial is given in the *gif* below:
+# z is removed
+chunks_container$ls()
+```
-
+## Handling errors (and warnings)
+The function `teal.code::chunks_safe_eval` is named `"safe_eval"` because it performs an additional step to handle errors by calling another method of the chunks container object, `validate_is_ok`. If any error occurs during the evaluation of expressions pushed into the chunks container, the error is handled and stored in the `chunk` object that contains the expression, and thus no error is thrown to the calling environment.
-For more information about the implementation of chunks inside of shiny/teal module, please visit the Advanced chunks article.
+The function `teal.code::chunks_is_ok` will return `TRUE` if all evaluated expressions in the chunks container evaluated without throwing an error.
-Please find below the implicit vs. explicit usage of code chunks containers.
+`teal.code::chunks_validate_is_ok` returns a useful `validate(need(...))` which a shiny app will use to display an error message in the UI instead of crashing the app.
----
+```{r, error=TRUE}
+teal.code::chunks_is_ok(chunks_container)
+teal.code::chunks_validate_is_ok(chunks = chunks_container)
-## Implementation of code chunks containers
+# Trying an error inside a chunk ------------------------
+teal.code::chunks_push(quote(stop("ERROR")), chunks = chunks_container)
+teal.code::chunks_safe_eval(chunks_container)
-There are two ways to initialize the code chunks inside shiny modules:
+teal.code::chunks_is_ok(chunks_container)
-- Using R6 implementation: `session_chunks <- chunks$new()`.
+# internally, teal.code::chunks_safe_eval calls teal.code::chunks_validate_is_ok before returning
+teal.code::chunks_validate_is_ok(chunks = chunks_container)
+```
-- Using `teal.code` wrappers: `teal.code::init_chunks()`.
+
-The `teal.code` functions can be used in both cases:
+The use of the `teal.code::chunks_safe_eval` is good practice in a reactive context. Since errors are not thrown to the environment calling the chunks container, it will not crash the shiny app, which is a good thing. However, the shiny app will also not know that an error has occurred. Calling `teal.code::chunks_safe_eval` instead of the `eval` method of the chunks container ensures that a validation step occurs.
+## Tutorial Summary
-```{r}
-session <- init_session()
-teal.code::init_chunks()
-a <- 1
-b <- 2
-
-# set a & b in env
-teal.code::chunks_reset()
-# push to chunks
-teal.code::chunks_push(expression = bquote(a <- a + 1))
-# eval gives return value
-teal.code::chunks_safe_eval()
-stopifnot(teal.code::chunks_get_var("a") == 2)
-
-teal.code::chunks_push(expression = bquote(c <- a + b))
-teal.code::chunks_safe_eval()
-stopifnot(teal.code::chunks_get_var("c") == 4)
-teal.code::chunks_push(expression = quote(a + b + c))
-stopifnot(teal.code::chunks_safe_eval() == 8)
-# create a new chunks object explicitly
-chunks2 <- teal.code::chunks$new()
-# push into this object
-teal.code::chunks_push(bquote(d <- 1), chunks = chunks2)
-# push the whole of chunks2 into our main chunks object
-teal.code::chunks_push_chunks(chunks2)
-# evaluate and get results
-teal.code::chunks_safe_eval()
-teal.code::chunks_get_var("d")
-```
+In summary:
-The _default_ `chunks` object in many `teal.code` functions is the `chunks` object coupled to the shiny session. But as shown above it is possible to use other `chunk` objects with these functions using their `chunks` argument. The `chunks` object is an R6 object and consult the function documentation for details of its explicit methods.
+1. chunks containers host code snippets
+2. chunks containers host their own environment
+3. chunks container can be accessed to retrieve variables from the environment using `teal.code::chunks_get_var`
+4. expressions can be added to the chunks container by `teal.code::chunks_push`
+5. code inside a container is executed by its `eval` method.
+6. `teal.code::chunks_is_ok` allows checking for execution errors
+7. `teal.code::chunks_validate_is_ok` allows a shiny app to display a validate message of the errors in the UI
+8. `teal.code::chunks_safe_eval` will evaluate all snippets of the chunks container and then call `validate(need(...))` to let a shiny app silently handle any errors that occurred so that error messages can be outputted in the UI.
+
+For more information about the implementation of chunks inside of shiny/teal module, please go on to the Advanced chunks article.
diff --git a/vignettes/images/chunks_animation.gif b/vignettes/images/chunks_animation.gif
deleted file mode 100644
index 2fcc6a2b..00000000
Binary files a/vignettes/images/chunks_animation.gif and /dev/null differ
diff --git a/vignettes/images/initialize_env.png b/vignettes/images/initialize_env.png
new file mode 100644
index 00000000..f2ae8bb3
Binary files /dev/null and b/vignettes/images/initialize_env.png differ
diff --git a/vignettes/images/is_ok.png b/vignettes/images/is_ok.png
index f61f20fc..06c03306 100644
Binary files a/vignettes/images/is_ok.png and b/vignettes/images/is_ok.png differ
diff --git a/vignettes/images/reset.png b/vignettes/images/reset.png
index 444e9f76..d2581df0 100644
Binary files a/vignettes/images/reset.png and b/vignettes/images/reset.png differ