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 (Xie 2025) 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:
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” (Hadley Wickham and Grolemund (2026)), the use of absolute paths hinders sharing. Thus one should only ever use relative paths in scripts.
The autoharp relies heavily on the concept of environments within R. As described in chapter 7 (Wickham (2019)), 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.
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 HooksAs described in chapter 13 (Xie et al.
(2020)), 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.