---
title: "Key Concepts"
output:
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 2
vignette: >
  %\VignetteIndexEntry{Key Concepts}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
bibliography: references.bib
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

# Working Directories

As part of the grading process, student scripts are converted into HTML
documents. It is easier for the instructor to review this format, if necessary,
since it incorporates both the code and output in a single document. The
autoharp uses the `knitr` package [@knitr1] to achieve this goal. The process
of rendering an R script (or Rmd/qmd) into an HTML file is referred to as *knitting*.

As part of the assignments, student scripts may need to read in local datasets,
or to write to output files. Hence it is important to consider the
*working directory* when knitting a file. The working directory is the default
location that R looks when it is asked to load a file or save output. When a
file is knitted, the working directory is typically the location of the file.
However, this may not be ideal when grading hundreds of student scripts, across
multiple assignments. The instructor would want to keep their own files separate
from student output. To achieve this, the autoharp provides the
functionality to specify the working directory when knitting a file, and to
specify the directory where output should be written.

The only impositions that the package prescribes are:

*   students should mirror the instructor set-up with respect to data and output 
    files.
*   students should use relative paths in all their scripts.

Relative paths are file paths that refer to files *relative* to the working directory.
The alternative to relative paths are absolute paths, where a path is hard-coded. 
However, as pointed out in section 6.4 of "R for Data Science" (@r4ds), the use of absolute 
paths hinders sharing. Thus *one should only ever use relative paths in scripts*.

# Environments

The autoharp relies heavily on the concept of environments within R. As
described in chapter 7 (@wickham2019advanced), an environment is simply 
a data structure that associates a set of names to a set of values. It is the key 
structure in how R implements lexical scoping. Every environment (except the empty 
environment) also contains a pointer to a parent environment. When a function is 
executed, it first looks within it's execution environment for objects required. If 
an object cannot be found, the functions looks to the enclosing parent, and so on 
and so forth, until the object is found. If the object cannot be found, an error 
occurs.

The autoharp creates a separate environment for each student's script.
Objects created when rendering the student scripts are compared against model
objects, which are created in a *solution* environment when the solution
template is rendered.

# Forked R Processes

The `parallel` package allows a user to create forked R processes from a 
session. A forked session is a separate R session. It is primarily used for running
parallel code. However, the autoharp uses it to sandbox the execution of 
student scripts.

For each student script, `render_one` creates a new fork, within which the script 
is rendered. The objects generated by the student code are stored in an environment
within the forked process. Subsequently, test chunks are executed by the forked 
process within the student environment. 

The above implementation ensures that objects in the global environment (where
the instructor executes `render_one`) and packages loaded by the instructor do
not interfere with the student code. Suppose, on the other hand, that the
student scripts were executed in the same R process as the grading code. Then,
if the student had forgotten to load certain packages that their code needed,
but the instructor session had loaded those packages. Instead of failing to
render (which is what should happen in this case), the rendering would be
successful.

# `knitr` Hooks

As described in chapter 13 (@rmarkdown3), a chunk hook is a function that is
triggered by a chunk option, when the value of this chunk option is not `NULL`.
When defining a chunk hook, one can specify if the hook is to be run before or
after the execution of the subsequent chunk. 

The autoharp defines two hooks:

* `autoharp.objs`: The input to this hook must be a character vector. When the 
  input is not `NULL`, the chunk hook will create a copy of each object specified
  in the character vector, pre-prended with a period. For instance, if the 
  user specifies `autoharp.objs = "X"`, an object named `.X` will be created in the 
  execution environment of the Rmd file.
  
  The names of model solution objects in the solution environment begin with a period.
* `autoharp.scalars`: Once again, the input to this hook must be a character 
  vector. When not `NULL`, this character vector will be appended to a vector in
  the solution environment named `.scalars_to_keep`. 
  
  This serves as a reference vector. When the test chunks are executed in the student
  solution environment, the objects specified in `.scalars_to_keep` will be copied 
  out as columns in the correctness dataframe.

# References
