Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make data/ directory automatically accessible to exercises #539

Merged
merged 70 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
c16f532
Make files accessible to tutorials
rossellhayes Jun 12, 2021
86f32df
Handle cases where `data/` directory, `use_remote_files()`, and chunk…
rossellhayes Jun 14, 2021
f7e2cd3
Remove `strwrap()` (doesn't work in R Markdown pane)
rossellhayes Jun 14, 2021
e7f1f1f
Ensure remote files are either URLs or system.file()s
rossellhayes Jun 14, 2021
cbd3571
Namespace `utils::download.file()`
rossellhayes Jun 15, 2021
3380ae1
Simplify code with better return values
rossellhayes Jun 15, 2021
818fc45
Add `system.file()` examples
rossellhayes Jun 15, 2021
7c60243
Add tests for `use_remote_files()`
rossellhayes Jun 15, 2021
f691484
Add tests for `copy_files()`
rossellhayes Jun 15, 2021
dee7aa0
Refactor `is_system_file()` as a recursive function
rossellhayes Jun 15, 2021
11a0a1e
Multiple calls to use_remote_files() now merge instead of overwriting
rossellhayes Jun 15, 2021
fd6df39
Copy entire data directory during `evaluate_exercise()`
rossellhayes Jun 16, 2021
9729a91
Remove infrastructure around `use_remote_files()`
rossellhayes Jun 16, 2021
26b61e1
Add `use_data_dir()` function for specifiying a different place to fi…
rossellhayes Jun 16, 2021
9266073
Add data dir test documents to sandbox
rossellhayes Jun 16, 2021
5241eba
Only copy the data directory if the data directory exists
rossellhayes Jun 16, 2021
d812349
Test overwriting and restoring files
rossellhayes Jun 16, 2021
8d14c06
Add test without a data directory
rossellhayes Jun 16, 2021
5fe2118
Remove `cli` formatting
rossellhayes Jun 16, 2021
28a7455
Update documentation of `use_data_dir()`
rossellhayes Jun 16, 2021
4e2e336
Add test with here()
rossellhayes Jun 17, 2021
9037bfa
Prioritize environment variable over `use_data_dir()`
rossellhayes Jun 20, 2021
9f30645
Add tests for data files
rossellhayes Jun 20, 2021
95e547e
Merged upstream/master into rossellhayes-data-files
gadenbuie Jun 21, 2021
7f641b4
Remove commented-out code
rossellhayes Jun 21, 2021
a653af5
Give friendlier error if data dir is not set up successfully in the t…
rossellhayes Jun 21, 2021
5b4a0ee
Raise error if data directory is set by envvar or `options()` and can…
rossellhayes Jun 21, 2021
e3eb7b6
Use "tutorial" instead of "learnr" as prefix in envvar and `options()`
rossellhayes Jun 21, 2021
6dad0f9
Merge branch 'data-files' of https://github.com/rossellhayes/learnr i…
rossellhayes Jun 21, 2021
4b84ff9
Fix option name in `use_data_dir()`
rossellhayes Jun 21, 2021
4ef3078
Split and label data dir tests
rossellhayes Jun 21, 2021
6672a55
Default data directory to "" and only set to "data/" if data director…
rossellhayes Jun 21, 2021
a896a39
Add tests for missing data directory
rossellhayes Jun 21, 2021
19c792e
Change data directory precedence to `options()` > env var > "data/"
rossellhayes Jun 21, 2021
3dc1352
Pass `source_dir` from `evaluate_exercise()` to `copy_data_dir()`
rossellhayes Jun 21, 2021
ba6acca
Update tests to reflect change in data dir precedence
rossellhayes Jun 21, 2021
11657fc
Remove `use_data_dir()`; data directory must now be specified with en…
rossellhayes Jun 22, 2021
5f63026
Remove braces in one-line if-else
rossellhayes Jun 23, 2021
7674d68
Update error message
rossellhayes Jun 23, 2021
be64636
Update error class
rossellhayes Jun 23, 2021
aceb3a2
Update error message
rossellhayes Jun 23, 2021
78b5864
Update error class
rossellhayes Jun 23, 2021
8324144
Reenable data dir set with `options()`
rossellhayes Jun 24, 2021
9e78a7c
Compact code for determining data dir
rossellhayes Jun 24, 2021
7ddafbd
Replace `with_tempdir()` with `local_dir(local_tempdir())`
rossellhayes Jun 24, 2021
d3ed875
Use `check = TRUE` to simplfiy tests of `evaluate_exercise()`
rossellhayes Jun 24, 2021
89d6840
Only test that files have not been modified in tests focused on file …
rossellhayes Jun 24, 2021
cef6ae7
Update sandbox demo
rossellhayes Jun 25, 2021
e19baa4
Remove sandbox/data_dir/
gadenbuie Jun 30, 2021
b1bd8a4
Minor edits to test labels
gadenbuie Jun 30, 2021
509ddaf
Merge branch 'master' into 'rosselhayes/data-files'
gadenbuie Jun 30, 2021
1d4cf7b
Move option/envvar checking into `copy_data_dir()`
gadenbuie Jun 30, 2021
a836094
Merge
rossellhayes Jul 1, 2021
0eea1fd
Add `protect_options()` function which restores `options()` and envva…
rossellhayes Jul 1, 2021
6b32eeb
Add `local_restore_options()` function which *actually* restores `opt…
rossellhayes Jul 1, 2021
792b28d
Merge branch 'data-files' of https://github.com/rossellhayes/learnr i…
rossellhayes Jul 1, 2021
9847989
Add entry to NEWS
rossellhayes Jul 7, 2021
73483f9
[docs] Increase toc_depth to show level-3 headings in TOC
gadenbuie Jul 8, 2021
168249e
[docs] Move setup chunks to level-3 heading and break into smaller ch…
gadenbuie Jul 8, 2021
84e9849
[docs] Make level-3 headings title case
gadenbuie Jul 8, 2021
ed861e2
[docs] Add "Using Files in Exercises" to Exercise Setup
gadenbuie Jul 8, 2021
337cc2d
[docs] Rebuild site
gadenbuie Jul 8, 2021
fcbf1da
[docs] Summarize setup chunk options with links
gadenbuie Jul 8, 2021
aabfe07
Reword NEWS entry
gadenbuie Jul 8, 2021
70fa098
`options` -> `opts`
rossellhayes Jul 8, 2021
7ea8cce
Add `local_restore_envvars()`
rossellhayes Jul 8, 2021
020557b
Use `local_restore_envvars()`
rossellhayes Jul 8, 2021
8b091e5
Use `local_restore_envvars()`
rossellhayes Jul 8, 2021
c114b08
Add `.local_envir = parent.frame()` as default in `local_restore_envv…
rossellhayes Jul 8, 2021
b00b736
Add wrapper function `local_restore_options_and_envvars()`
rossellhayes Jul 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ learnr (development version)
* Previously, when a question submission was reset, it would be recorded as a `"question_submission"` event with the value `reset=TRUE`. Now it a separate event, `"reset_question_submission"`. ([#398](https://github.com/rstudio/learnr/pull/398))
* Added a new `polyglot` tutorial to learnr. This tutorial displays mixing R, python, and sql exercises. See [`run_tutorial("polyglot", "learnr")`](https://learnr-examples.shinyapps.io/polyglot) for a an example. ([#397](https://github.com/rstudio/learnr/pull/397))
* Text throughout the learnr interface can be customized or localized using the new `language` argument of `tutorial()`. Translations for English and French are provided and contributes will be welcomed. Read more about these features in `vignette("multilang", package = "learnr")`. ([#456](https://github.com/rstudio/learnr/pull/456), [#479](https://github.com/rstudio/learnr/pull/479))
* When a "data/" directory is found in the same directory as the tutorial R Markdown document, it is now automatically made available within exercises. An alternative directory can be specified using the `tutorial.data_dir` global option. ([#539](https://github.com/rstudio/learnr/pull/539))

## Minor new features and improvements

Expand Down
34 changes: 34 additions & 0 deletions R/data_dir.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
copy_data_dir <- function(source_dir, exercise_dir) {
if (is.null(source_dir)) {
# First check options(), then environment variable, then default to "data/"
source_dir <- getOption(
"tutorial.data_dir",
Sys.getenv("TUTORIAL_DATA_DIR", if (dir.exists("data")) "data" else "")
)
}

if (identical(source_dir, "")) {
return(invisible(NULL))
}

if (!dir.exists(source_dir)) {
rlang::abort(
"An error occurred with the tutorial: the data directory does not exist.",
class = "learnr_missing_source_data_dir"
)
}

dest_dir <- file.path(exercise_dir, "data")
dir.create(dest_dir)

if (!dir.exists(dest_dir)) {
rlang::abort(
"An error occurred with the tutorial: we weren't able to create the data directory for this exercise.",
class = "learnr_missing_dest_data_dir"
)
}

file.copy(dir(source_dir, full.names = TRUE), dest_dir, recursive = TRUE)
rossellhayes marked this conversation as resolved.
Show resolved Hide resolved

return(invisible(dest_dir))
}
41 changes: 36 additions & 5 deletions R/exercise.R
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,11 @@ required_names <- c("code", "label", "options", "chunks", require_items)
# been executed, so they'd typically use `FALSE`, the default. Remote
# evaluators, if they choose to use this function, might want to include the
# global setup.
evaluate_exercise <- function(exercise, envir, evaluate_global_setup = FALSE) {
evaluate_exercise <- function(
exercise, envir, evaluate_global_setup = FALSE, data_dir = NULL
) {
# Protect global options and environment vars from permanent modification
withr::local_options(list())
withr::local_envvar(as.list(Sys.getenv()))
local_restore_options_and_envvars()

# adjust exercise version to match the current learnr version
exercise <- upgrade_exercise(
Expand All @@ -312,6 +313,9 @@ evaluate_exercise <- function(exercise, envir, evaluate_global_setup = FALSE) {
dir.create(exercise_dir)
on.exit(unlink(exercise_dir), add = TRUE)

# Copy files from data directory into exercise
copy_data_dir(data_dir, exercise_dir)

checker_feedback <- NULL
# Run the checker pre-evaluation _if_ there is code checking to do
if (length(exercise$code_check)) {
Expand Down Expand Up @@ -434,8 +438,7 @@ get_checker_func <- function(exercise, name, envir) {

render_exercise <- function(exercise, envir) {
# Protect global options and environment vars from modification by student
withr::local_options(list())
withr::local_envvar(as.list(Sys.getenv()))
local_restore_options_and_envvars()

# Make sure exercise (& setup) chunk options and code are prepped for rendering
exercise <- prepare_exercise(exercise)
Expand Down Expand Up @@ -789,6 +792,34 @@ merge_options <- function(preserved_opts, inherited_opts, static_opts = list())
opts[!grepl("^exercise", names(opts))]
}

local_restore_options_and_envvars <- function(.local_envir = parent.frame()) {
local_restore_options(.local_envir)
local_restore_envvars(.local_envir)
}

local_restore_options <- function(.local_envir = parent.frame()) {
opts <- options()
withr::defer(restore_options(opts), envir = .local_envir)
}

local_restore_envvars <- function(.local_envir = parent.frame()) {
envvars <- Sys.getenv()
withr::defer(restore_envvars(envvars), envir = .local_envir)
}

restore_options <- function(old) {
current <- options()
nulls <- setdiff(names(current), names(old))
old[nulls] <- list(NULL)
options(old)
}

restore_envvars <- function(old) {
current <- Sys.getenv()
nulls <- setdiff(names(current), names(old))
Sys.unsetenv(nulls)
do.call(Sys.setenv, as.list(old))
}

#' An Exercise Checker for Debugging
#'
Expand Down
4 changes: 2 additions & 2 deletions docs/_site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ output:
theme: cosmo
highlight: textmate
toc: true
toc_depth: 2
toc_depth: 3
toc_float:
collapsed: false
collapsed: true
css: styles.css
includes:
in_header: _include/header.html
104 changes: 32 additions & 72 deletions docs/examples.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,22 @@

<title>Examples</title>

<script src="site_libs/header-attrs-2.9/header-attrs.js"></script>
<script src="site_libs/jquery-1.11.3/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="site_libs/bootstrap-3.3.5/css/cosmo.min.css" rel="stylesheet" />
<script src="site_libs/bootstrap-3.3.5/js/bootstrap.min.js"></script>
<script src="site_libs/bootstrap-3.3.5/shim/html5shiv.min.js"></script>
<script src="site_libs/bootstrap-3.3.5/shim/respond.min.js"></script>
<style>h1 {font-size: 34px;}
h1.title {font-size: 38px;}
h2 {font-size: 30px;}
h3 {font-size: 24px;}
h4 {font-size: 18px;}
h5 {font-size: 16px;}
h6 {font-size: 12px;}
code {color: inherit; background-color: rgba(0, 0, 0, 0.04);}
pre:not([class]) { background-color: white }</style>
<script src="site_libs/navigation-1.1/tabsets.js"></script>
<link href="site_libs/highlightjs-9.12.0/textmate.css" rel="stylesheet" />
<script src="site_libs/highlightjs-9.12.0/highlight.js"></script>
Expand Down Expand Up @@ -47,11 +57,6 @@
</style>

<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
pre:not([class]) {
background-color: white;
}
</style>
<script type="text/javascript">
if (window.hljs) {
hljs.configure({languages: []});
Expand All @@ -64,32 +69,6 @@



<style type="text/css">
h1 {
font-size: 34px;
}
h1.title {
font-size: 38px;
}
h2 {
font-size: 30px;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 16px;
}
h6 {
font-size: 12px;
}
.table th:not([align]) {
text-align: left;
}
</style>


<link rel="stylesheet" href="styles.css" type="text/css" />
Expand All @@ -102,10 +81,6 @@
margin-left: auto;
margin-right: auto;
}
code {
color: inherit;
background-color: rgba(0, 0, 0, 0.04);
}
img {
max-width:100%;
}
Expand All @@ -121,40 +96,13 @@
summary {
display: list-item;
}
pre code {
padding: 0;
}
</style>


<style type="text/css">
/* padding for bootstrap navbar */
body {
padding-top: 51px;
padding-bottom: 40px;
}
/* offset scroll position for anchor links (for fixed navbar) */
.section h1 {
padding-top: 56px;
margin-top: -56px;
}
.section h2 {
padding-top: 56px;
margin-top: -56px;
}
.section h3 {
padding-top: 56px;
margin-top: -56px;
}
.section h4 {
padding-top: 56px;
margin-top: -56px;
}
.section h5 {
padding-top: 56px;
margin-top: -56px;
}
.section h6 {
padding-top: 56px;
margin-top: -56px;
}
.dropdown-submenu {
position: relative;
}
Expand Down Expand Up @@ -182,7 +130,7 @@
margin-right: -10px;
}
.dropdown-submenu:hover>a:after {
border-left-color: #ffffff;
border-left-color: #adb5bd;
}
.dropdown-submenu.pull-left {
float: none;
Expand All @@ -194,7 +142,7 @@
}
</style>

<script>
<script type="text/javascript">
// manage active state of menu based on current page
$(document).ready(function () {
// active menu anchor
Expand All @@ -205,10 +153,23 @@
var menuAnchor = $('a[href="' + href + '"]');

// mark it active
menuAnchor.parent().addClass('active');
menuAnchor.tab('show');

// if it's got a parent navbar menu mark it active as well
menuAnchor.closest('li.dropdown').addClass('active');

// Navbar adjustments
var navHeight = $(".navbar").first().height() + 15;
var style = document.createElement('style');
var pt = "padding-top: " + navHeight + "px; ";
var mt = "margin-top: -" + navHeight + "px; ";
var css = "";
// offset scroll position for anchor links (for fixed navbar)
for (var i = 1; i <= 6; i++) {
css += ".section h" + i + "{ " + pt + mt + "}\n";
}
style.innerHTML = "body {" + pt + "padding-bottom: 40px; }\n" + css;
document.head.appendChild(style);
});
</script>

Expand All @@ -220,7 +181,6 @@
max-height: 500px;
min-height: 44px;
overflow-y: auto;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
}
Expand Down Expand Up @@ -318,7 +278,7 @@
<ul class="nav navbar-nav navbar-right">
<li>
<a href="https://github.com/rstudio/learnr">
<span class="fas fa-github"></span>
<span class="fa fa-github"></span>

</a>
</li>
Expand All @@ -327,7 +287,7 @@
</div><!--/.container -->
</div><!--/.navbar -->

<div class="fluid-row" id="header">
<div id="header">



Expand Down Expand Up @@ -460,7 +420,7 @@ <h1 class="title toc-ignore">Examples</h1>

$(document).ready(function () {
$('.tabset-dropdown > .nav-tabs > li').click(function () {
$(this).parent().toggleClass('nav-tabs-open')
$(this).parent().toggleClass('nav-tabs-open');
});
});
</script>
Expand Down
Loading