diff --git a/.Rbuildignore b/.Rbuildignore index 640d6ab..bb993f0 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,6 +1,9 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^LICENSE\.md$ +^LICENSE-CONTENT\.md$ +^LICENSES\.md$ +^pkgdown$ ^\.github$ ^ROADMAP\.md$ ^docs$ @@ -14,3 +17,7 @@ ^codemeta\.json$ ^paper$ ^SECURITY.md$ +^.*\.Rcheck$ +^\.\.Rcheck$ +^tutorizeR_[0-9.]+\.tar\.gz$ +^CRAN-SUBMISSION$ diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..92d469d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Questions and discussion + url: https://github.com/AurelienNicosiaULaval/tutorizeR/discussions + about: Use discussions for open-ended teaching workflow questions. diff --git a/.github/ISSUE_TEMPLATE/jose_readiness.md b/.github/ISSUE_TEMPLATE/jose_readiness.md new file mode 100644 index 0000000..2771dfd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/jose_readiness.md @@ -0,0 +1,21 @@ +--- +name: JOSE readiness item +about: Track a task related to JOSE preparation or review +title: "[JOSE] " +labels: jose, documentation +assignees: '' +--- + +## Review item + +Describe the JOSE readiness issue. + +## Evidence + +Link to repository files, examples, tests, or documentation that support the item. + +## Acceptance criteria + +- [ ] Repository evidence is added or updated. +- [ ] The claim is verifiable from repository contents. +- [ ] Tests or documentation are updated if needed. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a789bad..a63ff79 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,6 +2,7 @@ - What this PR changes - Why it is needed for teacher workflow reliability +- Whether this changes generated tutorial output ## Validation @@ -9,6 +10,14 @@ - [ ] Tests pass (`testthat`) - [ ] Lint clean (`lintr::lint_package()`) - [ ] Coverage thresholds met (if touching core conversion path) +- [ ] Example conversion checked with at least one `.Rmd` or `.qmd` fixture +- [ ] Documentation or vignette updated when user-facing behavior changes + +## Educational impact + +- What instructor workflow is improved? +- What student interaction changes, if any? +- Is any classroom adoption claim supported by repository evidence? ## Additional notes diff --git a/.github/workflows/r.yml b/.github/workflows/r.yml index 3e97b9a..92bec3f 100644 --- a/.github/workflows/r.yml +++ b/.github/workflows/r.yml @@ -4,7 +4,7 @@ on: push: branches: [main] pull_request: - branches: [main] + branches: [main, release/v0.4.4] permissions: contents: read @@ -27,6 +27,7 @@ jobs: with: r-version: ${{ matrix.config.r }} use-public-rspm: true + extra-repositories: https://rstudio.r-universe.dev - uses: r-lib/actions/setup-r-dependencies@v2 with: @@ -37,6 +38,27 @@ jobs: run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning") shell: Rscript {0} + testthat: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: 'release' + use-public-rspm: true + extra-repositories: https://rstudio.r-universe.dev + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + needs: tests + extra-packages: any::testthat + + - name: Run tests + run: testthat::test_local(reporter = "summary") + shell: Rscript {0} + lintr: runs-on: ubuntu-latest @@ -47,6 +69,7 @@ jobs: with: r-version: 'release' use-public-rspm: true + extra-repositories: https://rstudio.r-universe.dev - uses: r-lib/actions/setup-r-dependencies@v2 with: @@ -69,6 +92,7 @@ jobs: with: r-version: 'release' use-public-rspm: true + extra-repositories: https://rstudio.r-universe.dev - uses: r-lib/actions/setup-r-dependencies@v2 with: @@ -78,17 +102,17 @@ jobs: run: | cov <- covr::package_coverage() print(cov) - by <- as.data.frame(covr::coverage_to_list(cov)) - by$file <- rownames(by) + cov_list <- covr::coverage_to_list(cov) + file_coverage <- cov_list$filecoverage core_files <- c("R/parser.R", "R/transform.R", "R/validation.R", "R/report.R") - missing <- setdiff(core_files, by$file) + missing <- setdiff(core_files, names(file_coverage)) if (length(missing) > 0L) { stop(sprintf("Missing core files in coverage table: %s", paste(missing, collapse = ", "))) } - core_pct <- mean(by$filecoverage[match(core_files, by$file)]) - total_pct <- covr::percent_coverage(cov) + core_pct <- mean(unname(file_coverage[core_files])) + total_pct <- as.numeric(cov_list$totalcoverage) cat(sprintf("Coverage total: %.2f%%\n", total_pct)) cat(sprintf("Coverage core: %.2f%%\n", core_pct)) @@ -96,3 +120,32 @@ jobs: stop(sprintf("Core coverage threshold not met: %.2f%% < 80%%", core_pct)) } shell: Rscript {0} + + installed-example: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: 'release' + use-public-rspm: true + extra-repositories: https://rstudio.r-universe.dev + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + needs: check + + - name: Install package + run: R CMD INSTALL . + + - name: Run installed example module + run: | + source(system.file( + "examples", + "example_course_module", + "run-example.R", + package = "tutorizeR" + )) + shell: Rscript {0} diff --git a/.gitignore b/.gitignore index d8d0066..341a500 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ ..Rcheck tutorizeR.Rcheck tutorizeR_*.tar.gz +pkgdown/ diff --git a/CITATION.cff b/CITATION.cff index 8eec3ed..c3f1854 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -11,7 +11,7 @@ version: 0.4.4 license: MIT repository-code: https://github.com/AurelienNicosiaULaval/tutorizeR url: https://github.com/AurelienNicosiaULaval/tutorizeR -date-released: '2026-02-13' +date-released: '2026-02-14' keywords: - learnr - quarto @@ -26,5 +26,4 @@ authors: email: aurelien.nicosia@mat.ulaval.ca affiliation: >- Université Laval - orcid: null role: author diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION new file mode 100644 index 0000000..11919fa --- /dev/null +++ b/CRAN-SUBMISSION @@ -0,0 +1,3 @@ +Version: 0.4.4 +Date: 2026-05-31 17:07:44 UTC +SHA: 839f3487567ac6950161c56ebeda225fb8e07373 diff --git a/DESCRIPTION b/DESCRIPTION index 84f62e0..2e96ebd 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -17,7 +17,7 @@ Description: Helps teachers convert existing '.Rmd' and '.qmd' teaching conversion reports. License: MIT + file LICENSE Encoding: UTF-8 -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Depends: R (>= 4.0) Imports: @@ -31,10 +31,13 @@ Imports: Suggests: commonmark, covr, + dplyr, + ggplot2, knitr, learnr, lintr, miniUI, + readr, shiny, testthat (>= 3.0.0) VignetteBuilder: knitr diff --git a/LICENSE-CONTENT.md b/LICENSE-CONTENT.md new file mode 100644 index 0000000..6db1d9f --- /dev/null +++ b/LICENSE-CONTENT.md @@ -0,0 +1,14 @@ +# Creative Commons Attribution 4.0 International + +Educational example materials in `inst/examples/` and graphical documentation assets in `man/figures/` are licensed under the Creative Commons Attribution 4.0 International License unless otherwise specified. + +You are free to: + +- share, copy, and redistribute the material in any medium or format; +- adapt, remix, transform, and build upon the material for any purpose, including teaching and research. + +You must give appropriate credit, provide a link to the license, and indicate if changes were made. + +License text: + +https://creativecommons.org/licenses/by/4.0/legalcode diff --git a/LICENSES.md b/LICENSES.md new file mode 100644 index 0000000..c2278a1 --- /dev/null +++ b/LICENSES.md @@ -0,0 +1,14 @@ +# License clarification + +This file clarifies licensing for reviewers and downstream instructors. + +| Repository content | License | Notes | +|---|---|---| +| R package code in `R/`, `inst/scripts/`, tests, and package infrastructure | MIT | The CRAN-style license fields are in `DESCRIPTION` and `LICENSE`; the full MIT text is in `LICENSE.md`. | +| Technical package documentation, including README examples, function documentation, and vignettes | MIT | These files document use of the package and are treated as package documentation. | +| Educational content in `inst/examples/` | CC-BY 4.0 | This includes the example course module, lesson source, question bank, dataset, and generated expected outputs. | +| Generated expected outputs in `inst/examples/example_course_module/expected/` | CC-BY 4.0 | These files are educational artifacts derived from the example course module. | +| Graphical documentation assets in `man/figures/` | CC-BY 4.0 | Includes the logo and workflow figure unless a file-level notice states otherwise. | +| Reviewer documentation in `docs/` | MIT | These files support package review and release preparation. | + +The Creative Commons Attribution 4.0 International license text is available at . diff --git a/NEWS.md b/NEWS.md index b53e2db..c3322cb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,9 +2,17 @@ ## Release finalization -- Finalized JOSS-ready release artifacts and metadata alignment. +- Finalized JOSE-oriented reviewer artifacts and metadata alignment. - Refreshed reproducibility and reviewer guidance docs. - Synchronized version fields for release publication. +- Added JOSE preparation artifacts, educational use-case documentation, + expanded vignettes, an example course module, publication-readiness tests, + and pkgdown navigation for educational examples. +- Recentered the review branch on JOSE software-submission requirements, + clarified educational evidence boundaries, added CC-BY content licensing, + and replaced internal smoke-test paths with installable example workflows. +- Reworked the README as a package-facing overview and added pkgdown-oriented + documentation articles for educational use cases and website maintenance. # tutorizeR 0.4.3 diff --git a/R/transform.R b/R/transform.R index e681426..d4af4bb 100644 --- a/R/transform.R +++ b/R/transform.R @@ -703,7 +703,7 @@ transform_setup_chunk <- function(block, format, language, seed, registry) { } body <- block$body_lines - required <- c("library(learnr)", "library(gradethis)", "gradethis_setup()") + required <- learnr_setup_lines() for (line in required) { if (!any(trimws(body) == line)) { @@ -738,14 +738,23 @@ build_default_setup_chunk <- function(language, seed = NULL) { c( "```{r setup, include=FALSE}", tr("labels.setup_added", language = language), - "library(learnr)", - "library(gradethis)", - "gradethis_setup()", + learnr_setup_lines(), seed_line, "```" ) } +# Build setup lines required for generated learnr tutorials. +learnr_setup_lines <- function() { + c( + "library(learnr)", + "if (requireNamespace(\"gradethis\", quietly = TRUE)) {", + " library(gradethis)", + " gradethis_setup()", + "}" + ) +} + #' Build knitr R chunk header #' @keywords internal build_r_chunk_header <- function(label = NULL, options = character()) { diff --git a/README.md b/README.md index a84c534..feb37b9 100644 --- a/README.md +++ b/README.md @@ -2,184 +2,235 @@ tutorizeR hex sticker

-[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17771142.svg)](https://doi.org/10.5281/zenodo.17771142) [![R-CMD-check](https://github.com/AurelienNicosiaULaval/tutorizeR/actions/workflows/r.yml/badge.svg)](https://github.com/AurelienNicosiaULaval/tutorizeR/actions/workflows/r.yml) +[![Lifecycle: maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://lifecycle.r-lib.org/articles/stages.html) # tutorizeR -`tutorizeR` helps teachers convert `.Rmd` and `.qmd` material into interactive -`learnr` or `quarto-live` resources with linting, reusable MCQ banks, and -export/report tooling. +`tutorizeR` is an R package for converting existing R Markdown (`.Rmd`) and Quarto (`.qmd`) teaching material into interactive tutorial documents for `learnr` and `quarto-live`. + +The package is designed for instructors who want to keep one source document while generating student-facing exercises, solution scaffolds, multiple-choice questions, and conversion reports. The core workflow is source-first: revise the lesson source, rerun the conversion, review the generated tutorial, and distribute the result through the course infrastructure already in use. + +![tutorizeR workflow](man/figures/tutorize-workflow.svg) + +## Scope + +`tutorizeR` supports the following teaching workflows: + +- Convert `.Rmd` and `.qmd` lessons to `learnr` tutorials. +- Convert `.qmd` lessons to `quarto-live`-oriented resources. +- Generate exercise and solution blocks from existing R chunks. +- Add conceptual checks through inline MCQ blocks or reusable YAML/JSON question banks. +- Lint source lessons before conversion. +- Write JSON or YAML conversion reports for review and reproducibility. +- Process a folder of lessons with a consistent conversion policy. +- Export LMS-oriented manifests for downstream integration. + +The package does not replace instructor review. Generated tutorials should be inspected before they are used with students, especially when assessment, feedback, or grading logic is involved. + +The repository currently demonstrates package functionality through tests, vignettes, documentation, and an installable example module. It does not currently contain formal classroom outcome data or measured learning-gain evidence. ## Installation +Choose the installation source that matches your use case. + ```r -# install.packages("remotes") -remotes::install_github("AurelienNicosiaULaval/tutorizeR") +# CRAN, once the package is available there +install.packages("tutorizeR") ``` -To use `r-universe`: +```r +# Tagged GitHub release +install.packages("remotes") +remotes::install_github("AurelienNicosiaULaval/tutorizeR@v0.4.4") +``` ```r -install.packages( - "tutorizeR", - repos = c( - "https://aureliennicosiaulaval.r-universe.dev", - "https://cloud.r-project.org" - ) -) +# Current development branch used for review work +install.packages("remotes") +remotes::install_github("AurelienNicosiaULaval/tutorizeR@review/jose-readiness") ``` -## End-to-end workflow +## Quick Start + +The installed example module contains a Quarto lesson, a small local dataset, a question bank, and expected outputs. The following example copies the lesson to a temporary directory and converts it to a `learnr` tutorial. ```r library(tutorizeR) -# 1) Load reusable question bank -qb <- load_question_bank("inst/question-bank") +example_dir <- system.file( + "examples", + "example_course_module", + package = "tutorizeR" +) -# 2) Lint source before conversion -lint <- lint_source("lesson.qmd", question_bank = qb, strict = FALSE) -print(lint) +work_dir <- file.path(tempdir(), "tutorizeR-example") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) -# 3) Convert with mixed MCQ strategy (inline + bank) -rep <- tutorize( - input = "lesson.qmd", - format = "learnr", - assessment = "both", - question_bank = qb, - mcq_source = "mixed", - lint_strict = TRUE, +file.copy( + from = file.path(example_dir, "lesson-source.qmd"), + to = work_dir, + overwrite = TRUE +) +file.copy( + from = file.path(example_dir, "student_activity.csv"), + to = work_dir, overwrite = TRUE ) -print(rep) +question_bank <- load_question_bank(file.path(example_dir, "question-bank")) -# 4) Export conversion report JSON for CI tracing -write_tutorize_report(rep, "lesson-report.json", format = "json") +report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) -# 5) Export LMS manifest -manifest <- export_lms_manifest("lesson.qmd", profile = "canvas") -print(manifest) +print(report) ``` -## Reproducibility checklist (reviewer/journal-ready) +The returned report records the input file, output file, output format, assessment mode, generated exercises, generated MCQs, lint summary, warnings, and render status when applicable. -```bash -# 1) Install dependencies -Rscript -e 'remotes::install_github("AurelienNicosiaULaval/tutorizeR")' +## Main Functions -# 2) Lint and tests -Rscript -e "lintr::lint_package()" -Rscript -e "devtools::test()" +| Task | Functions | +| --- | --- | +| Convert one lesson | `tutorize()`, `convert_to_tutorial()` | +| Convert a folder | `convert_folder()` | +| Work with question banks | `load_question_bank()`, `validate_question_bank()` | +| Check lesson structure | `lint_source()`, `validate_input()`, `validate_output()` | +| Save conversion metadata | `write_tutorize_report()` | +| Export course integration artifacts | `export_lms_manifest()`, `export_tutorial_package()` | +| Use RStudio addins | `launch_tutorizeR_addin()`, `launch_tutorizeR_folder_addin()`, `launch_tutorizeR_preview_addin()` | -# 3) Build and CRAN-style check from a tarball -R CMD build . -R CMD check --as-cran --no-manual tutorizeR_0.4.3.tar.gz +## Authoring Syntax -# 4) Manual smoke path (requires learnr in the environment) -Rscript -e "library(tutorizeR); tutorize('tests/testthat/fixtures/rmd/basic_code.Rmd', format = 'learnr', overwrite = TRUE, output_dir = tempdir(), verbose = FALSE)" -``` +Instructor comments inside R chunks control conversion. -Expected on this repository: +```r +# tutorizeR: hints=Group by program before summarising|Use .groups = "drop" +activity |> + dplyr::group_by(program) |> + dplyr::summarise( + mean_hours = mean(study_hours), + mean_score = mean(quiz_score), + .groups = "drop" + ) +``` -- `devtools::test()` passes (currently 98 tests + new fixtures). -- `R CMD check --as-cran --no-manual` yields no errors, no warnings; one NOTE for a first submission is acceptable. +Supported tags include: -## JOSS submission note +- `skip` +- `exercise-only` +- `solution-only` +- `mcq` +- `narrative-only` +- `locked` +- `hints=Hint 1|Hint 2` -For JOSS, you submit the manuscript source (`paper/paper.md`) and bibliography (`paper/paper.bib`). -You do **not** need to attach a PDF in the repository for submission. -If you want a local PDF preview, render it with: +Inline MCQs use YAML inside a `tutorizeR-mcq` fenced block. -```bash -cd paper -Rscript -e "rmarkdown::render('paper.md', output_format = 'pdf_document', output_file = 'paper.pdf')" +```yaml +question: "Which variable identifies the academic program?" +answers: + - text: "program" + correct: true + - text: "quiz_score" + correct: false ``` -For reviewers/authors, full submission steps are in: +Reusable question-bank references use YAML inside a `tutorizeR-mcq-ref` fenced block. -- `docs/joss_submission_guide.md` -- `docs/joss_release_bundle.md` +```yaml +ids: [visualization-aesthetic] +strategy: ordered +shuffle_answers: false +``` -JOSS 2026 scope checks (important): +## Batch Conversion -- Confirm repository-wide value (not a thin/one-off utility), open development evidence, and at least ~6 months public history. -- Keep issue/PR traces visible and use a stable release/tag strategy. -- Include the AI usage disclosure in `paper/paper.md` if AI was used during coding, docs, or writing. +```r +library(tutorizeR) -## Main API +question_bank <- load_question_bank("course/question-bank") -- `tutorize()` / `convert_to_tutorial()` -- `convert_folder()` -- `load_question_bank()` / `validate_question_bank()` -- `lint_source()` -- `write_tutorize_report()` -- `export_lms_manifest()` -- `export_tutorial_package()` -- `check_tutorial()` +folder_report <- convert_folder( + dir = "course/lessons", + recursive = TRUE, + output_dir = "course/tutorials", + format = "learnr", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + lint_strict = TRUE, + overwrite = TRUE +) -## Teacher tags +print(folder_report) +``` -Inside R chunks: +## Documentation -- `# tutorizeR: skip` -- `# tutorizeR: exercise-only` -- `# tutorizeR: solution-only` -- `# tutorizeR: mcq` -- `# tutorizeR: narrative-only` -- `# tutorizeR: locked` -- `# tutorizeR: hints=Hint 1|Hint 2` +The package includes vignettes that are also used as pkgdown articles: -## MCQ block schemas +- [Getting started](vignettes/getting-started.Rmd) +- [Teaching workflow scenario](vignettes/teaching-workflow-scenario.Rmd) +- [Converting a Quarto lesson into an interactive tutorial](vignettes/quarto-lesson-interactive-tutorial.Rmd) +- [Building reproducible data science assignments](vignettes/reproducible-data-science-assignments.Rmd) +- [Reusable question banks](vignettes/question-bank.Rmd) +- [Tags and annotation syntax](vignettes/tags-and-annotations.Rmd) +- [MCQ and assessment modes](vignettes/mcq-and-assessment.Rmd) +- [Lint and debug workflow](vignettes/lint-and-debug.Rmd) +- [Debugging and common errors](vignettes/debugging-and-errors.Rmd) +- [Educational use cases](vignettes/educational-use-cases.Rmd) +- [Documentation website](vignettes/documentation-website.Rmd) +- [JOSE submission readiness](vignettes/jose-submission-readiness.Rmd) -Explicit question block: +The pkgdown site configuration is stored in `_pkgdown.yml`. The generated site is built into `pkgdown/` so it does not overwrite the repository's source documentation in `docs/`. -```text -```{tutorizeR-mcq} -question: "2 + 2 = ?" -answers: - - text: "4" - correct: true - - text: "5" - correct: false -``` +```r +pkgdown::build_site() ``` -Question-bank reference block: - -```text -```{tutorizeR-mcq-ref} -ids: [mean-basic, sum-basic] -strategy: ordered -shuffle_answers: false -``` -``` +## Quality Control -## Addins +Recommended local checks for maintainers: -- Convert active file -- Convert folder -- Preview conversion (Source / Output / Diff / Lint / Logs) +```bash +Rscript -e "testthat::test_local('.')" +Rscript -e "lintr::lint_package()" +Rscript -e "urlchecker::url_check()" +Rscript -e "devtools::document()" +R CMD build . +R CMD check --as-cran tutorizeR_0.4.4.tar.gz +``` -## CLI mode +Installed example smoke test: ```bash -Rscript inst/scripts/tutorizeR-cli.R --input=lesson.qmd --format=learnr --assessment=both --overwrite=true -Rscript inst/scripts/tutorizeR-cli.R --dir=course_material --recursive=true --format=learnr +Rscript -e "source(system.file('examples', 'example_course_module', 'run-example.R', package = 'tutorizeR'))" ``` -## Known limitations +## Known Limitations -- `learnr` render checks require `learnr` and `gradethis` installed. -- LMS export is manifest-only in v0.4 (no direct remote publishing API). -- Question bank is local file based (YAML/JSON) in v0.4. +- `learnr` render checks require `learnr` to be installed. +- Generated `learnr` tutorials activate `gradethis` setup only when `gradethis` is installed. +- `quarto-live` output requires the Quarto live extension in the teaching project. +- LMS export is manifest-only in version 0.4 and does not publish directly to a remote LMS API. +- Question banks are local YAML or JSON files in version 0.4. +- Formal learning-outcome evaluation is not included in the repository. -## Documentation +## Review and Publication Materials + +Reviewer-facing JOSE and JOSS preparation materials are maintained in the source repository under `docs/` and `paper/`. These files are intentionally kept separate from the CRAN package contents. Claims about classroom deployment, broad adoption, or learning outcomes should be added only when supported by verifiable repository evidence. + +## Licensing + +The package code is released under the MIT license. The CRAN-style license metadata is stored in `LICENSE`, and the full MIT license text is available in `LICENSE.md`. -- `vignettes/getting-started.Rmd` -- `vignettes/question-bank.Rmd` -- `vignettes/tags-and-annotations.Rmd` -- `vignettes/conversion-rmd-vs-qmd.Rmd` -- `vignettes/mcq-and-assessment.Rmd` -- `vignettes/lint-and-debug.Rmd` +Educational example materials in `inst/examples/`, generated expected educational outputs, and graphical documentation assets in `man/figures/` are released under CC-BY 4.0 unless otherwise specified. See `LICENSE-CONTENT.md` and `LICENSES.md` in the source repository. diff --git a/_pkgdown.yml b/_pkgdown.yml index 453d6d9..29c43f1 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,9 +1,16 @@ +destination: pkgdown + template: bootstrap: 5 home: title: tutorizeR - description: Convert existing Rmd/qmd teaching materials into interactive tutorials. + description: Convert existing R Markdown and Quarto teaching material into interactive tutorial documents. + +navbar: + structure: + left: [intro, articles, reference, news] + right: [search, github] reference: - title: Core conversion @@ -16,21 +23,54 @@ reference: - validate_input - validate_output - check_tutorial + - lint_source + - title: Question banks and reports + contents: + - load_question_bank + - validate_question_bank + - write_tutorize_report + - print.tutorize_report + - print.tutorize_lint_report + - print.tutorize_folder_report + - title: Exports + contents: + - export_lms_manifest + - export_tutorial_package + - print.tutorize_lms_manifest - title: Addins contents: - launch_tutorizeR_addin - launch_tutorizeR_folder_addin + - launch_tutorizeR_preview_addin + - title: Internationalization + contents: + - tr articles: - - title: Getting started - navbar: Getting started + - title: Start here + navbar: Start here contents: - getting-started - - title: Authoring and syntax + - teaching-workflow-scenario + - quarto-lesson-interactive-tutorial + - reproducible-data-science-assignments + - title: Authoring and assessment navbar: Authoring contents: - - question-bank - tags-and-annotations - - conversion-rmd-vs-qmd + - question-bank - mcq-and-assessment + - automatic-exercise-generation-feedback + - conversion-rmd-vs-qmd + - title: Course operations + navbar: Course operations + contents: + - large-undergraduate-courses - lint-and-debug + - debugging-and-errors + - educational-use-cases + - title: Project documentation + navbar: Project documentation + contents: + - documentation-website + - jose-submission-readiness diff --git a/cran-comments.md b/cran-comments.md index 394bff5..40ff3bb 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -7,7 +7,10 @@ - 0 errors - 0 warnings -- 1 note: New submission +- 2 notes on local `R CMD check --as-cran`: + - New submission. + - HTML manual validation was skipped because the local `tidy` executable is + not recent enough. This is a local toolchain note. ## Downstream impact @@ -15,5 +18,9 @@ ## Notes +- This is a new submission. - `convert_to_tutorial()` remains available for backward compatibility. - New canonical API is `tutorize()`. +- Generated `learnr` tutorial scaffolds activate `gradethis` setup only when + `gradethis` is installed. `gradethis` is not required to load, test, or run + the package. diff --git a/docs/educational_use_cases.md b/docs/educational_use_cases.md new file mode 100644 index 0000000..c8d64cb --- /dev/null +++ b/docs/educational_use_cases.md @@ -0,0 +1,110 @@ +# Educational Use Cases for tutorizeR + +## Purpose + +`tutorizeR` is educational infrastructure for instructors who already write course material in R Markdown or Quarto and want to convert those source documents into interactive learning experiences. The package supports a source-first workflow: instructors maintain one reproducible lesson source, then generate student-facing tutorials, exercises, feedback scaffolds, and reporting artifacts. + +## Classroom Usage + +Typical classroom settings include undergraduate statistics, data science, and R programming courses where students learn by reading short explanations, running code, editing code, answering conceptual questions, and receiving structured feedback. + +Relevant classroom activities include: + +- converting lecture notes into interactive pre-class tutorials; +- converting laboratory handouts into `learnr` tutorials; +- generating `quarto-live` activities for browser-based experimentation; +- inserting student answer areas into existing code examples; +- adding MCQ prompts for conceptual checks; +- creating reproducible assignment templates with consistent structure; +- exporting conversion reports for teaching assistants or course coordination. + +Specific course adoption: Not verifiable from repository contents. + +## Instructor Workflows + +An instructor can prepare a source lesson as a `.qmd` or `.Rmd` file: + +```r +library(tutorizeR) + +report <- tutorize( + input = "lessons/week03-data-visualization.qmd", + output_dir = "tutorials", + format = "learnr", + assessment = "both", + overwrite = TRUE +) + +print(report) +``` + +For a course folder, the instructor can process all lessons consistently: + +```r +library(tutorizeR) + +folder_report <- convert_folder( + dir = "lessons", + recursive = TRUE, + output_dir = "tutorials", + format = "learnr", + assessment = "both", + overwrite = TRUE +) + +print(folder_report) +``` + +Before distributing materials, the instructor can lint a source file and inspect the conversion report: + +```r +library(tutorizeR) + +lint <- lint_source("lessons/week03-data-visualization.qmd", strict = FALSE) +print(lint) +``` + +## Student Workflows + +Students interact with the converted output rather than the conversion pipeline. In a generated tutorial, a student can: + +- read the original lesson narrative; +- run setup code prepared by the instructor; +- complete generated code exercises; +- compare their answer to hidden or collapsible solution material; +- answer MCQs generated from inline blocks or question banks; +- work with the same source datasets and code patterns used in the original lesson. + +For large classes, this workflow can reduce inconsistencies between lecture notes, labs, and assignments because the student-facing tutorial remains derived from a single source file. + +## Learning Objectives + +Examples of learning objectives supported by the package include: + +- write reproducible R code from a partially completed scaffold; +- apply tidy data transformations to realistic teaching data; +- construct and interpret `ggplot2` visualizations; +- identify common errors in data manipulation pipelines; +- connect conceptual questions to executable code; +- practice iterative programming with immediate feedback; +- understand the relationship between source documents and generated learning resources. + +## Example Lesson Pattern + +A realistic data science lesson can be organized as follows: + +1. Short conceptual introduction. +2. Dataset import. +3. Data cleaning with `dplyr`. +4. Visualization with `ggplot2`. +5. Interpretation prompt. +6. MCQ conceptual check. +7. Reproducible summary exercise. + +The example module in `inst/examples/example_course_module/` follows this pattern with a small, local dataset and generated tutorial artifacts. + +## Evidence Boundaries + +The repository demonstrates educational intent, package functionality, examples, tests, and reviewer-facing documentation. It does not contain verifiable classroom outcome data, anonymized student analytics, external adoption records, or formal evaluation results. Therefore, any claim about actual classroom adoption should be written as: + +Not verifiable from repository contents. diff --git a/docs/educational_use_evidence.md b/docs/educational_use_evidence.md new file mode 100644 index 0000000..dbd124d --- /dev/null +++ b/docs/educational_use_evidence.md @@ -0,0 +1,76 @@ +# Educational Use Evidence + +Date: 2026-05-31 + +This document separates demonstrated repository evidence from plausible but unevaluated educational claims. + +## What Is Currently Demonstrated by the Repository + +The repository demonstrates: + +- an R package that converts `.Rmd` and `.qmd` teaching documents into `learnr` or `quarto-live` resources; +- parser, transformation, validation, linting, question-bank, reporting, export, and addin functionality; +- test fixtures covering conversion, MCQ handling, question-bank validation, reports, exports, and edge cases; +- an installable example module in `inst/examples/example_course_module/`; +- vignettes describing instructor workflows and limitations; +- reviewer-facing JOSE documentation; +- open-source governance files, including contribution guide and code of conduct. + +## What Is Plausible but Not Yet Formally Evaluated + +It is plausible that `tutorizeR` may help instructors: + +- reduce manual duplication between source lessons and tutorials; +- maintain reproducible teaching materials more consistently; +- create more frequent formative practice opportunities; +- review generated learning resources with teaching assistants; +- adapt source-first workflows across multiple course modules. + +These are workflow plausibility statements, not measured educational outcomes. + +Formal learning-outcome evaluation: Not verifiable from repository contents. + +## What Is Not Claimed + +The repository does not claim: + +- improved student grades; +- improved student engagement; +- improved learning outcomes; +- reduced teaching time measured in controlled conditions; +- documented classroom deployment; +- broad adoption by external instructors; +- JOSE submission, review, or acceptance; +- CRAN publication. + +## Evidence Available to Reviewers + +Reviewers can inspect: + +- `inst/examples/example_course_module/README.md`; +- `inst/examples/example_course_module/run-example.R`; +- `vignettes/teaching-workflow-scenario.Rmd`; +- `tests/testthat/test-examples.R`; +- `tests/testthat/test-jose-readiness.R`; +- `paper/paper.md`; +- `docs/jose_review_checklist.md`; +- `docs/jose_submission_guide.md`. + +## Evidence Still Missing Before a Stronger JOSE Submission + +- Actual classroom deployment: Not verifiable from repository contents. +- Instructor adoption outside the maintainer: Not verifiable from repository contents. +- Formal student feedback: Not verifiable from repository contents. +- Student outcome data: Not verifiable from repository contents. +- Teaching assistant workflow evidence: Not verifiable from repository contents. +- Long-term use across multiple cohorts: Not verifiable from repository contents. + +## Claims that must not be made + +- Do not claim improved student grades unless measured. +- Do not claim improved engagement unless measured. +- Do not claim classroom deployment unless documented. +- Do not claim broad adoption unless usage evidence exists. +- Do not claim JOSE readiness solely because R CMD check passes. +- Do not claim direct LMS publishing, because current support is manifest-oriented. +- Do not claim current CRAN availability unless verified. diff --git a/docs/jose_audit.md b/docs/jose_audit.md new file mode 100644 index 0000000..fc45174 --- /dev/null +++ b/docs/jose_audit.md @@ -0,0 +1,102 @@ +# tutorizeR JOSE Repository Audit + +Audit date: 2026-05-31 +Repository path: `/Users/aureliennicosia/Documents/tutorizeR` + +## Evidence sources + +This audit is based on repository contents and the current public guidance from Open Journals and R Core: + +- Open Journals, 2026. Submitting a paper to JOSE. https://openjournals.readthedocs.io/en/jose/submitting.html +- Open Journals, 2026. Reviewing for JOSE. https://openjournals.readthedocs.io/en/jose/reviewer_guidelines.html +- JOSS, 2026. Review criteria. https://joss.readthedocs.io/en/latest/review_criteria.html +- JOSS, 2026. Submitting a paper to JOSS. https://joss.readthedocs.io/en/latest/submitting.html +- R Core Team, 2026. Writing R Extensions, R version 4.6.0. https://stat.ethz.ch/CRAN/doc/manuals/r-release/R-exts.html + +## Scope + +The audit inspected the package metadata, source code, tests, vignettes, documentation, continuous integration, paper assets, governance files, templates, and examples currently present in the repository. + +## Strengths + +- The repository is structured as a conventional R package with `DESCRIPTION`, `NAMESPACE`, `R/`, `man/`, `tests/`, `vignettes/`, and package metadata. +- The package has a clear educational technology focus: converting `.Rmd` and `.qmd` teaching documents into `learnr` or `quarto-live` materials. +- The public API includes conversion, folder processing, validation, linting, question-bank handling, report writing, LMS manifest export, package scaffold export, and RStudio addins. +- Core parser and transform behavior is covered by `testthat` tests with fixtures for `.Rmd`, `.qmd`, MCQ blocks, non-R chunks, duplicate labels, inline chunks, question banks, regression fixtures, exports, validation, and reports. +- GitHub Actions already run multi-platform `R CMD check`, linting, and coverage. +- Governance files already exist: `LICENSE`, `LICENSE.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `NEWS.md`, `CITATION.cff`, `SECURITY.md`, issue templates, and a pull request template. +- A JOSE/JOSS-style `paper/paper.md` and `paper/paper.bib` are present. +- The package includes teacher-facing documentation through `README.md`, vignettes, templates, and release support documents. +- `DESCRIPTION` declares a standard MIT license and package URLs. + +## Weaknesses + +- Educational adoption evidence: Not verifiable from repository contents. +- The README is technically useful but still stronger as developer documentation than as a JOSE reviewer landing page. +- Existing vignettes before this audit were short and did not fully cover the five educational scenarios requested for JOSE positioning. +- `pkgdown` configuration existed but did not yet expose a dedicated JOSE submission section, educational examples section, or visual workflow assets. +- CRAN status: Not verifiable from repository contents. +- The JOSE paper requires careful maintenance of truthful educational use statements. The repository can document intended classroom workflows, but actual deployment in named courses must remain marked as not verifiable unless evidence is added. +- Optional dependencies such as `learnr`, `gradethis`, `quarto-live`, and `tidyverse` affect some example workflows but are not all hard dependencies. This is reasonable for package weight, but reviewer documentation must state when optional packages are required. + +## Missing JOSE Requirements + +Based on Open Journals guidance, JOSE software submissions should have an open repository, an OSI-approved license, `paper.md`, `paper.bib`, a statement of need, functionality, and recent teaching or learning use where applicable. + +Current status: + +- Open repository: PARTIAL. Public visibility and GitHub history: Not verifiable from repository contents. +- OSI-approved license: READY. MIT license files are present. +- `paper.md`: READY. Present in `paper/paper.md`. +- `paper.bib`: READY. Present in `paper/paper.bib`. +- Statement of Need: READY. Present in `paper/paper.md`, but should emphasize computational teaching and adoption by instructors. +- Functionality: READY. Present in README, man pages, vignettes, and paper. +- Recent use in teaching and learning situations: PARTIAL. Concrete adoption evidence: Not verifiable from repository contents. +- Reviewer-friendly installation and examples: PARTIAL. Installation exists; a dedicated educational example module was missing before this JOSE pass. +- Educational positioning: PARTIAL. The package purpose is educational, but a dedicated use-case document and broader vignettes were needed. + +## Missing JOSS Requirements + +Based on JOSS review criteria, the repository should include a license, clear documentation, installation instructions, examples, tests, community guidelines, paper, and evidence of scholarly significance. + +Current status: + +- License file: READY. +- Installation instructions: READY. +- Example usage: READY. +- Tests: READY. +- Automated checks: READY. +- Community guidelines: READY. +- Paper with summary, need, comparison, and references: PARTIAL. Present, but title and JOSE-centered content required revision. +- Development history and open-source practice: PARTIAL. Local repository content cannot verify public timeline, issue activity, or external contributors. +- Scholarly significance outside a single local use case: PARTIAL. External adoption: Not verifiable from repository contents. +- AI usage disclosure: PARTIAL. The paper must be kept current if AI tools are used for code, documentation, or manuscript preparation. + +## Missing CRAN Requirements + +Based on R Core Team package guidance and standard CRAN checks: + +- Standard package structure: READY. +- `DESCRIPTION`: READY, with standard metadata and dependencies. +- `NAMESPACE`: READY. +- Rd documentation: READY. +- Tests: READY. +- Vignettes: READY, with further expansion recommended. +- License declaration: READY. +- `R CMD check --as-cran`: PARTIAL. Prior check artifacts exist, but a fresh check should be run before any release. +- CRAN comments: READY. `cran-comments.md` exists. +- CRAN publication evidence: MISSING. Not verifiable from repository contents. +- Reverse dependency checks: Not verifiable from repository contents. + +## Priority Fixes + +1. Create a dedicated JOSE audit, checklist, and submission report. +2. Expand educational documentation with explicit instructor, student, and classroom workflows. +3. Add the five requested vignettes with realistic, pedagogically motivated scenarios. +4. Add a complete teaching demonstration under `inst/examples/example_course_module/`. +5. Add explicit tests for `gradethis` setup generation, `quarto-live` output, MCQ reference error handling, and publication assets. +6. Update GitHub Actions with a separate test job in addition to `R CMD check` and coverage. +7. Update `_pkgdown.yml` with JOSE submission and educational examples navigation. +8. Add visual workflow and screenshot assets for README/pkgdown. +9. Revise `paper/paper.md` with the exact JOSE-oriented title and sections requested in the prompt. +10. Keep all educational adoption claims limited to what is verifiable from repository contents. diff --git a/docs/jose_blockers_report.md b/docs/jose_blockers_report.md new file mode 100644 index 0000000..6c8650f --- /dev/null +++ b/docs/jose_blockers_report.md @@ -0,0 +1,109 @@ +# JOSE Blockers Report + +Date: 2026-05-31 +Branch: `review/jose-readiness` +PR: https://github.com/AurelienNicosiaULaval/tutorizeR/pull/5 + +## Executive Summary + +The repository is a credible candidate for a future JOSE software submission because it is open-source educational infrastructure for converting reproducible R Markdown and Quarto teaching materials into interactive tutorials. The main weakness before this pass was that the PR still read like a JOSS/CRAN readiness pass rather than a JOSE submission package. The central corrections are to make the educational contribution explicit, avoid unverified pedagogical claims, provide an installable teaching example, and document the evidence boundary. + +Sources consulted: + +- Open Journals. JOSE submitting guide. https://openjournals.readthedocs.io/en/jose/submitting.html +- Open Journals. JOSE review criteria. https://openjournals.readthedocs.io/en/jose/review_criteria.html +- Open Journals. JOSE review checklist. https://openjournals.readthedocs.io/en/jose/review_checklist.html + +## Blocking Issues for JOSE + +| Severity | Issue | Status | Required action | +|---|---|---|---| +| BLOCKER | JOSE framing was mixed with JOSS framing. | Addressed in PR | README, paper, and docs now make JOSE the primary target and keep JOSS secondary. | +| BLOCKER | Paper needed to explain JOSE eligibility and educational contribution rather than list API details. | Addressed in PR | `paper/paper.md` rewritten as a JOSE-oriented paper. | +| BLOCKER | Educational evidence boundary was not explicit enough. | Addressed in PR | `docs/educational_use_evidence.md` states what is demonstrated, plausible, not claimed, and missing. | +| BLOCKER | Example module was not in the expected installable structure. | Addressed in PR | `inst/examples/example_course_module/` now includes source, question bank, expected outputs, report, and run script. | +| BLOCKER | Example expected outputs included placeholder MCQs. | Addressed in PR | The example question bank now provides realistic comprehension, interpretation, and code/output questions; tests prevent generic editable placeholder answers in JOSE-facing outputs. | +| MAJOR | Example dependencies were not fully declared. | Addressed in PR | `DESCRIPTION` now declares `dplyr`, `ggplot2`, `readr`, `learnr`, and `gradethis`; CI runs the installed example. | +| MAJOR | README smoke tests used internal test fixtures. | Addressed in PR | README now uses `system.file("examples", "example_course_module", package = "tutorizeR")`. | +| MAJOR | Content and figure licensing was not explicit. | Addressed in PR | Added `LICENSE-CONTENT.md` and README/example licensing notes. | +| MAJOR | AI usage statement needed cautious wording. | Addressed in PR | Paper now states that generative AI supported planning, review, or documentation-support stages. | +| MAJOR | Need final verification before submission. | Remaining | Rerun tests, lint, source build, R CMD check, and remote CI immediately before an actual JOSE submission. | + +## Factual Risks + +| Severity | Risk | Required wording | +|---|---|---| +| BLOCKER | Claiming classroom deployment without evidence. | `Not verifiable from repository contents.` | +| BLOCKER | Claiming improved learning outcomes, grades, or engagement without measured evidence. | Do not claim. | +| MAJOR | Claiming JOSE submission, review, or acceptance. | Do not claim until it happens and is documented. | +| MAJOR | Claiming CRAN publication. | Do not claim unless CRAN publication is verified. | +| MAJOR | Claiming CI is green without checking remote Actions. | Addressed during this review; rerun on final release commit. | + +## Package Quality Risks + +| Severity | Risk | Status | +|---|---|---| +| MAJOR | Example conversion can fail if user examples depend on working-directory-relative data. | Addressed through `run-example.R`, which copies files to a temporary working directory. | +| MAJOR | Coverage job used a fragile `covr::coverage_to_list()` data-frame conversion. | Addressed with direct access to named `filecoverage` values. | +| MINOR | `R CMD build .` can be slow or fail in the live repository because R copies `.git` before applying exclusions. | Documented in final report; clean source copy build succeeds. | +| MINOR | Optional packages `learnr`, `gradethis`, `quarto-live`, and `tidyverse` affect examples. | Documented in README and example files. | + +## Documentation Gaps + +| Severity | Gap | Status | +|---|---|---| +| MAJOR | Dedicated JOSE submission guide. | Addressed in `docs/jose_submission_guide.md`. | +| MAJOR | Dedicated JOSE review checklist with official categories. | Addressed in `docs/jose_review_checklist.md`. | +| MAJOR | Educational evidence and non-claims document. | Addressed in `docs/educational_use_evidence.md`. | +| MAJOR | Teaching workflow scenario vignette. | Addressed in `vignettes/teaching-workflow-scenario.Rmd`. | +| MINOR | Existing vignettes were concise. | Expanded with goals, examples, realistic workflow notes, limits, and reproducibility commands. | + +## Evidence Gaps + +| Severity | Gap | Current evidence | +|---|---|---| +| BLOCKER | Formal learning-outcome evaluation. | Not verifiable from repository contents. | +| BLOCKER | Documented classroom deployment. | Not verifiable from repository contents. | +| MAJOR | External instructor adoption. | Not verifiable from repository contents. | +| MAJOR | Final release DOI. | Not verifiable from repository contents. | +| MAJOR | Remote CI status after this commit. | Must be verified after push. | +| MINOR | Long-term maintenance history after release. | Partly visible in Git history, but public activity should be checked on GitHub. | + +## Exact Files to Change + +Files addressed in this PR: + +- `README.md` +- `paper/paper.md` +- `paper/paper.bib` +- `_pkgdown.yml` +- `.github/workflows/r.yml` +- `tests/testthat/test-examples.R` +- `tests/testthat/test-jose-readiness.R` +- `inst/examples/example_course_module/` +- `vignettes/teaching-workflow-scenario.Rmd` +- `vignettes/getting-started.Rmd` +- `vignettes/question-bank.Rmd` +- `vignettes/conversion-rmd-vs-qmd.Rmd` +- `vignettes/mcq-and-assessment.Rmd` +- `vignettes/lint-and-debug.Rmd` +- `docs/jose_submission_guide.md` +- `docs/jose_release_bundle.md` +- `docs/jose_review_checklist.md` +- `docs/educational_use_evidence.md` +- `docs/jose_pr_final_report.md` +- `LICENSE-CONTENT.md` +- `LICENSES.md` + +## Final Checklist Before Submission + +- [ ] Confirm remote GitHub Actions pass on PR #5 after this final pass. +- [ ] Rerun `Rscript -e "testthat::test_local('.')"` on a clean checkout. +- [ ] Rerun `Rscript -e "lintr::lint_package()"`. +- [ ] Rerun source build from a clean source copy or another checkout that does not copy `.git`. +- [ ] Rerun `R CMD check --as-cran --no-manual`. +- [ ] Confirm all paper references are cited and BibTeX parses. +- [ ] Confirm the example module runs after package installation. +- [ ] Confirm the installed-example CI job passes. +- [ ] Add documented classroom use only if evidence can be added to the repository. +- [ ] Do not submit until factual claims have been reviewed by the maintainer. diff --git a/docs/jose_checklist.md b/docs/jose_checklist.md new file mode 100644 index 0000000..78fa02b --- /dev/null +++ b/docs/jose_checklist.md @@ -0,0 +1,53 @@ +# JOSE Review Checklist + +Checklist date: 2026-05-31 + +Status labels: + +- READY: evidence is present in the repository. +- PARTIAL: evidence is present but incomplete. +- MISSING: no evidence was found in the repository. + +## Checklist + +| Item | Status | Repository evidence | Notes | +|---|---:|---|---| +| Open source license | READY | `LICENSE`, `LICENSE.md`, `DESCRIPTION` | MIT license present. | +| Open repository | PARTIAL | `DESCRIPTION` URL | Public visibility: Not verifiable from repository contents. | +| Educational contribution | READY | README, vignettes, `docs/educational_use_cases.md`, `paper/paper.md` | Focus is educational technology for R-based teaching. | +| Installation instructions | READY | `README.md` | GitHub and r-universe instructions present. | +| Basic usage examples | READY | `README.md`, vignettes, `inst/examples/` | Includes single-file and folder conversion workflows. | +| Tests | READY | `tests/testthat/` | Parser, conversion, MCQ, question-bank, export, validation, regression, and publication readiness tests. | +| Continuous integration | READY | `.github/workflows/r.yml` | R CMD check, tests, lint, and coverage jobs configured. | +| Coverage reporting | READY | `.github/workflows/r.yml` | `covr::package_coverage()` configured with core threshold. | +| Documentation | READY | `README.md`, `man/`, vignettes, docs | Reviewer-facing docs added. | +| Vignettes | READY | `vignettes/` | Includes JOSE-oriented educational vignettes, including a teaching workflow scenario. | +| Reproducibility | READY | examples, tests, workflow, local dataset | Source-first conversion workflow documented. | +| Educational adoption evidence | PARTIAL | package examples and use cases | Actual classroom adoption: Not verifiable from repository contents. | +| JOSE paper | READY | `paper/paper.md` | Title and required sections present. | +| Bibliography | READY | `paper/paper.bib` | Key references present. | +| Code of conduct | READY | `CODE_OF_CONDUCT.md` | Present. | +| Contribution guide | READY | `CONTRIBUTING.md` | Present. | +| Citation metadata | READY | `CITATION.cff`, `CITATION` | Present. | +| Issue templates | READY | `.github/ISSUE_TEMPLATE/` | Bug, feature, and JOSE readiness templates present. | +| Pull request template | READY | `.github/PULL_REQUEST_TEMPLATE.md` | Present and expanded. | +| CRAN readiness evidence | READY | `cran-comments.md`, tests, DESCRIPTION | Clean temporary source check on 2026-05-31 returned Status: 1 NOTE for new submission. | +| Screenshots and workflow visuals | READY | `man/figures/` | Workflow diagram and report screenshot asset present. | + +## Remaining JOSE Blockers + +- Public GitHub history, issue activity, and repository visibility: Not verifiable from repository contents. +- Actual classroom adoption: Not verifiable from repository contents. +- The clean check should be rerun immediately before submission because package and system state can change. + +## Recommended Pre-Submission Commands + +```bash +Rscript -e "testthat::test_local()" +Rscript -e "lintr::lint_package()" +tmpdir=$(mktemp -d) +rsync -a --exclude='.git' --exclude='*.Rcheck' --exclude='*.tar.gz' ./ "$tmpdir/tutorizeR/" +cd "$tmpdir/tutorizeR" +R CMD build . +R CMD check --as-cran --no-manual tutorizeR_*.tar.gz +``` diff --git a/docs/jose_pr_final_report.md b/docs/jose_pr_final_report.md new file mode 100644 index 0000000..ab49287 --- /dev/null +++ b/docs/jose_pr_final_report.md @@ -0,0 +1,206 @@ +# JOSE PR Final Report + +Date: 2026-05-31 +Branch: `review/jose-readiness` +PR: https://github.com/AurelienNicosiaULaval/tutorizeR/pull/5 + +## What Was Changed + +- Recentered the README on JOSE as the primary target and moved JOSS to a secondary-target section. +- Rewrote `paper/paper.md` as a JOSE-oriented software paper, not API documentation. +- Added pedagogical references to `paper/paper.bib` and cited them in the paper. +- Added cautious AI usage disclosure. +- Added explicit educational evidence boundaries. +- Rebuilt the example module as an installable teaching example with source lesson, question bank, expected outputs, JSON report, and run script. +- Added a teaching workflow scenario vignette. +- Expanded core vignettes with user goals, minimal examples, realistic examples, limitations, and reproducibility checks. +- Added CC-BY 4.0 content licensing for educational examples, expected outputs, and figures. +- Replaced placeholder MCQs in the JOSE-facing example outputs with realistic question-bank items. +- Added an installed-example CI job. +- Removed the placeholder ORCID field, the generic group paper author, and the unverified Zenodo DOI badge. +- Added example-module tests and README fixture-path checks. +- Updated GitHub Actions coverage logic to use named coverage values and run on PRs targeting `release/v0.4.4`. + +## Why Each Change Matters for JOSE + +- JOSE evaluates educational contribution, not only package mechanics. +- The paper now explains the teaching problem, educational infrastructure role, adoption workflow, and limitations. +- The example module gives reviewers an installable artifact they can run without relying on internal test fixtures. +- The evidence document prevents overclaiming about student outcomes or classroom adoption. +- The review checklist maps repository evidence to JOSE-style review concerns. +- The content license clarifies reuse rights for teaching examples and figures. + +## Factual Claims Corrected + +- Removed framing that treated the branch primarily as JOSS preparation. +- Avoided claims of classroom deployment, improved engagement, improved grades, or improved learning outcomes. +- Replaced any categorical AI non-use framing with a cautious disclosure. +- Clarified that LMS support is manifest-oriented, not direct publishing. +- Clarified that CRAN publication is not claimed. +- Clarified that JOSE submission, review, or acceptance is not claimed. + +## Educational Evidence Added + +- `docs/educational_use_evidence.md` +- `inst/examples/example_course_module/` +- `vignettes/teaching-workflow-scenario.Rmd` +- Expanded getting started, question-bank, conversion, assessment, and lint/debug vignettes. + +## Remaining Limitations + +- Formal learning-outcome evaluation: Not verifiable from repository contents. +- Actual classroom deployment: Not verifiable from repository contents. +- Broad external instructor adoption: Not verifiable from repository contents. +- Remote GitHub Actions must be checked again after the final push from this pass. +- Final release DOI: Not verifiable from repository contents. +- ORCID should be added only if the maintainer wants to publish a verified ORCID. + +## Validation Commands Run + +Official JOSE pages reviewed: + +- https://openjournals.readthedocs.io/en/jose/submitting.html +- https://openjournals.readthedocs.io/en/jose/review_criteria.html +- https://openjournals.readthedocs.io/en/jose/review_checklist.html + +Local validation: + +```bash +Rscript -e "devtools::document()" +``` + +Result: PASS. Documentation regenerated and `RoxygenNote` updated to `7.3.3`. + +```bash +Rscript -e "testthat::test_local('.')" +``` + +Result: PASS. The full test suite completed with no failures. + +```bash +Rscript -e "lintr::lint_package()" +``` + +Result: PASS. No lints found. + +```bash +Rscript -e "yaml::read_yaml('_pkgdown.yml')" +``` + +Result: PASS. `_pkgdown.yml` parsed successfully. + +```bash +Rscript - <<'EOF' +out_dir <- tempfile('tutorizer-pkgdown-') +pkgdown::build_site( + override = list(destination = out_dir), + preview = FALSE, + install = FALSE, + new_process = FALSE +) +EOF +``` + +Result: PASS. The site was built in a temporary directory. `pkgdown` reported that the site URL is missing; this was left unset because a published pkgdown URL is Not verifiable from repository contents. + +```bash +Rscript -e "rmarkdown::render('paper/paper.md', output_format = rmarkdown::md_document(variant = 'gfm'), output_file = tempfile(fileext = '.md'), quiet = TRUE)" +``` + +Result: PASS. Paper rendered successfully and bibliography citations resolved. + +```bash +Rscript - <<'EOF' +files <- list.files('vignettes', pattern = '\\.[Rr]md$', full.names = TRUE) +out_dir <- tempfile('tutorizer-vignettes-') +dir.create(out_dir) +for (file in files) { + rmarkdown::render(file, output_dir = out_dir, quiet = TRUE) +} +EOF +``` + +Result: PASS. 13 vignettes rendered successfully. + +```bash +tmp_lib=$(mktemp -d) +R CMD INSTALL --library="$tmp_lib" . +TMP_LIB="$tmp_lib" Rscript -e ".libPaths(c(Sys.getenv('TMP_LIB'), .libPaths())); source(system.file('examples', 'example_course_module', 'run-example.R', package = 'tutorizeR'))" +``` + +Result: PASS. The installed package example generated `learnr`, `quarto-live`, and JSON report outputs in a temporary directory. + +```bash +Rscript - <<'EOF' +cov <- covr::package_coverage(quiet = TRUE) +cov_list <- covr::coverage_to_list(cov) +file_coverage <- cov_list$filecoverage +core_files <- c('R/parser.R', 'R/transform.R', 'R/validation.R', 'R/report.R') +missing <- setdiff(core_files, names(file_coverage)) +if (length(missing) > 0L) stop(sprintf('Missing core files: %s', paste(missing, collapse = ', '))) +core_pct <- mean(unname(file_coverage[core_files])) +total_pct <- as.numeric(cov_list$totalcoverage) +cat(sprintf('Coverage total: %.2f%%\n', total_pct)) +cat(sprintf('Coverage core: %.2f%%\n', core_pct)) +if (core_pct < 80) stop(sprintf('Core coverage threshold not met: %.2f%% < 80%%', core_pct)) +EOF +``` + +Result: PASS in the previous PR pass. Coverage total: 71.58%. Coverage core: 93.36%. + +Clean source-copy validation: + +```bash +tmpdir=$(mktemp -d) +rsync -a --exclude='.git' --exclude='*.Rcheck' --exclude='..Rcheck' --exclude='*.tar.gz' ./ "$tmpdir/tutorizeR/" +cd "$tmpdir/tutorizeR" +R CMD build . +R CMD check --as-cran --no-manual tutorizeR_0.4.4.tar.gz +``` + +Result: PASS with 1 NOTE for new submission. + +The NOTE also records that `gradethis` is suggested from `https://rstudio.r-universe.dev` via `Additional_repositories`. + +## CI Status + +GitHub Actions must be checked after the final commit is pushed because this pass adds a new `installed-example` job. + +## Files Modified + +Key changed or added files: + +- `README.md` +- `paper/paper.md` +- `paper/paper.bib` +- `LICENSE-CONTENT.md` +- `LICENSES.md` +- `_pkgdown.yml` +- `.Rbuildignore` +- `.github/workflows/r.yml` +- `docs/jose_blockers_report.md` +- `docs/jose_submission_guide.md` +- `docs/jose_review_checklist.md` +- `docs/educational_use_evidence.md` +- `docs/jose_release_bundle.md` +- `docs/jose_pr_final_report.md` +- `inst/examples/example_course_module/` +- `tests/testthat/test-examples.R` +- `tests/testthat/test-jose-readiness.R` +- `vignettes/teaching-workflow-scenario.Rmd` +- `vignettes/getting-started.Rmd` +- `vignettes/question-bank.Rmd` +- `vignettes/conversion-rmd-vs-qmd.Rmd` +- `vignettes/mcq-and-assessment.Rmd` +- `vignettes/lint-and-debug.Rmd` + +## Remaining Blockers Before Actual JOSE Submission + +- Documented classroom deployment: Not verifiable from repository contents. +- Formal learning-outcome evaluation: Not verifiable from repository contents. +- Final release DOI: Not verifiable from repository contents. +- ORCID metadata should be added only after maintainer confirmation. + +Recommendation: Not ready for JOSE submission. + +The repository is substantially more JOSE-ready, but a real submission should wait until the maintainer confirms final release metadata and decides whether to add documented classroom-use evidence. diff --git a/docs/jose_release_bundle.md b/docs/jose_release_bundle.md new file mode 100644 index 0000000..5afd216 --- /dev/null +++ b/docs/jose_release_bundle.md @@ -0,0 +1,59 @@ +# JOSE Release Bundle + +Date: 2026-05-31 + +This file lists the repository artifacts to prepare before a possible JOSE submission. + +## Core Submission Files + +- `paper/paper.md` +- `paper/paper.bib` +- `README.md` +- `DESCRIPTION` +- `LICENSE` +- `LICENSE.md` +- `LICENSE-CONTENT.md` +- `LICENSES.md` +- `CITATION.cff` + +## Reviewer Documentation + +- `docs/jose_submission_guide.md` +- `docs/jose_review_checklist.md` +- `docs/jose_blockers_report.md` +- `docs/educational_use_evidence.md` +- `docs/jose_pr_final_report.md` + +## Teaching Demonstration + +- `inst/examples/example_course_module/README.md` +- `inst/examples/example_course_module/lesson-source.qmd` +- `inst/examples/example_course_module/question-bank/questions.yml` +- `inst/examples/example_course_module/expected/lesson-source-tutorial.Rmd` +- `inst/examples/example_course_module/expected/lesson-source-live.qmd` +- `inst/examples/example_course_module/expected/conversion-report.json` +- `inst/examples/example_course_module/run-example.R` + +## Validation Commands + +Run immediately before submission: + +```bash +Rscript -e "testthat::test_local('.')" +Rscript -e "lintr::lint_package()" +Rscript -e "devtools::document()" +tmpdir=$(mktemp -d) +rsync -a --exclude='.git' --exclude='*.Rcheck' --exclude='*.tar.gz' ./ "$tmpdir/tutorizeR/" +cd "$tmpdir/tutorizeR" +R CMD build . +R CMD check --as-cran --no-manual tutorizeR_0.4.4.tar.gz +Rscript -e "source(system.file('examples', 'example_course_module', 'run-example.R', package = 'tutorizeR'))" +``` + +## Remaining Before a Real Submission + +- Confirm remote GitHub Actions status. +- Confirm final version number and release tag. +- Final release DOI: Not verifiable from repository contents. +- Confirm ORCID metadata only if the maintainer wants to publish an ORCID. +- Add classroom-use evidence only if it can be documented in the repository. diff --git a/docs/jose_review_checklist.md b/docs/jose_review_checklist.md new file mode 100644 index 0000000..cc6199e --- /dev/null +++ b/docs/jose_review_checklist.md @@ -0,0 +1,102 @@ +# JOSE Review Checklist + +Date: 2026-05-31 + +Status labels: + +- READY: supported by repository evidence. +- PARTIAL: partially supported, but incomplete. +- MISSING: expected evidence is absent. +- NOT VERIFIABLE: cannot be verified from repository contents. + +Official JOSE checklist source: https://openjournals.readthedocs.io/en/jose/review_checklist.html + +## License + +| Item | Status | Evidence | +|---|---|---| +| Code has an OSI-approved license. | READY | `DESCRIPTION`, `LICENSE`, `LICENSE.md`. | +| Educational content license is clear. | READY | `LICENSE-CONTENT.md`, `LICENSES.md`, README, example README. | +| Repository is public. | NOT VERIFIABLE | Public visibility cannot be proven from local files alone. | + +## Statement of Need + +| Item | Status | Evidence | +|---|---|---| +| Paper explains the educational need. | READY | `paper/paper.md`. | +| Paper explains why software is needed. | READY | `paper/paper.md`. | +| Paper avoids being API documentation. | READY | Detailed API remains in README, vignettes, and man pages. | + +## Community Guidelines + +| Item | Status | Evidence | +|---|---|---| +| Contribution guide exists. | READY | `CONTRIBUTING.md`. | +| Code of conduct exists. | READY | `CODE_OF_CONDUCT.md`. | +| Issue and PR templates exist. | READY | `.github/ISSUE_TEMPLATE/`, `.github/PULL_REQUEST_TEMPLATE.md`. | + +## Documentation + +| Item | Status | Evidence | +|---|---|---| +| Installation instructions exist. | READY | `README.md`. | +| User workflow is documented. | READY | `README.md`, vignettes. | +| Example module is documented. | READY | `inst/examples/example_course_module/README.md`. | +| Limitations are documented. | READY | README, paper, `docs/educational_use_evidence.md`. | + +## Tests + +| Item | Status | Evidence | +|---|---|---| +| Automated tests exist. | READY | `tests/testthat/`. | +| Example module tests exist. | READY | `tests/testthat/test-examples.R`. | +| Local tests pass. | READY | `testthat::test_local('.')` passed locally with 144 tests on 2026-05-31. | +| Remote CI passes. | PARTIAL | Must be checked again after the final commit in this pass. | + +## Examples + +| Item | Status | Evidence | +|---|---|---| +| Installable example exists. | READY | `inst/examples/example_course_module/`. | +| Example includes source lesson. | READY | `lesson-source.qmd`. | +| Example includes question bank. | READY | `question-bank/questions.yml`. | +| Example includes expected outputs. | READY | `expected/`. | +| Example can be run with installed package. | READY | `run-example.R` exists and is covered by tests and CI. | +| Example dependencies are declared. | READY | `DESCRIPTION` lists the packages used by the example module; `gradethis` is available through `Additional_repositories`. | +| JOSE-facing example outputs avoid placeholder MCQs. | READY | Example tests check that expected outputs do not contain generic editable placeholder answers. | + +## Functionality + +| Item | Status | Evidence | +|---|---|---| +| Feature-complete conversion workflow exists. | READY | `R/`, tests, examples. | +| `.Rmd` and `.qmd` inputs supported. | READY | tests and vignettes. | +| `learnr` and `quarto-live` targets supported. | READY | tests and examples. | +| Question bank support exists. | READY | `R/question_bank.R`, tests, example bank. | +| LMS direct publishing exists. | MISSING | Current export is manifest-only. This is documented as a limitation. | + +## Educational Contribution + +| Item | Status | Evidence | +|---|---|---| +| Educational technology contribution is explained. | READY | README, paper, docs. | +| Teaching workflow is demonstrated. | READY | example module and `teaching-workflow-scenario` vignette. | +| Learning-outcome evidence exists. | NOT VERIFIABLE | Formal learning-outcome evaluation: Not verifiable from repository contents. | + +## Adoption by Instructors + +| Item | Status | Evidence | +|---|---|---| +| Adoption workflow for other instructors is documented. | READY | README, example README, vignettes. | +| Actual classroom deployment is documented. | NOT VERIFIABLE | No repository evidence. | +| Broad external adoption is documented. | NOT VERIFIABLE | No repository evidence. | + +## Paper Readiness + +| Item | Status | Evidence | +|---|---|---| +| JOSE-oriented paper exists. | READY | `paper/paper.md`. | +| Bibliography exists. | READY | `paper/paper.bib`. | +| Pedagogical references are cited. | READY | paper and bibliography. | +| AI usage disclosure is cautious. | READY | `paper/paper.md`. | +| Final metadata is complete. | PARTIAL | ORCID placeholder was removed. Final release DOI remains Not verifiable from repository contents. | diff --git a/docs/jose_submission_guide.md b/docs/jose_submission_guide.md new file mode 100644 index 0000000..d9e8410 --- /dev/null +++ b/docs/jose_submission_guide.md @@ -0,0 +1,112 @@ +# JOSE Submission Guide for tutorizeR + +Date: 2026-05-31 + +This guide prepares `tutorizeR` for a possible Journal of Open Source Education submission. It does not state that the package has been submitted, reviewed, or accepted. + +Official JOSE guidance used: + +- Submitting guide: https://openjournals.readthedocs.io/en/jose/submitting.html +- Review criteria: https://openjournals.readthedocs.io/en/jose/review_criteria.html +- Review checklist: https://openjournals.readthedocs.io/en/jose/review_checklist.html + +## Why tutorizeR Fits JOSE + +JOSE accepts software that functions as educational technology or infrastructure. `tutorizeR` fits that category because it helps instructors transform reproducible R Markdown and Quarto teaching documents into interactive tutorials and browser-executable resources. Its contribution is educational infrastructure: reducing manual conversion work and supporting source-first development of computational learning materials. + +The repository does not claim measured learning gains, improved grades, improved engagement, classroom deployment, or broad adoption. Not verifiable from repository contents. + +## What to Submit + +For a JOSE submission, prepare: + +- repository URL; +- release tag and archive DOI if available; +- `paper/paper.md`; +- `paper/paper.bib`; +- license information for code and educational content; +- reviewer instructions for installation, tests, and examples. + +The paper should explain the educational need, intended teaching context, adoption workflow, current evidence, limitations, licensing, and references. It should not replace package documentation. + +## How to Reproduce the Example + +After installing the package: + +```r +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +source_file <- file.path(example_dir, "lesson-source.qmd") +question_bank <- load_question_bank(file.path(example_dir, "question-bank")) + +report <- tutorize( + input = source_file, + format = "learnr", + assessment = "both", + output_dir = tempdir(), + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) + +print(report) +``` + +The full script is available in `inst/examples/example_course_module/run-example.R`. + +## How a Reviewer Can Test the Package + +Developer checks: + +```bash +Rscript -e "testthat::test_local('.')" +Rscript -e "lintr::lint_package()" +tmpdir=$(mktemp -d) +rsync -a --exclude='.git' --exclude='*.Rcheck' --exclude='*.tar.gz' ./ "$tmpdir/tutorizeR/" +cd "$tmpdir/tutorizeR" +Rscript -e "devtools::document()" +R CMD build . +R CMD check --as-cran --no-manual tutorizeR_0.4.4.tar.gz +``` + +Installed example check: + +```bash +Rscript -e "source(system.file('examples', 'example_course_module', 'run-example.R', package = 'tutorizeR'))" +``` + +If optional rendering dependencies are missing, reviewers should still be able to inspect generated output files and conversion reports. + +## What Remains to Verify Before Submission + +- Remote GitHub Actions status on the final branch. +- Final source build and R CMD check from a clean checkout. +- Current release tag. +- Final release DOI: Not verifiable from repository contents. +- ORCID metadata, if the maintainer wants to publish it. +- Any classroom deployment evidence, if the maintainer wants to claim it. + +## Demonstrated Claims + +The repository demonstrates: + +- conversion of `.Rmd` and `.qmd` sources; +- `learnr` and `quarto-live` output scaffolding; +- exercise and solution generation; +- MCQ block and question-bank handling; +- conversion reports; +- installable educational example; +- local tests and vignettes. + +## Claims Not Demonstrated + +- Formal learning-outcome evaluation: Not verifiable from repository contents. +- Improved student grades: Not verifiable from repository contents. +- Improved student engagement: Not verifiable from repository contents. +- Documented classroom deployment: Not verifiable from repository contents. +- Broad external adoption: Not verifiable from repository contents. +- JOSE acceptance or current JOSE review status: Not verifiable from repository contents. +- Current CRAN publication: Not verifiable from repository contents. +- Final release DOI: Not verifiable from repository contents. diff --git a/docs/jose_submission_report.md b/docs/jose_submission_report.md new file mode 100644 index 0000000..1e246b6 --- /dev/null +++ b/docs/jose_submission_report.md @@ -0,0 +1,115 @@ +# JOSE Submission Report + +Report date: 2026-05-31 +Repository: tutorizeR + +## Evaluation Basis + +This report evaluates only files and evidence present in the repository. It does not assume public GitHub history, external classroom adoption, CRAN publication, or journal acceptance likelihood unless those facts are verifiable from repository contents. + +## Current Readiness Score + +Current readiness score: 86 / 100 + +Rationale: + +- strong package structure, tests, documentation, governance files, and manuscript assets; +- clear educational infrastructure purpose; +- remaining uncertainty around external adoption evidence, public repository history, and CRAN publication status. + +## JOSE Readiness Score + +JOSE readiness score: 87 / 100 + +Strengths: + +- educational technology scope is clear; +- `paper/paper.md` and `paper/paper.bib` are present; +- educational use cases and JOSE-oriented vignettes are present; +- example course module demonstrates instructor adoption workflow; +- governance, contribution, issue, and PR templates are present. + +Main limitations: + +- actual classroom adoption: Not verifiable from repository contents; +- public repository history and public review readiness: Not verifiable from repository contents; +- GitHub Actions passed on PR #5 during this review; checks should still be rerun immediately before upload. + +## JOSS Readiness Score + +JOSS readiness score: 76 / 100 + +Strengths: + +- standard open-source software package structure; +- tests, CI, coverage, documentation, and paper assets are present; +- installation and usage instructions are available; +- source code has a clear reusable workflow. + +Main limitations: + +- JOSS significance outside an educational technology context is less direct than JOSE; +- external research adoption and public development history: Not verifiable from repository contents; +- JOSS may be secondary because the project is primarily educational infrastructure. + +## CRAN Readiness Score + +CRAN readiness score: 83 / 100 + +Strengths: + +- conventional R package structure; +- documented functions and exported namespace; +- tests and vignettes exist; +- MIT license declared; +- `cran-comments.md` exists. + +Main limitations: + +- current CRAN publication: Not verifiable from repository contents; +- a clean temporary source copy produced `R CMD check --as-cran --no-manual` Status: 1 NOTE on 2026-05-31; +- optional teaching dependencies should remain clearly documented so examples do not imply unavailable hard dependencies. + +## Verification Performed + +On 2026-05-31, the following checks were performed locally: + +- Full `testthat` suite: PASS. +- `lintr::lint_package()`: PASS, no lints found. +- Thirteen vignettes rendered to a temporary output directory: PASS. +- `_pkgdown.yml` parsed with `yaml::read_yaml()`: PASS. +- Paper rendered with bibliography resolution: PASS. +- Coverage gate script: PASS, 71.58% total coverage and 93.36% core coverage. +- Clean temporary source copy built with `R CMD build`: PASS. +- `R CMD check --as-cran --no-manual`: PASS with 1 NOTE for new submission. +- GitHub Actions on PR #5 during this review: PASS for coverage, lintr, testthat, and R CMD check on Ubuntu, macOS, and Windows. + +Direct `R CMD build .` from the live Git checkout was attempted but interrupted because R spent too long copying `.git` into the temporary build directory before applying package build exclusions. Building from a clean source copy without `.git`, `.Rcheck`, or local tarballs succeeded. + +## Remaining Blockers + +- Actual classroom adoption: Not verifiable from repository contents. +- Public GitHub issue and pull request activity: Not verifiable from repository contents. +- Current CRAN publication: Not verifiable from repository contents. +- Final release DOI: Not verifiable from repository contents. +- A fresh full check should be rerun immediately before submission. + +## Recommended Next Actions + +1. Run tests, linting, coverage, and `R CMD check --as-cran --no-manual` on a clean checkout. +2. Confirm that GitHub Actions still pass on the final release commit. +3. Add anonymized, permission-safe teaching evidence if available. +4. Confirm that all paper metadata is final, including ORCID if the maintainer wants to publish one. +5. Create a tagged release before submission. +6. Confirm that `paper/paper.md` truthfully discloses any AI-assisted work if applicable. +7. Submit to JOSE first, with JOSS as a secondary route only if JOSE scope is not pursued. + +Recommendation: Not ready for JOSE submission until remote CI is verified and the maintainer decides whether to add documented classroom-use evidence. + +## Estimated Probability of Acceptance + +JOSE: Not verifiable from repository contents. + +JOSS: Not verifiable from repository contents. + +No acceptance probability is assigned because acceptance depends on editor scope decisions, reviewer assessment, public repository state, external evidence, and responses during review. diff --git a/inst/examples/example_course_module/README.md b/inst/examples/example_course_module/README.md new file mode 100644 index 0000000..2666c03 --- /dev/null +++ b/inst/examples/example_course_module/README.md @@ -0,0 +1,74 @@ +# Example Course Module: Data Visualization and Summarisation + +This module demonstrates a small, generic data science lesson that can be converted with `tutorizeR`. It is designed for instructors who want to see a source-first workflow using Quarto, `learnr`, `quarto-live`, MCQs, a reusable question bank, and conversion reports. + +The dataset is synthetic and intended only for documentation and testing of teaching workflows. + +Educational example materials in this directory are released under CC-BY 4.0 unless otherwise specified. See `LICENSE-CONTENT.md` in the repository root. + +## Teaching context + +The example represents a short undergraduate activity on data summarisation and visualization with R. Students inspect a small table of weekly study activity, compute grouped summaries, and create a scatterplot relating study time to quiz score. + +This module demonstrates an adoption pattern. It does not provide evidence of classroom deployment or student learning gains. Not verifiable from repository contents. + +## Learning objectives + +After completing the activity, students should be able to: + +- import a local CSV file; +- compute grouped summaries with `dplyr`; +- create a basic visualization with `ggplot2`; +- interpret a small exploratory graph cautiously; +- answer conceptual questions about variables and summaries. + +Files: + +- `lesson-source.qmd`: instructor-maintained Quarto source. +- `student_activity.csv`: local teaching dataset. +- `question-bank/questions.yml`: reusable MCQ question bank. +- `expected/lesson-source-tutorial.Rmd`: expected `learnr` output scaffold. +- `expected/lesson-source-live.qmd`: expected `quarto-live` output scaffold. +- `expected/conversion-report.json`: expected conversion report for the `learnr` conversion. +- `run-example.R`: reproducible script that runs the example after package installation. + +## Reproduce the example + +From an installed package: + +```r +library(tutorizeR) + +module_dir <- system.file( + "examples", + "example_course_module", + package = "tutorizeR" +) + +source(file.path(module_dir, "run-example.R")) +``` + +The script copies the module to a temporary directory, loads the question bank, converts the lesson to `learnr`, converts the lesson to `quarto-live`, writes a JSON conversion report, and prints the output paths. + +## What tutorizeR automates + +The package automates: + +- transformation of ordinary R chunks into student exercise areas; +- generation of solution chunks; +- conversion of explicit MCQ blocks; +- insertion of question-bank MCQs; +- insertion of `learnr` setup code and optional `gradethis` setup code; +- generation of conversion reports. + +## What instructors still need to review + +Instructors should manually verify: + +- grading checks and feedback language; +- dataset availability in the deployment environment; +- optional package availability, especially `learnr`, `dplyr`, `ggplot2`, `readr`, and `gradethis` for teacher-authored feedback checks; +- accessibility and clarity of generated prompts; +- final suitability for the course context. + +Formal learning-outcome evaluation: Not verifiable from repository contents. diff --git a/inst/examples/example_course_module/expected/conversion-report.json b/inst/examples/example_course_module/expected/conversion-report.json new file mode 100644 index 0000000..5d301cf --- /dev/null +++ b/inst/examples/example_course_module/expected/conversion-report.json @@ -0,0 +1,35 @@ +{ + "schema_version": "1.0", + "input_file": "lesson-source.qmd", + "output_file": "expected/lesson-source-tutorial.Rmd", + "format": "learnr", + "assessment": "both", + "stats": { + "exercises": 3, + "solutions": 4, + "mcq": 5, + "mcq_explicit": 1, + "mcq_from_bank": 4, + "skipped": 0, + "setup_chunks": 1, + "preserved_chunks": 0, + "sections": 8, + "chunks_total": 7, + "estimated_minutes": 23.5 + }, + "sections": 8, + "chunks_total": 7, + "mcq_explicit": 1, + "mcq_from_bank": 4, + "estimated_minutes": 23.5, + "render_ok": true, + "render_message": "", + "warnings": [], + "lint_summary": { + "errors": 0, + "warnings": 0, + "infos": 0 + }, + "messages": [], + "generated_at": "example" +} diff --git a/inst/examples/example_course_module/expected/lesson-source-live.qmd b/inst/examples/example_course_module/expected/lesson-source-live.qmd new file mode 100644 index 0000000..f9ad4fd --- /dev/null +++ b/inst/examples/example_course_module/expected/lesson-source-live.qmd @@ -0,0 +1,162 @@ +--- +title: Introduction to Data Visualization and Summarisation with R +author: Example instructor +format: live-html +engine: knitr +--- + +{{< include ./_extensions/r-wasm/live/_knitr.qmd >}} + + +## Learning objectives + +By the end of this lesson, students should be able to: + +- import a small CSV file; +- compute grouped summaries with `dplyr`; +- create a scatterplot with `ggplot2`; +- interpret an exploratory pattern without overclaiming. + +## Context + +The synthetic dataset records weekly study activity for a small group of students. The lesson is intentionally compact so that instructors can inspect the complete conversion workflow. + +## Setup + +```{r setup} +library(dplyr) +library(ggplot2) +library(readr) + +activity <- read_csv("student_activity.csv", show_col_types = FALSE) +``` + + +## Instructor demonstration + +**Hint(s)** +- Recognize the output of head(activity, 3) + +_Locked exercise: enable this block only for demonstration._ +```{webr} +# Write your code below +``` + +::: {.callout-tip collapse='true'} +## Solution +```r +head(activity, 3) +``` +::: + +::: {.callout-note} +## Quiz +What does `head(activity, 3)` return in this lesson? + +- [ ] The first three rows of the activity data. +- [ ] A grouped summary by program. +- [ ] A scatterplot of study hours and quiz score. +::: + + +## Data manipulation exercise + +**Hint(s)** +- Group by program before summarising +- Compute mean study hours and mean quiz score +- Use .groups = "drop" + +```{webr} +# Write your code below +``` + +::: {.callout-tip collapse='true'} +## Solution +```r +activity |> + group_by(program) |> + summarise( + mean_hours = mean(study_hours), + mean_score = mean(quiz_score), + .groups = "drop" + ) +``` +::: + +::: {.callout-note} +## Quiz +After grouping by `program`, what does `mean_hours` represent? + +- [ ] The average study hours within each academic program. +- [ ] The total study hours across all students. +- [ ] The quiz score for the first student in each program. +::: + + +::: {.callout-note} +## Quiz +Which variable identifies the academic program? + +- [ ] program +- [ ] week +- [ ] quiz_score +::: + + +::: {.callout-note} +## Quiz +In `ggplot2`, which aesthetic should be mapped to show quiz score on the vertical axis? + +- [ ] y +- [ ] x +- [ ] color +::: + + +## Visualization exercise + +**Hint(s)** +- Map study_hours to x and quiz_score to y +- Use color for program +- Use geom_point() + +```{webr} +# Write your code below +``` + +::: {.callout-tip collapse='true'} +## Solution +```r +ggplot(activity, aes(x = study_hours, y = quiz_score, color = program)) + + geom_point(size = 2) + + labs( + x = "Study hours", + y = "Quiz score", + color = "Program" + ) +``` +::: + +::: {.callout-note} +## Quiz +Which interpretation is appropriate for the scatterplot in this synthetic example? + +- [ ] Students with more study hours tend to have higher quiz scores in this small dataset, but the plot is not causal evidence. +- [ ] The plot proves that increasing study hours causes higher quiz scores. +- [ ] The plot shows that all programs have identical quiz scores. +::: + + +## Instructor solution note + +::: {.callout-tip collapse='true'} +## Solution +```r +"In this small synthetic dataset, higher study time is associated with higher quiz score. This is not causal evidence." +``` +::: + + +## Manual interpretation + +Students should describe the plot cautiously. The dataset is small and synthetic, so the goal is to practice code and interpretation rather than estimate a population effect. diff --git a/inst/examples/example_course_module/expected/lesson-source-tutorial.Rmd b/inst/examples/example_course_module/expected/lesson-source-tutorial.Rmd new file mode 100644 index 0000000..969cd55 --- /dev/null +++ b/inst/examples/example_course_module/expected/lesson-source-tutorial.Rmd @@ -0,0 +1,158 @@ +--- +title: Introduction to Data Visualization and Summarisation with R +author: Example instructor +output: learnr::tutorial +runtime: shiny_prerendered +--- + + +## Learning objectives + +By the end of this lesson, students should be able to: + +- import a small CSV file; +- compute grouped summaries with `dplyr`; +- create a scatterplot with `ggplot2`; +- interpret an exploratory pattern without overclaiming. + +## Context + +The synthetic dataset records weekly study activity for a small group of students. The lesson is intentionally compact so that instructors can inspect the complete conversion workflow. + +## Setup + +```{r setup, include=FALSE} +library(dplyr) +library(ggplot2) +library(readr) + +activity <- read_csv("student_activity.csv", show_col_types = FALSE) +library(learnr) +if (requireNamespace("gradethis", quietly = TRUE)) { + library(gradethis) + gradethis_setup() +} +``` + + +## Instructor demonstration + +**Hint(s)** +- Recognize the output of head(activity, 3) + +_Locked exercise: enable this block only for demonstration._ +```{r trz-ex-demo-preview, exercise.lines=3, exercise=TRUE} +# Write your code below +``` + +```{r trz-sol-demo-preview, include=FALSE} +head(activity, 3) +``` + +```{r trz-mcq-demo-preview, echo=FALSE} +learnr::question( + "What does `head(activity, 3)` return in this lesson?", + learnr::answer("The first three rows of the activity data.", correct = TRUE), + learnr::answer("A grouped summary by program.", correct = FALSE), + learnr::answer("A scatterplot of study hours and quiz score.", correct = FALSE), + allow_retry = TRUE +) +``` + + +## Data manipulation exercise + +**Hint(s)** +- Group by program before summarising +- Compute mean study hours and mean quiz score +- Use .groups = "drop" + +```{r trz-ex-summarize-program, exercise.lines=7, exercise=TRUE} +# Write your code below +``` + +```{r trz-sol-summarize-program, include=FALSE} +activity |> + group_by(program) |> + summarise( + mean_hours = mean(study_hours), + mean_score = mean(quiz_score), + .groups = "drop" + ) +``` + +```{r trz-mcq-summarize-program, echo=FALSE} +learnr::question( + "After grouping by `program`, what does `mean_hours` represent?", + learnr::answer("The average study hours within each academic program.", correct = TRUE), + learnr::answer("The total study hours across all students.", correct = FALSE), + learnr::answer("The quiz score for the first student in each program.", correct = FALSE), + allow_retry = TRUE +) +``` + + +```{r trz-mcq-explicit-004, echo=FALSE} +learnr::question( + "Which variable identifies the academic program?", + learnr::answer("program", correct = TRUE), + learnr::answer("week", correct = FALSE), + learnr::answer("quiz_score", correct = FALSE), + allow_retry = TRUE +) +``` + + +```{r trz-mcq-bank-005-001, echo=FALSE} +learnr::question( + "In `ggplot2`, which aesthetic should be mapped to show quiz score on the vertical axis?", + learnr::answer("y", correct = TRUE), + learnr::answer("x", correct = FALSE), + learnr::answer("color", correct = FALSE), + allow_retry = TRUE +) +``` + + +## Visualization exercise + +**Hint(s)** +- Map study_hours to x and quiz_score to y +- Use color for program +- Use geom_point() + +```{r trz-ex-plot-study-score, exercise.lines=7, exercise=TRUE} +# Write your code below +``` + +```{r trz-sol-plot-study-score, include=FALSE} +ggplot(activity, aes(x = study_hours, y = quiz_score, color = program)) + + geom_point(size = 2) + + labs( + x = "Study hours", + y = "Quiz score", + color = "Program" + ) +``` + +```{r trz-mcq-plot-study-score, echo=FALSE} +learnr::question( + "Which interpretation is appropriate for the scatterplot in this synthetic example?", + learnr::answer("Students with more study hours tend to have higher quiz scores in this small dataset, but the plot is not causal evidence.", correct = TRUE), + learnr::answer("The plot proves that increasing study hours causes higher quiz scores.", correct = FALSE), + learnr::answer("The plot shows that all programs have identical quiz scores.", correct = FALSE), + allow_retry = TRUE +) +``` + + +## Instructor solution note + +```{r trz-sol-interpretation-note, include=FALSE} +"In this small synthetic dataset, higher study time is associated with higher quiz score. This is not causal evidence." +``` + + +## Manual interpretation + +Students should describe the plot cautiously. The dataset is small and synthetic, so the goal is to practice code and interpretation rather than estimate a population effect. diff --git a/inst/examples/example_course_module/lesson-source.qmd b/inst/examples/example_course_module/lesson-source.qmd new file mode 100644 index 0000000..5d85950 --- /dev/null +++ b/inst/examples/example_course_module/lesson-source.qmd @@ -0,0 +1,91 @@ +--- +title: "Introduction to Data Visualization and Summarisation with R" +author: "Example instructor" +format: html +--- + +## Learning objectives + +By the end of this lesson, students should be able to: + +- import a small CSV file; +- compute grouped summaries with `dplyr`; +- create a scatterplot with `ggplot2`; +- interpret an exploratory pattern without overclaiming. + +## Context + +The synthetic dataset records weekly study activity for a small group of students. The lesson is intentionally compact so that instructors can inspect the complete conversion workflow. + +## Setup + +```{r setup} +library(dplyr) +library(ggplot2) +library(readr) + +activity <- read_csv("student_activity.csv", show_col_types = FALSE) +``` + +## Instructor demonstration + +```{r demo-preview} +# tutorizeR: locked +# tutorizeR: hints=Recognize the output of head(activity, 3) +head(activity, 3) +``` + +## Data manipulation exercise + +```{r summarize-program} +# tutorizeR: hints=Group by program before summarising|Compute mean study hours and mean quiz score|Use .groups = "drop" +activity |> + group_by(program) |> + summarise( + mean_hours = mean(study_hours), + mean_score = mean(quiz_score), + .groups = "drop" + ) +``` + +```{tutorizeR-mcq} +question: "Which variable identifies the academic program?" +answers: + - text: "program" + correct: true + - text: "week" + correct: false + - text: "quiz_score" + correct: false +allow_retry: true +``` + +```{tutorizeR-mcq-ref} +ids: [visualization-aesthetic] +strategy: ordered +shuffle_answers: false +``` + +## Visualization exercise + +```{r plot-study-score} +# tutorizeR: hints=Map study_hours to x and quiz_score to y|Use color for program|Use geom_point() +ggplot(activity, aes(x = study_hours, y = quiz_score, color = program)) + + geom_point(size = 2) + + labs( + x = "Study hours", + y = "Quiz score", + color = "Program" + ) +``` + +## Instructor solution note + +```{r interpretation-note} +# tutorizeR: solution-only +"In this small synthetic dataset, higher study time is associated with higher quiz score. This is not causal evidence." +``` + +## Manual interpretation + +Students should describe the plot cautiously. The dataset is small and synthetic, so the goal is to practice code and interpretation rather than estimate a population effect. diff --git a/inst/examples/example_course_module/question-bank/questions.yml b/inst/examples/example_course_module/question-bank/questions.yml new file mode 100644 index 0000000..8d934ad --- /dev/null +++ b/inst/examples/example_course_module/question-bank/questions.yml @@ -0,0 +1,65 @@ +- id: preview-output + question: "What does `head(activity, 3)` return in this lesson?" + answers: + - text: "The first three rows of the activity data." + correct: true + - text: "A grouped summary by program." + correct: false + - text: "A scatterplot of study hours and quiz score." + correct: false + tags: + - data-import + - "Recognize the output of head(activity, 3)" + difficulty: introductory + language: en + explanation: "`head(activity, 3)` previews the first three rows, which helps students inspect the data structure before analysis." + +- id: grouped-summary + question: "After grouping by `program`, what does `mean_hours` represent?" + answers: + - text: "The average study hours within each academic program." + correct: true + - text: "The total study hours across all students." + correct: false + - text: "The quiz score for the first student in each program." + correct: false + tags: + - summarisation + - dplyr + - "Compute mean study hours and mean quiz score" + difficulty: introductory + language: en + explanation: "The `summarise()` call computes an average separately within each `program` group." + +- id: visualization-aesthetic + question: "In `ggplot2`, which aesthetic should be mapped to show quiz score on the vertical axis?" + answers: + - text: "y" + correct: true + - text: "x" + correct: false + - text: "color" + correct: false + tags: + - visualization + - ggplot2 + difficulty: introductory + language: en + explanation: "The y aesthetic controls the vertical position in a two-dimensional plot." + +- id: plot-interpretation + question: "Which interpretation is appropriate for the scatterplot in this synthetic example?" + answers: + - text: "Students with more study hours tend to have higher quiz scores in this small dataset, but the plot is not causal evidence." + correct: true + - text: "The plot proves that increasing study hours causes higher quiz scores." + correct: false + - text: "The plot shows that all programs have identical quiz scores." + correct: false + tags: + - visualization + - interpretation + - "Map study_hours to x and quiz_score to y" + difficulty: introductory + language: en + explanation: "The plot supports a cautious descriptive statement only; the data are synthetic and not designed for causal inference." diff --git a/inst/examples/example_course_module/run-example.R b/inst/examples/example_course_module/run-example.R new file mode 100644 index 0000000..15c66de --- /dev/null +++ b/inst/examples/example_course_module/run-example.R @@ -0,0 +1,104 @@ +# Reproduce the example course module after package installation. + +required_packages <- c( + "tutorizeR", + "dplyr", + "ggplot2", + "readr", + "learnr" +) + +missing_packages <- required_packages[!vapply( + required_packages, + requireNamespace, + quietly = TRUE, + FUN.VALUE = logical(1) +)] + +if (length(missing_packages) > 0L) { + stop( + paste0( + "The example course module requires these installed R packages: ", + paste(missing_packages, collapse = ", "), + ". Install the package dependencies declared in DESCRIPTION before ", + "running this script." + ), + call. = FALSE + ) +} + +library(tutorizeR) + +example_dir <- system.file( + "examples", + "example_course_module", + package = "tutorizeR" +) + +if (!nzchar(example_dir)) { + stop("Could not locate the installed example module.", call. = FALSE) +} + +work_dir <- file.path(tempdir(), "tutorizeR-example-course-module") +if (dir.exists(work_dir)) { + unlink(work_dir, recursive = TRUE) +} +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) + +file.copy( + from = file.path(example_dir, "lesson-source.qmd"), + to = file.path(work_dir, "lesson-source.qmd"), + overwrite = TRUE +) +file.copy( + from = file.path(example_dir, "student_activity.csv"), + to = file.path(work_dir, "student_activity.csv"), + overwrite = TRUE +) + +if (!file.exists(file.path(work_dir, "lesson-source.qmd")) || + !file.exists(file.path(work_dir, "student_activity.csv"))) { + stop("Could not copy the example source files to the temporary directory.", call. = FALSE) +} + +question_bank <- load_question_bank(file.path(example_dir, "question-bank")) + +learnr_report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) + +write_tutorize_report( + report = learnr_report, + file = file.path(work_dir, "conversion-report.json"), + format = "json" +) + +live_report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "quarto-live", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) + +message("Example files written to: ", work_dir) +message("learnr output: ", learnr_report$output_file) +message("quarto-live output: ", live_report$output_file) +message("conversion report: ", file.path(work_dir, "conversion-report.json")) + +invisible(list( + work_dir = work_dir, + learnr_report = learnr_report, + live_report = live_report, + conversion_report = file.path(work_dir, "conversion-report.json") +)) diff --git a/inst/examples/example_course_module/student_activity.csv b/inst/examples/example_course_module/student_activity.csv new file mode 100644 index 0000000..1af1228 --- /dev/null +++ b/inst/examples/example_course_module/student_activity.csv @@ -0,0 +1,14 @@ +student_id,program,week,study_hours,practice_tasks,quiz_score +S001,Statistics,1,4.5,6,78 +S002,Statistics,1,6.0,8,84 +S003,Data Science,1,5.5,7,82 +S004,Data Science,1,7.0,9,89 +S005,Mathematics,1,3.5,5,72 +S006,Mathematics,1,5.0,6,77 +S007,Statistics,2,5.5,7,83 +S008,Statistics,2,6.5,8,87 +S009,Data Science,2,7.5,10,92 +S010,Data Science,2,6.0,8,86 +S011,Mathematics,2,4.0,5,74 +S012,Mathematics,2,5.5,7,80 + diff --git a/inst/templates/learnr_header.Rmd b/inst/templates/learnr_header.Rmd index 03803bf..ec15147 100644 --- a/inst/templates/learnr_header.Rmd +++ b/inst/templates/learnr_header.Rmd @@ -6,6 +6,8 @@ runtime: shiny_prerendered ```{r setup, include=FALSE} library(learnr) -library(gradethis) -gradethis_setup() -``` \ No newline at end of file +if (requireNamespace("gradethis", quietly = TRUE)) { + library(gradethis) + gradethis_setup() +} +``` diff --git a/man/figures/conversion-report-screenshot.svg b/man/figures/conversion-report-screenshot.svg new file mode 100644 index 0000000..885be1e --- /dev/null +++ b/man/figures/conversion-report-screenshot.svg @@ -0,0 +1,29 @@ + + Example tutorizeR conversion report screenshot + A static screenshot-style illustration of a tutorizeR conversion report with status, exercises, MCQs, warnings, and output file. + + + + tutorizeR conversion report + + Input + lessons/week03-data-visualization.qmd + Output + tutorials/week03-data-visualization-tutorial.Rmd + Format + learnr + Generated + 4 exercises, 4 solutions, 3 MCQs + Lint + 0 errors, 1 warning + Render + ready for local review + + + + + + + + + diff --git a/man/figures/tutorize-workflow.svg b/man/figures/tutorize-workflow.svg new file mode 100644 index 0000000..7ce745f --- /dev/null +++ b/man/figures/tutorize-workflow.svg @@ -0,0 +1,40 @@ + + tutorizeR conversion workflow + A diagram showing source teaching documents converted into interactive tutorials, reports, and teaching exports. + + + Source-first teaching workflow + One reproducible lesson source can generate interactive learning artifacts. + + + + + + + + + Rmd or qmd + Narrative, code, + MCQ blocks, tags + tutorizeR + Parse, lint, convert, + label, report + Tutorials + learnr or quarto-live + with exercises + Teaching + Feedback, LMS + and reuse + + + + + + + + + + + Review artifacts: conversion report, tests, examples, vignettes, JOSE paper + + diff --git a/paper/paper.bib b/paper/paper.bib index 90efea4..6e28cf9 100644 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -7,23 +7,96 @@ @Manual{rCoreTeam2025 url = {https://www.R-project.org/} } -@Manual{learnr2025, +@misc{rmarkdownDocs, + title = {rmarkdown: Dynamic Documents for R}, + author = {{Posit Software, PBC}}, + year = {2026}, + url = {https://rmarkdown.rstudio.com/}, + note = {Accessed 2026-05-31} +} + +@misc{learnrDocs, title = {learnr: Authoring Interactive Tutorials}, - author = {RStudio}, - year = {2025}, - url = {https://rstudio.github.io/learnr/} + author = {{Posit Software, PBC}}, + year = {2026}, + url = {https://rstudio.github.io/learnr/}, + note = {Accessed 2026-05-31} } -@Manual{quarto2025, +@misc{quartoDocs, title = {Quarto}, - author = {Posit}, - year = {2025}, - url = {https://quarto.org} + author = {{Posit Software, PBC}}, + year = {2026}, + url = {https://quarto.org}, + note = {Accessed 2026-05-31} } -@Manual{gradethis2025, - title = {gradethis: Automatically check student code in learnr tutorials}, +@misc{gradethisDocs, + title = {gradethis: Automatically Check Student Code in learnr Tutorials}, author = {{R Consortium}}, - year = {2025}, - url = {https://rstudio.github.io/gradethis/} + year = {2026}, + url = {https://rstudio.github.io/gradethis/}, + note = {Accessed 2026-05-31} +} + +@article{knuth1984, + title = {Literate Programming}, + author = {Knuth, Donald E.}, + journal = {The Computer Journal}, + volume = {27}, + number = {2}, + pages = {97--111}, + year = {1984}, + doi = {10.1093/comjnl/27.2.97} +} + +@article{rule2019, + title = {Ten Simple Rules for Writing and Sharing Computational Analyses in {Jupyter} Notebooks}, + author = {Rule, Adam and Birmingham, Amanda and Zuniga, Cristal and Altintas, Ilkay and Huang, Shih-Cheng and Knight, Rob and Moshiri, Niema and Nguyen, Mai H. and Rosenthal, Sara Brin and P{\\'e}rez, Fernando and Rose, Peter W.}, + journal = {PLOS Computational Biology}, + volume = {15}, + number = {7}, + pages = {e1007007}, + year = {2019}, + doi = {10.1371/journal.pcbi.1007007} +} + +@article{wilson2017, + title = {Good Enough Practices in Scientific Computing}, + author = {Wilson, Greg and Bryan, Jennifer and Cranston, Karen and Kitzes, Justin and Nederbragt, Lex and Teal, Tracy K.}, + journal = {PLOS Computational Biology}, + volume = {13}, + number = {6}, + pages = {e1005510}, + year = {2017}, + doi = {10.1371/journal.pcbi.1005510} +} + +@article{freeman2014, + title = {Active Learning Increases Student Performance in Science, Engineering, and Mathematics}, + author = {Freeman, Scott and Eddy, Sarah L. and McDonough, Miles and Smith, Michelle K. and Okoroafor, Nnadozie and Jordt, Hannah and Wenderoth, Mary Pat}, + journal = {Proceedings of the National Academy of Sciences}, + volume = {111}, + number = {23}, + pages = {8410--8415}, + year = {2014}, + doi = {10.1073/pnas.1319030111} +} + +@article{black1998, + title = {Assessment and Classroom Learning}, + author = {Black, Paul and Wiliam, Dylan}, + journal = {Assessment in Education: Principles, Policy \& Practice}, + volume = {5}, + number = {1}, + pages = {7--74}, + year = {1998}, + doi = {10.1080/0969595980050102} +} + +@misc{unesco2019, + title = {Recommendation on Open Educational Resources ({OER})}, + author = {{UNESCO}}, + year = {2019}, + url = {https://www.unesco.org/en/legal-affairs/recommendation-open-educational-resources-oer} } diff --git a/paper/paper.md b/paper/paper.md index 4d4688c..0af3901 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -1,5 +1,5 @@ --- -title: 'tutorizeR: Convert teaching materials in R Markdown and Quarto into interactive, assessable tutorials' +title: 'tutorizeR: Converting Reproducible Data Science Lessons into Interactive Learning Experiences' short-title: tutorizeR tags: - R @@ -7,20 +7,15 @@ tags: - learnr - quarto - gradethis - - lms + - reproducibility authors: - name: Aurélien Nicosia - orcid: null affiliation: 1 - equal-contrib: true corresponding: true - - name: "tutorizeR contributors" - affiliation: 1 - equal-contrib: false affiliations: - name: Université Laval index: 1 -date: 2026-02-13 +date: 2026-05-31 output: md_document: variant: gfm @@ -31,69 +26,54 @@ bibliography: paper.bib ## Summary -Many teachers build course content with `.Rmd` or `.qmd` documents and need to quickly deliver interactive learning experiences to students. `tutorizeR` converts these source materials into `learnr` tutorials and `quarto-live` resources while preserving narrative text, setup chunks, and key execution options. It integrates with the broader R-based ecosystem for education and reproducible publishing, including `R` itself, `learnr`, `gradethis`, and `Quarto` for teaching and delivery workflows (@rCoreTeam2025; @learnr2025; @gradethis2025; @quarto2025). +`tutorizeR` is open-source educational infrastructure for instructors who prepare statistics, data science, or R programming lessons in R Markdown or Quarto and want to turn those source documents into interactive learning resources. The package converts `.Rmd` and `.qmd` files into `learnr` tutorials or `quarto-live` resources, while preserving a source-first workflow: instructors maintain one reproducible lesson and generate student-facing exercise material from it. It is built in R [@rCoreTeam2025] and works with the R Markdown, Quarto, `learnr`, and `gradethis` ecosystems [@rmarkdownDocs; @quartoDocs; @learnrDocs; @gradethisDocs]. -The package adds structured pedagogical primitives: automatic exercise/solution chunk generation, MCQ extraction (inline or reference bank-driven), linting checks for teaching-oriented issues, conversion report export (JSON/YAML), and LMS-ready manifest export for generic Canvas/Moodle workflows. +The educational problem is practical and recurring. Many instructors already write lessons as computational narratives, where text, code, figures, and interpretation are interleaved. This approach has roots in literate programming [@knuth1984] and is consistent with current recommendations for computational notebooks and reproducible analyses [@rule2019; @wilson2017]. However, preparing an interactive tutorial from an existing source lesson often requires manual duplication of chunks, insertion of exercise areas, management of solutions, creation of conceptual checks, and coordination of feedback scaffolds. `tutorizeR` automates much of that transformation while leaving final pedagogical judgement to the instructor. -## Statement of need +## Statement of Need -Existing workflows for turning `.Rmd`/`.qmd` teaching documents into interactive materials are often manual: instructors duplicate code chunks, handcraft MCQ syntax, and maintain separate scripts for grading scaffolds. This is especially costly for large course folders with mixed formats and heterogeneous chunk options. +JOSE accepts open-source software that supports teaching and learning or makes an educational process better, easier, simpler, or faster. `tutorizeR` fits this software-submission category as infrastructure for computational education. It does not replace course design, teaching expertise, or assessment design. Instead, it reduces the mechanical cost of converting reproducible teaching documents into interactive activities. -`tutorizeR` addresses this by offering a stable conversion pipeline with: +The need is especially visible in courses where instructors maintain weekly laboratories, tutorials, and assignments. A single update to a dataset, plot, or explanation can otherwise require changes in multiple versions of the same lesson. `tutorizeR` supports a workflow in which the instructor revises the source `.qmd` or `.Rmd` file, reruns the conversion pipeline, reviews the generated output, and distributes the result. The package also supports formative practice by generating code exercises, MCQs, and `gradethis`-ready `learnr` tutorials. This design is aligned with broad evidence that active learning and formative feedback can be valuable in STEM education [@freeman2014; @black1998], but this repository does not claim that `tutorizeR` itself improves grades, engagement, or learning outcomes. -- conversion of both `.Rmd` and `.qmd` inputs, -- deterministic label management to avoid render collisions, -- optional strict linting before rendering, -- reusable question-bank integration (YAML/JSON), -- and reporting artifacts suitable for CI. +## Educational context and target users -## Functionality +The primary users are instructors, teaching assistants, and course teams who create computational teaching materials in R. Target contexts include introductory data science, applied statistics, R programming, and methods courses where students learn through executable examples and short practice tasks. The package is also relevant to open educational resource workflows because its example materials can be reused and adapted under an open content license, consistent with open education principles [@unesco2019]. -The package exposes a canonical `tutorize()` API and keeps backward-compatible wrappers (`convert_to_tutorial()`, `convert_folder()`). Additional authoring tools include: +The repository includes a complete installable example module on data summarisation and visualization with R. The example is generic and synthetic. It is designed to show how another instructor could adopt the package without access to private course material. -- `lint_source()` for pedagogy-focused validations, -- `load_question_bank()` / `validate_question_bank()` for external banked MCQs, -- `write_tutorize_report()` for machine-readable conversion summaries, -- `export_lms_manifest()` and `export_tutorial_package()` for downstream sharing. +## Functionality -For workflow robustness, `tutorizeR` provides both interactive UI paths (RStudio addins) and non-interactive CLI execution. +`tutorizeR` parses source documents, preserves narrative text, detects setup and R chunks, preserves non-R fenced blocks, generates exercise and solution areas, transforms explicit MCQ blocks, resolves references to local question banks, adds `learnr` and `gradethis` setup code when needed, and writes conversion reports. The package includes validation and linting helpers so instructors can inspect source documents before conversion, plus batch conversion for folders of lessons. -## State of the art and alternatives +The detailed API is documented in the package reference, vignettes, and examples. The JOSE paper intentionally does not duplicate that documentation. -Prior approaches generally require one of three manual paths: +## Teaching and adoption workflow -- direct authoring of `learnr` tutorials from scratch in the RStudio environment; -- copy-and-paste conversion from teaching notebooks or Quarto documents into a dedicated tutorial repository; -- ad-hoc scripts for grading heuristics and QCM/MCQ insertion. +A typical adoption workflow has five steps. First, an instructor writes a lesson in Quarto or R Markdown with learning objectives, narrative explanation, executable R chunks, and optional instructor tags. Second, the instructor adds MCQ blocks or question-bank references where conceptual checks are useful. Third, the instructor runs `tutorize()` to generate a `learnr` or `quarto-live` resource. Fourth, the instructor reviews the generated tutorial, adjusts wording or grading checks, and confirms that datasets and optional dependencies are available. Fifth, the resulting file can be distributed through the course platform, rendered locally, or incorporated into a broader teaching workflow. -`tutorizeR` unifies these steps by preserving a source-first workflow: -source content remains in `.Rmd`/`.qmd` format, while conversion to interactive -activities is performed automatically with deterministic labels, optional linting, -and explicit reporting artefacts. This reduces duplicated maintenance work and -keeps a single source of truth for instructors. +The example module in `inst/examples/example_course_module/` demonstrates this workflow with a source lesson, local question bank, expected converted outputs, JSON report, and reproducible run script. -## Quality assurance +## Experience of use and current limitations -The package includes tests and linting, with automated checks covering core parser/transform/validation/report paths. New/changed features are documented via roxygen and vignettes, and conversion edge cases are regression tested (including non-R chunks, inline code fences, duplicated labels, and Quarto-only fixtures). +The repository demonstrates intended use through tests, vignettes, and an installable example. The following claims are not made because supporting evidence is not present in the repository. -## AI usage disclosure +- Formal learning-outcome evaluation: Not verifiable from repository contents. +- Actual classroom deployment: Not verifiable from repository contents. +- Broad external adoption: Not verifiable from repository contents. -No generative AI tools were used in the production of the software implementation or the `tutorizeR` manuscript. +Current limitations are also part of the educational story. `quarto-live` output requires the relevant Quarto live extension in the teaching project. `learnr` rendering requires optional runtime dependencies. LMS support is currently manifest-oriented rather than direct LMS publication. Generated material should always be reviewed by an instructor before release, especially grading logic and feedback wording. -When using `tutorizeR` by others for educational material conversion, the package does not impose any AI model dependency and remains fully script-driven and reproducible. +## Availability and licensing -## Limitations +The package source is available at `https://github.com/AurelienNicosiaULaval/tutorizeR`. The package code is distributed under the MIT license. Educational examples and graphical documentation assets are released under CC-BY 4.0 unless otherwise specified. The repository includes tests, continuous integration configuration, contribution guidelines, a code of conduct, vignettes, reviewer documentation, and citation metadata. -- LMS publication is currently manifest-first export (Canvas/Moodle/generic); no direct LMS API publishing is included yet. -- Learnr rendering is optional and requires optional dependencies (`learnr`, `gradethis`) at render-time. -- Question-bank integration is file-based (local YAML/JSON) in the current release. -- The output currently targets single-file conversion pipelines and folder conversion with documented defaults. +Final release DOI: Not verifiable from repository contents. -## Availability and contribution +## AI usage disclosure -The package source is available on GitHub at: -`https://github.com/AurelienNicosiaULaval/tutorizeR`. +Generative AI tools were used during planning, review, or documentation-support stages for this repository. The author reviewed, edited, tested, and takes responsibility for all submitted code, documentation, and manuscript text. -Contributions and bug reports are welcome via GitHub Issues/PRs with the repository’s contribution guide and code of conduct. +The package itself does not depend on any generative AI model. Its conversion pipeline is deterministic and script-driven. ## References diff --git a/tests/testthat/regression-fixtures/expected/regression_a-expected.Rmd b/tests/testthat/regression-fixtures/expected/regression_a-expected.Rmd index 423cc4e..9882b29 100644 --- a/tests/testthat/regression-fixtures/expected/regression_a-expected.Rmd +++ b/tests/testthat/regression-fixtures/expected/regression_a-expected.Rmd @@ -7,8 +7,10 @@ runtime: shiny_prerendered ```{r setup, include=FALSE} # Setup chunk added by tutorizeR library(learnr) -library(gradethis) -gradethis_setup() +if (requireNamespace("gradethis", quietly = TRUE)) { + library(gradethis) + gradethis_setup() +} ``` diff --git a/tests/testthat/regression-fixtures/expected/regression_b-expected.Rmd b/tests/testthat/regression-fixtures/expected/regression_b-expected.Rmd index 6c62d27..54a3360 100644 --- a/tests/testthat/regression-fixtures/expected/regression_b-expected.Rmd +++ b/tests/testthat/regression-fixtures/expected/regression_b-expected.Rmd @@ -7,8 +7,10 @@ runtime: shiny_prerendered ```{r setup, include=FALSE} # Setup chunk added by tutorizeR library(learnr) -library(gradethis) -gradethis_setup() +if (requireNamespace("gradethis", quietly = TRUE)) { + library(gradethis) + gradethis_setup() +} ``` diff --git a/tests/testthat/test-convert-core.R b/tests/testthat/test-convert-core.R index 34aca07..b8ce571 100644 --- a/tests/testthat/test-convert-core.R +++ b/tests/testthat/test-convert-core.R @@ -118,9 +118,8 @@ test_that("quarto-live output contains required include and format", { expect_true(any(grepl("```\\{webr\\}", lines))) }) -test_that("learnr smoke render succeeds when dependencies are available", { +test_that("learnr smoke render succeeds when learnr is available", { skip_if_not_installed("learnr") - skip_if_not_installed("gradethis") rep <- tutorize( input = fixture("rmd", "basic_code.Rmd"), diff --git a/tests/testthat/test-examples.R b/tests/testthat/test-examples.R new file mode 100644 index 0000000..9addc04 --- /dev/null +++ b/tests/testthat/test-examples.R @@ -0,0 +1,214 @@ +local_edition(3) + +example_module_dir <- function() { + source_dir <- testthat::test_path("..", "..", "inst", "examples", "example_course_module") + installed_dir <- system.file("examples", "example_course_module", package = "tutorizeR") + + if (dir.exists(source_dir)) { + return(source_dir) + } + + installed_dir +} + +copy_example_to_temp <- function(example_dir) { + work_dir <- file.path(tempdir(check = TRUE), paste0("tutorizeR-example-", as.integer(runif(1, 1, 1e8)))) + dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) + + file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) + file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + + work_dir +} + +cleanup_example_packages <- function() { + for (pkg in c("package:readr", "package:ggplot2", "package:dplyr")) { + if (pkg %in% search()) { + detach(pkg, character.only = TRUE, unload = FALSE) + } + } +} + +declared_description_packages <- function() { + desc_file <- testthat::test_path("..", "..", "DESCRIPTION") + desc <- if (file.exists(desc_file)) { + read.dcf(desc_file)[1, ] + } else { + utils::packageDescription("tutorizeR") + } + fields <- c("Depends", "Imports", "Suggests", "Enhances") + raw <- vapply(fields, function(field) { + value <- if (field %in% names(desc)) desc[[field]] else NULL + if (is.null(value)) "" else value + }, character(1)) + raw <- paste(raw, collapse = ",") + packages <- trimws(unlist(strsplit(raw, ",", fixed = TRUE), use.names = FALSE)) + packages <- sub("\\s*\\(.*\\)$", "", packages) + unique(packages[nzchar(packages)]) +} + +extract_example_packages <- function(files) { + lines <- unlist(lapply(files, readLines, warn = FALSE), use.names = FALSE) + library_matches <- regmatches(lines, gregexpr( + "(library|require)\\([[:space:]]*[A-Za-z][A-Za-z0-9.]*", + lines, + perl = TRUE + )) + namespace_matches <- regmatches(lines, gregexpr( + "\\b[A-Za-z][A-Za-z0-9.]*::", + lines, + perl = TRUE + )) + + packages <- c( + sub(".*\\([[:space:]]*", "", unlist(library_matches, use.names = FALSE)), + sub("::$", "", unlist(namespace_matches, use.names = FALSE)) + ) + + unique(packages[nzchar(packages)]) +} + +test_that("example course module has required installable structure", { + example_dir <- example_module_dir() + + expect_true(dir.exists(example_dir)) + expect_true(file.exists(file.path(example_dir, "README.md"))) + expect_true(file.exists(file.path(example_dir, "lesson-source.qmd"))) + expect_true(file.exists(file.path(example_dir, "question-bank", "questions.yml"))) + expect_true(file.exists(file.path(example_dir, "expected", "lesson-source-tutorial.Rmd"))) + expect_true(file.exists(file.path(example_dir, "expected", "lesson-source-live.qmd"))) + expect_true(file.exists(file.path(example_dir, "expected", "conversion-report.json"))) + expect_true(file.exists(file.path(example_dir, "run-example.R"))) +}) + +test_that("example question bank loads and validates", { + example_dir <- example_module_dir() + + bank <- load_question_bank(file.path(example_dir, "question-bank")) + report <- validate_question_bank(bank, strict = FALSE) + + expect_s3_class(bank, "tutorize_question_bank") + expect_gte(length(bank$questions), 4L) + expect_false(any(report$findings$severity == "error")) +}) + +test_that("example module dependencies are declared", { + example_dir <- example_module_dir() + example_files <- c( + file.path(example_dir, "lesson-source.qmd"), + file.path(example_dir, "run-example.R"), + list.files( + file.path(example_dir, "expected"), + pattern = "\\.(Rmd|qmd)$", + full.names = TRUE + ) + ) + + used_packages <- setdiff(extract_example_packages(example_files), "tutorizeR") + declared_packages <- declared_description_packages() + + expect_setequal( + intersect(used_packages, c("dplyr", "ggplot2", "readr", "learnr")), + c("dplyr", "ggplot2", "readr", "learnr") + ) + expect_true("gradethis" %in% used_packages) + expect_false("gradethis" %in% declared_packages) + expect_true(all(setdiff(used_packages, "gradethis") %in% declared_packages)) +}) + +test_that("example module does not expose placeholder MCQs", { + example_dir <- example_module_dir() + jose_files <- c( + file.path(example_dir, "lesson-source.qmd"), + file.path(example_dir, "question-bank", "questions.yml"), + list.files(file.path(example_dir, "expected"), full.names = TRUE) + ) + text <- unlist(lapply(jose_files, readLines, warn = FALSE), use.names = FALSE) + + expect_false(any(grepl("Answer A \\(edit me\\)", text))) + expect_false(any(grepl("\\bedit me\\b", text, ignore.case = TRUE))) +}) + +test_that("example module converts to learnr and writes JSON report", { + on.exit(cleanup_example_packages(), add = TRUE) + + example_dir <- example_module_dir() + work_dir <- copy_example_to_temp(example_dir) + bank <- load_question_bank(file.path(example_dir, "question-bank")) + + report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE + ) + + report_file <- file.path(work_dir, "conversion-report.json") + write_tutorize_report(report, report_file, format = "json") + + lines <- readLines(report$output_file, warn = FALSE) + report_json <- jsonlite::fromJSON(report_file) + + expect_true(file.exists(report$output_file)) + expect_true(file.exists(report_file)) + expect_true(any(grepl("learnr::tutorial", lines, fixed = TRUE))) + expect_true(any(grepl("requireNamespace(\"gradethis\"", lines, fixed = TRUE))) + expect_true(any(grepl("gradethis_setup()", lines, fixed = TRUE))) + expect_true(any(grepl("trz-mcq-bank", lines, fixed = TRUE))) + expect_false(any(grepl("Answer A \\(edit me\\)", lines))) + expect_equal(report_json$format, "learnr") +}) + +test_that("example module converts to quarto-live", { + on.exit(cleanup_example_packages(), add = TRUE) + + example_dir <- example_module_dir() + work_dir <- copy_example_to_temp(example_dir) + bank <- load_question_bank(file.path(example_dir, "question-bank")) + + report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "quarto-live", + assessment = "both", + question_bank = bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE + ) + + lines <- readLines(report$output_file, warn = FALSE) + + expect_true(file.exists(report$output_file)) + expect_true(any(grepl("format: live-html", lines, fixed = TRUE))) + expect_true(any(grepl("```\\{webr\\}", lines))) + expect_true(any(grepl("::: \\{\\.callout-note\\}", lines))) + expect_false(any(grepl("Answer A \\(edit me\\)", lines))) +}) + +test_that("run-example.R works from installed-style example path", { + on.exit(cleanup_example_packages(), add = TRUE) + + example_dir <- example_module_dir() + env <- new.env(parent = globalenv()) + + result <- source(file.path(example_dir, "run-example.R"), local = env) + + expect_true(dir.exists(result$value$work_dir)) + expect_true(file.exists(result$value$learnr_report$output_file)) + expect_true(file.exists(result$value$live_report$output_file)) + expect_true(file.exists(result$value$conversion_report)) +}) + +test_that("README user smoke tests do not use internal test fixtures", { + readme_file <- testthat::test_path("..", "..", "README.md") + skip_if_not(file.exists(readme_file), "README.md is not available in installed-package tests.") + + readme <- readLines(readme_file, warn = FALSE) + + expect_false(any(grepl("tests/testthat/fixtures", readme, fixed = TRUE))) +}) diff --git a/tests/testthat/test-jose-readiness.R b/tests/testthat/test-jose-readiness.R new file mode 100644 index 0000000..191e93a --- /dev/null +++ b/tests/testthat/test-jose-readiness.R @@ -0,0 +1,116 @@ +local_edition(3) + +test_that("learnr conversion injects gradethis setup and exercise scaffolds", { + input <- tempfile(fileext = ".Rmd") + writeLines(c( + "---", + "title: feedback test", + "---", + "", + "```{r setup}", + "x <- 1", + "```", + "", + "```{r add-one}", + "# tutorizeR: hints=Use x + 1", + "x + 1", + "```" + ), input) + + report <- tutorize( + input = input, + output_dir = tempdir(check = TRUE), + format = "learnr", + assessment = "code", + overwrite = TRUE, + verbose = FALSE + ) + + lines <- readLines(report$output_file, warn = FALSE) + expect_true(any(grepl("library\\(learnr\\)", lines))) + expect_true(any(grepl("requireNamespace\\(\"gradethis\"", lines))) + expect_true(any(grepl("library\\(gradethis\\)", lines))) + expect_true(any(grepl("gradethis_setup\\(\\)", lines))) + expect_true(any(grepl("exercise=TRUE", lines, fixed = TRUE))) + expect_true(any(grepl("trz-sol-add-one", lines, fixed = TRUE))) + expect_true(any(grepl("Use x \\+ 1", lines))) +}) + +test_that("quarto-live conversion creates webr exercises and solution callouts", { + input <- tempfile(fileext = ".qmd") + writeLines(c( + "---", + "title: quarto live test", + "---", + "", + "```{r summarize}", + "mean(1:5)", + "```" + ), input) + + report <- tutorize( + input = input, + output_dir = tempdir(check = TRUE), + format = "quarto-live", + assessment = "both", + overwrite = TRUE, + verbose = FALSE + ) + + lines <- readLines(report$output_file, warn = FALSE) + expect_true(any(grepl("format: live-html", lines, fixed = TRUE))) + expect_true(any(grepl("_extensions/r-wasm/live/_knitr.qmd", lines, fixed = TRUE))) + expect_true(any(grepl("```\\{webr\\}", lines))) + expect_true(any(grepl("::: \\{\\.callout-tip collapse='true'\\}", lines))) + expect_true(any(grepl("::: \\{\\.callout-note\\}", lines))) +}) + +test_that("MCQ references require an explicit question bank", { + input <- tempfile(fileext = ".qmd") + writeLines(c( + "---", + "title: bank test", + "---", + "", + "```{tutorizeR-mcq-ref}", + "ids: [missing-id]", + "strategy: ordered", + "```" + ), input) + + expect_error( + tutorize( + input = input, + output_dir = tempdir(check = TRUE), + format = "learnr", + assessment = "both", + overwrite = TRUE, + verbose = FALSE + ), + class = "tutorizeR_error_validation" + ) +}) + +test_that("example course module is packaged with expected teaching artifacts", { + source_example_dir <- testthat::test_path( + "..", "..", "inst", "examples", "example_course_module" + ) + installed_example_dir <- system.file( + "examples", "example_course_module", package = "tutorizeR" + ) + + example_dir <- if (dir.exists(source_example_dir)) { + source_example_dir + } else { + installed_example_dir + } + + expect_true(dir.exists(example_dir)) + expect_true(file.exists(file.path(example_dir, "lesson-source.qmd"))) + expect_true(file.exists(file.path(example_dir, "question-bank", "questions.yml"))) + expect_true(file.exists(file.path(example_dir, "expected", "lesson-source-tutorial.Rmd"))) + expect_true(file.exists(file.path(example_dir, "expected", "lesson-source-live.qmd"))) + expect_true(file.exists(file.path(example_dir, "expected", "conversion-report.json"))) + expect_true(file.exists(file.path(example_dir, "run-example.R"))) + expect_true(file.exists(file.path(example_dir, "student_activity.csv"))) +}) diff --git a/vignettes/automatic-exercise-generation-feedback.Rmd b/vignettes/automatic-exercise-generation-feedback.Rmd new file mode 100644 index 0000000..0a01a95 --- /dev/null +++ b/vignettes/automatic-exercise-generation-feedback.Rmd @@ -0,0 +1,59 @@ +--- +title: "Automatic Exercise Generation and Feedback" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Automatic Exercise Generation and Feedback} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +`tutorizeR` turns ordinary R chunks into student exercise areas and hidden or collapsible solution material. For `learnr`, the setup chunk includes `learnr` and activates `gradethis_setup()` when `gradethis` is installed, so that instructors can add answer checks after conversion. + +## Annotated source chunk + + ```r + # tutorizeR: hints=Use group_by() before summarise()|Remember .groups = "drop" + activity |> + group_by(program) |> + summarise( + mean_hours = mean(study_hours), + mean_score = mean(quiz_score), + .groups = "drop" + ) + ``` + +## Conversion + +```{r eval=FALSE} +library(tutorizeR) + +report <- tutorize( + input = "lesson-source.qmd", + format = "learnr", + assessment = "code", + overwrite = TRUE +) + +print(report) +``` + +## Adding a gradethis check + +After conversion, instructors can add `gradethis` checks to generated exercise chunks using the normal `learnr` conventions: + + ```r + grade_this({ + pass_if(~ identical(names(.result), c("program", "mean_hours", "mean_score"))) + fail("Check the grouping variable and summary column names.") + }) + ``` + +This pattern keeps the initial conversion automated while leaving final grading logic under instructor control. + +## Feedback design + +Feedback should focus on the learning objective rather than only the final answer. For example, an exercise about grouped summaries should check that students identify the grouping variable, compute the intended summaries, and produce a tidy table. diff --git a/vignettes/conversion-rmd-vs-qmd.Rmd b/vignettes/conversion-rmd-vs-qmd.Rmd index cfba82c..eb14619 100644 --- a/vignettes/conversion-rmd-vs-qmd.Rmd +++ b/vignettes/conversion-rmd-vs-qmd.Rmd @@ -1,8 +1,8 @@ --- -title: "Conversion for Rmd and qmd" +title: "Conversion for R Markdown and Quarto" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Conversion for Rmd and qmd} + %\VignetteIndexEntry{Conversion for R Markdown and Quarto} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -11,22 +11,70 @@ vignette: > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` -`tutorizeR` accepts both `.Rmd` and `.qmd` sources. +## User goal -## Learnr output +This vignette helps instructors decide whether to target `learnr` or `quarto-live` when converting existing R Markdown or Quarto material. + +## Minimal examples ```{r eval=FALSE} +library(tutorizeR) + tutorize("lesson.Rmd", format = "learnr", assessment = "both") +tutorize("lesson.qmd", format = "quarto-live", assessment = "code") ``` -## Quarto live output +## Choosing an output format + +Use `learnr` when the course already supports RStudio or Shiny-based tutorials and when `gradethis` feedback is useful. Use `quarto-live` when browser-based execution is preferred and the teaching project has the Quarto live extension installed. + +## Realistic installed example ```{r eval=FALSE} -tutorize("lesson.qmd", format = "quarto-live", assessment = "code") +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +work_dir <- file.path(tempdir(), "tutorizeR-formats") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) +file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) +file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + +qb <- load_question_bank(file.path(example_dir, "question-bank")) + +learnr_report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = qb, + overwrite = TRUE, + verbose = FALSE +) + +live_report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "quarto-live", + assessment = "both", + question_bank = qb, + overwrite = TRUE, + verbose = FALSE +) ``` -When targeting `quarto-live`, install the extension in your project root: +## Limits + +When targeting `quarto-live`, install the extension in the teaching project: ```{r eval=FALSE} system("quarto add r-wasm/quarto-live") ``` + +Generated output should be reviewed in the environment where students will use it, because package availability and browser execution settings can differ. + +## Reproducibility checklist + +```{r eval=FALSE} +file.exists(learnr_report$output_file) +file.exists(live_report$output_file) +``` diff --git a/vignettes/documentation-website.Rmd b/vignettes/documentation-website.Rmd new file mode 100644 index 0000000..b137759 --- /dev/null +++ b/vignettes/documentation-website.Rmd @@ -0,0 +1,57 @@ +--- +title: "Documentation Website" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Documentation Website} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +## Purpose + +The repository includes a pkgdown configuration so that the README, function reference pages, and vignettes can be rendered as a documentation website. The site configuration is stored in `_pkgdown.yml`. + +The generated site is written to `pkgdown/`. This keeps generated website files separate from the repository's source documentation in `docs/`. + +## Build Locally + +```{r eval=FALSE} +library(pkgdown) + +build_site() +``` + +For a documentation-only check, build the articles and reference index locally before pushing changes. + +```{r eval=FALSE} +library(pkgdown) + +build_articles() +build_reference() +``` + +## Article Groups + +The pkgdown site organizes vignettes into four groups: + +- Start here: first conversion workflow and common teaching scenarios. +- Authoring and assessment: tags, MCQs, question banks, and output formats. +- Course operations: batch conversion, linting, debugging, and educational use cases. +- Project documentation: site maintenance and reviewer-facing readiness notes. + +## Maintenance Checklist + +Before publishing documentation changes, run: + +```bash +Rscript -e "devtools::document()" +Rscript -e "testthat::test_local('.')" +Rscript -e "lintr::lint_package()" +Rscript -e "pkgdown::build_site()" +``` + +If a user-facing function, argument, or workflow changes, update at least one vignette and the relevant reference documentation. diff --git a/vignettes/educational-use-cases.Rmd b/vignettes/educational-use-cases.Rmd new file mode 100644 index 0000000..a01f69b --- /dev/null +++ b/vignettes/educational-use-cases.Rmd @@ -0,0 +1,102 @@ +--- +title: "Educational Use Cases" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Educational Use Cases} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +## Purpose + +`tutorizeR` is intended for instructors who maintain statistical, data science, or R programming lessons in R Markdown or Quarto. The package supports a source-first workflow: the instructor edits one source document, then generates an interactive tutorial, solution scaffolds, conceptual questions, and conversion reports from that source. + +This vignette describes plausible educational use cases. Actual classroom deployment and measured learning outcomes are not verifiable from repository contents. + +## Pre-class Tutorial + +An instructor can convert a lecture note into a pre-class activity. Students read the narrative, run short examples, answer MCQs, and complete a few code exercises before the in-person session. + +```{r eval=FALSE} +library(tutorizeR) + +report <- tutorize( + input = "lessons/week03-data-visualization.qmd", + output_dir = "tutorials/preclass", + format = "learnr", + assessment = "both", + overwrite = TRUE +) + +print(report) +``` + +## Laboratory Handout + +A laboratory handout can be maintained as a regular `.qmd` file and converted into an interactive tutorial before release. Teacher tags can mark which chunks become exercises, which chunks remain locked, and which hints should be shown to students. + +```r +# tutorizeR: hints=Start with group_by()|Then compute a summary statistic +activity |> + dplyr::group_by(program) |> + dplyr::summarise( + mean_hours = mean(study_hours), + .groups = "drop" + ) +``` + +## Reusable Concept Checks + +Question banks are useful when the same concepts appear across several modules. The instructor can store MCQs in YAML or JSON and reference them from different lessons. + +```yaml +ids: [visualization-aesthetic, grouped-summary] +strategy: ordered +shuffle_answers: false +``` + +```{r eval=FALSE} +library(tutorizeR) + +question_bank <- load_question_bank("question-bank") + +report <- tutorize( + input = "lessons/week04-summarisation.qmd", + format = "learnr", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE +) +``` + +## Course Team Review + +For courses with teaching assistants or multiple instructors, conversion reports can be saved and reviewed before distributing materials. + +```{r eval=FALSE} +library(tutorizeR) + +report <- tutorize( + input = "lessons/week05-models.qmd", + output_dir = "generated", + format = "learnr", + assessment = "both", + lint_strict = TRUE, + overwrite = TRUE +) + +write_tutorize_report( + report = report, + file = "generated/week05-conversion-report.json", + format = "json" +) +``` + +## Evidence Boundary + +The repository provides source code, tests, vignettes, reviewer documentation, and an installable example module. It does not currently provide anonymized classroom analytics, controlled learning studies, or external adoption records. Any future claim about classroom deployment or learning impact should be tied to verifiable evidence. diff --git a/vignettes/getting-started.Rmd b/vignettes/getting-started.Rmd index f58782a..5871cca 100644 --- a/vignettes/getting-started.Rmd +++ b/vignettes/getting-started.Rmd @@ -1,8 +1,8 @@ --- -title: "Getting started for teachers" +title: "Getting Started with tutorizeR" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Getting started for teachers} + %\VignetteIndexEntry{Getting Started with tutorizeR} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -11,15 +11,15 @@ vignette: > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` -`tutorizeR` converts existing `.Rmd` or `.qmd` files into interactive -teaching material. +## User goal -## Minimal reproducible workflow +This vignette helps an instructor convert one existing `.qmd` or `.Rmd` lesson into an interactive tutorial. The pedagogical goal is to keep one source document while generating student-facing practice material. + +## Minimal example ```{r eval=FALSE} library(tutorizeR) -# Convert one file to learnr report <- tutorize( input = "lesson.qmd", format = "learnr", @@ -30,9 +30,41 @@ report <- tutorize( print(report) ``` +The report records the input file, output file, format, assessment mode, generated exercises, MCQs, warnings, lint results, and render status. + +## Realistic installed example + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +work_dir <- file.path(tempdir(), "tutorizeR-example") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) + +file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) +file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + +question_bank <- load_question_bank(file.path(example_dir, "question-bank")) + +report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = question_bank, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) + +print(report) +``` + ## Batch conversion ```{r eval=FALSE} +library(tutorizeR) + folder_report <- convert_folder( dir = "course_material/", recursive = TRUE, @@ -56,15 +88,15 @@ Use comments inside R chunks: - `# tutorizeR: locked` - `# tutorizeR: hints=Hint 1|Hint 2` -## Explicit MCQ block schema +## Limits -```text -```{tutorizeR-mcq} -question: "2 + 2 = ?" -answers: - - text: "4" - correct: true - - text: "5" - correct: false -``` +Generated tutorials should be reviewed before release. The package can scaffold exercises, solutions, MCQs, and reports, but it does not decide whether a prompt is pedagogically appropriate for a course. Formal learning-outcome evaluation: Not verifiable from repository contents. + +## Reproducibility checklist + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +source(file.path(example_dir, "run-example.R")) ``` diff --git a/vignettes/jose-submission-readiness.Rmd b/vignettes/jose-submission-readiness.Rmd new file mode 100644 index 0000000..a38b6d6 --- /dev/null +++ b/vignettes/jose-submission-readiness.Rmd @@ -0,0 +1,54 @@ +--- +title: "JOSE Submission Readiness" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{JOSE Submission Readiness} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +This vignette points reviewers to the repository artifacts prepared for a future Journal of Open Source Education submission. + +## Main artifacts + +- `paper/paper.md` +- `paper/paper.bib` +- `docs/jose_blockers_report.md` +- `docs/educational_use_evidence.md` +- `docs/jose_review_checklist.md` +- `docs/jose_submission_guide.md` +- `inst/examples/example_course_module/` + +## Local verification + +```{r eval=FALSE} +testthat::test_local() +lintr::lint_package() + +tmpdir <- tempfile("tutorizeR-source-") +dir.create(tmpdir) +system2("rsync", c( + "-a", + "--exclude=.git", + "--exclude=*.Rcheck", + "--exclude=*.tar.gz", + "./", + file.path(tmpdir, "tutorizeR/") +)) +old <- setwd(file.path(tmpdir, "tutorizeR")) +on.exit(setwd(old), add = TRUE) +system("R CMD build .") +system("R CMD check --as-cran --no-manual tutorizeR_0.4.4.tar.gz") +``` + +## Evidence boundaries + +Educational use cases are documented in the repository. + +- Actual classroom deployment: Not verifiable from repository contents. +- Broad external adoption: Not verifiable from repository contents. +- Public GitHub history: Not verifiable from repository contents. diff --git a/vignettes/large-undergraduate-courses.Rmd b/vignettes/large-undergraduate-courses.Rmd new file mode 100644 index 0000000..35a1806 --- /dev/null +++ b/vignettes/large-undergraduate-courses.Rmd @@ -0,0 +1,72 @@ +--- +title: "Workflow Pattern for Large Undergraduate Courses" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Workflow Pattern for Large Undergraduate Courses} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +This vignette is an illustrative scenario. Actual classroom deployment is not verifiable from repository contents. + +Large undergraduate courses need consistent materials, reproducible updates, and clear handoffs between instructors and teaching assistants. `tutorizeR` is designed for this kind of operational teaching workflow. + +## Course folder workflow + +```text +course/ + lessons/ + week01-introduction.qmd + week02-data-import.qmd + week03-visualization.qmd + question-bank/ + core-concepts.yml + tutorials/ + reports/ +``` + +## Batch conversion + +```{r eval=FALSE} +library(tutorizeR) + +qb <- load_question_bank("course/question-bank") + +folder_report <- convert_folder( + dir = "course/lessons", + recursive = TRUE, + output_dir = "course/tutorials", + format = "learnr", + assessment = "both", + question_bank = qb, + mcq_source = "mixed", + lint_strict = TRUE, + overwrite = TRUE +) + +print(folder_report) +``` + +## Teaching assistant review + +Teaching assistants can review generated outputs and reports before release: + +```{r eval=FALSE} +library(tutorizeR) + +lint <- lint_source( + input = "course/lessons/week03-visualization.qmd", + question_bank = qb, + strict = FALSE +) + +print(lint) +``` + +## Operational benefits + +The main benefit is not that tutorials are generated automatically once. The benefit is that a whole course team can regenerate the same materials after corrections, new datasets, or revised learning objectives. diff --git a/vignettes/lint-and-debug.Rmd b/vignettes/lint-and-debug.Rmd index effab0a..4e491a4 100644 --- a/vignettes/lint-and-debug.Rmd +++ b/vignettes/lint-and-debug.Rmd @@ -1,8 +1,8 @@ --- -title: "Lint and debug workflow" +title: "Lint and Debug Workflow" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Lint and debug workflow} + %\VignetteIndexEntry{Lint and Debug Workflow} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -11,11 +11,15 @@ vignette: > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` -Run lint checks before conversion and export machine-readable reports. +## User goal -## Source linting +Linting helps instructors detect common authoring problems before conversion. This is useful in teaching teams where several people maintain source lessons. + +## Minimal example ```{r eval=FALSE} +library(tutorizeR) + lint <- lint_source("lesson.qmd", strict = FALSE) print(lint) ``` @@ -23,15 +27,49 @@ print(lint) ## Strict conversion ```{r eval=FALSE} -rep <- tutorize( +library(tutorizeR) + +report <- tutorize( input = "lesson.qmd", assessment = "both", - lint_strict = TRUE + lint_strict = TRUE, + overwrite = TRUE +) +``` + +## Realistic installed example + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +source_file <- file.path(example_dir, "lesson-source.qmd") +question_bank <- load_question_bank(file.path(example_dir, "question-bank")) + +lint <- lint_source( + input = source_file, + question_bank = question_bank, + strict = FALSE ) + +print(lint) +``` + +## Conversion reports + +```{r eval=FALSE} +write_tutorize_report(report, "conversion-report.json", format = "json") ``` -## JSON report for CI +Reports are useful in continuous integration and course release workflows because they record the generated output path, number of exercises, MCQs, warnings, and lint summary. + +## Limits + +Linting can detect structural issues, but it cannot judge whether a lesson is pedagogically effective. Generated reports should support instructor review, not replace it. + +## Reproducibility checklist ```{r eval=FALSE} -write_tutorize_report(rep, "report.json", format = "json") +stopifnot(inherits(lint, "tutorize_lint_report")) ``` + diff --git a/vignettes/mcq-and-assessment.Rmd b/vignettes/mcq-and-assessment.Rmd index 6d326c4..f75a8f4 100644 --- a/vignettes/mcq-and-assessment.Rmd +++ b/vignettes/mcq-and-assessment.Rmd @@ -1,8 +1,8 @@ --- -title: "MCQ and assessment modes" +title: "MCQ and Assessment Modes" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{MCQ and assessment modes} + %\VignetteIndexEntry{MCQ and Assessment Modes} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -11,14 +11,73 @@ vignette: > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` -Assessment modes: +## User goal -- `code`: generate exercises and solutions. +Assessment modes let instructors decide whether a lesson should generate coding practice, conceptual questions, or both. + +## Minimal examples + +```{r eval=FALSE} +library(tutorizeR) + +tutorize("lesson.qmd", assessment = "code") +tutorize("lesson.qmd", assessment = "mcq") +tutorize("lesson.qmd", assessment = "both") +``` + +## Modes + +- `code`: generate exercise and solution scaffolds. - `mcq`: generate MCQ blocks only. -- `both`: generate code exercises and MCQ blocks. +- `both`: generate code exercises, solutions, and MCQs. + +## Realistic source pattern + +```yaml +question: "Which variable identifies the academic program?" +answers: + - text: "program" + correct: true + - text: "quiz_score" + correct: false +``` + +In a source lesson, this YAML would be placed inside a `tutorizeR-mcq` fenced block. + +## Realistic installed example ```{r eval=FALSE} -tutorize("tp.qmd", assessment = "code") -tutorize("tp.qmd", assessment = "mcq") -tutorize("tp.qmd", assessment = "both") +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +work_dir <- file.path(tempdir(), "tutorizeR-assessment") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) +file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) +file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + +qb <- load_question_bank(file.path(example_dir, "question-bank")) + +report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + assessment = "both", + question_bank = qb, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) + +print(report$mcq) ``` + +## Limits + +Generated MCQs are scaffolds. Instructors should verify that questions are aligned with learning objectives and that distractors are plausible. The package does not measure whether an MCQ improves learning. + +## Reproducibility checklist + +```{r eval=FALSE} +lines <- readLines(report$output_file) +any(grepl("learnr::question", lines, fixed = TRUE)) +``` + diff --git a/vignettes/quarto-lesson-interactive-tutorial.Rmd b/vignettes/quarto-lesson-interactive-tutorial.Rmd new file mode 100644 index 0000000..3f36524 --- /dev/null +++ b/vignettes/quarto-lesson-interactive-tutorial.Rmd @@ -0,0 +1,82 @@ +--- +title: "Converting a Quarto Lesson into an Interactive Tutorial" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Converting a Quarto Lesson into an Interactive Tutorial} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +Many instructors prepare lessons in Quarto because it supports narrative, executable code, figures, tables, and reproducible publishing. `tutorizeR` keeps that authoring workflow intact while producing an interactive tutorial for students. + +## Source lesson + +A source `.qmd` lesson can contain narrative text, setup code, examples, and MCQ blocks: + + --- + title: "Weekly study patterns" + --- + + ## Learning goal + + Students will summarize study time and relate it to quiz performance. + + ```r + library(tidyverse) + activity <- readr::read_csv("student_activity.csv") + ``` + + ```r + activity |> + group_by(program) |> + summarise(mean_hours = mean(study_hours), .groups = "drop") + ``` + + ```yaml + question: "Which summary is most appropriate for comparing programs?" + answers: + - text: "Mean study hours by program" + correct: true + - text: "The first row of the data" + correct: false + ``` + +## Conversion + +```{r eval=FALSE} +library(tutorizeR) + +report <- tutorize( + input = "lesson-source.qmd", + output_dir = "generated", + format = "learnr", + assessment = "both", + overwrite = TRUE +) + +print(report) +``` + +## Quarto live output + +For browser-executable Quarto output, target `quarto-live`: + +```{r eval=FALSE} +library(tutorizeR) + +report <- tutorize( + input = "lesson-source.qmd", + output_dir = "generated", + format = "quarto-live", + assessment = "code", + overwrite = TRUE +) + +print(report) +``` + +The `quarto-live` workflow requires the Quarto live extension in the teaching project. That dependency is intentionally not vendored by `tutorizeR`. diff --git a/vignettes/question-bank.Rmd b/vignettes/question-bank.Rmd index 9f5b9fd..ff91685 100644 --- a/vignettes/question-bank.Rmd +++ b/vignettes/question-bank.Rmd @@ -1,8 +1,8 @@ --- -title: "Reusable question bank" +title: "Reusable Question Banks" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Reusable question bank} + %\VignetteIndexEntry{Reusable Question Banks} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -11,32 +11,84 @@ vignette: > knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` -Use local YAML/JSON files to maintain reusable MCQ content. +## User goal + +Question banks help instructors reuse conceptual checks across lessons. This is useful when multiple tutorials should assess the same core ideas without rewriting each MCQ by hand. + +## Minimal bank + +```yaml +questions: + - id: visualization-aesthetic + question: "Which aesthetic maps a variable to the vertical axis?" + answers: + - text: "y" + correct: true + - text: "x" + correct: false + tags: [visualization] + difficulty: introductory + language: en +``` ## Load and validate ```{r eval=FALSE} -qb <- load_question_bank("inst/question-bank") -print(validate_question_bank(qb, strict = FALSE)) +library(tutorizeR) + +qb <- load_question_bank("question-bank") +report <- validate_question_bank(qb, strict = FALSE) + +print(report) ``` -## Reference bank questions in source files +## Reference bank questions in a lesson + +The YAML content inside a `tutorizeR-mcq-ref` block can reference existing bank items: -```text -```{tutorizeR-mcq-ref} -ids: [sample-mean] +```yaml +ids: [visualization-aesthetic] strategy: ordered shuffle_answers: false ``` -``` -## Convert with bank-enabled MCQ mode +## Realistic installed example ```{r eval=FALSE} -rep <- tutorize( - input = "lesson.qmd", +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +qb <- load_question_bank(file.path(example_dir, "question-bank")) + +work_dir <- file.path(tempdir(), "tutorizeR-qb-example") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) +file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) +file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + +report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, assessment = "both", question_bank = qb, - mcq_source = "mixed" + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE ) + +print(report) +``` + +## Limits + +Question banks improve reuse, but they do not guarantee good assessment design. Instructors should check that each MCQ is aligned with the learning objective, has plausible distractors, and uses language appropriate for the course. + +## Reproducibility checklist + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +qb <- load_question_bank(file.path(example_dir, "question-bank")) +validate_question_bank(qb, strict = TRUE) ``` + diff --git a/vignettes/reproducible-data-science-assignments.Rmd b/vignettes/reproducible-data-science-assignments.Rmd new file mode 100644 index 0000000..9705f6f --- /dev/null +++ b/vignettes/reproducible-data-science-assignments.Rmd @@ -0,0 +1,72 @@ +--- +title: "Building Reproducible Data Science Assignments" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Building Reproducible Data Science Assignments} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +Data science assignments are easier to maintain when the instructor can keep one source document and regenerate student-facing materials after revisions. `tutorizeR` supports that workflow by converting annotated source documents into tutorials with exercises and solutions. + +## Suggested assignment structure + +```text +assignment-week03/ + lesson-source.qmd + data/ + student_activity.csv + generated/ + week03-tutorial.Rmd + conversion-report.json +``` + +## Reproducible conversion script + +```{r eval=FALSE} +library(tutorizeR) + +source_file <- "assignment-week03/lesson-source.qmd" + +report <- tutorize( + input = source_file, + output_dir = "assignment-week03/generated", + format = "learnr", + assessment = "both", + seed = 20260531, + overwrite = TRUE, + lint_strict = TRUE +) + +write_tutorize_report( + report = report, + file = "assignment-week03/generated/conversion-report.json", + format = "json" +) +``` + +## Why the seed matters + +For teaching workflows, a fixed seed makes generated setup chunks reproducible. This is useful when students, teaching assistants, and instructors need to see the same randomized example or simulated dataset. + +## LMS manifest + +```{r eval=FALSE} +library(tutorizeR) + +manifest <- export_lms_manifest( + input = "assignment-week03/lesson-source.qmd", + output_file = "assignment-week03/generated/lms-manifest.json", + profile = "canvas", + include_solutions = FALSE +) + +print(manifest) +``` + +The manifest is a local metadata artifact. Direct LMS publication is not part of the current package functionality. + diff --git a/vignettes/tags-and-annotations.Rmd b/vignettes/tags-and-annotations.Rmd index f4da785..242d63c 100644 --- a/vignettes/tags-and-annotations.Rmd +++ b/vignettes/tags-and-annotations.Rmd @@ -26,6 +26,11 @@ This vignette documents supported teacher tags. ## Example ```{r eval=FALSE} -# tutorizeR: mcq, hints=Inspect the data|Use summary() -summary(mtcars) +# tutorizeR: mcq, hints=Inspect the grouping variable|Summarise by program +activity |> + dplyr::group_by(program) |> + dplyr::summarise( + mean_hours = mean(study_hours), + .groups = "drop" + ) ``` diff --git a/vignettes/teaching-workflow-scenario.Rmd b/vignettes/teaching-workflow-scenario.Rmd new file mode 100644 index 0000000..68a68f2 --- /dev/null +++ b/vignettes/teaching-workflow-scenario.Rmd @@ -0,0 +1,115 @@ +--- +title: "Teaching Workflow Scenario" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Teaching Workflow Scenario} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +``` + +This vignette is an illustrative scenario. Actual classroom deployment is not verifiable from repository contents. + +## Teaching problem + +An instructor has a Quarto lesson on introductory data summarisation and visualization. The lesson contains narrative explanation, R chunks, a small dataset, and interpretation prompts. The instructor wants a student-facing tutorial with exercises, solution material, MCQs, and a conversion report without maintaining a separate tutorial by hand. + +## Source-first workflow + +The instructor keeps `lesson-source.qmd` as the source of truth. Generated `learnr` or `quarto-live` files are outputs that can be regenerated after edits. + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +``` + +## Annotating a `.qmd` lesson + +Instructor comments inside R chunks control conversion: + +```r +# tutorizeR: hints=Group by program before summarising|Use .groups = "drop" +``` + +The comments stay close to the source code, which helps course teams review the pedagogical intent of each chunk. + +## Adding MCQs and question-bank references + +Inline MCQs are useful for lesson-specific checks. Question-bank references are useful when a concept should be reused across modules. + +```yaml +ids: [visualization-aesthetic] +strategy: ordered +shuffle_answers: false +``` + +## Running `tutorize()` + +```{r eval=FALSE} +work_dir <- file.path(tempdir(), "tutorizeR-scenario") +dir.create(work_dir, recursive = TRUE, showWarnings = FALSE) + +file.copy(file.path(example_dir, "lesson-source.qmd"), work_dir, overwrite = TRUE) +file.copy(file.path(example_dir, "student_activity.csv"), work_dir, overwrite = TRUE) + +qb <- load_question_bank(file.path(example_dir, "question-bank")) + +report <- tutorize( + input = file.path(work_dir, "lesson-source.qmd"), + output_dir = work_dir, + format = "learnr", + assessment = "both", + question_bank = qb, + mcq_source = "mixed", + overwrite = TRUE, + verbose = FALSE +) +``` + +## Interpreting the conversion report + +```{r eval=FALSE} +print(report) + +write_tutorize_report( + report = report, + file = file.path(work_dir, "conversion-report.json"), + format = "json" +) +``` + +The report helps an instructor check how many exercises, solutions, and MCQs were generated. It also records warnings and lint summaries. + +## Reviewing the generated tutorial + +The instructor should open the generated file and verify: + +- the generated exercise prompts are clear; +- solutions are appropriate for release policy; +- MCQs are aligned with the intended concept; +- datasets are available where the tutorial will be rendered; +- optional packages are available to students. + +## Publishing or sharing + +The package creates local artifacts. Publishing depends on the teaching environment. Instructors may render `learnr` tutorials, distribute Quarto output, or use generated reports in course release workflows. Direct LMS publication is not implemented in the current version. + +## Limitations and manual checks + +This workflow demonstrates feasibility and reproducibility, not measured learning impact. + +- Formal learning-outcome evaluation: Not verifiable from repository contents. +- Actual classroom deployment: Not verifiable from repository contents. + +## Reproducibility checklist + +```{r eval=FALSE} +library(tutorizeR) + +example_dir <- system.file("examples", "example_course_module", package = "tutorizeR") +source(file.path(example_dir, "run-example.R")) +```