Title: | Manage Rubrics or Assessment Grids for GitHub Repositories |
---|---|
Description: | Create and manage semi-automatically rubrics to assess GitHub projects (R scripts, R Markdown or Quarto files). Create directed projects where students have to complete documents and submit them to GitHub (classroom) so that they are evaluated using the rubric (or assessment grid). |
Authors: | Philippe Grosjean [aut, cre] , Guyliann Engels [aut] |
Maintainer: | Philippe Grosjean <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.9.0 |
Built: | 2024-11-10 03:31:22 UTC |
Source: | https://github.com/learnitr/learnitgrid |
Check all evaluation grids in a correction set and computes the required statistics for the summary page of the learnitgrid shiny app.
check_grids(dir, save.log = TRUE, save.rds = TRUE)
check_grids(dir, save.log = TRUE, save.rds = TRUE)
dir |
The path to the evaluation grids |
save.log |
Should a log file be saved (yes by default)? |
save.rds |
Should an RDS file with the data be saved (yes by default)? |
A data frame with the results of the evaluation grids check for the learnitgrid Shiny app.
Make proper Rmd/Qmd chunk labels from strings for parsermd::parse_rmd()
chunk_labels(x)
chunk_labels(x)
x |
A character string of chunk labels to convert |
A character string of the same length as x
with "educated" labels.
chunk_labels(c("Summer is hot", "", NA, " ", "Winter is cold "))
chunk_labels(c("Summer is hot", "", NA, " ", "Winter is cold "))
When GitHub repositories for a Classroom assessment are cloned, the data
cache is not present. For large datasets, it may take a long time to get
the data from an URL for each repository. By using a single version of the
data cache, on can populated the corresponding folder in each repository.
The CC()
function can be used to remove the data from the cache.
copy_cache() CC(only_if_copied = FALSE, cache_data = cache_data)
copy_cache() CC(only_if_copied = FALSE, cache_data = cache_data)
only_if_copied |
If |
cache_data |
The list of copied files, returned by |
The list of copied files is returned invisibly.
Make sure that Rmd/Qmd chunk labels are written without spaces
correct_rmd(rmd)
correct_rmd(rmd)
rmd |
Character string with the content of a Rmd/Qmd file. |
The same Rmd/Qmd content, but with "educated" chunk labels.
Create a list that contains context for a given correction set (must be recalculated when a different correction set/project is selected).
create_context( correction, base_corr_dir, base_templ_dir, base_repos_dir, repositories, assignments, github_url, branch )
create_context( correction, base_corr_dir, base_templ_dir, base_repos_dir, repositories, assignments, github_url, branch )
correction |
The correction set |
base_corr_dir |
The base directory for correction sets |
base_templ_dir |
The base directory for correction templates |
base_repos_dir |
The vase directory for GitHub repositories to correct |
repositories |
The repositories |
assignments |
The assignments |
github_url |
The GitHub URL (base part) |
branch |
The GitHub branch concerned by this correction |
A list with the context information for the learnitgrid Shiny app.
Transformation functions for creating reference or result objects for testing progress of the students in their project.
df_structure(object, ...) digest(object, algo = "md5", ...) object_attr(object, attrib = "class", ...) object_part(object, part = "x", ...) object_str(object, part = "x", ...)
df_structure(object, ...) digest(object, algo = "md5", ...) object_attr(object, attrib = "class", ...) object_part(object, part = "x", ...) object_str(object, part = "x", ...)
object |
The object to transform |
... |
Further arguments (not used for now) |
algo |
algorithm to use for digest, |
attrib |
The attribute(s) to record from the object |
part |
The part(s) to record from the object (list items) |
df_structure()
returns names, attributes "label" and "units",
number of row and columns, classes, if there are missing data and comment in
a data frame. digest()
returns a hash of the object. object_attr()
returns the attribute(s) of the object. object_part()
returns the part(s)
of an object (list items). object_str()
returns a str() representation of
the object parts.
Make sure a directory exists, or create it
dir_path_create(...) dir_path_check(...) file_path_check(...)
dir_path_create(...) dir_path_check(...) file_path_check(...)
... |
The successive folders that make the path. |
A path object is returned invisibly.
dir_path_check()
: Check that a directory exists.
file_path_check()
: Check that a file exists.
test_path <- dir_path_create(tempdir(), "dir_path_create_test", "subfolder") test_path dir.exists(test_path) # Should be TRUE dir_path_check(test_path) # Return the path only if it exists # Remove unlink(test_path) unlink(dirname(test_path))
test_path <- dir_path_create(tempdir(), "dir_path_create_test", "subfolder") test_path dir.exists(test_path) # Should be TRUE dir_path_check(test_path) # Return the path only if it exists # Remove unlink(test_path) unlink(dirname(test_path))
..._solution.xxx.aes
filesThese functions manage encryption and decryption of solution files. The
password must be defined in an option learnitgrid.key
or an environment
variable LEARNITGRID_KEY
under a digest form.
encrypt_solutions(key = NULL, error = TRUE) decrypt_solutions(key = NULL, error = TRUE) set_key()
encrypt_solutions(key = NULL, error = TRUE) decrypt_solutions(key = NULL, error = TRUE) set_key()
key |
The key to use for encryption/decryption. If not provided, it is asked |
error |
If |
NULL
invisibly.
Use data from a git_stats.csv file to get a history of commits done in a repository for the learnitgrid Shiny app.
get_git_stats( dir, exclude_authors = "github-classroom[bot]", type = "all", tz = "UTC" )
get_git_stats( dir, exclude_authors = "github-classroom[bot]", type = "all", tz = "UTC" )
dir |
The path the the git_stats.csv file |
exclude_authors |
The list of authors to exclude from the stats |
type |
The type of files to consider ("all", "R", "Rmd", or "Qmd") |
tz |
The time zone to use for times |
A data frame with git stats data to be used by the learnitgrid Shiny app.
Change the Knitr renderer so that the last computed object is automatically
saved as .Last.chunk
, and to record results from a chunk with chunk options
record=
.
hook_last_chunk()
hook_last_chunk()
The opts_chunk
or the knit_hook
set accordingly.
Install an extended example dataset to try the learnitgrid Shiny application
install_grid_example(dir = tempdir(), browse = FALSE)
install_grid_example(dir = tempdir(), browse = FALSE)
dir |
The directory where to decompress the extended example |
browse |
Should we browse the example directory after decompression? |
The path to the example learnitgrid data is returned invisibly.
# Install the extended examples in a temporary directory ## Not run: library(learnitgrid) ex_dir <- install_grid_example(browse = TRUE) ## End(Not run)
# Install the extended examples in a temporary directory ## Not run: library(learnitgrid) ex_dir <- install_grid_example(browse = TRUE) ## End(Not run)
Functions to be used in testthat test of the project
is_identical_to_ref(name, part = NULL, attr = NULL) is_equal_to_ref(name, part = NULL, attr = NULL) is_rendered(quarto, format = "html") is_rendered_current(quarto, format = "html") is_data(name, dir = "data", format = "rds", check_df = FALSE) is_data_df(name, dir = "data", format = "rds", check_df = TRUE) has_labels_all(name, part = NULL) has_labels_any(name, part = NULL) has_units_all(name, part = NULL) has_units_any(name, part = NULL) is_display_equation(text, object) is_display_param_equation(text, object) is_inline_equation(text, object) is_inline_param_equation(text, object)
is_identical_to_ref(name, part = NULL, attr = NULL) is_equal_to_ref(name, part = NULL, attr = NULL) is_rendered(quarto, format = "html") is_rendered_current(quarto, format = "html") is_data(name, dir = "data", format = "rds", check_df = FALSE) is_data_df(name, dir = "data", format = "rds", check_df = TRUE) has_labels_all(name, part = NULL) has_labels_any(name, part = NULL) has_units_all(name, part = NULL) has_units_any(name, part = NULL) is_display_equation(text, object) is_display_param_equation(text, object) is_inline_equation(text, object) is_inline_param_equation(text, object)
name |
The name of the result and reference files |
part |
The part(s) (list item(s)) to co=pare |
attr |
The attribute(s) to compare |
quarto |
The name of the Quarto or R Markdown file |
format |
The format of the rendered file. For |
dir |
The subdirectory in the package where to look for ( |
check_df |
Check if the data file contains a data frame |
text |
The text to check |
object |
The object to look for in the |
TRUE
if the result is identical to the reference, FALSE
otherwise
Symbolic links in the www subdirectory of the Shiny app are required for the application to properly display html documents or images in html tags.
link_to_www(path, link) www_relative(path)
link_to_www(path, link) www_relative(path)
path |
The (absolute) path containing the documents. |
link |
The name to use for the symbolic link under the www subdirectory of the Shiny app. |
TRUE
if the symbolic link exists for link_to_www()
or FALSE
otherwise. The modified path is returned by www_relative()
www_relative()
: Strip www/ in front of the relative paths for a Shiny app.
Reference files allow to check if results are correct. They are not just a copy of the result files. They are reencoded to avoid someone could just copy and paste from the reference to the results directories and cheat.
make_ref( name, ..., dir1 = here::here("tests", "results"), dir2 = here::here("tests", "reference"), nthreads = parallel::detectCores(logical = FALSE) ) read_ref( name, ..., dir = here::here("tests", "reference"), nthreads = parallel::detectCores(logical = FALSE) )
make_ref( name, ..., dir1 = here::here("tests", "results"), dir2 = here::here("tests", "reference"), nthreads = parallel::detectCores(logical = FALSE) ) read_ref( name, ..., dir = here::here("tests", "reference"), nthreads = parallel::detectCores(logical = FALSE) )
name |
Name of the result file to transform into a reference file |
... |
Further parameters passed to |
dir1 |
Directory containing the result file |
dir2 |
Directory where to place the reference file |
nthreads |
Number of threads to use for reading or writing the files |
dir |
Directory containing the reference file |
The decoded content of the result file for read_ref()
or the
number of bytes written for make_ref()
.
The five possible actions are "test", to launch the test on the repository, "clean" to delete several generated files, "original" to configure the repository with original files, "solution" to configure the repository with solution files, and "prepare" to prepare the repository for the final version ready for the assignment in, say Github classroom.
make_test() make_clean() make_original() make_solution() make_prepare()
make_test() make_clean() make_original() make_solution() make_prepare()
The result from make
is returned
Populate a DT table according to selected items with a list of grids (or "all") or according to a selected grid with a list of items (or "all")
populate_table( items, grids = "all", context, reorder = (length(items) == 1), highlight = FALSE, max_lines = 30L, on_github = TRUE )
populate_table( items, grids = "all", context, reorder = (length(items) == 1), highlight = FALSE, max_lines = 30L, on_github = TRUE )
items |
The items of the evaluation grid to display in the table, usually either one item, or "all" for everything |
grids |
The evaluation grids to display, usually either "all" if only one item, or one grid if "all" items |
context |
A context object as computed by |
reorder |
Should the rows in the table be reordered by similarities?
This is usually |
highlight |
Syntax highlighting for code (slow, thus |
max_lines |
The maximum number of content lines that are displayed (truncate very long contents). |
on_github |
Should the links point to the GitHub repository or to the
local files (default is |
A data frame with the content to be displayed in a DT::datatable object.
Make sure all files are original or solution versions, and possibly also remove last_saved versions. This is typically used to prepare the repository for an assignment, or to switch from originals to solution to verify the tests.
prepare_files(type = "original", remove_last_saved = FALSE, error = TRUE)
prepare_files(type = "original", remove_last_saved = FALSE, error = TRUE)
type |
Either |
remove_last_saved |
Should we also remove the last_saved version
( |
error |
If |
NULL
Create a testthat reporter suitable to test projects
project_reporter()
project_reporter()
A testthat reporter
Record, read and write results that capture given characteristics of an object
record_res( object = ".Last.chunk", name = object, fun = NULL, ..., dir = here::here("tests", "results"), env = parent.frame() ) read_res( name, ..., dir = here::here("tests", "results"), nthreads = parallel::detectCores(logical = FALSE) ) write_res( object, name, ..., dir = here::here("tests", "results"), nthreads = parallel::detectCores(logical = FALSE) ) RO( object = ".Last.chunk", name = object, fun = NULL, ..., dir = here::here("tests", "results"), env = parent.frame() ) RN(name, object = ".Last.chunk", fun = NULL, ..., env = parent.frame()) RODFS( object = ".Last.chunk", name = object, fun = df_structure, ..., env = parent.frame() ) RNDFS( name, object = ".Last.chunk", fun = df_structure, ..., env = parent.frame() ) ROMD5( object = ".Last.chunk", name = object, fun = digest, ..., env = parent.frame() ) RNMD5(name, object = ".Last.chunk", fun = digest, ..., env = parent.frame()) ROP( object = ".Last.chunk", part = "x", name = object, fun = object_part, ..., env = parent.frame() ) RNP( name, part = "x", object = ".Last.chunk", fun = object_part, ..., env = parent.frame() ) ROA( object = ".Last.chunk", attrib = "class", name = object, fun = object_attr, ..., env = parent.frame() ) RNA( name, attrib = "class", object = ".Last.chunk", fun = object_attr, ..., env = parent.frame() ) ROSTR( object = ".Last.chunk", part = "x", name = object, fun = object_str, ..., env = parent.frame() ) RNSTR( name, part = "x", object = ".Last.chunk", fun = object_str, ..., env = parent.frame() )
record_res( object = ".Last.chunk", name = object, fun = NULL, ..., dir = here::here("tests", "results"), env = parent.frame() ) read_res( name, ..., dir = here::here("tests", "results"), nthreads = parallel::detectCores(logical = FALSE) ) write_res( object, name, ..., dir = here::here("tests", "results"), nthreads = parallel::detectCores(logical = FALSE) ) RO( object = ".Last.chunk", name = object, fun = NULL, ..., dir = here::here("tests", "results"), env = parent.frame() ) RN(name, object = ".Last.chunk", fun = NULL, ..., env = parent.frame()) RODFS( object = ".Last.chunk", name = object, fun = df_structure, ..., env = parent.frame() ) RNDFS( name, object = ".Last.chunk", fun = df_structure, ..., env = parent.frame() ) ROMD5( object = ".Last.chunk", name = object, fun = digest, ..., env = parent.frame() ) RNMD5(name, object = ".Last.chunk", fun = digest, ..., env = parent.frame()) ROP( object = ".Last.chunk", part = "x", name = object, fun = object_part, ..., env = parent.frame() ) RNP( name, part = "x", object = ".Last.chunk", fun = object_part, ..., env = parent.frame() ) ROA( object = ".Last.chunk", attrib = "class", name = object, fun = object_attr, ..., env = parent.frame() ) RNA( name, attrib = "class", object = ".Last.chunk", fun = object_attr, ..., env = parent.frame() ) ROSTR( object = ".Last.chunk", part = "x", name = object, fun = object_str, ..., env = parent.frame() ) RNSTR( name, part = "x", object = ".Last.chunk", fun = object_str, ..., env = parent.frame() )
object |
The object to record results from ( |
name |
The name of the result file |
fun |
The function used to compute results for the object |
... |
Additional arguments to pass to |
dir |
The directory where to save the results |
env |
The environment where to look for the object |
nthreads |
The number of threads to use for reading and writing |
part |
The part(s) (list item(s)) to use |
attrib |
The attribute(s) to use |
The main function to record the results is record_res()
. However, there are
several shortcuts to record specific characteristics of an object: RO
is
the same as record_res()
, RN()
records by default ".Last.chunk"
but
focuses on the name of the result file, RODFS()
records the main structure
of a data frame, RNDFS()
is the same as RODFS()
but focuses on the name
of the result file, ROMD5()
records the MD5 hash of an object, RNMD5()
is
the same focusing on the name, ROP()
records one or several parts of an
object (items from a list), RNP()
is the same focusing on the name, ROA()
records one or several attributes of the objects with RNA()
focusing on the
name, ROSTR()
records the utils::str()
summary of the object, and
RNSTR()
is the same focusing on the name of the result file.
The deserialized results for read_res()
or the number of bytes
written invisibly for write_res()
. record_res()
invisibly returns
TRUE
or FALSE
depending on the success of the operation.
Run the learnitgrid Shiny application
run_grid(data_dir = getOption("learnitgrid.data.dir", NULL))
run_grid(data_dir = getOption("learnitgrid.data.dir", NULL))
data_dir |
The directory containing the 'learnitgrid' data. If missing,
the "learnitgrid.data.dir" option is used. If |
Nothing is returned, the function is used for its side-effect of running the learnitgrid Shiny application.
## Not run: library(learnitgrid) # Run a basic example in the learnitgrid package run_grid("") # Please, note that the .Rmd reports that are analyzed in this example # are NOT included to save space, hence, error messages in corresponding # columns of the evaluation grids. # Install an extended example in tempdir() (inspect its content) install_grid_example(browse = TRUE) # ... and run the app with it run_grid() # The .Rmd reports are included in this example. ## End(Not run)
## Not run: library(learnitgrid) # Run a basic example in the learnitgrid package run_grid("") # Please, note that the .Rmd reports that are analyzed in this example # are NOT included to save space, hence, error messages in corresponding # columns of the evaluation grids. # Install an extended example in tempdir() (inspect its content) install_grid_example(browse = TRUE) # ... and run the app with it run_grid() # The .Rmd reports are included in this example. ## End(Not run)
A simple multiple choice system in a R chunk, compatible with git and R
Markdown or Quarto documents. obfuscate()
and get_word()
are used to hide
correct answers in the testthat tests.
select_answer(x, name = NULL) obfuscate(x) get_word(x)
select_answer(x, name = NULL) obfuscate(x) get_word(x)
x |
A String with the different answers, starting with []. The user has to "check" the correct items by adding 'x' or 'X' inside the brackets |
name |
The name of the select_answer. If not provided, the label of the
chunk where the |
A Markdown paragraph containing only the selected items (and the selected items are also written in a result file)
When there are several versions of a document (R script, R
Markdown or Quarto document), switch the main file to one of the saved
versions: original version, solution with the correction, or last saved
version. The save_as_original()
and save_as_solution()
functions are
used to create respectively the original and solution versions of the
document. These files have same name as the initial file but ending with
_original
, _solution
or _last_saved
., and starting with a dot .
.
They are thus "hidden" files. For R scripts, the extension is also changed
into .Rscript
for the original and solution versions.
switch_to_original(file = NULL, error = TRUE) switch_to_solution(file = NULL, error = TRUE) switch_to_last_saved(file = NULL, error = TRUE) save_as_original(file = NULL) save_as_solution(file = NULL)
switch_to_original(file = NULL, error = TRUE) switch_to_solution(file = NULL, error = TRUE) switch_to_last_saved(file = NULL, error = TRUE) save_as_original(file = NULL) save_as_solution(file = NULL)
file |
The file to switch to a version. If not provided, the currently edited file in RStudio is used by default |
error |
In case the version does not exists, do we issue an error or not (no by default) |
NULL
is returned invisibly. The functions are used for their
side-effect of switching document versions.
Test a project directory, possibly limit the number of uses
test_dir(path, reporter = project_reporter(), times = 10L, ...)
test_dir(path, reporter = project_reporter(), times = 10L, ...)
path |
The path to test |
reporter |
The testthat reporter to use |
times |
The maximum number of times the tests can be run by the end-user |
... |
Additional arguments to pass to |
The result of testthat::test_dir()