├── .Rbuildignore ├── .Rprofile ├── .github ├── .gitignore └── workflows │ └── render-rmarkdown.yaml ├── .gitignore ├── DESCRIPTION ├── README.Rmd ├── README.md ├── compile_course.R ├── courses ├── 00-first-last-slides.Rmd ├── C00-package-objectives.en.Rmd ├── C00-package_preambule.en.Rmd ├── C01a-package_fusen_discover.en.Rmd ├── C01b-package_express_fusen.en.Rmd ├── C04-comment_interagir_zoom.en.Rmd ├── C05-comment_utiliser_bakacode.en.Rmd ├── C06-pkg_avance_test.en.Rmd ├── C09-pkg_avance_data.en.Rmd ├── C13-git_fusen.en.Rmd ├── C14-data-analyses-packages.en.Rmd ├── images │ ├── 00_connection.png │ ├── 01_home.png │ ├── 02_chapters.png │ ├── 03_launch.png │ ├── 04_separator.png │ ├── 05_slides.png │ ├── 05_slides_overview.png │ ├── 06_rstudio_right.png │ ├── 07_export.png │ ├── 08_back_home.png │ ├── 09_back_courses.png │ ├── 10_rstudio_full.png │ ├── 11_go_to_chat.png │ ├── 12_rocket_chat.png │ ├── 13_resources.png │ ├── 14_disconnect.png │ ├── almost-package-no-data.png │ ├── baka_courses.png │ ├── baka_courses_launch.png │ ├── baka_export.png │ ├── baka_login.png │ ├── baka_rstudio.png │ ├── baka_search.png │ ├── baka_search_slide.png │ ├── baka_sessions.png │ ├── baka_toc.png │ ├── bakacode_long_3.png │ ├── cruz_classic_fondnoir.png │ ├── exemple_test.png │ ├── flat_minimal_skeleton.png │ ├── fusen-write-package.png │ ├── fusen_description_file.png │ ├── fusen_fold_inflate.png │ ├── fusen_inflate_functions.png │ ├── fusen_inflate_vignette.png │ ├── fusen_mytools_complete.png │ ├── fusen_new_project.png │ ├── fusen_rmd_folds_pkg.png │ ├── fusen_skeleton.png │ ├── fusen_skeleton_desc.png │ ├── fusen_skeleton_fun.png │ ├── fusen_start_hello.png │ ├── marmot.png │ ├── new_package_fusen_minimal.png │ ├── new_package_fusen_teaching.png │ ├── packages-move-function.png │ ├── pkg_attachment_badges.png │ ├── pkg_attachment_cran.png │ ├── pkg_attachment_doc_function.png │ ├── pkg_attachment_examples.png │ ├── pkg_attachment_index.png │ ├── pkg_attachment_vignette.png │ ├── present_zoom.en.png │ ├── squirrels_inflated.png │ ├── squirrels_pkgdown.png │ ├── squirrels_rmd_html_snapshot.png │ ├── vignette.png │ ├── vignette2.png │ └── zoom_aide.png └── quizz.Rmd ├── dev_history.R ├── img ├── 00_connection.png ├── 01_home.png ├── 02_chapters.png ├── 03_launch.png ├── 04_separator.png ├── 05_slides.png ├── 05_slides_overview.png ├── 06_rstudio_right.png ├── 07_export.png ├── 08_back_home.png ├── 09_back_courses.png ├── 10_rstudio_full.png ├── 11_go_to_chat.png ├── 12_rocket_chat.png ├── 13_resources.png ├── 14_disconnect.png ├── cruz_classic_fondnoir.png └── present_zoom.en.png ├── renv.lock ├── renv ├── .gitignore ├── activate.R └── settings.dcf ├── submission.Rmd └── teach-package-dev-rmdfirst.Rproj /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | ^\.github$ 4 | ^.*\.Rproj$ 5 | ^\.Rproj\.user$ 6 | -------------------------------------------------------------------------------- /.Rprofile: -------------------------------------------------------------------------------- 1 | source("renv/activate.R") 2 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/render-rmarkdown.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | - master 6 | - the-ci 7 | pull_request: 8 | branches: 9 | - main 10 | - master 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-20.04 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | GITLAB_THINKR_PAT: ${{ secrets.GITLAB_THINKR_PAT }} 18 | REPO_NAME: "https://packagemanager.rstudio.com/all/__linux__/focal/latest" 19 | FILL_HOME: "FALSE" 20 | steps: 21 | - name: Checkout repo 22 | uses: actions/checkout@v2 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Setup R 27 | uses: r-lib/actions/setup-r@v1 28 | 29 | - uses: r-lib/actions/setup-pandoc@v1 30 | 31 | - name: Query dependencies 32 | run: | 33 | install.packages('remotes') 34 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 35 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 36 | shell: Rscript {0} 37 | 38 | - name: Install system dependencies 39 | if: runner.os == 'Linux' 40 | run: | 41 | while read -r cmd 42 | do 43 | eval sudo $cmd 44 | done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') 45 | 46 | - name: Cache Renv packages 47 | uses: actions/cache@v2 48 | with: 49 | path: $HOME/.local/share/renv 50 | key: r-${{ hashFiles('renv.lock') }} 51 | restore-keys: r- 52 | 53 | - name: Install packages 54 | run: | 55 | source("renv/activate.R") 56 | install.packages("git2r") 57 | install.packages("remotes") 58 | options(renv.auth.formation = list(GIT_PAT = Sys.getenv("GITLAB_THINKR_PAT"))) 59 | renv::restore() 60 | tmpform <- tempfile(pattern = "form-") 61 | git2r::clone("https://forge.thinkr.fr/thinkr/thinkrverse/formation", local_path = tmpform, 62 | credentials = git2r::cred_user_pass("gitlab-ci-token", Sys.getenv("GITLAB_THINKR_PAT"))) 63 | remotes::install_local(path = tmpform, upgrade = FALSE, force = TRUE) 64 | # Rscript -e 'options(remotes.git_credentials = git2r::cred_user_pass("gitlab-ci-token", Sys.getenv("GITLAB_THINKR_PAT")));renv::restore()' 65 | shell: Rscript {0} 66 | 67 | # Mettre les options pour avec renv, qui n'est pas pareil que remotes... 68 | 69 | - name: Render Rmarkdown files 70 | run: | 71 | source("compile_course.R") 72 | dir.create("public") 73 | file.copy("les_cours/complet/support", "public", recursive = TRUE) 74 | writeLines("!*.html\n!*.pdf\n!*_files/", "public/support/.gitignore") 75 | shell: Rscript {0} 76 | 77 | - name: Deploy 78 | uses: peaceiris/actions-gh-pages@v3 79 | with: 80 | github_token: ${{ secrets.GITHUB_TOKEN }} 81 | publish_dir: ./public/support 82 | force_orphan: true 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | *.html 6 | *.md 7 | *_files/ 8 | !README.md 9 | token.txt 10 | les_cours 11 | admin/ 12 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: user2021.rmdd 2 | Title: What the Package Does (One Line, Title Case) 3 | Version: 0.0.0.9000 4 | Authors@R: 5 | person("First", "Last", , "first.last@example.com", role = c("aut", "cre"), 6 | comment = c(ORCID = "YOUR-ORCID-ID")) 7 | Description: What the package does (one paragraph). 8 | License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a 9 | license 10 | Imports: 11 | attachment, 12 | dplyr, 13 | flextable, 14 | fusen, 15 | git2r, 16 | here, 17 | knitr, 18 | remotes, 19 | testthat, 20 | usethis, 21 | xaringan, 22 | xaringanExtra 23 | Suggests: 24 | future, 25 | purrr, 26 | tidyverse 27 | Remotes: 28 | gadenbuie/xaringanExtra 29 | Encoding: UTF-8 30 | LazyData: true 31 | Roxygen: list(markdown = TRUE) 32 | RoxygenNote: 7.1.1 33 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>" 11 | ) 12 | ``` 13 | 14 | # How to build a package with "Rmd First" method 15 | 16 | > Build reproducible and shareable data analyses using R packages 17 | 18 | 19 | 20 | 21 | 22 | This repository contains the course material of our [useR! 2021 tutorial](https://user2021.r-project.org/), then [AFH 2022](https://www.association-francaise-halieutique.fr). 23 | 24 | Instructors: [Sébastien Rochette](https://statnmap.com), Florence Mounier 25 | 26 | ## Tutorial purpose 27 | 28 | The tutorial is designed for R users from a variety of fields who are interested in organizing their analyses or development, usually written in RMarkdown files, into R packages. 29 | 30 | ## Modifications 31 | 32 | Please use a branch to add modifications and open a merge request to ask to add them in the _master_. You can assign me to this. 33 | 34 | ## Content of this repository 35 | 36 | - `courses/`: Rmd for different courses 37 | - `data/`: shapefiles and data used in the slides and in exercises 38 | - `exercises/` : Rmd of the exercises with complete answers 39 | - `submission.Rmd` : Tutorial submission 40 | 41 | ## What we proposed 42 | 43 | ### Abstract 44 | 45 | "Rmd First" method can reduce mental load when building packages by keeping users in a natural environment, using a tool they know: a RMarkdown document. 46 | 47 | The step between writing your own R code to analyze some data and refactoring it into a well-documented, ready-to-share R package seems unreachable to many R users. 48 | The package structure is sometimes perceived as useful only for building general-purpose tools for data analysis to be shared on official platforms. 49 | However, packages can be used for a broader range of purposes, from internal use to open-source sharing. 50 | Because packages are designed for robustness and enforce helpful standards for documentation and testing, the package structure provides a useful framework for refactoring analyses and preparing them to go into production. 51 | The following approach to write a development or an analysis inside a Rmd, will significantly reduce the work to transform a Rmd into a package : 52 | 53 | - _Design_ : define the goal of your next steps and the tools needed to reach them 54 | - _Prototype_ : use some small examples to prototype your script in Rmd 55 | - _Build_ : Build your script as functions and document your work to be able to use them, in the future, on real-life datasets 56 | - _Strengthen_ : Create tests to assure stability of your code and follow modifications through time 57 | - _Deploy_ : Transform as a well-structured package to deploy and share with your community 58 | 59 | During this tutorial, we will work through the steps of Rmd Driven Development to persuade attendees that their experience writing R code means that they already know how to build a package. They only need to be in a safe environment to find it out, which will be what we propose. 60 | We will take advantage of all existing tools such as {devtools}, {testthat}, {attachment} and {usethis} that ease package development from Rmd to building a package. 61 | The recent package [{fusen}](https://thinkr-open.github.io/fusen), which "inflates a package from a simple flat Rmd", will be presented to further reduce the step between well-designed Rmd and package deployment. 62 | Attendees will leave this workshop having built their first package with the "Rmd First" method and with the skills and tools to build more packages on their own. 63 | 64 | ### The learning goals 65 | 66 | By the end of the tutorial participants should: 67 | 68 | - understand the methodology proposed by Rmd Driven Development 69 | - be able to refactor their code into correctly formatted functions 70 | - understand the structure of a package 71 | - be able to build a documented and tested R package 72 | - know how to share their work with the community on GitHub 73 | 74 | ## What can you do after this tutorial? 75 | 76 | - Practice again, following complementary 'Rmd-first' / 'RMDD' presentations 77 | + https://rtask.thinkr.fr/when-development-starts-with-documentation/ 78 | + https://emilyriederer.netlify.com/post/rmarkdown-driven-development/ 79 | + https://malco.io/talk/you-re-already-ready-zen-and-the-art-of-r-package-development-rsg/ 80 | 81 | - Try ["{fusen}: inflate a package from a simple flat Rmd"](https://rtask.thinkr.fr/fusen-create-a-package-from-a-single-rmarkdown-file/) 82 | 83 | # For instructors 84 | 85 | The content will be built using an internal ThinkR package called {formation}. 86 | This ensures that the HTML output, datasets, and extra files are stored in the correct place to be added to the ThinkR e-learning platform. 87 | Each instructor is still able to locally knit each chapter using {xaringan}. 88 | The content of the course is: 89 | 90 | - courses/C00-package-objectives.en.Rmd: What we will present during this tutorial, and how it will be held 91 | - courses/00-cruz.Rmd: How the e-learning platform works 92 | - courses/C00-package_preambule.en.Rmd: What means package first ? 93 | - courses/C01a-package_fusen_discover.en.Rmd: Discover the structure of a package with {fusen} 94 | - courses/C01b-package_express_fusen.en.Rmd: Build a package using {fusen} 95 | 96 | - courses/C09-pkg_avance_data.en.Rmd: Include datasets in your package 97 | - courses/C13-git_fusen.en.Rmd: Use git with {fusen} projects 98 | - courses/C14-data-analyses-packages.en.Rmd: What about data analyses in a package? 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # How to build a package with “Rmd First” method 5 | 6 | > Build reproducible and shareable data analyses using R packages 7 | 8 | 9 | 10 | 11 | This repository contains the course material of our [useR! 2021 12 | tutorial](https://user2021.r-project.org/), then [AFH 13 | 2022](https://www.association-francaise-halieutique.fr). 14 | 15 | Instructors: [Sébastien Rochette](https://statnmap.com), Florence 16 | Mounier 17 | 18 | ## Tutorial purpose 19 | 20 | The tutorial is designed for R users from a variety of fields who are 21 | interested in organizing their analyses or development, usually written 22 | in RMarkdown files, into R packages. 23 | 24 | ## Modifications 25 | 26 | Please use a branch to add modifications and open a merge request to ask 27 | to add them in the *master*. You can assign me to this. 28 | 29 | ## Content of this repository 30 | 31 | - `courses/`: Rmd for different courses 32 | - `data/`: shapefiles and data used in the slides and in exercises 33 | - `exercises/` : Rmd of the exercises with complete answers 34 | - `submission.Rmd` : Tutorial submission 35 | 36 | ## What we proposed 37 | 38 | ### Abstract 39 | 40 | “Rmd First” method can reduce mental load when building packages by 41 | keeping users in a natural environment, using a tool they know: a 42 | RMarkdown document. 43 | 44 | The step between writing your own R code to analyze some data and 45 | refactoring it into a well-documented, ready-to-share R package seems 46 | unreachable to many R users. The package structure is sometimes 47 | perceived as useful only for building general-purpose tools for data 48 | analysis to be shared on official platforms. However, packages can be 49 | used for a broader range of purposes, from internal use to open-source 50 | sharing. Because packages are designed for robustness and enforce 51 | helpful standards for documentation and testing, the package structure 52 | provides a useful framework for refactoring analyses and preparing them 53 | to go into production. The following approach to write a development or 54 | an analysis inside a Rmd, will significantly reduce the work to 55 | transform a Rmd into a package : 56 | 57 | - *Design* : define the goal of your next steps and the tools needed 58 | to reach them 59 | - *Prototype* : use some small examples to prototype your script in 60 | Rmd 61 | - *Build* : Build your script as functions and document your work to 62 | be able to use them, in the future, on real-life datasets 63 | - *Strengthen* : Create tests to assure stability of your code and 64 | follow modifications through time 65 | - *Deploy* : Transform as a well-structured package to deploy and 66 | share with your community 67 | 68 | During this tutorial, we will work through the steps of Rmd Driven 69 | Development to persuade attendees that their experience writing R code 70 | means that they already know how to build a package. They only need to 71 | be in a safe environment to find it out, which will be what we propose. 72 | We will take advantage of all existing tools such as {devtools}, 73 | {testthat}, {attachment} and {usethis} that ease package development 74 | from Rmd to building a package. The recent package 75 | [{fusen}](https://thinkr-open.github.io/fusen), which “inflates a 76 | package from a simple flat Rmd”, will be presented to further reduce the 77 | step between well-designed Rmd and package deployment. Attendees will 78 | leave this workshop having built their first package with the “Rmd 79 | First” method and with the skills and tools to build more packages on 80 | their own. 81 | 82 | ### The learning goals 83 | 84 | By the end of the tutorial participants should: 85 | 86 | - understand the methodology proposed by Rmd Driven Development 87 | - be able to refactor their code into correctly formatted functions 88 | - understand the structure of a package 89 | - be able to build a documented and tested R package 90 | - know how to share their work with the community on GitHub 91 | 92 | ## What can you do after this tutorial? 93 | 94 | - Practice again, following complementary ‘Rmd-first’ / ‘RMDD’ 95 | presentations 96 | - 97 | - 98 | - 99 | - Try [“{fusen}: inflate a package from a simple flat 100 | Rmd”](https://rtask.thinkr.fr/fusen-create-a-package-from-a-single-rmarkdown-file/) 101 | 102 | # For instructors 103 | 104 | The content will be built using an internal ThinkR package called 105 | {formation}. This ensures that the HTML output, datasets, and extra 106 | files are stored in the correct place to be added to the ThinkR 107 | e-learning platform. 108 | Each instructor is still able to locally knit each chapter using 109 | {xaringan}. 110 | The content of the course is: 111 | 112 | - courses/C00-package-objectives.en.Rmd: What we will present during 113 | this tutorial, and how it will be held 114 | - courses/00-cruz.Rmd: How the e-learning platform works 115 | - courses/C00-package_preambule.en.Rmd: What means package first ? 116 | - courses/C01a-package_fusen_discover.en.Rmd: Discover the structure 117 | of a package with {fusen} 118 | - courses/C01b-package_express_fusen.en.Rmd: Build a package using 119 | {fusen} 120 | 121 | - courses/C09-pkg_avance_data.en.Rmd: Include datasets in your package 122 | - courses/C13-git_fusen.en.Rmd: Use git with {fusen} projects 123 | - courses/C14-data-analyses-packages.en.Rmd: What about data analyses 124 | in a package? 125 | -------------------------------------------------------------------------------- /compile_course.R: -------------------------------------------------------------------------------- 1 | # Compile Courses for SC platform 2 | library(tidyverse) 3 | library(formation) 4 | 5 | # Compiler en parallèle 6 | future::plan(future::multisession(workers = 4)) # Parallèle 7 | # plan(sequential) # Non parallèle. Default. 8 | 9 | # Client - Nom de dossier 10 | client_dir <- "afh2022" 11 | 12 | # Combien de sessions 13 | all_sessions <- c("1") # Nom des sessions 14 | all_dates <- paste(28, "June 2022") # Dates des sessions 15 | 16 | # First and last slides 17 | # first_last_slides 18 | # formation::support() %>% cat(file = "first_last.Rmd") 19 | 20 | # Create logo useR bottom 21 | # cat('.remark-slide-number-left { 22 | # background: url("', knitr::image_uri("img/userlogo-small.png"),'") no-repeat left top; 23 | # background-size: 20px; 24 | # } 25 | # .prez_github { 26 | # background: #ffffffd4; 27 | # } 28 | # ', sep = "", 29 | # file = "prez.css") 30 | 31 | 32 | # Partial - Create course - Nom du (de la) formateur.trice ==== 33 | create_session <- purrr::partial( 34 | formation::create_session, 35 | title = "Build reproducible and shareable data analyses using R packages", 36 | formateur = "Sébastien Rochette, Florence Mounier", 37 | email = "sebastien@thinkr.fr, florence@thinkr.fr", 38 | telephone = "", 39 | dossier = here::here(), 40 | render_pdf = c("none", "pagedown")[2], 41 | types = c("stagiaire", "formateur")[1], 42 | # dataWD = dataWD, 43 | footer = "S. Rochette, F. Mounier", 44 | # add_footer_chapitre = FALSE, 45 | url = "AFH 2022 - tutorial", 46 | # css = here::here("prez.css"), 47 | # logo_home = here::here("courses/images/marmot.png"), 48 | first_last_slides = here::here("courses/00-first-last-slides.Rmd"), 49 | first_last_slides_seal = FALSE, 50 | ... = 51 | ) 52 | 53 | # Listes des supports de cours ==== 54 | tous_les_cours <- list( 55 | cours_1 = c( 56 | "courses/C00-package-objectives.en.Rmd", 57 | # "courses/00-cruz.Rmd"#, 58 | "courses/C05-comment_utiliser_bakacode.en.Rmd", 59 | # "courses/C04-comment_interagir_zoom.en.Rmd", 60 | "courses/C00-package_preambule.en.Rmd", 61 | "courses/C01a-package_fusen_discover.en.Rmd", 62 | "courses/C01b-package_express_fusen.en.Rmd", 63 | # "courses/C06-pkg_avance_test.en.Rmd"#, 64 | "courses/C09-pkg_avance_data.en.Rmd", 65 | "courses/C13-git_fusen.en.Rmd", 66 | "courses/C14-data-analyses-packages.en.Rmd" 67 | ) 68 | ) 69 | 70 | # Projets avec data, exos et td ---- 71 | # il faut définir des projet et leur contenus 72 | # les element qui s'appellent 73 | # - "empty" vont etre preparé comme exos, en vidant les chunk d'exo, 74 | # - "render" comme "empty", mais en plus l'exercice est compilé en HTML dans le dossier 75 | # - "formateur" : les fichiers à déplacer dans le dossier formateur uniquement 76 | # - les autres (avec ou sans nom) sont déposés tel quel dans le dossier 77 | 78 | # Do not create home on Github Actions 79 | if (Sys.getenv("FILL_HOME", unset = "TRUE") == "TRUE") { 80 | # Create empty fusen packages 81 | dirfusen <- tempfile(pattern = "fusen-") 82 | dir.create(dirfusen) 83 | mytools <- file.path(dirfusen, "mytools.solution") 84 | hello <- file.path(dirfusen, "hello.solution") 85 | wd <- getwd() 86 | 87 | usethis::with_project(path = dirfusen, { 88 | # mytools 89 | dir.create(mytools, recursive = TRUE) 90 | fusen::add_flat_template(pkg = mytools, flat_name = "teaching", open = FALSE) 91 | # hello 92 | dir.create(hello, recursive = TRUE) 93 | fusen::add_flat_template(pkg = hello, flat_name = "minimal", open = FALSE) 94 | }, force = TRUE) 95 | 96 | setwd(wd) 97 | 98 | home <- list( 99 | projet1 = list( 100 | root = c( 101 | formateur = "courses/quizz.Rmd"# , 102 | # render = "nyc_squirrels_rmd/nyc_squirrels_rmd_simple.Rmd" 103 | ), 104 | data = c( 105 | # "nyc_squirrels_rmd" 106 | ) 107 | ), 108 | mytools.solution = list( 109 | root = c(file.path(mytools, "dev")) 110 | ), 111 | hello.solution = list( 112 | root = c(file.path(hello, "dev")) 113 | ) 114 | ) 115 | } 116 | 117 | # All sessions - Normally used 118 | if (TRUE) { 119 | create_session( 120 | tous_les_cours, client_dir, 121 | which_cours = 1:seq_along(all_sessions), 122 | which_session = all_sessions, 123 | which_date = paste(all_dates[c(1, length(all_dates))], collapse = " - "), 124 | output_pattern = "complet", 125 | output_dir = "complet" 126 | ) 127 | } 128 | 129 | # Do not create home on Github Actions 130 | if (Sys.getenv("FILL_HOME", unset = "TRUE") == "TRUE") { 131 | # Fonction - peuple_home() ---- 132 | formation::peuple_home(home = home, dossier = paste0(client_dir, "_home")) 133 | formation::copy_pdf() 134 | # Fonction - export_pour_sc() ---- 135 | # formation::export_pour_sc(pattern = client_dir) 136 | } 137 | -------------------------------------------------------------------------------- /courses/00-first-last-slides.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Build reproducible and shareable data analyses using R packages" 3 | subtitle: "AFH 2022" 4 | output: 5 | formation::chapitre: 6 | seal: false 7 | add_auto_title_slide: true 8 | add_footer_chapitre: false 9 | xaringan::moon_reader: default 10 | --- 11 | class: center middle inverse title-slide 12 | 13 | ```{r include=FALSE} 14 | knitr::opts_chunk$set( 15 | cache = FALSE, 16 | message = FALSE, 17 | warning = FALSE, 18 | eval = TRUE 19 | ) 20 | ``` 21 | 22 | ```{r xaringanExtra-search, echo=FALSE} 23 | xaringanExtra::use_search(show_icon = TRUE, case_sensitive = FALSE, position = "top-right") 24 | # xaringanExtra::use_xaringan_extra("tile_view") 25 | # xaringanExtra::style_search(match_background = "pink") 26 | ``` 27 | 28 | 38 | 39 | .top_left[ 40 | ```{r logo, echo=FALSE, out.width="20%", eval=TRUE} 41 | # knitr::include_graphics("images/marmot.png") 42 | ``` 43 | ] 44 | 45 | 46 | # "Build reproducible and shareable data analyses using R packages 47 | 48 | ## _Conférence AFH 2022_ 49 | 50 | ### Sébastien Rochette, Florence Mounier 51 | 52 | .prez_github[ 53 | Material of this course is on Github: statnmap/teach-package-dev-rmdfirst 54 | ] 55 | 56 | --- 57 | 58 | layout:true 59 | .remark-slide-number-left[`r '\u200B'`] 60 | 61 | --- 62 | class: slide 63 | 64 | ## Thanks for joining this tutorial! 65 | 66 | ### Sébastien Rochette, Florence Mounier 67 | ### sebastien@thinkr.fr, florence@thinkr.fr 68 | 69 | Material of this course is on Github (with answers): statnmap/teach-package-dev-rmdfirst 70 | 71 | ```{r meetup-lille-21, out.width="50%", echo=FALSE} 72 | knitr::include_graphics("images/fusen-write-package.png") 73 | ``` 74 | -------------------------------------------------------------------------------- /courses/C00-package-objectives.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "One step package building" 3 | subtitle: "From Rmd to package" 4 | code: "M13S01C00" 5 | prerequis: [""] 6 | output: formation::chapitre 7 | obj_pred: ["Objectives of the course"] 8 | slug: package-flash-build 9 | --- 10 | class: slide 11 | 12 | ```{r, results='asis', eval=FALSE, echo=FALSE} 13 | # cat('') 18 | ``` 19 | 20 | 21 | ### Learning goals 22 | 23 | - Understand the methodology proposed by the "Rmd First" method 24 | - Be able to refactor a code into correctly formatted functions 25 | - Understand the structure of a package 26 | - Be able to build a documented and tested R package 27 | 28 | --- 29 | class: slide 30 | 31 | ### Building a package in a few steps 32 | 33 | - Start with a Rmd 34 | - Build your functions inside 35 | - Document your functions 36 | - Inflate as a Package 37 | 38 | .pull-left[ 39 | ```{r, echo=FALSE, out.width="90%"} 40 | knitr::include_graphics("images/squirrels_rmd_html_snapshot.png") 41 | ``` 42 | 43 | ] 44 | .pull-right[ 45 | ```{r, echo=FALSE, out.width="90%"} 46 | knitr::include_graphics("images/squirrels_inflated.png") 47 | ``` 48 | ] 49 | 50 | --- 51 | class: slide 52 | 53 | ### How this tutorial will be held 54 | 55 | - E-learning platform: https://bakacode.io 56 | - Instructors speak on slides 57 | 58 | 59 | - Quizz where every attendees will be able to participate 60 | - Direct questions where attendees are asked to participate 61 | - Hands-on parts, in breakout rooms, where attendees are asked to share their screens for instructors to help 62 | - A 5 minutes break every hour 63 | - We stop 15 minutes before the end to say goodbye 64 | 65 | 66 | --- 67 | class: slide 68 | 69 | ### Code of Conduct 70 | 71 | All conference participants agree to: 72 | 73 | - Be considerate in language and actions, and respect the boundaries of fellow participants. 74 | - Refrain from demeaning, discriminatory, or harassing behaviour and language. 75 | - Alert a member of the ThinkR team if you notice someone in distress, or observe violations of this code of conduct, even if they seem inconsequential. 76 | 77 | 78 | -------------------------------------------------------------------------------- /courses/C00-package_preambule.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Start with the documentation" 3 | subtitle: "What are vignettes?" 4 | code: "M13S01C00" 5 | prerequis: [""] 6 | output: 7 | formation::chapitre: default 8 | xaringan::moon_reader: default 9 | obj_pred: ["know what is a vignette"] 10 | slug: package-preambule-en 11 | --- 12 | class: slide 13 | 14 | ```{r echo=FALSE, include=FALSE} 15 | library(dplyr) 16 | ``` 17 | 18 | 19 | ### Do you know package {attachment}? 20 | 21 | Let's say you don't! 22 | 23 | #### How to discover what does a package? 24 | 25 | --- 26 | class: slide 27 | 28 | ### How to discover what does a package? 29 | #### My questions as a user 30 | 31 | - What does it do? 32 | - How to install it with its dependencies? 33 | - What are its function? 34 | - How to fill parameters of this function? 35 | - Can I have an example on how to use this function? 36 | - Can I have an example on how to use the package as a whole? 37 | - Will it work with the last version of R and dependencies? 38 | 39 | --- 40 | class: slide 41 | 42 | ### How to discover what does a package? 43 | #### What does it do? 44 | 45 | - CRAN page: https://cran.r-project.org/web/packages/attachment/index.html 46 | 47 | ```{r, echo=FALSE} 48 | knitr::include_graphics("images/pkg_attachment_cran.png") 49 | ``` 50 | 51 | --- 52 | class: slide 53 | 54 | ### How to discover what does a package? 55 | #### How to install it with its dependencies? 56 | 57 | - `install.packages('attachment')` 58 | 59 | ??? 60 | 61 | You don't have to think about dependencies... 62 | The developers prepared everything for you 63 | 64 | --- 65 | class: slide 66 | 67 | ### How to discover what does a package? 68 | #### What are its functions? 69 | 70 | - Index of the package 71 | 72 | ```{r echo=FALSE, out.width="70%"} 73 | knitr::include_graphics("images/pkg_attachment_index.png") 74 | ``` 75 | 76 | --- 77 | class: slide 78 | 79 | ### How to discover what does a package? 80 | #### How to fill parameters of this function? 81 | 82 | - `?att_amend_desc` 83 | 84 | ```{r echo=FALSE, out.width="70%"} 85 | knitr::include_graphics("images/pkg_attachment_doc_function.png") 86 | ``` 87 | 88 | --- 89 | class: slide 90 | 91 | ### How to discover what does a package? 92 | #### Can I have an example on how to use this function? 93 | 94 | - `?att_amend_desc` => Examples 95 | 96 | ```{r echo=FALSE, out.width="90%"} 97 | knitr::include_graphics("images/pkg_attachment_examples.png") 98 | ``` 99 | 100 | --- 101 | class: slide 102 | 103 | ### How to discover what does a package? 104 | #### Can I have an overview on how to use the package as a whole? 105 | 106 | - Vignettes 107 | - GitHub: https://thinkr-open.github.io/attachment/articles/fill-pkg-description.html 108 | 109 | ```{r echo=FALSE, out.width="50%"} 110 | knitr::include_graphics("images/pkg_attachment_vignette.png") 111 | ``` 112 | 113 | --- 114 | class: slide 115 | 116 | ### How to discover what does a package? 117 | #### Will it work with the last version of R and dependencies? 118 | 119 | - README Check, https://github.com/ThinkR-open/attachment 120 | - Unit tests, code coverage, Continuous Integration 121 | 122 | ```{r echo=FALSE, out.width="80%"} 123 | knitr::include_graphics("images/pkg_attachment_badges.png") 124 | ``` 125 | 126 | ??? 127 | 128 | Unit tests and CI are set up by developers to ensure reproducibility and maintainability 129 | 130 | --- 131 | class: slide 132 | 133 | ### How to discover what does a package? 134 | #### My answers as a user 135 | 136 | ```{r, echo=FALSE} 137 | tribble( 138 | ~Questions, ~Answers, 139 | "What does it do?", "CRAN page", 140 | "How to install it with its dependencies?", "`install.packages('attachment')`", 141 | "What are its functions?", "`?attachment` => Index", 142 | "How to fill parameters of this function?", "`?att_amend_desc`", 143 | "Can I have an example on how to use this function?", "`?att_amend_desc` => Examples", 144 | "Can I have an overview on how to use the package as a whole?", "Vignettes, GitHub", 145 | "Will it work with the last version of R and dependencies?", "README Check" 146 | ) %>% 147 | knitr::kable() 148 | ``` 149 | 150 | _There is a dedicated website that gathers all these answers: https://thinkr-open.github.io/attachment/_ 151 | 152 | ??? 153 | 154 | We will explore this website later 155 | 156 | 157 | --- 158 | class: slide 159 | 160 | ### How to discover what does a package? 161 | #### Developers point of view 162 | 163 | - All these sources of information are adressed by developers 164 | 165 | -- 166 | 167 | #### If you start with the documentation, from the vignette, you will not have to think too much about all of these 168 | 169 | ??? 170 | 171 | You will build all the doc along the way 172 | 173 | --- 174 | class: slide 175 | 176 | ### Let's talk again about vignettes 177 | 178 | + HTML pages telling the stories of the package 179 | + List vignettes using: `vignette(package = "thepackage")`. 180 | 181 | ```{r, echo=FALSE, out.width="90%"} 182 | knitr::include_graphics("images/vignette.png") 183 | ``` 184 | 185 | --- 186 | class: slide 187 | 188 | ### Let's talk again about vignettes 189 | 190 | #### Content of a vignette 191 | 192 | ```{r eval=FALSE} 193 | vignette(topic = "colwise", package = "dplyr") 194 | ``` 195 | 196 | ```{r, echo=FALSE, out.width="60%"} 197 | knitr::include_graphics("images/vignette2.png") 198 | ``` 199 | 200 | ??? 201 | 202 | The story of the package as a whole 203 | 204 | --- 205 | class: slide 206 | 207 | ### Let's talk again about vignettes 208 | 209 | #### Vignette = Rmarkdown (usually) 210 | 211 | - What is the story of the package 212 | - What is the function for 213 | - How to use it with or without parameters 214 | - Reproducible examples 215 | - Different outputs depending on chosen parameters 216 | 217 | -- 218 | 219 | #### Let's start building our package from its story ! 220 | 221 | --- 222 | class: slide 223 | 224 | ### Quizz: What is a vignette? 225 | 226 | - A: A website somewhere on Internet 227 | - B: A Sticker you can add on your laptop 228 | - C: A R script with the help of function accessible in the installed package 229 | - D: A html page built from a Rmd file, accessible in the installed package 230 | 231 | 232 | --- 233 | class: slide 234 | 235 | ### Quizz: Have you already built a package with all these? 236 | 237 | - A: Yes, everything. Functions, examples, tests, vignettes 238 | - B: Only part of documentation. Functions, examples, maybe vignettes 239 | - C: Only functions in a R/ directory 240 | - D: No. I never built a package from scratch 241 | -------------------------------------------------------------------------------- /courses/C01a-package_fusen_discover.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Discover the structure of a package with {fusen}" 3 | subtitle: "Where does all of this come from?" 4 | code: "M13S01C04" 5 | prerequis: ["M13S01C00"] 6 | output: 7 | formation::chapitre: default 8 | xaringan::moon_reader: default 9 | obj_pred: ["discover the structure of a package"] 10 | slug: package-fusen-discover-en 11 | --- 12 | class: slide 13 | 14 | ```{r include=FALSE} 15 | # Verify {fusen} works here 16 | library(fusen) 17 | library(testthat) 18 | 19 | # Create a new project 20 | dummypackage <- tempfile("inflate.tests") 21 | dir.create(dummypackage) 22 | 23 | # {fusen} steps 24 | fill_description(pkg = dummypackage, fields = list(Title = "Dummy Package")) 25 | dev_file <- suppressMessages(add_flat_template(pkg = dummypackage, overwrite = TRUE, open = FALSE)) 26 | flat_file <- dev_file[grepl("flat_", dev_file)] 27 | 28 | usethis::with_project(dummypackage, { 29 | suppressMessages( 30 | inflate(pkg = dummypackage, flat_file = flat_file, 31 | vignette_name = "Get started", check = FALSE, 32 | open_vignette = FALSE) 33 | ) 34 | }) 35 | 36 | test_that("inflate() worked correctly", { 37 | # R files 38 | my_median_file <- file.path(dummypackage, "R", "my_median.R") 39 | expect_true(file.exists(my_median_file)) 40 | }) 41 | ``` 42 | 43 | 44 | ### {fusen} : adopt "Rmd-first" method 45 | 46 | - Start with documentation 47 | - Develop everything in a familiar place: the RMarkdown 48 | - {fusen} inflates the package for you 49 | 50 |
51 | 52 | > What if there was a package that could take an Rmd file, kind of like a sheet of paper, and if you follow the right folding, you can blow it up like a package? 53 | 54 | ```{r, echo=FALSE, out.width="80%"} 55 | knitr::include_graphics("images/fusen_fold_inflate.png") 56 | ``` 57 | 58 | --- 59 | class: slide 60 | ### [Short version] - Preamble 61 | 62 | - What are the principal components of a package? 63 | - Where do I have to write what? 64 | - How does {fusen} make my life easier? 65 | 66 | 67 | 68 | We suggest you to : 69 | 70 | + Watch your trainers create a package {mytools} by following these short steps, without practicing yourself 71 | 72 | -- 73 | 74 | + Redo this package {mytools} on your own in a new project 75 | 76 | -- 77 | 78 | We won't explain everything here, but you will see the components of a package and where they fit. For the details, that's the goal of your complete training! 79 | 80 | --- 81 | class: slide 82 | ### [Short] 1: Create a new {fusen} project 83 | 84 | In Rstudio : 85 | 86 | - File > New project > New directory > Package using {fusen} 87 | - Choose the name of the package (explicit, in lower case) 88 | - Name of the package: "mytools" 89 | > _no capital letters, underscores, spaces or special characters_ 90 | - Choose the {fusen} template in the dropdown menu: "teaching" 91 | 92 | - Choose the directory where to save the project 93 | - Create the project 94 | 95 | ```{r, echo=FALSE, out.width="40%"} 96 | knitr::include_graphics("images/new_package_fusen_teaching.png") 97 | ``` 98 | 99 | ??? 100 | 101 | - You are about to build a package. This is a set of tools for testing package structure. 102 | Thus, {mytools} 103 | 104 | - The directory is the "Home" in our platform using `~` 105 | 106 | 107 | 108 | --- 109 | class: slide 110 | ### [Short] 2: Open the {fusen} Rmd flat template 111 | 112 | - The project opens up on a flat template file: "flat_teaching.Rmd" 113 | 114 | -- 115 | 116 | - Here are the main components of a package, in a unique Rmd file 117 | + Note the name of the chunks that are required 118 | + The present file is pre-filled with examples 119 | 120 | .pull-left[ 121 | ```{r, echo=FALSE, out.width="75%"} 122 | knitr::include_graphics("images/fusen_skeleton_desc.png") 123 | ``` 124 | ] 125 | 126 | .pull-right[ 127 | ```{r, echo=FALSE, out.width="75%"} 128 | knitr::include_graphics("images/fusen_skeleton_fun.png") 129 | ``` 130 | ] 131 | 132 | ??? 133 | 134 | You can see that {fusen} opens up the "flat_teaching.Rmd" file in RStudio. 135 | There are a few additional files that we will explore later. 136 | This Rmd file is the "teaching" template with different chunks, which you will not modify this time. 137 | 138 | Let's quickly explore the content of this Rmd. A description, some functions along with examples and tests. 139 | And a final 'development' chunk asking to inflate 140 | 141 | --- 142 | class: slide 143 | ### [Short] 3 : Description 144 | 145 | Describe your future package: 146 | 147 | - Change the name with yours in the `description` chunk 148 | - Execute the complete content of the `description` chunk 149 | + "CTRL + SHIFT + ENTER" should be good 150 | + There are two functions to execute here 151 | - A "DESCRIPTION" file appears with the same information 152 | 153 | -- 154 | 155 | #### DESCRIPTION is the first source of documentation for your package 156 | 157 | ```{r, echo=FALSE, out.width="40%"} 158 | knitr::include_graphics("images/fusen_description_file.png") 159 | ``` 160 | 161 | 162 | ??? 163 | 164 | Yeah, you started with documentation ! 165 | There are some more fields in the DESCRIPTION file, but we'll see them later 166 | 167 | --- 168 | class: slide 169 | ### [Short] 4 : Inflate the package 170 | 171 | - Go down the Rmd file and inflate 172 | 173 | ```{r, eval=FALSE} 174 | fusen::inflate(flat_file = "dev/flat_teaching.Rmd") 175 | ``` 176 | 177 | ```{r, echo=FALSE, out.width="80%"} 178 | knitr::include_graphics("images/fusen_fold_inflate.png") 179 | ``` 180 | 181 | -- 182 | 183 | **You built a package!** 184 | 185 | --- 186 | class: slide 187 | ### [Short] 5 : Does it work ? 188 | 189 | - The 'Build' tab should already appear in RStudio 190 | + Otherwise, restart your RStudio session 191 | 192 | - Install the package 193 | + Panel Build > Install and Restart 194 | 195 | - Test the package directly in the console 196 | + `mytools::add_one(value = 56)` 197 | 198 | - Test the knit of the *vignette* 199 | + The vignette is opened "get-started.Rmd" 200 | + Hit the "Knit" button 201 | 202 | - Check that the help for your function appears 203 | + `?add_one` 204 | + Run the reproducible example from help 205 | 206 | --- 207 | class: slide 208 | ### [Short] 5 : Does it work ? 209 | 210 | If you verified everything listed above, your RStudio should look like this 211 | 212 | ```{r, echo=FALSE, out.width="100%"} 213 | knitr::include_graphics("images/fusen_mytools_complete.png") 214 | ``` 215 | 216 | --- 217 | class: slide 218 | ### Your turn 219 | 220 | #### Go back to section "[Short] 1" and execute the steps yourself until this slide 221 | -------------------------------------------------------------------------------- /courses/C01b-package_express_fusen.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Package express with {fusen}" 3 | subtitle: "An Rmd is a package" 4 | code: "M13S01C02" 5 | prerequis: ["M13S01C00"] 6 | output: 7 | formation::chapitre: default 8 | xaringan::moon_reader: default 9 | obj_pred: ["get principal components of a package"] 10 | slug: package-express-fusen-en 11 | --- 12 | class: slide 13 | 14 | ```{r include=FALSE} 15 | # Verify {fusen} works here 16 | library(fusen) 17 | library(testthat) 18 | 19 | # Create a new project 20 | dummypackage <- tempfile("inflate.tests") 21 | dir.create(dummypackage) 22 | 23 | # {fusen} steps 24 | fill_description(pkg = dummypackage, fields = list(Title = "Dummy Package")) 25 | dev_file <- suppressMessages(add_flat_template(pkg = dummypackage, overwrite = TRUE, open = FALSE)) 26 | flat_file <- dev_file[grepl("flat_", dev_file)] 27 | 28 | usethis::with_project(dummypackage, { 29 | suppressMessages( 30 | inflate(pkg = dummypackage, flat_file = flat_file, 31 | vignette_name = "Get started", check = FALSE, 32 | open_vignette = FALSE) 33 | ) 34 | }) 35 | 36 | test_that("inflate() worked correctly", { 37 | # R files 38 | my_median_file <- file.path(dummypackage, "R", "my_median.R") 39 | expect_true(file.exists(my_median_file)) 40 | }) 41 | ``` 42 | 43 | ### Preparation: Tools 44 | 45 | To create a package, we will use: 46 | 47 | + RStudio. 48 | + {fusen} package 49 | + the packages {pkgbuild}, {devtools}, {usethis} and {attachment} to save time. 50 | + the {roxygen2} package to generate the documentation. 51 | + the {testthat} package to generate unit tests. 52 | + Rtools.exe (optional and under windows only). 53 | 54 | 55 | ```{r eval = FALSE} 56 | install.packages(c("fusen", "devtools", "usethis", "pkgbuild", "roxygen2", "attachment", "testthat")) 57 | ``` 58 | 59 | Rtools is available here: [https://cran.r-project.org/bin/windows/Rtools/](https://cran.r-project.org/bin/windows/Rtools/) 60 | Once (properly) installed `pkgbuild::has_rtools()` should return `TRUE`. 61 | Rtools installs everything needed to compile c++ etc. 62 | 63 | ??? 64 | 65 | All of these should be installed on the server already 66 | 67 | --- 68 | class: slide 69 | 70 | ### {fusen}: adopt "Rmd-first" method 71 | 72 | - Start with documentation 73 | - Develop everything in a familiar place: the RMarkdown 74 | - {fusen} inflates the package for you 75 | 76 |
77 | 78 | > What if there was a package that could take an Rmd file, kind of like a sheet of paper, and if you follow the right folding, you can blow it up like a package? 79 | 80 | ```{r, echo=FALSE, out.width="80%"} 81 | knitr::include_graphics("images/fusen_fold_inflate.png") 82 | ``` 83 | 84 | --- 85 | class: slide 86 | 87 | ### How {fusen} works? 88 | 89 | - {fusen} copy-pastes in the right place 90 | 91 | ```{r, echo=FALSE, out.width="100%"} 92 | knitr::include_graphics("images/fusen_inflate_functions.png") 93 | ``` 94 | 95 | --- 96 | class: slide 97 | ### Longer version - Preamble 98 | 99 | This procedure contains **10 steps**, to be done in order. 100 | Some points are not explained in detail to allow you to obtain a functional R package quickly. 101 | 102 | We suggest you to: 103 | 104 | + Watch your trainers create a package by following these steps, without practicing yourself 105 | -- 106 | 107 | + Do this package {hello} on your own in a new project 108 | 109 | -- 110 | 111 | > Procedure is split in two parts to let you practice. You will thus have 2 times: "Watch - Do" 112 | 113 | --- 114 | class: slide 115 | ### Step 1: Create a new {fusen} project 116 | 117 | In Rstudio: 118 | 119 | - File > New project > New directory > Package using {fusen} 120 | - Choose the name of the package (explicit, in lower case) 121 | - Name of the package: "hello" 122 | > _no capital letters, underscores, spaces or special characters_ 123 | - Choose the {fusen} template in the dropdown menu: "minimal" 124 | 125 | - Choose the directory where to save the project 126 | - Create the project 127 | 128 | 129 | ```{r, echo=FALSE, out.width="30%"} 130 | knitr::include_graphics("images/new_package_fusen_minimal.png") 131 | ``` 132 | 133 | > You could also directly run: `fusen::create_fusen(path = "~/hello", template = "minimal")` 134 | 135 | ??? 136 | 137 | You are about to build a package. This is a set of tools to be polite with other people, starting by saying hello. 138 | Thus, {hello} 139 | 140 | - The directory is the "Home" in our platform using `~` 141 | 142 | --- 143 | class: slide 144 | 145 | ### Step 2: Open the {fusen} Rmd templates 146 | 147 | This time the template is divided into two flat Rmd files 148 | 149 | - "0-dev_history.Rmd" with the general development commands. In particular the `description` part. 150 | - "flat_minimal.Rmd" with the empty skeleton for creating a function like in the previous "teaching" template 151 | 152 | ```{r, echo=FALSE, out.width="50%"} 153 | knitr::include_graphics("images/flat_minimal_skeleton.png") 154 | ``` 155 | 156 | ??? 157 | 158 | You can see that {fusen} opens up the "0-dev_history.Rmd" file in RStudio. 159 | There are a few additional files that we will explore later. 160 | This Rmd file is the "minimal" template with different chunks, empty or not empty, that we will fill together in the next steps 161 | 162 | --- 163 | class: slide 164 | ### Step 3: Description 165 | 166 | The description of the package takes place in the first `description` chunk of the "dev_history.Rmd" file 167 | 168 | The first fields to fill in: 169 | 170 | - Title: "Quick Description of the Goal of your Package" (Title Case, no dot at the end) 171 | - Description: "Long description. Sentence case with a dot at the end of the sentences." 172 | - `Authors@R`: vector of one or more `person()` 173 | + `person("Sébastien", "Rochette", email = "sebastien@thinkr.fr", role = c("aut", "cre"))` 174 | - License: The choice of the license 175 | 176 | -- 177 | 178 | #### Let's run the content of chunk `description` 179 | 180 | > Observe the content of file "DESCRIPTION" created 181 | 182 | ??? 183 | 184 | You are about to build a package, you need to inform the user about its aim. Here, the aim is a set of tools to be polite with other people, starting by saying hello. 185 | You also need to say who you are, so that users know who to call in case of problems. 186 | Finally, the license allows you to say how you want your package to be used and shared. Without license, no one is supposed to use your package. 187 | 188 | Observe the content of DESCRIPTION. Note that what you wrote in the Rmd is now copied in this file, but you did not have to move from your Rmd. So we stay in the Rmd, and we continue the development. 189 | 190 | --- 191 | class: slide 192 | 193 | ### Step 4: Documentation of the package 194 | 195 | A package is created to automate some operations. 196 | Starting with the documentation forces you to think about the structure of the package and the logical sequence of operations. 197 | 198 | - Say what you do in the Rmd text part 199 | - Do what you said in the `function` chunk 200 | 201 | #### Open the "flat_minimal.Rmd" template 202 | 203 | #### Let's run the content of chunk `development` 204 | 205 | --- 206 | class: slide 207 | 208 | ### Step 4: Documentation of the package 209 | 210 | #### Let's see the process of writing a function 211 | 212 | 213 | .pull-left[ 214 | ````markdown 215 | ## Say hello to someone 216 | 217 | You can say hello to someone in particular using `say_hello()`. 218 | 219 | ```{r development}`r ''` 220 | library(glue) # On top with others 221 | 222 | message("Hello someone") 223 | 224 | someone <- "Seb" 225 | message(glue("Hello {someone}")) 226 | ``` 227 | ```` 228 | ] 229 | 230 | 231 | .pull-right[ 232 | 1. Describe in words the first operation that the package will have to solve 233 | 2. Define the input data, the possible modifiable parameters, the output result 234 | 3. Write the R code to perform these operations in a `development` chunk 235 | 4. Call necessary packages in a `development` chunk only, at the very beginning, with other `library()` calls 236 | ] 237 | 238 | ??? 239 | 240 | Here we take a simple example with a code to say hello. This will be the first tool of our package to be polite with people around us. 241 | Forget that you are about to build a package. Now we develop in a Rmd as usual. 242 | First, we write what we are about to do. 243 | Then, we write some code to say hello. But, I want it to be able to say hello to someone else than me. 244 | So I add a parameter. 245 | 246 | --- 247 | class: slide 248 | 249 | ### Step 5: Embed in a function 250 | 251 | - Move code in the `function` chunk as soon as you transformed it as a function 252 | - Add examples of use in the `examples` chunk 253 | 254 | 255 | ````markdown 256 | ## Say hello to someone 257 | 258 | You can say hello to someone in particular using `say_hello()`. 259 | 260 | ```{r function}`r ''` 261 | say_hello <- function(someone) { 262 | message(glue("Hello {someone}")) 263 | } 264 | ``` 265 | 266 | ```{r examples}`r ''` 267 | say_hello(someone = "Seb") 268 | ``` 269 | ```` 270 | 271 | - Each chunk has a specific task 272 | - Run the chunk `function` to make it available 273 | - Run the function in the `examples` chunk of the Rmd to try it 274 | 275 | 276 | ??? 277 | 278 | - Use the code written previously. 279 | - Embed in the `function()` function. 280 | - Use the parameter as a parameter of the function. 281 | 282 | - In the examples chunk, we have a reproducible example. 283 | - We will use it as much as we can 284 | - We use it to illustrate the use of the function. 285 | - You'll see that we will also use it for unit tests. Later. 286 | 287 | --- 288 | class: slide 289 | 290 | ### Step 5: Embed in a function 291 | 292 | The created function can now be documented 293 | 294 | - Add the doc in {roxygen2} format 295 | + `@param` to present the content of inputs 296 | + `@export` for the function to be accessible to the users 297 | + `@importFrom package function` for functions coming from other packages 298 | + `@return` to describe the object that comes out of the function 299 | 300 | - Use RStudio menu: Code > Insert Roxygen Skeleton 301 | 302 | > You must declare the dependencies for the package with `@importFrom`. 303 | The calls to `library()` are only there for development, like a classic Rmd, but are not used by the package when inflated 304 | 305 | ??? 306 | 307 | As you just wrote the code of your function, you know exactly 308 | 309 | - what the aim is, 310 | - what are the parameters for, 311 | - what is the output 312 | - what are the dependencies needed 313 | 314 | Write it now. In an hour, you will have forgotten it! 315 | 316 | Note that: 317 | 318 | - because we are in an Rmd, you won't be able to get the auto-completion for roxygen 319 | - because we are in an RStudio Server, the keyboard shortcut for roxygen may be in competition with your browser shortcuts 320 | 321 | Let's see how it looks on the next slide 322 | 323 | --- 324 | class: slide 325 | 326 | ### Step 5: Embed in a function 327 | 328 | - Your "flat_minimal.Rmd" file should look like this: 329 | 330 | ````markdown 331 | ## Say hello to someone 332 | 333 | You can say hello to someone in particular using `say_hello()`. 334 | 335 | ```{r function}`r ''` 336 | #' Show a message in the console to say Hello to someone 337 | #' 338 | #' @param someone Character. Name of the person to say hello to 339 | #' @importFrom glue glue 340 | #' @return Used for side effect. Outputs a message in the console 341 | #' @examples 342 | #' @export 343 | 344 | say_hello <- function(someone) { 345 | message(glue("Hello {someone}")) 346 | } 347 | ``` 348 | 349 | ```{r examples}`r ''` 350 | say_hello(someone = "Seb") 351 | ``` 352 | ```` 353 | 354 | ??? 355 | 356 | Here you can see the minimal roxygen content. 357 | 358 | - Title 359 | - Use of param 360 | - importFrom external dependencies 361 | - return an output. This one's special. There is no re-usable output. 362 | - example is in the following chunk. We will let {fusen} deal with this. This is specific to {fusen} to not fill the example here. We'll see this later. 363 | - export the function to let it available to the user when they will call library(your package) 364 | - There may still be a `development` chunk. That's ok. 365 | 366 | 367 | --- 368 | class: slide 369 | 370 | ### Your turn! 371 | 372 | - We are in the half way point of the process 373 | - Got back to Step 1 of this Longer version 374 | - Follow the 5 steps until this slide 375 | 376 | ??? 377 | 378 | Tell us in the Chatroom when you are done 379 | 380 | --- 381 | class: slide 382 | 383 | ### Step 6: Write a unit test 384 | 385 | - What do you look for when you run your example? 386 | - What makes you say "it works"? 387 | 388 | #### Write your thoughts into code 389 | 390 | ````markdown 391 | ```{r tests}`r ''` 392 | test_that("say_hello works", { 393 | expect_message(say_hello(someone = "Seb"), "Hello Seb") 394 | }) 395 | ``` 396 | ```` 397 | 398 | ??? 399 | 400 | - We use the same exact example to write the unit test directly. 401 | - I won't detail the syntax here, and I won't detail all possible test functions. 402 | - For now, I only want you to have the reflex to do it right after your example, because you already have the test in your mind 403 | 404 | --- 405 | class: slide 406 | 407 | ### Step 7: Inflate the package 408 | 409 | - Let {fusen} inflate the Rmd into a documented and tested package 410 | 411 | ```{r, eval=FALSE} 412 | fusen::inflate(flat_file = "dev/flat_minimal.Rmd", vignette_name = "Say Hello!") 413 | ``` 414 | 415 | ```{r, echo=FALSE, out.width="80%"} 416 | knitr::include_graphics("images/fusen_fold_inflate.png") 417 | ``` 418 | 419 | > If there are any errors or warnings, read them carrefuly, address them in the "flat_minimal.Rmd" and inflate the package again. 420 | 421 | ??? 422 | 423 | - Let {fusen} inflate the Rmd into a package 424 | - There are multiple messages, we do not read all of them. 425 | - We try to address errors at least and re-inflate if needed 426 | 427 | --- 428 | class: slide 429 | 430 | ### Step 8: Explore created folders and files 431 | 432 | - "DESCRIPTION" with dependencies 433 | - "R/" with the function 434 | - "man/" with LateX documentation 435 | - "tests/testthat/" with unit tests 436 | - "vignettes/" with documentation 437 | 438 | ```{r, echo=FALSE, out.width="80%"} 439 | knitr::include_graphics("images/fusen_inflate_functions.png") 440 | ``` 441 | 442 | 443 | --- 444 | class: slide 445 | 446 | ### Step 8: Explore created folders and files 447 | 448 | - "DESCRIPTION" with dependencies 449 | - "R/" with the function 450 | - "man/" with LateX documentation 451 | - "tests/testthat/" with unit tests 452 | - "vignettes/" with documentation 453 | 454 | ```{r, echo=FALSE, out.width="80%"} 455 | knitr::include_graphics("images/fusen_inflate_vignette.png") 456 | ``` 457 | 458 | 459 | --- 460 | class: slide 461 | 462 | ### Quiz: Find good definitions 463 | 464 | Link files to their description: 465 | 466 | .pull-left[ 467 | *Files and folders* 468 | 469 | 1. DESCRIPTION 470 | 471 | 2. dev_history / flat_minimal 472 | 473 | 3. vignettes 474 | 475 | 4. script with roxygen 476 | 477 | 5. testthat 478 | 479 |
480 |
481 |
482 | **Possible answers:** 483 | 484 | - a: ACBDE 485 | 486 | - c: EABCD 487 | ] 488 | .pull-right[ 489 | *Documentation* 490 | 491 | A. Development process for developers 492 | 493 | B. Present all the functions of the package and its story 494 | 495 | C. How to use each function (for the user) 496 | 497 | D. Testing the functions for the developers 498 | 499 | E. Content and objectives of the package for all 500 | 501 |
502 |
503 | - b: EDCBA 504 | 505 | - d: BAECD 506 | ] 507 | 508 | ??? 509 | - 1E and dependencies for installation 510 | - 2A reusable from one package to another 511 | - 3B with a story 512 | - 4C and build info (@importFrom, @export) 513 | - 5D unit tests 514 | 515 | --- 516 | class: slide 517 | 518 | ### Step 9: Verify again the package 519 | 520 | Generate documentation 521 | 522 | - `attachment::att_amend_desc()` 523 | 524 | Check that the package follows the packages rules 525 | 526 | - `devtools::check()` 527 | 528 | - Solve potential problems in the "flat_minimal.Rmd" 529 | - Re-inflate the package if necessary 530 | 531 | - Reach **0 Error, 0 Warnings, 0 Notes** 532 | 533 | > Store this commands in the "0-dev_history.Rmd" file 534 | 535 |
536 | 537 | > Note that `fusen::inflate()` already launches this two commands, but who knows! 538 | 539 | ??? 540 | 541 | It is always good to know these commands, although `inflate()` already does them. You may need them if you go back to a classical way of maintaining your package 542 | 543 | --- 544 | class: slide 545 | 546 | ### Step 10: Install and use your package 547 | 548 | - The 'Build' tab should already appear in RStudio 549 | + Otherwise, restart your RStudio session 550 | 551 | - Note that you can "check" in the 'Build' panel 552 | + Panel "Build" > "Check" 553 | 554 | - Install the package 555 | + Panel "Build" > "Install and Restart 556 | 557 | - Test the package directly in the console 558 | + `hello::say_hello("Toto")` 559 | 560 | - Test the knit of the vignette 561 | 562 | - Check that the help for your function appears 563 | + `?say_hello` 564 | + Run the reproducible example from help 565 | 566 | --- 567 | class: slide 568 | 569 | ### Your turn 570 | 571 | - Go back to step 6 of this Longer version 572 | - Continue development and inflate your package 573 | 574 | > Edit "flat_minimal.Rmd" and re-execute `inflate()` as many times as necessary until everything runs smoothly. 575 | 576 |
577 | ```{r echo=FALSE, out.width="90%"} 578 | knitr::include_graphics("images/fusen_rmd_folds_pkg.png") 579 | ``` 580 | 581 |
582 |
583 | > Bonus: If you are motivated, you can start again from the beginning of the 10 steps procedure with a new package name {hello2} 584 | 585 | --- 586 | class: slide 587 | 588 | ### How to add new functionnalities? 589 | 590 | This would require to start over from 'Step 4' to: 591 | 592 | - Upgrade your existing function 593 | 594 | - Add a new function in the current flat template 595 | + New entitled section with `function`, `examples`, `tests` 596 | + Inflate 597 | + Install 598 | 599 | - There is a RStudio _Addin_ to "Add {fusen} chunks" 600 | 601 | -- 602 | 603 | - Or create a new flat template using `fusen::add_flat_template("add")` for a new family of functions, thus new vignette 604 | 605 | - There is a RStudio _Addin_ to "Add {fusen} flat template" 606 | 607 | -- 608 | 609 | - And `inflate()` this new "flat_additional.Rmd" 610 | 611 | --- 612 | class: slide 613 | 614 | ### And the classical way without {fusen}? 615 | 616 | - You can use the 'Rmd first ' approach writing your code in a Rmarkdown file 617 | + this can directly be your vignette 618 | - Then, you'll need to fill / copy the different files yourself 619 | - "R/" 620 | - "tests/" 621 | - "vignettes/" 622 | 623 | 624 | --- 625 | class: slide 626 | 627 | ### And the classical way without {fusen}? 628 | 629 | - File > New Project > New directory > Package with devtools 630 | - Fill DESCRIPTION file 631 | - Run function for the desired license 632 | + `usethis::use_*_license()` 633 | - Develop in a Rmd 634 | + Either in the sub-directory "dev/" + `usethis::use_build_ignore("dev/")` 635 | + Or, develop in a vignette directly 636 | - Copy/Cut in the correct place 637 | + functions + examples => "R/" 638 | + `usethis::use_r("ma_fonction")` 639 | + tests => "tests/testthat/" 640 | + `usethis::use_testthat()` 641 | + `usethis::use_test("ma_fonction")` 642 | + vignettes => "vignettes/" 643 | + `usethis::use_vignette("Le titre de ma vignette")` 644 | - Generate documentation 645 | + Either `attachment::att_amend_desc()` 646 | + Ou `roxygen2::roxygenise()` + Fill in DESCRIPTION (Suggests, Imports) 647 | - Check the package 648 | + `devtools::check()` => `0 errors, 0 warnings, 0 notes` 649 | 650 | --- 651 | class: slide 652 | 653 | ### And the classical way without {fusen}? 654 | 655 | - You need to fill the different files yourself 656 | - "R/" 657 | - "tests/" 658 | - "vignettes/" 659 | 660 | - While developing you could 661 | - Run an example of your function in "R/" directly with Ctrl + Enter 662 | - Run the unit test by clicking on "Run test" 663 | - Run the vignette if your package is installed 664 | 665 | - Note that you can still do these actions using {fusen} after `inflate()` 666 | 667 | > Be careful, when using {fusen}, if you want to modify some code, go back to the "flat_*.Rmd" and do `inflate()` again 668 | 669 | ??? 670 | 671 | Show that we can do it with fusen too as it is a real classical package 672 | 673 | --- 674 | class: slide 675 | 676 | ### Exercise: Take time to finish your drawings 677 | 678 | Where were moved the pieces of code from chunks: 679 | 680 | - `description`? 681 | - `function`? 682 | - `example`? 683 | - `tests`? 684 | - `development`? 685 | 686 | > Verify and update your previous drawings. 687 | > See each thing that {fusen} does for you! 688 | 689 | ??? 690 | 691 | - `description`: in DESCRIPTION 692 | - `function`: in the independent .R file with the name of the function 693 | - `example`: in the independent .R file 694 | + in the independent .R file with the function name 695 | + in the thumbnail 696 | - tests`: in the independent tests/testthat folder with the function name 697 | - development`: nowhere. it stays in the development tracking file "dev_history.Rmd 698 | 699 | -------------------------------------------------------------------------------- /courses/C04-comment_interagir_zoom.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How to interact with Zoom ?" 3 | code: "M01S02C04" 4 | subtitle: "Features" 5 | output: formation::chapitre 6 | prerequis: 7 | chapitre: ["M01S02C01"] 8 | sequence: ["M01S01"] 9 | obj_ped: "communiquer avec nous dans le cadre de la formation avec Zoom" 10 | slug: how-to-interact-with-zoom 11 | --- 12 | class: slide 13 | 14 | ```{r, include = FALSE} 15 | knitr::opts_chunk$set(echo = TRUE, 16 | warning = FALSE, 17 | message = FALSE) 18 | ``` 19 | 20 | ### Using Zoom 21 | 22 | ```{r, echo=FALSE, out.width="95%"} 23 | knitr::include_graphics("images/present_zoom.en.png") 24 | ``` 25 | 26 | --- 27 | class:slide 28 | 29 | ### Using Zoom 30 | 31 | 32 | Call for help during a breakout rooms session 33 | 34 | ```{r, echo=FALSE, out.width="55%"} 35 | knitr::include_graphics("images/zoom_aide.png") 36 | ``` 37 | 38 | --- 39 | class:slide 40 | 41 | ### How to interact? 42 | 43 | - Please mute your microphone during the slides presentations 44 | - You can share your screen during exercises if you are stuck so that we can help you 45 | - Please cut your webcam off to reduce bandwidth use 46 | + Please turn it back on for interaction with trainers. 47 | + To avoid the impression of talking to a wall, trainers can ask 2-3 people to keep their webcam on. 48 | 49 | - In case you feel blocked in full screen mode 50 | + Double click on the full screen should make it come back in a small window. 51 | + If not, press "Esc" 52 | - In case of "loss" of the bar to switch off your micro/webcam 53 | + In full screen mode, it appears at the top of the screen 54 | + Move the mouse over the small green banner with the name of your computer or your name, the menu should appear. 55 | 56 | - Tip 57 | + Hold the space key to temporarily open the microphone. 58 | 59 | -------------------------------------------------------------------------------- /courses/C05-comment_utiliser_bakacode.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "What is Bakacode?" 3 | subtitle: "The ThinkR e-learning platform" 4 | output: formation::chapitre 5 | params: 6 | dataWD: "/mnt/Data/ThinkR/Seafile/Dossier_ThinkR/ressources Formations/support/data" 7 | slug: what-is-bakacode-en 8 | --- 9 | class: slide 10 | 11 | ```{r include=FALSE} 12 | knitr::opts_chunk$set( 13 | cache = FALSE, 14 | message = FALSE, 15 | warning = FALSE, 16 | eval = TRUE, 17 | fig.align = "center" 18 | ) 19 | 20 | # pagedown::chrome_print(here::here("courses/M01-presentation/M01S02-a_quelle_sauce_on_va_vous_manger/C05-comment_utiliser_bakacode.html"), here::here("C05-comment_utiliser_bakacode.en.pdf")) 21 | 22 | ``` 23 | 24 | ### Take a tour! 25 | 26 | **BakACode** is the home-made [ThinkR](https://rtask.thinkr.fr) e-learning platform 27 | 28 | - Everything you need during the course is available in one place 29 | - The server has all dependencies required for your tutorial 30 | - You can communicate directly with your instructors 31 | 32 |

33 | ```{r, echo=FALSE, out.width="55%"} 34 | knitr::include_graphics("images/bakacode_long_3.png") 35 | ``` 36 |

37 | **Please take this tour to get used to the platform** 38 | 39 | --- 40 | class: slide 41 | 42 | ### Take the tour and use it to answer the quiz at the end of the chapter 43 | 44 | - The instructor creates a file named "hello.Rmd" in the "shared/" directory 45 | + You will need it for the quiz 46 | 47 | -- 48 | 49 | Now we let you 3 minutes to read the following slides and answer the quiz at the end of this chapter 50 | 51 | 52 | --- 53 | class: slide 54 | ### Connection 55 | 56 | .pull-left[ 57 | ```{r, echo=FALSE, out.width="100%"} 58 | knitr::include_graphics("images/baka_login.png") 59 | ``` 60 | ] 61 | .pull-right[ 62 | #### Connection 63 | 64 | - Use your credentials to connect with username and password 65 | ] 66 | 67 | Connect to 68 | 69 | --- 70 | class: slide 71 | ### Sessions 72 | 73 | .pull-left[ 74 | ```{r, echo=FALSE, out.width="100%"} 75 | knitr::include_graphics("images/baka_sessions.png") 76 | ``` 77 | ] 78 | .pull-right[ 79 | #### Sessions overview 80 | 81 | - View your current and past training sessions 82 | 83 | ] 84 | 85 | --- 86 | class: slide 87 | ### Home page 88 | 89 | .pull-left[ 90 | ```{r, echo=FALSE, out.width="100%"} 91 | knitr::include_graphics("images/baka_courses.png") 92 | ``` 93 | ] 94 | .pull-right[ 95 | #### Learning objectives 96 | 97 | - Learning objectives of the tutorial 98 | 99 | ] 100 | 101 | --- 102 | class: slide 103 | ### Home page 104 | 105 | .pull-left[ 106 | ```{r, echo=FALSE, out.width="100%"} 107 | knitr::include_graphics("images/baka_courses.png") 108 | ``` 109 | ] 110 | .pull-right[ 111 | #### Learning objectives 112 | 113 | - Learning objectives of the tutorial 114 | 115 | #### Sections 116 | 117 | - A box for each section 118 | - Date and description of the section 119 | - Click on the box to show chapters presented 120 | 121 | ] 122 | 123 | 124 | --- 125 | class: slide 126 | ### Home page - launch 127 | 128 | .pull-left[ 129 | ```{r, echo=FALSE, out.width="100%"} 130 | knitr::include_graphics("images/baka_courses_launch.png") 131 | ``` 132 | ] 133 | .pull-right[ 134 | #### Launch tutorial 135 | 136 | - Click on the Launch ("Lancer") button to start the tutorial 137 | 138 | ] 139 | 140 | --- 141 | class: slide 142 | 143 | ### Pratice - presentation 144 | 145 | .pull-left[ 146 | ```{r, echo=FALSE, out.width="100%"} 147 | knitr::include_graphics("images/baka_rstudio.png") 148 | ``` 149 | ] 150 | .pull-right[ 151 | #### Vertical separator 152 | 153 | - Maintain left click on the vertical bar and use the mouse to change left/right windows ratio 154 | 155 | ] 156 | 157 | --- 158 | class: slide 159 | 160 | ### Pratice - presentation 161 | 162 | .pull-left[ 163 | ```{r, echo=FALSE, out.width="100%"} 164 | knitr::include_graphics("images/baka_rstudio.png") 165 | ``` 166 | ] 167 | .pull-right[ 168 | #### Vertical separator 169 | 170 | - Maintain left click on the vertical bar and use the mouse to change left/right windows ratio 171 | 172 | #### Slides 173 | 174 | - Use arrows of your keyboard to go up and down in the slides 175 | - You can copy-paste code parts 176 | 177 | ] 178 | 179 | --- 180 | class: slide 181 | 182 | ### Pratice - presentation 183 | 184 | .pull-left[ 185 | ```{r, echo=FALSE, out.width="100%"} 186 | knitr::include_graphics("images/baka_rstudio.png") 187 | ``` 188 | ] 189 | .pull-right[ 190 | #### Vertical separator 191 | 192 | - Maintain left click on the vertical bar and use the mouse to change left/right windows ratio 193 | 194 | #### Slides 195 | 196 | - Use arrows of your keyboard to go up and down 197 | - You can copy-paste code parts 198 | 199 | #### RStudio server 200 | 201 | - RStudio project opened with your data and Rmd files for exercises 202 | - Be sure to work in a project! 203 | ] 204 | 205 | --- 206 | class: slide 207 | 208 | ### Pratice - search 209 | 210 | .pull-left[ 211 | ```{r, echo=FALSE, out.width="100%"} 212 | knitr::include_graphics("images/baka_toc.png") 213 | ``` 214 | ] 215 | .pull-right[ 216 | #### Search chapter 217 | 218 | - Click on the slides 219 | - Click on the black box in the top right corner to open the table of content 220 | - Choose your chapter 221 | - Click on the black box to quit the table of content and navigate 222 | 223 | ] 224 | 225 | --- 226 | class: slide 227 | 228 | ### Pratice - search 229 | 230 | .pull-left[ 231 | ```{r, echo=FALSE, out.width="100%"} 232 | knitr::include_graphics("images/baka_search.png") 233 | ``` 234 | ] 235 | .pull-right[ 236 | #### Search words 237 | 238 | - Click on the slides 239 | - Use CTRL + F to open the slides search bar or click on the magnifier icon 240 | - Write your word 241 | - Press Enter to find the next occurence of your word 242 | - Use ESC / ECH to quit the search bar and navigate 243 | 244 | ] 245 | 246 | --- 247 | class: slide 248 | 249 | ### Pratice - export 250 | 251 | .pull-left[ 252 | ```{r, echo=FALSE, out.width="100%"} 253 | knitr::include_graphics("images/baka_export.png") 254 | ``` 255 | ] 256 | .pull-right[ 257 | #### Download your files 258 | 259 | - Download files on your computer 260 | - Select one or more files in the file Pane using checkboxes 261 | - Open the 'More' menu 262 | - Choose 'Export' 263 | - 'Download' 264 | ] 265 | 266 | > We recommend that you export your full project at the end of the course 267 | 268 | --- 269 | class: slide 270 | 271 | ### Top menu 272 | 273 | .pull-left[ 274 | ```{r, echo=FALSE, out.width="100%"} 275 | knitr::include_graphics("images/baka_rstudio.png") 276 | ``` 277 | ] 278 | .pull-right[ 279 | #### Home 280 | 281 | - Go back to home page "Accueil" 282 | 283 | ] 284 | --- 285 | class: slide 286 | 287 | ### Top menu 288 | 289 | .pull-left[ 290 | ```{r, echo=FALSE, out.width="100%"} 291 | knitr::include_graphics("images/baka_rstudio.png") 292 | ``` 293 | ] 294 | .pull-right[ 295 | #### Courses 296 | 297 | - Navigate through the list of courses sections available 298 | ] 299 | 300 | --- 301 | class: slide 302 | 303 | ### Top menu 304 | 305 | .pull-left[ 306 | ```{r, echo=FALSE, out.width="100%"} 307 | knitr::include_graphics("images/baka_rstudio.png") 308 | ``` 309 | ] 310 | .pull-right[ 311 | #### RStudio 312 | 313 | - Opens your current RStudio session as full screen in a new tab 314 | - Note that this will close the RStudio session in the "Practice" interface 315 | 316 | ] 317 | 318 | --- 319 | class: slide 320 | 321 | ### Top menu 322 | 323 | .pull-left[ 324 | ```{r, echo=FALSE, out.width="100%"} 325 | knitr::include_graphics("images/baka_rstudio.png") 326 | ``` 327 | ] 328 | .pull-right[ 329 | #### Resources 330 | 331 | - Opens a new tab with R cheatsheets as PDF 332 | - You can open or download them 333 | 334 | ] 335 | 336 | --- 337 | class: slide 338 | 339 | ### Top menu 340 | 341 | .pull-left[ 342 | ```{r, echo=FALSE, out.width="100%"} 343 | knitr::include_graphics("images/baka_rstudio.png") 344 | ``` 345 | ] 346 | .pull-right[ 347 | 348 | #### Disconnect 349 | 350 | - Disconnect from BakACode 351 | 352 | ] 353 | 354 | --- 355 | class: slide 356 | 357 | ## Quiz 358 | 359 | - Can you download the pdf of the courses? 360 | + It is stored in the "pdf/" folder, in the Home directory 361 | + If you loose the connection, at least you have the slides 362 | 363 | - Did you find the "shared/hello.Rmd" file ? 364 | + You can open it and write your name in it. 365 | + Save it quickly as it is shared with other attendees! 366 | 367 | - Can you use the table of content or the search bar to retrieve my email somewhere at the end of the slides? 368 | + Write it in the chat in private, and keep it for yourself, just in case 369 | 370 | -------------------------------------------------------------------------------- /courses/C06-pkg_avance_test.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Test your code" 3 | subtitle: "Do yourself a favor by making the right decisions" 4 | code: "M13S02C06" 5 | output: formation::chapitre 6 | prerequis: ["M06-rbase"] 7 | obj_ped: "savoir mettre en place des tests unitaires" 8 | slug: tester-son-code-en 9 | --- 10 | class: slide 11 | 12 | 13 | 14 | ### Automate the testing of your code 15 | 16 | 17 | 18 | --- 19 | class: slide 20 | 21 | ### Automate the testing of your code 22 | 23 | #### Why automate your code testing? 24 | 25 | + To save time! 26 | + To work peacefully with others 27 | + To be able to transfer the project 28 | + Guarantee the stability of the project 29 | 30 | #### {testthat} runs at each `check()`. 31 | 32 | - Checks that all functions are still doing what they are supposed to do 33 | - {testthat} is integrated to Rstudio and {devtools} 34 | - Tests can be run with `devtools::test()` 35 | 36 | --- 37 | class: slide 38 | 39 | ### Add a new test file 40 | 41 | - Initiate a test file for a specific function: `usethis::use_test("my_function")` 42 | + Creates a "test/testthat/" folder 43 | + Adds {testthat} to the `Suggests` of DESCRIPTION 44 | + Creates "test/testthat.R" (do not touch) 45 | - Create a test file for each function or function family 46 | + Consistent with function script files in "R/" 47 | 48 | -- 49 | 50 | > Note that {fusen} will initiate all of these from the `tests` chunks 51 | 52 | ??? 53 | 54 | In a regular package, you can add tests manually. 55 | In {fusen}, tests are added in the `tests` chunks 56 | 57 | --- 58 | class: slide 59 | 60 | ### Writing tests 61 | 62 | Each test file is composed of one or multiple sections, with one or multiple tests: 63 | 64 | ```{r eval = FALSE} 65 | test_that("detail serie1", { 66 | test1a 67 | test1b 68 | }) 69 | 70 | test_that("detail serie2", { 71 | test2a 72 | test2b 73 | }) 74 | 75 | ``` 76 | 77 | If `test2b` fails, I will be informed that it is the second test of "detail serie2" in "my_function" file. 78 | 79 | ??? 80 | 81 | Note that if a test fails with {fusen}, you had better modify it in the dev_history.Rmd and `inflate()` again 82 | 83 | --- 84 | class: slide 85 | 86 | ### Writing tests 87 | 88 | - Your test functions start with `expect_*(object, expected)` 89 | + `object`: actual output 90 | + `expected`: the expected one. 91 | - If the test fails, the function returns an error 92 | - If the test passes, the function returns nothing 93 | 94 | Several types of tests are possible, including: 95 | 96 | ```{r eval=TRUE, error=TRUE} 97 | library(testthat) 98 | 99 | expect_equal(10, 10) 100 | 101 | a <- sample(1:10, 1) 102 | b <- sample(1:10, 1) 103 | expect_equal(a + b, 200) 104 | ``` 105 | 106 | --- 107 | class: slide 108 | 109 | ### Common tests available in {testthat} 110 | 111 | 112 | ```{r eval = FALSE} 113 | # Test using identical 114 | expect_identical() 115 | # Test error management 116 | expect_error() 117 | expect_message() 118 | expect_warning() 119 | # Test character against regular expression 120 | expect_match() 121 | # Test on logical 122 | expect_true() 123 | expect_false() 124 | # Test if object is lower of greater than expected 125 | expect_less_than() 126 | expect_more_than() 127 | # Test the exact length 128 | expect_length() 129 | # Skip a section if server is not available 130 | skip_if_offline() 131 | ``` 132 | 133 | --- 134 | class: slide 135 | 136 | ### What kind of tests do I write? 137 | 138 | - Test that function works correctly when inputs are those expected 139 | - Test outputs are correct for a few scenarios of inputs 140 | - Test each scenario that can trigger a specific line of code (like `if()`) 141 | - Test what happens if other formats of inputs are used 142 | + You may need {assertthat} in your original function 143 | 144 | -- 145 | 146 | #### Example of test script in a package : 147 | 148 | ```{r eval = FALSE} 149 | test_that("test weighted.mean", { 150 | expect_equal( weighted.mean(1:10, w = rep(1, 10)), 5.5 ) 151 | expect_equal( weighted.mean(1:10, w = 1:10), 7 ) 152 | }) 153 | 154 | test_that("log fails ", { 155 | expect_error( log("a") ) 156 | expect_error( log("bonjour") ) 157 | }) 158 | ``` 159 | 160 | --- 161 | class: slide 162 | 163 | ### Quizz: What does this code do? 164 | 165 | - `save_as_csv()` takes a `dataframe` and a `path` as input and save it as csv using the `path` 166 | + It outputs the `path` 167 | 168 | ```{r eval = FALSE} 169 | test_that("test errors save_as_csv", { 170 | data(iris) 171 | expect_error(save_as_csv(iris, "does/not/exists/out.csv"), "does not exist") 172 | expect_error(save_as_csv(iris, "file.R"), "does not have correct output extension") 173 | }) 174 | 175 | test_that("test correct save_as_csv", { 176 | data(iris) 177 | expect_is(save_as_csv(iris, "out.csv"), "character") 178 | expect_true(file.exists(save_as_csv(iris, "out.csv"))) 179 | expect_equal(iris, read.csv2("out.csv")) 180 | }) 181 | 182 | ``` 183 | 184 | ??? 185 | 186 | Ask 2 different persons to describe the 2 sections 187 | 188 | 189 | --- 190 | class: slide 191 | 192 | ### Run all tests 193 | 194 | ```{r eval=FALSE} 195 | devtools::test() 196 | ``` 197 | 198 | 199 | ```{r, echo=FALSE, out.width="35%"} 200 | knitr::include_graphics("images/exemple_test.png") 201 | ``` 202 | 203 | 204 | + Each line corresponds to a test file 205 | + Each test is counted as `OK`, `FAIL`, `WARNING`, `SKIP`. 206 | + Each test file is launched in its own environment, so it is necessary to think about loading the necessary libraries and data each time 207 | 208 | 209 | 210 | > Same applies to {fusen}, after `inflate()`, each `test` chunk is run in a separate environment, you need to keep it in mind while writing test chunks 211 | 212 | ??? 213 | 214 | - OK when test is good 215 | - FAIL when test fails 216 | - WARNING if a function in the test returned a warning 217 | - SKIP if skip conditions apply 218 | 219 | 220 | --- 221 | class: slide 222 | 223 | ### Quiz: How to test what is supposed to fail? 224 | 225 | - A - `expect_equal()` 226 | - B - `expect_false()` 227 | - C - `expect_error()` 228 | - D - `expect_warning()` 229 | 230 | ??? 231 | 232 | - If your function crashes, R returns an error. 233 | You can catch it with `expect_error()` to avoid crashing the test script 234 | and check that in this case, there is an error. 235 | It is best if the error is chosen and made explicit in your function with a `stop()` or with {assertthat} for example 236 | 237 | - Depending on your definition of fail, `expect_warning()` can also be a good answer. 238 | Generally speaking, a warning should be something that the user has to correct in his code. It is good practice to put `stop()` or `message()`, but not `warning()` in your functions. 239 | 240 | --- 241 | class: slide 242 | 243 | ### TD - Exercise 1 244 | 245 | - Create a {mytools} package: 246 | 247 | + A function that returns the first 6 values of a chosen column (as a parameter) from a dataset. The output is a vector. 248 | + `extract_six_from_col(mtcars, "mpg")` works 249 | + `extract_six_from_col(mtcars, "toto")` returns an error 250 | + unit tests for `extract_six_from_col()` 251 | 252 | > Your package must be documented, **tested** and return 0 errors, 0 warnings, and 0 notes 253 | 254 | --- 255 | class: slide 256 | 257 | 258 | ### TD - Exercise 2 259 | 260 | - Add checks to your `say_hello()` function in the {hello} package to ensure that the input variable is a `character`, of size `1`. Stop the function otherwise with `stop()`. 261 | - Provide the message text as a `character` output of the function, reusable for future processing 262 | - Add unit tests to test all possible outputs 263 | 264 | > Your package must be documented, **tested** and return 0 errors, 0 warnings, and 0 notes 265 | 266 | **Bonus** 267 | 268 | - In the {hello} package, create a new function `create_mail_content()` that 269 | + takes a first name, an email address and a password as input 270 | + uses the `say_hello()` function as a sub-function to get the text of "Hello Someone". 271 | + adds mail content after the "hello" formula, saying `remember your mail: xxx@xxx.xx and password zzz` 272 | - Create a reproducible example that takes a dataframe as input with three columns: `firstname`, `email`, `password` and returns a list with content of custom mails 273 | - Test the whole thing! 274 | 275 | > Your package must be documented, **tested** and return 0 errors, 0 warnings, and 0 notes 276 | 277 | ??? 278 | 279 | Note that reproducible example with `create_mail_content()` could be transformed as a new function to take the dataframe as input directly. 280 | 281 | -------------------------------------------------------------------------------- /courses/C09-pkg_avance_data.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Include datasets in your package" 3 | subtitle: "What about data?" 4 | code: "M13S02C09" 5 | output: formation::chapitre 6 | prerequis: ["M06-rbase"] 7 | obj_ped: "savoir intégrer des données dans un packages" 8 | slug: encapsuler-donnees-en 9 | --- 10 | class: slide 11 | 12 | 13 | ### Include datasets 14 | 15 | In a package, it can be useful to include data. 16 | 17 | + To demonstrate the use of a function with a relevant example 18 | + To disseminate information 19 | 20 | -- 21 | 22 | There are three types of datasets to include, thus three ways to include them into a package. 23 | 24 | 1. A raw data file (xlsx, csv or other), **NOT** available to the end user, but accessible to the developers only, stored in `data-raw/` folder 25 | 26 | -- 27 | 28 | 2. An example dataset in `rda` format, to be loaded as is, available to the user, stored in the `data/` folder (such as `iris` or `mtcars` for example) 29 | 30 | 31 | -- 32 | 33 | 3. A data file (xlsx, csv or other) not transformed into `rda`, available to the end user, stored in the `inst/` folder 34 | 35 | 36 | ??? 37 | 38 | Let's see how and why 39 | 40 | --- 41 | class: slide 42 | 43 | ### 1. Include datasets in `data-raw/` 44 | 45 | #### Internal dataset, accessible to developers only 46 | 47 | - Developers store raw datasets to keep the source of examples close to them 48 | - Users can not access them, there are not installed 49 | 50 | -- 51 | 52 | *Steps:* 53 | 54 | - Create folder `data-raw/` at the root of the package using: `usethis::use_data_raw()` 55 | - Insert raw datasets inside 56 | - Use R/Rmd scripts to prepare a cleaner / smaller dataset for future examples 57 | 58 | -- 59 | 60 | *Information:* 61 | 62 | - `data-raw` is not installed with the package 63 | + It is not accessible to the user 64 | - Example: 65 | 66 | ??? 67 | 68 | - Prepare data that you will need for your reproducible examples 69 | - Keep the original source of your datasets in a safe place 70 | - Note that with {fusen}, you can realise the preparation steps in a `development` chunk. 71 | 72 | --- 73 | class: slide 74 | 75 | ### 2. Include datasets in `data/` 76 | 77 | #### Exported dataset, accessible to the user 78 | 79 | - Developers includes a dataset in the package using: `usethis::use_data(my_dataset)` 80 | - Users load the dataset named `my_dataset` using: `data(my_dataset)` 81 | 82 | -- 83 | 84 | *Steps:* 85 | 86 | - Create `data-raw/` to prepare your dataset using: `usethis::use_data_raw("my_dataset")` 87 | - Prepare your dataset as needed for reproducible examples 88 | - Store `my_dataset` as internal data 89 | 90 | ```{r eval = FALSE} 91 | # Read some raw data 92 | # my_data_to_clean <- readr::read_csv("my_raw_data.csv") 93 | 94 | # Or use existing dataset like `diamonds` 95 | my_dataset <- dplyr::slice_sample(diamonds, prop = 0.2) 96 | usethis::use_data(my_dataset, overwrite = TRUE) 97 | ``` 98 | 99 | - `overwrite = TRUE` overwrite the dataset if already exists, as for an update 100 | - Have a look at the content of newly created folder `data/` 101 | 102 | ??? 103 | 104 | - We use the directory `data-raw` previously created to prepare dataset 105 | - `use_data()` stores the reproducible example at the right place in the right format 106 | 107 | --- 108 | class: slide 109 | 110 | ### 2. Include datasets in `data/` 111 | 112 | #### Exported dataset, accessible to the user 113 | 114 | - Developers includes a dataset in the package using: `usethis::use_data(my_dataset)` 115 | - Users load the dataset named `my_dataset` using: `data(my_dataset)` 116 | 117 | 118 | *Information:* 119 | 120 | - `my_dataset` is accessible to the user after package installation 121 | ```{r, eval=FALSE} 122 | library(mypackage) 123 | data(my_dataset) 124 | ``` 125 | - `my_dataset` is stored as `.rda` file, only readable by R, similar to `.RData` files 126 | 127 | ??? 128 | 129 | Package needs to be installed to access the dataset 130 | 131 | --- 132 | class: slide 133 | 134 | ### 2. Include datasets in `data/` 135 | 136 | #### Exported dataset, accessible to the user 137 | 138 | - Exported datasets need to be documented, like functions 139 | - by convention the documentation will be written in a file of the form "R/doc_my_dataset.R". 140 | -- 141 | 142 | - The following script will automatically build the documentation to be completed: 143 | 144 | 145 | ```{r eval=FALSE} 146 | my_dataset <- dplyr::slice_sample(diamonds, prop = 0.2) 147 | usethis::use_data(my_dataset, overwrite = TRUE) 148 | 149 | cat(sinew::makeOxygen("my_dataset"), 150 | file = "R/doc_my_dataset.R") 151 | rstudioapi::navigateToFile("R/doc_my_dataset.R") 152 | ``` 153 | 154 | _à rajouter dans "data-raw/my_dataset.R"_ 155 | 156 | 157 | ??? 158 | 159 | Documentation is always the key for a correct package. 160 | Check will remind you of missing data documentation. 161 | 162 | 163 | --- 164 | class: slide 165 | 166 | ### 2. Include datasets in `data/` 167 | 168 | #### Exported dataset, accessible to the user 169 | 170 | - Exported datasets need to be documented, like functions 171 | 172 | *Information:* 173 | 174 | 2 main tags: 175 | 176 | - `@format` (required) a summary of the data. 177 | - if `@format` is not specified, then roxygen will edit a standard one. 178 | 179 | - `@source` : the origin of the data, the source. 180 | 181 | We do not `@export` a dataset. 182 | 183 | --- 184 | class: slide 185 | 186 | ### 3. Include datasets in `inst/` 187 | 188 | #### Raw dataset, accessible to the user 189 | 190 | - Developers includes a dataset in the `inst/` folder as is directly 191 | - Users find the dataset using `system.file("my_dataset.csv", package = "mypackage")` 192 | 193 | -- 194 | 195 | *Steps* 196 | 197 | - Create `inst/` folder using: `dir.create(here::here("inst"))` 198 | - Add a dataset inside 199 | - Install the package 200 | - Users can access the path of the dataset and read the file as usual 201 | 202 | ```{r, eval=FALSE} 203 | # Store "my_dataset.csv" in "inst/" folder 204 | the_data_path <- system.file("my_dataset.csv", package = "mypackage") 205 | the_data <- readr::read_csv(the_data_path) 206 | ``` 207 | 208 | --- 209 | class: slide 210 | 211 | ### 3. Include datasets in `inst/` 212 | 213 | #### Raw dataset, accessible to the user 214 | 215 | - Developers includes a dataset in the `inst/` folder as is directly 216 | - Users find the dataset using `system.file("my_dataset.csv", package = "mypackage")` 217 | 218 | 219 | *Information* 220 | 221 | - Any type of data is allowed 222 | - Use the path for your reproducible examples 223 | - Organise the content of `inst/` as your want 224 | 225 | ??? 226 | 227 | - system.file() does not read the dataset, it returns the path to the dataset 228 | - The dataset is only available after installation of the package 229 | 230 | --- 231 | class: slide 232 | 233 | ### Deal with datasets during development 234 | 235 | - Datasets in `data/` or `inst/` are only available after package installation 236 | - Simulate installation using `pkgload::load_all()` during development 237 | + `system.file()` temporarily returns development path (not installed path) 238 | 239 | -- 240 | 241 | *Steps* 242 | 243 | - Check your reproducible examples in the Rmd file with package data 244 | 245 | ```{r, eval=FALSE} 246 | # For development only 247 | pkgload::load_all() 248 | 249 | # Same code to add in your `examples` or `tests` 250 | # Can be tested directly during development 251 | the_data_path <- system.file("my_dataset.csv", package = "mypackage") 252 | the_data <- readr::read_csv(the_data_path) 253 | ``` 254 | 255 | -- 256 | 257 | > Note that `pkgload::load_all()` also loads functions in development, as it simulates a real installation 258 | 259 | ??? 260 | 261 | 262 | --- 263 | class: slide 264 | 265 | ### Quizz 266 | 267 | If I want to provide a dataset to the user in any format I want, where do I store it? 268 | 269 | - A: `extdata/` 270 | - B: `inst/` 271 | - C: `data/` 272 | - D: `data-raw/` 273 | 274 | 275 | --- 276 | class: slide 277 | 278 | ### Your turn! 279 | 280 | 1. Look at the instructor demonstration with *Steps* 281 | 2. Do it yourself 282 | 283 | *Steps* 284 | 285 | - Create a new {fusen} project with `full` template 286 | - Run the content of the `description` chunk in the "dev_history.Rmd" 287 | - Uncomment `development` chunk in "Read data" section in the "flat_full.Rmd" 288 | - Play with data in `inst/` during development 289 | 290 | -- 291 | 292 | *Bonus* 293 | 294 | - Create function `check_data_integrity()` that reads a dataset like `nyc_squirrels` and check its integrity 295 | + For instance, `primary_fur_color` columns should only contains a unique color, there should not be any `+` sign inside this column 296 | + Stop the function if the integrity is not good 297 | + Return a message if everything is ok 298 | - Create a reproducible example using the dataset saved in `inst/` with `system.file()` 299 | - Create unit tests with reproducible examples where function should fail 300 | 301 | ??? 302 | 303 | https://github.com/statnmap/squirrels.fusen/blob/main/dev/dev_history.Rmd 304 | 305 | ```{r function-1, echo=TRUE, eval=FALSE} 306 | #' Check data integrity 307 | #' 308 | #' @param x dataframe with at least columns "lat", "long" and "primary_fur_color" 309 | #' 310 | #' @return Original dataframe if all tests are good. Otherwise stops. 311 | #' @export 312 | check_data_integrity <- function(x) { 313 | # Verify points are in New York around Central Park 314 | all_coords_ok <- all( 315 | c( 316 | min(x[["lat"]]) > 40.76400, 317 | max(x[["lat"]]) < 40.80100, 318 | min(x[["long"]]) > -73.98300, 319 | max(x[["long"]]) < -73.94735 320 | ) 321 | ) 322 | if (!all_coords_ok) {stop("Not all data are in Central Park")} 323 | 324 | # Verify there is only one color in primary_fur_color. 325 | # A `+` in the column is a sign of multiple colours 326 | if (any(grepl("+", x[["primary_fur_color"]], fixed = TRUE))) { 327 | stop("There are multiple colors in some 'primary_fur_color'") 328 | } 329 | 330 | message("All tests are good !") 331 | } 332 | ``` 333 | 334 | ```{r examples-1, echo=TRUE, eval=FALSE} 335 | # A working example 336 | my_data_example <- data.frame( 337 | lat = c(40.77, 40.78), 338 | long = c(-73.95, -73.96), 339 | primary_fur_color = c("grey", "black") 340 | ) 341 | check_data_integrity(my_data_example) 342 | ``` 343 | -------------------------------------------------------------------------------- /courses/C13-git_fusen.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Versioning a {fusen} package with git" 3 | subtitle: "And the particular case of {fusen}?" 4 | code: "M13S02C13" 5 | output: formation::chapitre 6 | prerequis: [""] 7 | obj_ped: "Know how to version a {fusen} package" 8 | slug: versionner-fusen-git-en 9 | --- 10 | class: slide 11 | 12 | ## Version a {fusen} package 13 | 14 | 2 possibilities: 15 | 16 | - Your {fusen} package has not been created yet, and you want to set up the versioning before starting the developments 17 | 18 | - Your {fusen} package has already been created, and you now want to version it 19 | 20 | --- 21 | class: slide 22 | 23 | ## Versioning a {fusen} package 24 | 25 | #### Case of a new {fusen} package 26 | 27 | - Initialize the empty project on GitLab _(remembering to use the name of your future package as project name)_ 28 | 29 | - Get the `https` link to your project by clicking on the `clone` button 30 | 31 | - In RStudio, create the new project File > New Project > Version Control > git and link to the Repository URL 32 | 33 | Initiate your new {fusen} package: 34 | 35 | ```{r, eval=FALSE} 36 | fusen::create_fusen(path = ".", 37 | template = "minimal", 38 | overwrite = TRUE) 39 | ``` 40 | 41 | --- 42 | class: slide 43 | 44 | ## Versioning a {fusen} package 45 | 46 | #### Case of a new {fusen} package 47 | 48 | In the *Terminal*, 49 | 50 | + Switch in a new _main_ branch: 51 | 52 | ```{bash eval=FALSE} 53 | git switch -c main 54 | ``` 55 | 56 | + Select modified files in your project: 57 | 58 | ```{bash eval=FALSE} 59 | git add . 60 | ``` 61 | 62 | + Write a commit (with an explicit message): 63 | 64 | ```{bash eval=FALSE} 65 | git commit -m "Init fusen package" 66 | ``` 67 | 68 | + Push your changes back to the remote: 69 | 70 | ```{bash eval=FALSE} 71 | git push -u origin main 72 | ``` 73 | 74 | You can now begin your developments. 75 | 76 | --- 77 | class: slide 78 | 79 | ## Versioning a {fusen} package 80 | 81 | #### Case of an existing {fusen} package 82 | 83 | > This procedure can be used for any type of R project, and therefore for any type of package (not only {fusen} packages) 84 | 85 | -- 86 | 87 | - Initialize the empty project on GitLab _(remembering to use the name of your package as project name)_ 88 | 89 | - Retrieve the `https` link to your project by clicking on the `clone` button 90 | 91 | - Open the RStudio project and run the command `usethis::use_git()` in the console _(the {usethis} package must be installed)_ 92 | 93 | - Answer yes to all the questions asked in the console, if relevant. A first "Initial Commit" is done for you. 94 | 95 | - RStudio restarts and git is operational locally 96 | 97 | ??? 98 | 99 | ATTENTION 100 | Si vous modifiez cette slide, modifiez aussi M14S01C06 pour git1jour 101 | 102 | --- 103 | class: slide 104 | 105 | ## Versioning a {fusen} package 106 | 107 | #### Case of an existing {fusen} package 108 | 109 | Now you have to link this project to your **`remote`**: 110 | 111 | ```{r eval=FALSE} 112 | usethis::use_git_remote("origin", 113 | url = "https://gitlab.com/my_name/mypackage.git", 114 | overwrite = TRUE) 115 | ``` 116 | 117 | In the *Terminal*, type: 118 | 119 | ``` 120 | git push -u origin main 121 | ``` 122 | 123 | You just added a **`remote`** and made a first **`push`** on the **`main`** branch. 124 | 125 | ??? 126 | 127 | ATTENTION 128 | Si vous modifiez cette slide, modifiez aussi M14S01C06 pour git1jour 129 | 130 | --- 131 | class: slide 132 | 133 | ## Exercise 134 | 135 | Set up the _git_ versioning for your `{hello}` package 136 | -------------------------------------------------------------------------------- /courses/C14-data-analyses-packages.en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "What about data analyses in a package?" 3 | subtitle: "From Rmd to package to Rmd" 4 | code: "" 5 | prerequis: [""] 6 | output: formation::chapitre 7 | obj_pred: ["use packages for data analyses"] 8 | slug: data-analyses-packages 9 | --- 10 | class: slide 11 | 12 | ## Create shareable reports through packages 13 | 14 | ### Create a package with your functions 15 | 16 | Then, two possible ways to build your analysis reports: 17 | 18 | - Classical package: Use external projects to use your package functions in Rmd reports 19 | - Compendium-like: Include the Rmd reports inside the package development project 20 | 21 | --- 22 | class: slide 23 | 24 | ## A Compendium is like a package 25 | 26 | The compendium logic is to separate code from the report output: 27 | 28 | - One place to store your R scripts in "R/" 29 | - One place to store the Rmarkdown report in "analyses/" 30 | 31 | This is similar to package logic: 32 | 33 | - One place to store R scripts in "R/" 34 | - One place to store Rmarkdown examples of use in "vignettes/" 35 | 36 | ### Let's combine both worlds to benefit from robustness of packages 37 | 38 | --- 39 | class: slide 40 | 41 | ## Combine {fusen} and Compendium structure 42 | 43 | - Create a {fusen} project, versioned with git 44 | 45 | ```{r, eval=FALSE} 46 | # install.packages("fusen") 47 | fusen::create_fusen(template = "full", with_git = TRUE) 48 | ``` 49 | 50 | - Add a "reports/" directory that will not interfer with the package 51 | 52 | ```{r, eval=FALSE} 53 | dir.create("reports") 54 | usethis::use_build_ignore("reports") 55 | ``` 56 | 57 | 58 | _Note: you can add the Compendium structure in the "reports/" sub-directory, with package {rcompendium}_ 59 | 60 | ```{r, eval=FALSE} 61 | # install.packages("rcompendium") 62 | rcompendium::add_compendium("reports") 63 | ``` 64 | 65 | --- 66 | class: slide 67 | 68 | ## Combine {fusen} and Compendium structure 69 | 70 | - Add a reduced dataset for the package in "inst/" or "data/" 71 | + Use it for examples, unit tests, documentation 72 | 73 | 74 | - Build your functions in a "flat" file, like any {fusen} package 75 | + Write the content of the vignette as a reduced version of your future report 76 | + Create examples, unit tests, documentation as usual 77 | + Commit regularly 78 | 79 | 80 | - Use the "reports/" directory to store your reports and outputs, while using the functions of your package 81 | + Create a Rmarkdown report using your functions loaded with `library(my.package)` 82 | + Do not forget to install your package prior to building your report 83 | 84 | --- 85 | class: slide 86 | 87 | ## Why would I include my analysis inside my package? 88 | 89 | **Because of:** 90 | 91 | - {rim}: manage R versions 92 | - {renv}: manage R packages versions 93 | - and Docker: manage OS and system dependencies 94 | 95 | --- 96 | class: slide 97 | 98 | ## Why would I include my analysis inside my package? 99 | 100 | - Develop your project in a controled environment, with fixed versions of packages 101 | - Functions, tests and examples are valid for a specific set of packages versions with a specific R version 102 | - Use your functions for your analysis reports with the same working environment 103 | - Use `attachment::create_renv_for_dev()` (>=0.2.5) to build your "renv.lock" file 104 | 105 | - Allow other users to create their analyses in the same environment, by cloning your repository 106 | + Share your work with the world, without bothering about their R installation 107 | 108 | - You can build a Docker container to also fix system dependencies when using your package. {dockerfiler} can help you to set up the container. 109 | 110 | --- 111 | class: slide 112 | 113 | ## Share your work 114 | 115 | - Build and publish your {pkgdown} website to present how to use your package 116 | 117 | ```{r, eval=FALSE} 118 | # Have a proper Readme - Fill and knit 119 | usethis::use_readme_rmd() 120 | 121 | # Allow {pkgdown} 122 | usethis::use_pkgdown() 123 | 124 | # Try it locally 125 | pkgdown::build_site() 126 | 127 | # GitHub 128 | # Add your credentials for GitHub 129 | gitcreds::gitcreds_set() 130 | # Send your project to a new GitHub project 131 | usethis::use_github() 132 | 133 | # Build and publish with GitHub Actions 134 | usethis::use_github_action("pkgdown") 135 | 136 | # Build and publish on GitLab 137 | gitlabr::use_gitlab_ci() 138 | ``` 139 | 140 | -------------------------------------------------------------------------------- /courses/images/00_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/00_connection.png -------------------------------------------------------------------------------- /courses/images/01_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/01_home.png -------------------------------------------------------------------------------- /courses/images/02_chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/02_chapters.png -------------------------------------------------------------------------------- /courses/images/03_launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/03_launch.png -------------------------------------------------------------------------------- /courses/images/04_separator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/04_separator.png -------------------------------------------------------------------------------- /courses/images/05_slides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/05_slides.png -------------------------------------------------------------------------------- /courses/images/05_slides_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/05_slides_overview.png -------------------------------------------------------------------------------- /courses/images/06_rstudio_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/06_rstudio_right.png -------------------------------------------------------------------------------- /courses/images/07_export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/07_export.png -------------------------------------------------------------------------------- /courses/images/08_back_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/08_back_home.png -------------------------------------------------------------------------------- /courses/images/09_back_courses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/09_back_courses.png -------------------------------------------------------------------------------- /courses/images/10_rstudio_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/10_rstudio_full.png -------------------------------------------------------------------------------- /courses/images/11_go_to_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/11_go_to_chat.png -------------------------------------------------------------------------------- /courses/images/12_rocket_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/12_rocket_chat.png -------------------------------------------------------------------------------- /courses/images/13_resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/13_resources.png -------------------------------------------------------------------------------- /courses/images/14_disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/14_disconnect.png -------------------------------------------------------------------------------- /courses/images/almost-package-no-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/almost-package-no-data.png -------------------------------------------------------------------------------- /courses/images/baka_courses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_courses.png -------------------------------------------------------------------------------- /courses/images/baka_courses_launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_courses_launch.png -------------------------------------------------------------------------------- /courses/images/baka_export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_export.png -------------------------------------------------------------------------------- /courses/images/baka_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_login.png -------------------------------------------------------------------------------- /courses/images/baka_rstudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_rstudio.png -------------------------------------------------------------------------------- /courses/images/baka_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_search.png -------------------------------------------------------------------------------- /courses/images/baka_search_slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_search_slide.png -------------------------------------------------------------------------------- /courses/images/baka_sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_sessions.png -------------------------------------------------------------------------------- /courses/images/baka_toc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/baka_toc.png -------------------------------------------------------------------------------- /courses/images/bakacode_long_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/bakacode_long_3.png -------------------------------------------------------------------------------- /courses/images/cruz_classic_fondnoir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/cruz_classic_fondnoir.png -------------------------------------------------------------------------------- /courses/images/exemple_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/exemple_test.png -------------------------------------------------------------------------------- /courses/images/flat_minimal_skeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/flat_minimal_skeleton.png -------------------------------------------------------------------------------- /courses/images/fusen-write-package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen-write-package.png -------------------------------------------------------------------------------- /courses/images/fusen_description_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_description_file.png -------------------------------------------------------------------------------- /courses/images/fusen_fold_inflate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_fold_inflate.png -------------------------------------------------------------------------------- /courses/images/fusen_inflate_functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_inflate_functions.png -------------------------------------------------------------------------------- /courses/images/fusen_inflate_vignette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_inflate_vignette.png -------------------------------------------------------------------------------- /courses/images/fusen_mytools_complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_mytools_complete.png -------------------------------------------------------------------------------- /courses/images/fusen_new_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_new_project.png -------------------------------------------------------------------------------- /courses/images/fusen_rmd_folds_pkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_rmd_folds_pkg.png -------------------------------------------------------------------------------- /courses/images/fusen_skeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_skeleton.png -------------------------------------------------------------------------------- /courses/images/fusen_skeleton_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_skeleton_desc.png -------------------------------------------------------------------------------- /courses/images/fusen_skeleton_fun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_skeleton_fun.png -------------------------------------------------------------------------------- /courses/images/fusen_start_hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/fusen_start_hello.png -------------------------------------------------------------------------------- /courses/images/marmot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/marmot.png -------------------------------------------------------------------------------- /courses/images/new_package_fusen_minimal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/new_package_fusen_minimal.png -------------------------------------------------------------------------------- /courses/images/new_package_fusen_teaching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/new_package_fusen_teaching.png -------------------------------------------------------------------------------- /courses/images/packages-move-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/packages-move-function.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_badges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_badges.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_cran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_cran.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_doc_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_doc_function.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_examples.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_index.png -------------------------------------------------------------------------------- /courses/images/pkg_attachment_vignette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/pkg_attachment_vignette.png -------------------------------------------------------------------------------- /courses/images/present_zoom.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/present_zoom.en.png -------------------------------------------------------------------------------- /courses/images/squirrels_inflated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/squirrels_inflated.png -------------------------------------------------------------------------------- /courses/images/squirrels_pkgdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/squirrels_pkgdown.png -------------------------------------------------------------------------------- /courses/images/squirrels_rmd_html_snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/squirrels_rmd_html_snapshot.png -------------------------------------------------------------------------------- /courses/images/vignette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/vignette.png -------------------------------------------------------------------------------- /courses/images/vignette2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/vignette2.png -------------------------------------------------------------------------------- /courses/images/zoom_aide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/courses/images/zoom_aide.png -------------------------------------------------------------------------------- /courses/quizz.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quizz" 3 | author: "Sébastien Rochette" 4 | date: "29/04/2021" 5 | output: html_document 6 | --- 7 | 8 | ```{r setup, include=FALSE} 9 | knitr::opts_chunk$set(echo = TRUE) 10 | ``` 11 | 12 | **Write additionnal quizz here, ready for Slack poll ?** 13 | 14 | ## Quizz 15 | 16 | Diapo 41: 17 | 18 | /poll "What is a vignette?" "A: A website somewhere on Internet" "B: A Sticker you can add on your laptop" "C: A R script with the help of function accessible in the installed package" "D: A html page built from a Rmd file, accessible in the installed package" 19 | 20 | 21 | Diapo 42: 22 | 23 | /poll "Have you already built a package with all these?" "A: Yes, everything. Functions, examples, tests, vignettes" "B: Only part of documentation. Functions, examples, maybe vignettes" "C: Only functions in a R/ directory" "D: No. I never built a package from scratch" 24 | 25 | 26 | Diapo 68: 27 | 28 | /poll "What is the correct order for documentation to be correclty associate to files and folders?" "a: ACBDE" "b: EDCBA" "c: EABCD" "d: BAECD" 29 | 30 | Diapo 87: 31 | 32 | /poll "How to test what is supposed to fail?" "A : expect_equal()" "B : expect_false()" "C : expect_error()" "D : expect_warning()" 33 | 34 | Diapo 98: 35 | 36 | /poll "If I want to provide a dataset to the user in any format I want, where do I store it?" "A: extdata/" "B: inst/" "C: data/" "D: data-raw/" 37 | 38 | -------------------------------------------------------------------------------- /dev_history.R: -------------------------------------------------------------------------------- 1 | usethis::use_git_ignore("*.html") 2 | usethis::use_git_ignore("*.md") 3 | usethis::use_git_ignore("!README.md") 4 | usethis::use_git_ignore("*_files/") 5 | usethis::use_git_ignore("token.txt") 6 | 7 | # Manage PR 8 | usethis::pr_fetch(1) 9 | usethis::pr_push() 10 | 11 | # Set {renv} 12 | renv::init() 13 | renv::install("git2r") 14 | renv::install("remotes") 15 | options(remotes.git_credentials = git2r::cred_user_pass("gitlab-ci-token", Sys.getenv("FORGE_THINKR_TOKEN"))) 16 | options(renv.auth.formation = list(GIT_PAT = Sys.getenv("FORGE_THINKR_TOKEN"))) 17 | renv::install("git::https://forge.thinkr.fr/thinkr/thinkrverse/formation") 18 | remotes::install_git("https://forge.thinkr.fr/thinkr/thinkrverse/formation", upgrade = FALSE, git = "git2r") 19 | 20 | tmpform <- tempfile(pattern = "form-") 21 | git2r::clone("https://forge.thinkr.fr/thinkr/thinkrverse/formation", local_path = tmpform, 22 | credentials = git2r::cred_user_pass("gitlab-ci-token", Sys.getenv("GITLAB_THINKR_TOKEN"))) 23 | # credentials = git2r::cred_user_pass("gitlab-ci-token", Sys.getenv("GIT_TOKEN"))) 24 | remotes::install_local(path = tmpform, upgrade = FALSE, force = TRUE) 25 | 26 | # fusen 27 | remotes::install_github("ThinkR-open/fusen") 28 | 29 | # Description 30 | # _Get all deps to run courses, except old ones -- SUGGESTS -- 31 | all_courses <- list.files(here::here("courses"), full.names = TRUE, pattern = "[.]Rmd", recursive = TRUE) 32 | all_deps_courses <- attachment::att_from_rmds(all_courses) 33 | # _Get all deps to run templates_sc -- IMPORTS -- 34 | all_compil_to_test <- "compile_course.R" 35 | # Extract all deps 36 | all_deps_compils <- attachment::att_from_rscripts(all_compil_to_test) 37 | 38 | supplements_imports <- c("git2r", "attachment", "testthat", "here", "flextable", 39 | "remotes") 40 | 41 | all_imports <- unique(c(supplements_imports, all_deps_courses)) 42 | all_imports <- all_imports[!all_imports == "formation"] 43 | all_deps_compils <- all_deps_compils[!all_deps_compils == "formation"] 44 | # Add to DESCRIPTION 45 | # usethis::use_description() 46 | attachment::att_to_desc_from_is( 47 | imports = all_imports, 48 | suggests = all_deps_compils 49 | ) 50 | 51 | custom_packages <- c( 52 | attachment::att_from_description(), 53 | "renv"#, 54 | # "devtools", "roxygen2", "usethis", "pkgload", 55 | # "testthat", "covr", "attachment", 56 | # remotes::install_github("ThinkR-open/checkhelper") 57 | # "pkgdown", "styler", "checkhelper" 58 | ) 59 | renv::snapshot(packages = custom_packages) 60 | 61 | 62 | 63 | # Snapshot before push 64 | options(repos = c("CRAN" = "https://packagemanager.rstudio.com/all/__linux__/focal/latest")) 65 | renv::snapshot() 66 | 67 | # Restore after pull 68 | renv::restore() 69 | 70 | # Set Actions 71 | usethis::use_github_action("render-rmarkdown") 72 | # Move course 73 | dir.create("public") 74 | file.copy("les_cours/complet/support", "public", recursive = TRUE) 75 | writeLines("!*.html\n!*.pdf\n!*_files/", "public/support/.gitignore") 76 | -------------------------------------------------------------------------------- /img/00_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/00_connection.png -------------------------------------------------------------------------------- /img/01_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/01_home.png -------------------------------------------------------------------------------- /img/02_chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/02_chapters.png -------------------------------------------------------------------------------- /img/03_launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/03_launch.png -------------------------------------------------------------------------------- /img/04_separator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/04_separator.png -------------------------------------------------------------------------------- /img/05_slides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/05_slides.png -------------------------------------------------------------------------------- /img/05_slides_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/05_slides_overview.png -------------------------------------------------------------------------------- /img/06_rstudio_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/06_rstudio_right.png -------------------------------------------------------------------------------- /img/07_export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/07_export.png -------------------------------------------------------------------------------- /img/08_back_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/08_back_home.png -------------------------------------------------------------------------------- /img/09_back_courses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/09_back_courses.png -------------------------------------------------------------------------------- /img/10_rstudio_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/10_rstudio_full.png -------------------------------------------------------------------------------- /img/11_go_to_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/11_go_to_chat.png -------------------------------------------------------------------------------- /img/12_rocket_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/12_rocket_chat.png -------------------------------------------------------------------------------- /img/13_resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/13_resources.png -------------------------------------------------------------------------------- /img/14_disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/14_disconnect.png -------------------------------------------------------------------------------- /img/cruz_classic_fondnoir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/cruz_classic_fondnoir.png -------------------------------------------------------------------------------- /img/present_zoom.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/statnmap/teach-package-dev-rmdfirst/1d0cc38057a0f6f4f073f075ce220a681892d267/img/present_zoom.en.png -------------------------------------------------------------------------------- /renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.2.0", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://packagemanager.rstudio.com/all/latest" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "BH": { 13 | "Package": "BH", 14 | "Version": "1.78.0-0", 15 | "Source": "Repository", 16 | "Repository": "RSPM", 17 | "Hash": "4e348572ffcaa2fb1e610e7a941f6f3a", 18 | "Requirements": [] 19 | }, 20 | "DBI": { 21 | "Package": "DBI", 22 | "Version": "1.1.2", 23 | "Source": "Repository", 24 | "Repository": "RSPM", 25 | "Hash": "dcd1743af4336156873e3ce3c950b8b9", 26 | "Requirements": [] 27 | }, 28 | "MASS": { 29 | "Package": "MASS", 30 | "Version": "7.3-57", 31 | "Source": "Repository", 32 | "Repository": "CRAN", 33 | "Hash": "71476c1d88d1ebdf31580e5a257d5d31", 34 | "Requirements": [] 35 | }, 36 | "Matrix": { 37 | "Package": "Matrix", 38 | "Version": "1.4-1", 39 | "Source": "Repository", 40 | "Repository": "CRAN", 41 | "Hash": "699c47c606293bdfbc9fd78a93c9c8fe", 42 | "Requirements": [ 43 | "lattice" 44 | ] 45 | }, 46 | "R6": { 47 | "Package": "R6", 48 | "Version": "2.5.1", 49 | "Source": "Repository", 50 | "Repository": "RSPM", 51 | "Hash": "470851b6d5d0ac559e9d01bb352b4021", 52 | "Requirements": [] 53 | }, 54 | "RColorBrewer": { 55 | "Package": "RColorBrewer", 56 | "Version": "1.1-3", 57 | "Source": "Repository", 58 | "Repository": "RSPM", 59 | "Hash": "45f0398006e83a5b10b72a90663d8d8c", 60 | "Requirements": [] 61 | }, 62 | "Rcpp": { 63 | "Package": "Rcpp", 64 | "Version": "1.0.8.3", 65 | "Source": "Repository", 66 | "Repository": "RSPM", 67 | "Hash": "32e79b908fda56ee57fe518a8d37b864", 68 | "Requirements": [] 69 | }, 70 | "askpass": { 71 | "Package": "askpass", 72 | "Version": "1.1", 73 | "Source": "Repository", 74 | "Repository": "RSPM", 75 | "Hash": "e8a22846fff485f0be3770c2da758713", 76 | "Requirements": [ 77 | "sys" 78 | ] 79 | }, 80 | "assertthat": { 81 | "Package": "assertthat", 82 | "Version": "0.2.1", 83 | "Source": "Repository", 84 | "Repository": "CRAN", 85 | "Hash": "50c838a310445e954bc13f26f26a6ecf", 86 | "Requirements": [] 87 | }, 88 | "attachment": { 89 | "Package": "attachment", 90 | "Version": "0.2.4", 91 | "Source": "CRAN", 92 | "Repository": "RSPM", 93 | "RemoteType": "standard", 94 | "RemotePkgRef": "attachment", 95 | "RemoteRef": "attachment", 96 | "RemoteRepos": "https://packagemanager.rstudio.com/cran/__linux__/bionic/2021-12-14", 97 | "RemotePkgPlatform": "source", 98 | "RemoteSha": "0.2.4", 99 | "Hash": "c30d6fbe723eec254196ac30cf8776d1", 100 | "Requirements": [ 101 | "desc", 102 | "glue", 103 | "knitr", 104 | "magrittr", 105 | "rmarkdown", 106 | "roxygen2", 107 | "stringr" 108 | ] 109 | }, 110 | "backports": { 111 | "Package": "backports", 112 | "Version": "1.4.1", 113 | "Source": "Repository", 114 | "Repository": "RSPM", 115 | "Hash": "c39fbec8a30d23e721980b8afb31984c", 116 | "Requirements": [] 117 | }, 118 | "base64enc": { 119 | "Package": "base64enc", 120 | "Version": "0.1-3", 121 | "Source": "Repository", 122 | "Repository": "RSPM", 123 | "Hash": "543776ae6848fde2f48ff3816d0628bc", 124 | "Requirements": [] 125 | }, 126 | "bit": { 127 | "Package": "bit", 128 | "Version": "4.0.4", 129 | "Source": "Repository", 130 | "Repository": "RSPM", 131 | "Hash": "f36715f14d94678eea9933af927bc15d", 132 | "Requirements": [] 133 | }, 134 | "bit64": { 135 | "Package": "bit64", 136 | "Version": "4.0.5", 137 | "Source": "Repository", 138 | "Repository": "RSPM", 139 | "Hash": "9fe98599ca456d6552421db0d6772d8f", 140 | "Requirements": [ 141 | "bit" 142 | ] 143 | }, 144 | "blob": { 145 | "Package": "blob", 146 | "Version": "1.2.3", 147 | "Source": "Repository", 148 | "Repository": "RSPM", 149 | "Hash": "10d231579bc9c06ab1c320618808d4ff", 150 | "Requirements": [ 151 | "rlang", 152 | "vctrs" 153 | ] 154 | }, 155 | "brew": { 156 | "Package": "brew", 157 | "Version": "1.0-7", 158 | "Source": "Repository", 159 | "Repository": "RSPM", 160 | "Hash": "38875ea52350ff4b4c03849fc69736c8", 161 | "Requirements": [] 162 | }, 163 | "brio": { 164 | "Package": "brio", 165 | "Version": "1.1.3", 166 | "Source": "Repository", 167 | "Repository": "RSPM", 168 | "Hash": "976cf154dfb043c012d87cddd8bca363", 169 | "Requirements": [] 170 | }, 171 | "broom": { 172 | "Package": "broom", 173 | "Version": "0.8.0", 174 | "Source": "Repository", 175 | "Repository": "RSPM", 176 | "Hash": "fe13cb670e14da57fd7a466578db8ce5", 177 | "Requirements": [ 178 | "backports", 179 | "dplyr", 180 | "ellipsis", 181 | "generics", 182 | "ggplot2", 183 | "glue", 184 | "purrr", 185 | "rlang", 186 | "stringr", 187 | "tibble", 188 | "tidyr" 189 | ] 190 | }, 191 | "bslib": { 192 | "Package": "bslib", 193 | "Version": "0.3.1", 194 | "Source": "Repository", 195 | "Repository": "RSPM", 196 | "Hash": "56ae7e1987b340186a8a5a157c2ec358", 197 | "Requirements": [ 198 | "htmltools", 199 | "jquerylib", 200 | "jsonlite", 201 | "rlang", 202 | "sass" 203 | ] 204 | }, 205 | "cachem": { 206 | "Package": "cachem", 207 | "Version": "1.0.6", 208 | "Source": "Repository", 209 | "Repository": "RSPM", 210 | "Hash": "648c5b3d71e6a37e3043617489a0a0e9", 211 | "Requirements": [ 212 | "fastmap", 213 | "rlang" 214 | ] 215 | }, 216 | "callr": { 217 | "Package": "callr", 218 | "Version": "3.7.0", 219 | "Source": "Repository", 220 | "Repository": "RSPM", 221 | "Hash": "461aa75a11ce2400245190ef5d3995df", 222 | "Requirements": [ 223 | "R6", 224 | "processx" 225 | ] 226 | }, 227 | "cellranger": { 228 | "Package": "cellranger", 229 | "Version": "1.1.0", 230 | "Source": "Repository", 231 | "Repository": "RSPM", 232 | "Hash": "f61dbaec772ccd2e17705c1e872e9e7c", 233 | "Requirements": [ 234 | "rematch", 235 | "tibble" 236 | ] 237 | }, 238 | "checkmate": { 239 | "Package": "checkmate", 240 | "Version": "2.1.0", 241 | "Source": "Repository", 242 | "Repository": "RSPM", 243 | "Hash": "147e4db6909d8814bb30f671b49d7e06", 244 | "Requirements": [ 245 | "backports" 246 | ] 247 | }, 248 | "cli": { 249 | "Package": "cli", 250 | "Version": "3.3.0", 251 | "Source": "Repository", 252 | "Repository": "RSPM", 253 | "Hash": "23abf173c2b783dcc43379ab9bba00ee", 254 | "Requirements": [ 255 | "glue" 256 | ] 257 | }, 258 | "clipr": { 259 | "Package": "clipr", 260 | "Version": "0.8.0", 261 | "Source": "Repository", 262 | "Repository": "RSPM", 263 | "Hash": "3f038e5ac7f41d4ac41ce658c85e3042", 264 | "Requirements": [] 265 | }, 266 | "codetools": { 267 | "Package": "codetools", 268 | "Version": "0.2-18", 269 | "Source": "Repository", 270 | "Repository": "CRAN", 271 | "Hash": "019388fc48e48b3da0d3a76ff94608a8", 272 | "Requirements": [] 273 | }, 274 | "colorspace": { 275 | "Package": "colorspace", 276 | "Version": "2.0-3", 277 | "Source": "CRAN", 278 | "Repository": "RSPM", 279 | "RemoteType": "standard", 280 | "RemotePkgRef": "colorspace", 281 | "RemoteRef": "colorspace", 282 | "RemoteRepos": "https://packagemanager.rstudio.com/all/__linux__/focal/latest", 283 | "RemotePkgPlatform": "source", 284 | "RemoteSha": "2.0-3", 285 | "Hash": "bb4341986bc8b914f0f0acf2e4a3f2f7", 286 | "Requirements": [] 287 | }, 288 | "commonmark": { 289 | "Package": "commonmark", 290 | "Version": "1.8.0", 291 | "Source": "Repository", 292 | "Repository": "RSPM", 293 | "Hash": "2ba81b120c1655ab696c935ef33ea716", 294 | "Requirements": [] 295 | }, 296 | "cpp11": { 297 | "Package": "cpp11", 298 | "Version": "0.4.2", 299 | "Source": "Repository", 300 | "Repository": "RSPM", 301 | "Hash": "fa53ce256cd280f468c080a58ea5ba8c", 302 | "Requirements": [] 303 | }, 304 | "crayon": { 305 | "Package": "crayon", 306 | "Version": "1.5.1", 307 | "Source": "Repository", 308 | "Repository": "RSPM", 309 | "Hash": "8dc45fd8a1ee067a92b85ef274e66d6a", 310 | "Requirements": [] 311 | }, 312 | "credentials": { 313 | "Package": "credentials", 314 | "Version": "1.3.2", 315 | "Source": "Repository", 316 | "Repository": "RSPM", 317 | "Hash": "93762d0a34d78e6a025efdbfb5c6bb41", 318 | "Requirements": [ 319 | "askpass", 320 | "curl", 321 | "jsonlite", 322 | "openssl", 323 | "sys" 324 | ] 325 | }, 326 | "curl": { 327 | "Package": "curl", 328 | "Version": "4.3.2", 329 | "Source": "Repository", 330 | "Repository": "RSPM", 331 | "Hash": "022c42d49c28e95d69ca60446dbabf88", 332 | "Requirements": [] 333 | }, 334 | "data.table": { 335 | "Package": "data.table", 336 | "Version": "1.14.2", 337 | "Source": "Repository", 338 | "Repository": "RSPM", 339 | "Hash": "36b67b5adf57b292923f5659f5f0c853", 340 | "Requirements": [] 341 | }, 342 | "dbplyr": { 343 | "Package": "dbplyr", 344 | "Version": "2.1.1", 345 | "Source": "Repository", 346 | "Repository": "RSPM", 347 | "Hash": "1f37fa4ab2f5f7eded42f78b9a887182", 348 | "Requirements": [ 349 | "DBI", 350 | "R6", 351 | "assertthat", 352 | "blob", 353 | "dplyr", 354 | "ellipsis", 355 | "glue", 356 | "lifecycle", 357 | "magrittr", 358 | "purrr", 359 | "rlang", 360 | "tibble", 361 | "tidyselect", 362 | "vctrs", 363 | "withr" 364 | ] 365 | }, 366 | "desc": { 367 | "Package": "desc", 368 | "Version": "1.4.1", 369 | "Source": "Repository", 370 | "Repository": "RSPM", 371 | "Hash": "eebd27ee58fcc58714eedb7aa07d8ad1", 372 | "Requirements": [ 373 | "R6", 374 | "cli", 375 | "rprojroot" 376 | ] 377 | }, 378 | "devtools": { 379 | "Package": "devtools", 380 | "Version": "2.4.3", 381 | "Source": "Repository", 382 | "Repository": "RSPM", 383 | "Hash": "fc35e13bb582e5fe6f63f3d647a4cbe5", 384 | "Requirements": [ 385 | "callr", 386 | "cli", 387 | "desc", 388 | "ellipsis", 389 | "fs", 390 | "httr", 391 | "lifecycle", 392 | "memoise", 393 | "pkgbuild", 394 | "pkgload", 395 | "rcmdcheck", 396 | "remotes", 397 | "rlang", 398 | "roxygen2", 399 | "rstudioapi", 400 | "rversions", 401 | "sessioninfo", 402 | "testthat", 403 | "usethis", 404 | "withr" 405 | ] 406 | }, 407 | "diffobj": { 408 | "Package": "diffobj", 409 | "Version": "0.3.5", 410 | "Source": "Repository", 411 | "Repository": "RSPM", 412 | "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8", 413 | "Requirements": [ 414 | "crayon" 415 | ] 416 | }, 417 | "digest": { 418 | "Package": "digest", 419 | "Version": "0.6.29", 420 | "Source": "Repository", 421 | "Repository": "RSPM", 422 | "Hash": "cf6b206a045a684728c3267ef7596190", 423 | "Requirements": [] 424 | }, 425 | "dplyr": { 426 | "Package": "dplyr", 427 | "Version": "1.0.9", 428 | "Source": "Repository", 429 | "Repository": "RSPM", 430 | "Hash": "f0bda1627a7f5d3f9a0b5add931596ac", 431 | "Requirements": [ 432 | "R6", 433 | "generics", 434 | "glue", 435 | "lifecycle", 436 | "magrittr", 437 | "pillar", 438 | "rlang", 439 | "tibble", 440 | "tidyselect", 441 | "vctrs" 442 | ] 443 | }, 444 | "dtplyr": { 445 | "Package": "dtplyr", 446 | "Version": "1.2.1", 447 | "Source": "Repository", 448 | "Repository": "RSPM", 449 | "Hash": "f5d195cd5fcc0a77499d9da698ef2ea3", 450 | "Requirements": [ 451 | "crayon", 452 | "data.table", 453 | "dplyr", 454 | "ellipsis", 455 | "glue", 456 | "lifecycle", 457 | "rlang", 458 | "tibble", 459 | "tidyselect", 460 | "vctrs" 461 | ] 462 | }, 463 | "ellipsis": { 464 | "Package": "ellipsis", 465 | "Version": "0.3.2", 466 | "Source": "Repository", 467 | "Repository": "RSPM", 468 | "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077", 469 | "Requirements": [ 470 | "rlang" 471 | ] 472 | }, 473 | "evaluate": { 474 | "Package": "evaluate", 475 | "Version": "0.15", 476 | "Source": "Repository", 477 | "Repository": "RSPM", 478 | "Hash": "699a7a93d08c962d9f8950b2d7a227f1", 479 | "Requirements": [] 480 | }, 481 | "fansi": { 482 | "Package": "fansi", 483 | "Version": "1.0.3", 484 | "Source": "Repository", 485 | "Repository": "RSPM", 486 | "Hash": "83a8afdbe71839506baa9f90eebad7ec", 487 | "Requirements": [] 488 | }, 489 | "farver": { 490 | "Package": "farver", 491 | "Version": "2.1.0", 492 | "Source": "Repository", 493 | "Repository": "RSPM", 494 | "Hash": "c98eb5133d9cb9e1622b8691487f11bb", 495 | "Requirements": [] 496 | }, 497 | "fastmap": { 498 | "Package": "fastmap", 499 | "Version": "1.1.0", 500 | "Source": "Repository", 501 | "Repository": "CRAN", 502 | "Hash": "77bd60a6157420d4ffa93b27cf6a58b8", 503 | "Requirements": [] 504 | }, 505 | "flextable": { 506 | "Package": "flextable", 507 | "Version": "0.7.0", 508 | "Source": "Repository", 509 | "Repository": "RSPM", 510 | "Hash": "c0ab683f6ee8b99be0e0cdce8ad53416", 511 | "Requirements": [ 512 | "base64enc", 513 | "data.table", 514 | "gdtools", 515 | "htmltools", 516 | "knitr", 517 | "officer", 518 | "rlang", 519 | "rmarkdown", 520 | "uuid", 521 | "xml2" 522 | ] 523 | }, 524 | "forcats": { 525 | "Package": "forcats", 526 | "Version": "0.5.1", 527 | "Source": "Repository", 528 | "Repository": "RSPM", 529 | "Hash": "81c3244cab67468aac4c60550832655d", 530 | "Requirements": [ 531 | "ellipsis", 532 | "magrittr", 533 | "rlang", 534 | "tibble" 535 | ] 536 | }, 537 | "fs": { 538 | "Package": "fs", 539 | "Version": "1.5.2", 540 | "Source": "Repository", 541 | "Repository": "RSPM", 542 | "Hash": "7c89603d81793f0d5486d91ab1fc6f1d", 543 | "Requirements": [] 544 | }, 545 | "fusen": { 546 | "Package": "fusen", 547 | "Version": "0.4.0", 548 | "Source": "Repository", 549 | "Repository": "RSPM", 550 | "Hash": "e29366df68d922c4d79605738596b2c1", 551 | "Requirements": [ 552 | "attachment", 553 | "cli", 554 | "desc", 555 | "devtools", 556 | "glue", 557 | "here", 558 | "magrittr", 559 | "parsermd", 560 | "roxygen2", 561 | "stringi", 562 | "tibble", 563 | "tidyr", 564 | "usethis" 565 | ] 566 | }, 567 | "future": { 568 | "Package": "future", 569 | "Version": "1.25.0", 570 | "Source": "Repository", 571 | "Repository": "RSPM", 572 | "Hash": "877024e372cf61e41f5d13eafd8d4bac", 573 | "Requirements": [ 574 | "digest", 575 | "globals", 576 | "listenv", 577 | "parallelly" 578 | ] 579 | }, 580 | "gargle": { 581 | "Package": "gargle", 582 | "Version": "1.2.0", 583 | "Source": "Repository", 584 | "Repository": "RSPM", 585 | "Hash": "9d234e6a87a6f8181792de6dc4a00e39", 586 | "Requirements": [ 587 | "cli", 588 | "fs", 589 | "glue", 590 | "httr", 591 | "jsonlite", 592 | "rappdirs", 593 | "rlang", 594 | "rstudioapi", 595 | "withr" 596 | ] 597 | }, 598 | "gdtools": { 599 | "Package": "gdtools", 600 | "Version": "0.2.4", 601 | "Source": "Repository", 602 | "Repository": "RSPM", 603 | "Hash": "bdfa7431687797edff8c9b0eb9271cc8", 604 | "Requirements": [ 605 | "Rcpp", 606 | "systemfonts" 607 | ] 608 | }, 609 | "generics": { 610 | "Package": "generics", 611 | "Version": "0.1.2", 612 | "Source": "Repository", 613 | "Repository": "RSPM", 614 | "Hash": "177475892cf4a55865868527654a7741", 615 | "Requirements": [] 616 | }, 617 | "gert": { 618 | "Package": "gert", 619 | "Version": "1.6.0", 620 | "Source": "Repository", 621 | "Repository": "RSPM", 622 | "Hash": "98c014c4c933f23ea5a0321a4d0b588b", 623 | "Requirements": [ 624 | "askpass", 625 | "credentials", 626 | "openssl", 627 | "rstudioapi", 628 | "sys", 629 | "zip" 630 | ] 631 | }, 632 | "ggplot2": { 633 | "Package": "ggplot2", 634 | "Version": "3.3.6", 635 | "Source": "CRAN", 636 | "Repository": "CRAN", 637 | "RemoteType": "standard", 638 | "RemotePkgRef": "ggplot2", 639 | "RemoteRef": "ggplot2", 640 | "RemoteRepos": "https://cran.rstudio.com", 641 | "RemotePkgPlatform": "source", 642 | "RemoteSha": "3.3.6", 643 | "Hash": "0fb26d0674c82705c6b701d1a61e02ea", 644 | "Requirements": [ 645 | "MASS", 646 | "digest", 647 | "glue", 648 | "gtable", 649 | "isoband", 650 | "mgcv", 651 | "rlang", 652 | "scales", 653 | "tibble", 654 | "withr" 655 | ] 656 | }, 657 | "gh": { 658 | "Package": "gh", 659 | "Version": "1.3.0", 660 | "Source": "Repository", 661 | "Repository": "RSPM", 662 | "Hash": "38c2580abbda249bd6afeec00d14f531", 663 | "Requirements": [ 664 | "cli", 665 | "gitcreds", 666 | "httr", 667 | "ini", 668 | "jsonlite" 669 | ] 670 | }, 671 | "git2r": { 672 | "Package": "git2r", 673 | "Version": "0.30.1", 674 | "Source": "Repository", 675 | "Repository": "RSPM", 676 | "Hash": "e0c6a04a3e7b90e64213d09128f74f1b", 677 | "Requirements": [] 678 | }, 679 | "gitcreds": { 680 | "Package": "gitcreds", 681 | "Version": "0.1.1", 682 | "Source": "Repository", 683 | "Repository": "CRAN", 684 | "Hash": "f3aefccc1cc50de6338146b62f115de8", 685 | "Requirements": [] 686 | }, 687 | "globals": { 688 | "Package": "globals", 689 | "Version": "0.15.0", 690 | "Source": "Repository", 691 | "Repository": "RSPM", 692 | "Hash": "ace993e2dad5e64ed46391302b79e94f", 693 | "Requirements": [ 694 | "codetools" 695 | ] 696 | }, 697 | "glue": { 698 | "Package": "glue", 699 | "Version": "1.6.2", 700 | "Source": "Repository", 701 | "Repository": "RSPM", 702 | "Hash": "4f2596dfb05dac67b9dc558e5c6fba2e", 703 | "Requirements": [] 704 | }, 705 | "googledrive": { 706 | "Package": "googledrive", 707 | "Version": "2.0.0", 708 | "Source": "Repository", 709 | "Repository": "RSPM", 710 | "Hash": "c3a25adbbfbb03f12e6f88c5fb1f3024", 711 | "Requirements": [ 712 | "cli", 713 | "gargle", 714 | "glue", 715 | "httr", 716 | "jsonlite", 717 | "lifecycle", 718 | "magrittr", 719 | "pillar", 720 | "purrr", 721 | "rlang", 722 | "tibble", 723 | "uuid", 724 | "vctrs", 725 | "withr" 726 | ] 727 | }, 728 | "googlesheets4": { 729 | "Package": "googlesheets4", 730 | "Version": "1.0.0", 731 | "Source": "Repository", 732 | "Repository": "RSPM", 733 | "Hash": "9a6564184dc4a81daea4f1d7ce357c6a", 734 | "Requirements": [ 735 | "cellranger", 736 | "cli", 737 | "curl", 738 | "gargle", 739 | "glue", 740 | "googledrive", 741 | "httr", 742 | "ids", 743 | "magrittr", 744 | "purrr", 745 | "rematch2", 746 | "rlang", 747 | "tibble", 748 | "vctrs" 749 | ] 750 | }, 751 | "gtable": { 752 | "Package": "gtable", 753 | "Version": "0.3.0", 754 | "Source": "Repository", 755 | "Repository": "CRAN", 756 | "Hash": "ac5c6baf7822ce8732b343f14c072c4d", 757 | "Requirements": [] 758 | }, 759 | "haven": { 760 | "Package": "haven", 761 | "Version": "2.5.0", 762 | "Source": "Repository", 763 | "Repository": "RSPM", 764 | "Hash": "e3058e4ac77f4fa686f68a1838d5b715", 765 | "Requirements": [ 766 | "cli", 767 | "cpp11", 768 | "forcats", 769 | "hms", 770 | "lifecycle", 771 | "readr", 772 | "rlang", 773 | "tibble", 774 | "tidyselect", 775 | "vctrs" 776 | ] 777 | }, 778 | "here": { 779 | "Package": "here", 780 | "Version": "1.0.1", 781 | "Source": "Repository", 782 | "Repository": "RSPM", 783 | "Hash": "24b224366f9c2e7534d2344d10d59211", 784 | "Requirements": [ 785 | "rprojroot" 786 | ] 787 | }, 788 | "highr": { 789 | "Package": "highr", 790 | "Version": "0.9", 791 | "Source": "Repository", 792 | "Repository": "RSPM", 793 | "Hash": "8eb36c8125038e648e5d111c0d7b2ed4", 794 | "Requirements": [ 795 | "xfun" 796 | ] 797 | }, 798 | "hms": { 799 | "Package": "hms", 800 | "Version": "1.1.1", 801 | "Source": "Repository", 802 | "Repository": "RSPM", 803 | "Hash": "5b8a2dd0fdbe2ab4f6081e6c7be6dfca", 804 | "Requirements": [ 805 | "ellipsis", 806 | "lifecycle", 807 | "pkgconfig", 808 | "rlang", 809 | "vctrs" 810 | ] 811 | }, 812 | "htmltools": { 813 | "Package": "htmltools", 814 | "Version": "0.5.2", 815 | "Source": "Repository", 816 | "Repository": "RSPM", 817 | "Hash": "526c484233f42522278ab06fb185cb26", 818 | "Requirements": [ 819 | "base64enc", 820 | "digest", 821 | "fastmap", 822 | "rlang" 823 | ] 824 | }, 825 | "httpuv": { 826 | "Package": "httpuv", 827 | "Version": "1.6.5", 828 | "Source": "Repository", 829 | "Repository": "RSPM", 830 | "Hash": "97fe71f0a4a1c9890e6c2128afa04bc0", 831 | "Requirements": [ 832 | "R6", 833 | "Rcpp", 834 | "later", 835 | "promises" 836 | ] 837 | }, 838 | "httr": { 839 | "Package": "httr", 840 | "Version": "1.4.3", 841 | "Source": "Repository", 842 | "Repository": "RSPM", 843 | "Hash": "88d1b310583777edf01ccd1216fb0b2b", 844 | "Requirements": [ 845 | "R6", 846 | "curl", 847 | "jsonlite", 848 | "mime", 849 | "openssl" 850 | ] 851 | }, 852 | "ids": { 853 | "Package": "ids", 854 | "Version": "1.0.1", 855 | "Source": "Repository", 856 | "Repository": "RSPM", 857 | "Hash": "99df65cfef20e525ed38c3d2577f7190", 858 | "Requirements": [ 859 | "openssl", 860 | "uuid" 861 | ] 862 | }, 863 | "ini": { 864 | "Package": "ini", 865 | "Version": "0.3.1", 866 | "Source": "Repository", 867 | "Repository": "RSPM", 868 | "Hash": "6154ec2223172bce8162d4153cda21f7", 869 | "Requirements": [] 870 | }, 871 | "isoband": { 872 | "Package": "isoband", 873 | "Version": "0.2.5", 874 | "Source": "Repository", 875 | "Repository": "RSPM", 876 | "Hash": "7ab57a6de7f48a8dc84910d1eca42883", 877 | "Requirements": [] 878 | }, 879 | "jquerylib": { 880 | "Package": "jquerylib", 881 | "Version": "0.1.4", 882 | "Source": "Repository", 883 | "Repository": "RSPM", 884 | "Hash": "5aab57a3bd297eee1c1d862735972182", 885 | "Requirements": [ 886 | "htmltools" 887 | ] 888 | }, 889 | "jsonlite": { 890 | "Package": "jsonlite", 891 | "Version": "1.8.0", 892 | "Source": "Repository", 893 | "Repository": "RSPM", 894 | "Hash": "d07e729b27b372429d42d24d503613a0", 895 | "Requirements": [] 896 | }, 897 | "knitr": { 898 | "Package": "knitr", 899 | "Version": "1.39", 900 | "Source": "Repository", 901 | "Repository": "RSPM", 902 | "Hash": "029ab7c4badd3cf8af69016b2ba27493", 903 | "Requirements": [ 904 | "evaluate", 905 | "highr", 906 | "stringr", 907 | "xfun", 908 | "yaml" 909 | ] 910 | }, 911 | "labeling": { 912 | "Package": "labeling", 913 | "Version": "0.4.2", 914 | "Source": "Repository", 915 | "Repository": "RSPM", 916 | "Hash": "3d5108641f47470611a32d0bdf357a72", 917 | "Requirements": [] 918 | }, 919 | "later": { 920 | "Package": "later", 921 | "Version": "1.3.0", 922 | "Source": "Repository", 923 | "Repository": "RSPM", 924 | "Hash": "7e7b457d7766bc47f2a5f21cc2984f8e", 925 | "Requirements": [ 926 | "Rcpp", 927 | "rlang" 928 | ] 929 | }, 930 | "lattice": { 931 | "Package": "lattice", 932 | "Version": "0.20-45", 933 | "Source": "Repository", 934 | "Repository": "CRAN", 935 | "Hash": "b64cdbb2b340437c4ee047a1f4c4377b", 936 | "Requirements": [] 937 | }, 938 | "lifecycle": { 939 | "Package": "lifecycle", 940 | "Version": "1.0.1", 941 | "Source": "Repository", 942 | "Repository": "RSPM", 943 | "Hash": "a6b6d352e3ed897373ab19d8395c98d0", 944 | "Requirements": [ 945 | "glue", 946 | "rlang" 947 | ] 948 | }, 949 | "listenv": { 950 | "Package": "listenv", 951 | "Version": "0.8.0", 952 | "Source": "Repository", 953 | "Repository": "RSPM", 954 | "Hash": "0bde42ee282efb18c7c4e63822f5b4f7", 955 | "Requirements": [] 956 | }, 957 | "lubridate": { 958 | "Package": "lubridate", 959 | "Version": "1.8.0", 960 | "Source": "Repository", 961 | "Repository": "RSPM", 962 | "Hash": "2ff5eedb6ee38fb1b81205c73be1be5a", 963 | "Requirements": [ 964 | "cpp11", 965 | "generics" 966 | ] 967 | }, 968 | "magrittr": { 969 | "Package": "magrittr", 970 | "Version": "2.0.3", 971 | "Source": "Repository", 972 | "Repository": "RSPM", 973 | "Hash": "7ce2733a9826b3aeb1775d56fd305472", 974 | "Requirements": [] 975 | }, 976 | "memoise": { 977 | "Package": "memoise", 978 | "Version": "2.0.1", 979 | "Source": "Repository", 980 | "Repository": "RSPM", 981 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c", 982 | "Requirements": [ 983 | "cachem", 984 | "rlang" 985 | ] 986 | }, 987 | "mgcv": { 988 | "Package": "mgcv", 989 | "Version": "1.8-40", 990 | "Source": "Repository", 991 | "Repository": "CRAN", 992 | "Hash": "c6b2fdb18cf68ab613bd564363e1ba0d", 993 | "Requirements": [ 994 | "Matrix", 995 | "nlme" 996 | ] 997 | }, 998 | "mime": { 999 | "Package": "mime", 1000 | "Version": "0.12", 1001 | "Source": "Repository", 1002 | "Repository": "RSPM", 1003 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104", 1004 | "Requirements": [] 1005 | }, 1006 | "modelr": { 1007 | "Package": "modelr", 1008 | "Version": "0.1.8", 1009 | "Source": "Repository", 1010 | "Repository": "RSPM", 1011 | "Hash": "9fd59716311ee82cba83dc2826fc5577", 1012 | "Requirements": [ 1013 | "broom", 1014 | "magrittr", 1015 | "purrr", 1016 | "rlang", 1017 | "tibble", 1018 | "tidyr", 1019 | "tidyselect", 1020 | "vctrs" 1021 | ] 1022 | }, 1023 | "munsell": { 1024 | "Package": "munsell", 1025 | "Version": "0.5.0", 1026 | "Source": "Repository", 1027 | "Repository": "CRAN", 1028 | "Hash": "6dfe8bf774944bd5595785e3229d8771", 1029 | "Requirements": [ 1030 | "colorspace" 1031 | ] 1032 | }, 1033 | "nlme": { 1034 | "Package": "nlme", 1035 | "Version": "3.1-157", 1036 | "Source": "Repository", 1037 | "Repository": "CRAN", 1038 | "Hash": "dbca60742be0c9eddc5205e5c7ca1f44", 1039 | "Requirements": [ 1040 | "lattice" 1041 | ] 1042 | }, 1043 | "officer": { 1044 | "Package": "officer", 1045 | "Version": "0.4.2", 1046 | "Source": "Repository", 1047 | "Repository": "RSPM", 1048 | "Hash": "d48468bc10938bc5e0c643603b33b29a", 1049 | "Requirements": [ 1050 | "R6", 1051 | "uuid", 1052 | "xml2", 1053 | "zip" 1054 | ] 1055 | }, 1056 | "openssl": { 1057 | "Package": "openssl", 1058 | "Version": "2.0.0", 1059 | "Source": "Repository", 1060 | "Repository": "RSPM", 1061 | "Hash": "cf4329aac12c2c44089974559c18e446", 1062 | "Requirements": [ 1063 | "askpass" 1064 | ] 1065 | }, 1066 | "parallelly": { 1067 | "Package": "parallelly", 1068 | "Version": "1.31.1", 1069 | "Source": "Repository", 1070 | "Repository": "RSPM", 1071 | "Hash": "115faaa1a50897c3e2339d1cb7d3d493", 1072 | "Requirements": [] 1073 | }, 1074 | "parsermd": { 1075 | "Package": "parsermd", 1076 | "Version": "0.1.2", 1077 | "Source": "Repository", 1078 | "Repository": "RSPM", 1079 | "Hash": "c529cbbfcc506e2d8b819676f20c1380", 1080 | "Requirements": [ 1081 | "BH", 1082 | "Rcpp", 1083 | "checkmate", 1084 | "cli", 1085 | "dplyr", 1086 | "lifecycle", 1087 | "magrittr", 1088 | "pillar", 1089 | "purrr", 1090 | "readr", 1091 | "rlang", 1092 | "rmarkdown", 1093 | "tibble", 1094 | "tidyr", 1095 | "tidyselect", 1096 | "withr", 1097 | "yaml" 1098 | ] 1099 | }, 1100 | "pillar": { 1101 | "Package": "pillar", 1102 | "Version": "1.7.0", 1103 | "Source": "Repository", 1104 | "Repository": "RSPM", 1105 | "Hash": "51dfc97e1b7069e9f7e6f83f3589c22e", 1106 | "Requirements": [ 1107 | "cli", 1108 | "crayon", 1109 | "ellipsis", 1110 | "fansi", 1111 | "glue", 1112 | "lifecycle", 1113 | "rlang", 1114 | "utf8", 1115 | "vctrs" 1116 | ] 1117 | }, 1118 | "pkgbuild": { 1119 | "Package": "pkgbuild", 1120 | "Version": "1.3.1", 1121 | "Source": "Repository", 1122 | "Repository": "RSPM", 1123 | "Hash": "66d2adfed274daf81ccfe77d974c3b9b", 1124 | "Requirements": [ 1125 | "R6", 1126 | "callr", 1127 | "cli", 1128 | "crayon", 1129 | "desc", 1130 | "prettyunits", 1131 | "rprojroot", 1132 | "withr" 1133 | ] 1134 | }, 1135 | "pkgconfig": { 1136 | "Package": "pkgconfig", 1137 | "Version": "2.0.3", 1138 | "Source": "Repository", 1139 | "Repository": "RSPM", 1140 | "Hash": "01f28d4278f15c76cddbea05899c5d6f", 1141 | "Requirements": [] 1142 | }, 1143 | "pkgload": { 1144 | "Package": "pkgload", 1145 | "Version": "1.2.4", 1146 | "Source": "Repository", 1147 | "Repository": "RSPM", 1148 | "Hash": "7533cd805940821bf23eaf3c8d4c1735", 1149 | "Requirements": [ 1150 | "cli", 1151 | "crayon", 1152 | "desc", 1153 | "rlang", 1154 | "rprojroot", 1155 | "rstudioapi", 1156 | "withr" 1157 | ] 1158 | }, 1159 | "praise": { 1160 | "Package": "praise", 1161 | "Version": "1.0.0", 1162 | "Source": "Repository", 1163 | "Repository": "CRAN", 1164 | "Hash": "a555924add98c99d2f411e37e7d25e9f", 1165 | "Requirements": [] 1166 | }, 1167 | "prettyunits": { 1168 | "Package": "prettyunits", 1169 | "Version": "1.1.1", 1170 | "Source": "Repository", 1171 | "Repository": "CRAN", 1172 | "Hash": "95ef9167b75dde9d2ccc3c7528393e7e", 1173 | "Requirements": [] 1174 | }, 1175 | "processx": { 1176 | "Package": "processx", 1177 | "Version": "3.5.3", 1178 | "Source": "Repository", 1179 | "Repository": "RSPM", 1180 | "Hash": "8bbae1a548d0d3fdf6647bdd9d35bf6d", 1181 | "Requirements": [ 1182 | "R6", 1183 | "ps" 1184 | ] 1185 | }, 1186 | "progress": { 1187 | "Package": "progress", 1188 | "Version": "1.2.2", 1189 | "Source": "Repository", 1190 | "Repository": "RSPM", 1191 | "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061", 1192 | "Requirements": [ 1193 | "R6", 1194 | "crayon", 1195 | "hms", 1196 | "prettyunits" 1197 | ] 1198 | }, 1199 | "promises": { 1200 | "Package": "promises", 1201 | "Version": "1.2.0.1", 1202 | "Source": "Repository", 1203 | "Repository": "RSPM", 1204 | "Hash": "4ab2c43adb4d4699cf3690acd378d75d", 1205 | "Requirements": [ 1206 | "R6", 1207 | "Rcpp", 1208 | "later", 1209 | "magrittr", 1210 | "rlang" 1211 | ] 1212 | }, 1213 | "ps": { 1214 | "Package": "ps", 1215 | "Version": "1.7.0", 1216 | "Source": "Repository", 1217 | "Repository": "RSPM", 1218 | "Hash": "eef74b13f32cae6bb0d495e53317c44c", 1219 | "Requirements": [] 1220 | }, 1221 | "purrr": { 1222 | "Package": "purrr", 1223 | "Version": "0.3.4", 1224 | "Source": "Repository", 1225 | "Repository": "RSPM", 1226 | "Hash": "97def703420c8ab10d8f0e6c72101e02", 1227 | "Requirements": [ 1228 | "magrittr", 1229 | "rlang" 1230 | ] 1231 | }, 1232 | "rappdirs": { 1233 | "Package": "rappdirs", 1234 | "Version": "0.3.3", 1235 | "Source": "Repository", 1236 | "Repository": "RSPM", 1237 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d", 1238 | "Requirements": [] 1239 | }, 1240 | "rcmdcheck": { 1241 | "Package": "rcmdcheck", 1242 | "Version": "1.4.0", 1243 | "Source": "Repository", 1244 | "Repository": "RSPM", 1245 | "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4", 1246 | "Requirements": [ 1247 | "R6", 1248 | "callr", 1249 | "cli", 1250 | "curl", 1251 | "desc", 1252 | "digest", 1253 | "pkgbuild", 1254 | "prettyunits", 1255 | "rprojroot", 1256 | "sessioninfo", 1257 | "withr", 1258 | "xopen" 1259 | ] 1260 | }, 1261 | "readr": { 1262 | "Package": "readr", 1263 | "Version": "2.1.2", 1264 | "Source": "Repository", 1265 | "Repository": "RSPM", 1266 | "Hash": "9c59de1357dc209868b5feb5c9f0fe2f", 1267 | "Requirements": [ 1268 | "R6", 1269 | "cli", 1270 | "clipr", 1271 | "cpp11", 1272 | "crayon", 1273 | "hms", 1274 | "lifecycle", 1275 | "rlang", 1276 | "tibble", 1277 | "tzdb", 1278 | "vroom" 1279 | ] 1280 | }, 1281 | "readxl": { 1282 | "Package": "readxl", 1283 | "Version": "1.4.0", 1284 | "Source": "Repository", 1285 | "Repository": "RSPM", 1286 | "Hash": "170c35f745563bb307e963bde0197e4f", 1287 | "Requirements": [ 1288 | "cellranger", 1289 | "cpp11", 1290 | "progress", 1291 | "tibble" 1292 | ] 1293 | }, 1294 | "rematch": { 1295 | "Package": "rematch", 1296 | "Version": "1.0.1", 1297 | "Source": "Repository", 1298 | "Repository": "CRAN", 1299 | "Hash": "c66b930d20bb6d858cd18e1cebcfae5c", 1300 | "Requirements": [] 1301 | }, 1302 | "rematch2": { 1303 | "Package": "rematch2", 1304 | "Version": "2.1.2", 1305 | "Source": "Repository", 1306 | "Repository": "RSPM", 1307 | "Hash": "76c9e04c712a05848ae7a23d2f170a40", 1308 | "Requirements": [ 1309 | "tibble" 1310 | ] 1311 | }, 1312 | "remotes": { 1313 | "Package": "remotes", 1314 | "Version": "2.4.2", 1315 | "Source": "Repository", 1316 | "Repository": "CRAN", 1317 | "Hash": "227045be9aee47e6dda9bb38ac870d67", 1318 | "Requirements": [] 1319 | }, 1320 | "renv": { 1321 | "Package": "renv", 1322 | "Version": "0.15.4", 1323 | "Source": "Repository", 1324 | "Repository": "CRAN", 1325 | "Hash": "c1078316e1d4f70275fc1ea60c0bc431", 1326 | "Requirements": [] 1327 | }, 1328 | "reprex": { 1329 | "Package": "reprex", 1330 | "Version": "2.0.1", 1331 | "Source": "Repository", 1332 | "Repository": "RSPM", 1333 | "Hash": "911d101becedc0fde495bd910984bdc8", 1334 | "Requirements": [ 1335 | "callr", 1336 | "cli", 1337 | "clipr", 1338 | "fs", 1339 | "glue", 1340 | "knitr", 1341 | "rlang", 1342 | "rmarkdown", 1343 | "rstudioapi", 1344 | "withr" 1345 | ] 1346 | }, 1347 | "rlang": { 1348 | "Package": "rlang", 1349 | "Version": "1.0.2", 1350 | "Source": "Repository", 1351 | "Repository": "RSPM", 1352 | "Hash": "04884d9a75d778aca22c7154b8333ec9", 1353 | "Requirements": [] 1354 | }, 1355 | "rmarkdown": { 1356 | "Package": "rmarkdown", 1357 | "Version": "2.14", 1358 | "Source": "Repository", 1359 | "Repository": "RSPM", 1360 | "Hash": "31b60a882fabfabf6785b8599ffeb8ba", 1361 | "Requirements": [ 1362 | "bslib", 1363 | "evaluate", 1364 | "htmltools", 1365 | "jquerylib", 1366 | "jsonlite", 1367 | "knitr", 1368 | "stringr", 1369 | "tinytex", 1370 | "xfun", 1371 | "yaml" 1372 | ] 1373 | }, 1374 | "roxygen2": { 1375 | "Package": "roxygen2", 1376 | "Version": "7.1.2", 1377 | "Source": "Repository", 1378 | "Repository": "RSPM", 1379 | "Hash": "eb9849556c4250305106e82edae35b72", 1380 | "Requirements": [ 1381 | "R6", 1382 | "brew", 1383 | "commonmark", 1384 | "cpp11", 1385 | "desc", 1386 | "digest", 1387 | "knitr", 1388 | "pkgload", 1389 | "purrr", 1390 | "rlang", 1391 | "stringi", 1392 | "stringr", 1393 | "xml2" 1394 | ] 1395 | }, 1396 | "rprojroot": { 1397 | "Package": "rprojroot", 1398 | "Version": "2.0.3", 1399 | "Source": "Repository", 1400 | "Repository": "RSPM", 1401 | "Hash": "1de7ab598047a87bba48434ba35d497d", 1402 | "Requirements": [] 1403 | }, 1404 | "rstudioapi": { 1405 | "Package": "rstudioapi", 1406 | "Version": "0.13", 1407 | "Source": "Repository", 1408 | "Repository": "CRAN", 1409 | "Hash": "06c85365a03fdaf699966cc1d3cf53ea", 1410 | "Requirements": [] 1411 | }, 1412 | "rversions": { 1413 | "Package": "rversions", 1414 | "Version": "2.1.1", 1415 | "Source": "Repository", 1416 | "Repository": "RSPM", 1417 | "Hash": "f88fab00907b312f8b23ec13e2d437cb", 1418 | "Requirements": [ 1419 | "curl", 1420 | "xml2" 1421 | ] 1422 | }, 1423 | "rvest": { 1424 | "Package": "rvest", 1425 | "Version": "1.0.2", 1426 | "Source": "CRAN", 1427 | "Repository": "RSPM", 1428 | "RemoteType": "standard", 1429 | "RemotePkgRef": "rvest", 1430 | "RemoteRef": "rvest", 1431 | "RemoteRepos": "https://packagemanager.rstudio.com/all/__linux__/focal/latest", 1432 | "RemotePkgPlatform": "source", 1433 | "RemoteSha": "1.0.2", 1434 | "Hash": "bb099886deffecd6f9b298b7d4492943", 1435 | "Requirements": [ 1436 | "httr", 1437 | "lifecycle", 1438 | "magrittr", 1439 | "rlang", 1440 | "selectr", 1441 | "tibble", 1442 | "xml2" 1443 | ] 1444 | }, 1445 | "sass": { 1446 | "Package": "sass", 1447 | "Version": "0.4.1", 1448 | "Source": "Repository", 1449 | "Repository": "RSPM", 1450 | "Hash": "f37c0028d720bab3c513fd65d28c7234", 1451 | "Requirements": [ 1452 | "R6", 1453 | "fs", 1454 | "htmltools", 1455 | "rappdirs", 1456 | "rlang" 1457 | ] 1458 | }, 1459 | "scales": { 1460 | "Package": "scales", 1461 | "Version": "1.2.0", 1462 | "Source": "Repository", 1463 | "Repository": "RSPM", 1464 | "Hash": "6e8750cdd13477aa440d453da93d5cac", 1465 | "Requirements": [ 1466 | "R6", 1467 | "RColorBrewer", 1468 | "farver", 1469 | "labeling", 1470 | "lifecycle", 1471 | "munsell", 1472 | "rlang", 1473 | "viridisLite" 1474 | ] 1475 | }, 1476 | "selectr": { 1477 | "Package": "selectr", 1478 | "Version": "0.4-2", 1479 | "Source": "CRAN", 1480 | "Repository": "RSPM", 1481 | "RemoteType": "standard", 1482 | "RemotePkgRef": "selectr", 1483 | "RemoteRef": "selectr", 1484 | "RemoteRepos": "https://packagemanager.rstudio.com/all/__linux__/focal/latest", 1485 | "RemotePkgPlatform": "source", 1486 | "RemoteSha": "0.4-2", 1487 | "Hash": "3838071b66e0c566d55cc26bd6e27bf4", 1488 | "Requirements": [ 1489 | "R6", 1490 | "stringr" 1491 | ] 1492 | }, 1493 | "servr": { 1494 | "Package": "servr", 1495 | "Version": "0.24", 1496 | "Source": "Repository", 1497 | "Repository": "RSPM", 1498 | "Hash": "e2c3e268d654becf0d78a1ec13a05b46", 1499 | "Requirements": [ 1500 | "httpuv", 1501 | "jsonlite", 1502 | "mime", 1503 | "xfun" 1504 | ] 1505 | }, 1506 | "sessioninfo": { 1507 | "Package": "sessioninfo", 1508 | "Version": "1.2.2", 1509 | "Source": "Repository", 1510 | "Repository": "RSPM", 1511 | "Hash": "3f9796a8d0a0e8c6eb49a4b029359d1f", 1512 | "Requirements": [ 1513 | "cli" 1514 | ] 1515 | }, 1516 | "stringi": { 1517 | "Package": "stringi", 1518 | "Version": "1.7.6", 1519 | "Source": "Repository", 1520 | "Repository": "RSPM", 1521 | "Hash": "bba431031d30789535745a9627ac9271", 1522 | "Requirements": [] 1523 | }, 1524 | "stringr": { 1525 | "Package": "stringr", 1526 | "Version": "1.4.0", 1527 | "Source": "Repository", 1528 | "Repository": "RSPM", 1529 | "Hash": "0759e6b6c0957edb1311028a49a35e76", 1530 | "Requirements": [ 1531 | "glue", 1532 | "magrittr", 1533 | "stringi" 1534 | ] 1535 | }, 1536 | "sys": { 1537 | "Package": "sys", 1538 | "Version": "3.4", 1539 | "Source": "Repository", 1540 | "Repository": "CRAN", 1541 | "Hash": "b227d13e29222b4574486cfcbde077fa", 1542 | "Requirements": [] 1543 | }, 1544 | "systemfonts": { 1545 | "Package": "systemfonts", 1546 | "Version": "1.0.4", 1547 | "Source": "Repository", 1548 | "Repository": "RSPM", 1549 | "Hash": "90b28393209827327de889f49935140a", 1550 | "Requirements": [ 1551 | "cpp11" 1552 | ] 1553 | }, 1554 | "testthat": { 1555 | "Package": "testthat", 1556 | "Version": "3.1.4", 1557 | "Source": "Repository", 1558 | "Repository": "RSPM", 1559 | "Hash": "f76c2a02d0fdc24aa7a47ea34261a6e3", 1560 | "Requirements": [ 1561 | "R6", 1562 | "brio", 1563 | "callr", 1564 | "cli", 1565 | "crayon", 1566 | "desc", 1567 | "digest", 1568 | "ellipsis", 1569 | "evaluate", 1570 | "jsonlite", 1571 | "lifecycle", 1572 | "magrittr", 1573 | "pkgload", 1574 | "praise", 1575 | "processx", 1576 | "ps", 1577 | "rlang", 1578 | "waldo", 1579 | "withr" 1580 | ] 1581 | }, 1582 | "tibble": { 1583 | "Package": "tibble", 1584 | "Version": "3.1.7", 1585 | "Source": "Repository", 1586 | "Repository": "RSPM", 1587 | "Hash": "08415af406e3dd75049afef9552e7355", 1588 | "Requirements": [ 1589 | "ellipsis", 1590 | "fansi", 1591 | "lifecycle", 1592 | "magrittr", 1593 | "pillar", 1594 | "pkgconfig", 1595 | "rlang", 1596 | "vctrs" 1597 | ] 1598 | }, 1599 | "tidyr": { 1600 | "Package": "tidyr", 1601 | "Version": "1.2.0", 1602 | "Source": "Repository", 1603 | "Repository": "RSPM", 1604 | "Hash": "d8b95b7fee945d7da6888cf7eb71a49c", 1605 | "Requirements": [ 1606 | "cpp11", 1607 | "dplyr", 1608 | "ellipsis", 1609 | "glue", 1610 | "lifecycle", 1611 | "magrittr", 1612 | "purrr", 1613 | "rlang", 1614 | "tibble", 1615 | "tidyselect", 1616 | "vctrs" 1617 | ] 1618 | }, 1619 | "tidyselect": { 1620 | "Package": "tidyselect", 1621 | "Version": "1.1.2", 1622 | "Source": "Repository", 1623 | "Repository": "RSPM", 1624 | "Hash": "17f6da8cfd7002760a859915ce7eef8f", 1625 | "Requirements": [ 1626 | "ellipsis", 1627 | "glue", 1628 | "purrr", 1629 | "rlang", 1630 | "vctrs" 1631 | ] 1632 | }, 1633 | "tidyverse": { 1634 | "Package": "tidyverse", 1635 | "Version": "1.3.1", 1636 | "Source": "Repository", 1637 | "Repository": "RSPM", 1638 | "Hash": "fc4c72b6ae9bb283416bd59a3303bbab", 1639 | "Requirements": [ 1640 | "broom", 1641 | "cli", 1642 | "crayon", 1643 | "dbplyr", 1644 | "dplyr", 1645 | "dtplyr", 1646 | "forcats", 1647 | "ggplot2", 1648 | "googledrive", 1649 | "googlesheets4", 1650 | "haven", 1651 | "hms", 1652 | "httr", 1653 | "jsonlite", 1654 | "lubridate", 1655 | "magrittr", 1656 | "modelr", 1657 | "pillar", 1658 | "purrr", 1659 | "readr", 1660 | "readxl", 1661 | "reprex", 1662 | "rlang", 1663 | "rstudioapi", 1664 | "rvest", 1665 | "stringr", 1666 | "tibble", 1667 | "tidyr", 1668 | "xml2" 1669 | ] 1670 | }, 1671 | "tinytex": { 1672 | "Package": "tinytex", 1673 | "Version": "0.38", 1674 | "Source": "Repository", 1675 | "Repository": "RSPM", 1676 | "Hash": "759d047596ac173433985deddf313450", 1677 | "Requirements": [ 1678 | "xfun" 1679 | ] 1680 | }, 1681 | "tzdb": { 1682 | "Package": "tzdb", 1683 | "Version": "0.3.0", 1684 | "Source": "Repository", 1685 | "Repository": "RSPM", 1686 | "Hash": "b2e1cbce7c903eaf23ec05c58e59fb5e", 1687 | "Requirements": [ 1688 | "cpp11" 1689 | ] 1690 | }, 1691 | "usethis": { 1692 | "Package": "usethis", 1693 | "Version": "2.1.5", 1694 | "Source": "Repository", 1695 | "Repository": "RSPM", 1696 | "Hash": "c499f488e6dd7718accffaee5bc5a79b", 1697 | "Requirements": [ 1698 | "cli", 1699 | "clipr", 1700 | "crayon", 1701 | "curl", 1702 | "desc", 1703 | "fs", 1704 | "gert", 1705 | "gh", 1706 | "glue", 1707 | "jsonlite", 1708 | "lifecycle", 1709 | "purrr", 1710 | "rappdirs", 1711 | "rlang", 1712 | "rprojroot", 1713 | "rstudioapi", 1714 | "whisker", 1715 | "withr", 1716 | "yaml" 1717 | ] 1718 | }, 1719 | "utf8": { 1720 | "Package": "utf8", 1721 | "Version": "1.2.2", 1722 | "Source": "Repository", 1723 | "Repository": "RSPM", 1724 | "Hash": "c9c462b759a5cc844ae25b5942654d13", 1725 | "Requirements": [] 1726 | }, 1727 | "uuid": { 1728 | "Package": "uuid", 1729 | "Version": "1.1-0", 1730 | "Source": "Repository", 1731 | "Repository": "RSPM", 1732 | "Hash": "f1cb46c157d080b729159d407be83496", 1733 | "Requirements": [] 1734 | }, 1735 | "vctrs": { 1736 | "Package": "vctrs", 1737 | "Version": "0.4.1", 1738 | "Source": "Repository", 1739 | "Repository": "RSPM", 1740 | "Hash": "8b54f22e2a58c4f275479c92ce041a57", 1741 | "Requirements": [ 1742 | "cli", 1743 | "glue", 1744 | "rlang" 1745 | ] 1746 | }, 1747 | "viridisLite": { 1748 | "Package": "viridisLite", 1749 | "Version": "0.4.0", 1750 | "Source": "Repository", 1751 | "Repository": "RSPM", 1752 | "Hash": "55e157e2aa88161bdb0754218470d204", 1753 | "Requirements": [] 1754 | }, 1755 | "vroom": { 1756 | "Package": "vroom", 1757 | "Version": "1.5.7", 1758 | "Source": "Repository", 1759 | "Repository": "RSPM", 1760 | "Hash": "976507b5a105bc3bdf6a5a5f29e0684f", 1761 | "Requirements": [ 1762 | "bit64", 1763 | "cli", 1764 | "cpp11", 1765 | "crayon", 1766 | "glue", 1767 | "hms", 1768 | "lifecycle", 1769 | "progress", 1770 | "rlang", 1771 | "tibble", 1772 | "tidyselect", 1773 | "tzdb", 1774 | "vctrs", 1775 | "withr" 1776 | ] 1777 | }, 1778 | "waldo": { 1779 | "Package": "waldo", 1780 | "Version": "0.4.0", 1781 | "Source": "Repository", 1782 | "Repository": "RSPM", 1783 | "Hash": "035fba89d0c86e2113120f93301b98ad", 1784 | "Requirements": [ 1785 | "cli", 1786 | "diffobj", 1787 | "fansi", 1788 | "glue", 1789 | "rematch2", 1790 | "rlang", 1791 | "tibble" 1792 | ] 1793 | }, 1794 | "whisker": { 1795 | "Package": "whisker", 1796 | "Version": "0.4", 1797 | "Source": "Repository", 1798 | "Repository": "RSPM", 1799 | "Hash": "ca970b96d894e90397ed20637a0c1bbe", 1800 | "Requirements": [] 1801 | }, 1802 | "withr": { 1803 | "Package": "withr", 1804 | "Version": "2.5.0", 1805 | "Source": "Repository", 1806 | "Repository": "RSPM", 1807 | "Hash": "c0e49a9760983e81e55cdd9be92e7182", 1808 | "Requirements": [] 1809 | }, 1810 | "xaringan": { 1811 | "Package": "xaringan", 1812 | "Version": "0.24", 1813 | "Source": "Repository", 1814 | "Repository": "RSPM", 1815 | "Hash": "714cfbdbc0775404c8df7894dfed0165", 1816 | "Requirements": [ 1817 | "htmltools", 1818 | "knitr", 1819 | "rmarkdown", 1820 | "servr", 1821 | "xfun" 1822 | ] 1823 | }, 1824 | "xaringanExtra": { 1825 | "Package": "xaringanExtra", 1826 | "Version": "0.5.5", 1827 | "Source": "GitHub", 1828 | "RemoteType": "github", 1829 | "RemoteHost": "api.github.com", 1830 | "RemoteRepo": "xaringanExtra", 1831 | "RemoteUsername": "gadenbuie", 1832 | "RemoteRef": "HEAD", 1833 | "RemoteSha": "ee5092d2d27bf4b813ea50ec4c264b331283face", 1834 | "Hash": "b58b67af85936c6519f1faa7df5d5149", 1835 | "Requirements": [ 1836 | "htmltools", 1837 | "jsonlite", 1838 | "knitr", 1839 | "uuid" 1840 | ] 1841 | }, 1842 | "xfun": { 1843 | "Package": "xfun", 1844 | "Version": "0.31", 1845 | "Source": "Repository", 1846 | "Repository": "RSPM", 1847 | "Hash": "a318c6f752b8dcfe9fb74d897418ab2b", 1848 | "Requirements": [] 1849 | }, 1850 | "xml2": { 1851 | "Package": "xml2", 1852 | "Version": "1.3.3", 1853 | "Source": "Repository", 1854 | "Repository": "RSPM", 1855 | "Hash": "40682ed6a969ea5abfd351eb67833adc", 1856 | "Requirements": [] 1857 | }, 1858 | "xopen": { 1859 | "Package": "xopen", 1860 | "Version": "1.0.0", 1861 | "Source": "Repository", 1862 | "Repository": "RSPM", 1863 | "Hash": "6c85f015dee9cc7710ddd20f86881f58", 1864 | "Requirements": [ 1865 | "processx" 1866 | ] 1867 | }, 1868 | "yaml": { 1869 | "Package": "yaml", 1870 | "Version": "2.3.5", 1871 | "Source": "Repository", 1872 | "Repository": "RSPM", 1873 | "Hash": "458bb38374d73bf83b1bb85e353da200", 1874 | "Requirements": [] 1875 | }, 1876 | "zip": { 1877 | "Package": "zip", 1878 | "Version": "2.2.0", 1879 | "Source": "Repository", 1880 | "Repository": "RSPM", 1881 | "Hash": "c7eef2996ac270a18c2715c997a727c5", 1882 | "Requirements": [] 1883 | } 1884 | } 1885 | } 1886 | -------------------------------------------------------------------------------- /renv/.gitignore: -------------------------------------------------------------------------------- 1 | cellar/ 2 | library/ 3 | local/ 4 | lock/ 5 | python/ 6 | staging/ 7 | -------------------------------------------------------------------------------- /renv/activate.R: -------------------------------------------------------------------------------- 1 | 2 | local({ 3 | 4 | # the requested version of renv 5 | version <- "0.15.4" 6 | 7 | # the project directory 8 | project <- getwd() 9 | 10 | # figure out whether the autoloader is enabled 11 | enabled <- local({ 12 | 13 | # first, check config option 14 | override <- getOption("renv.config.autoloader.enabled") 15 | if (!is.null(override)) 16 | return(override) 17 | 18 | # next, check environment variables 19 | # TODO: prefer using the configuration one in the future 20 | envvars <- c( 21 | "RENV_CONFIG_AUTOLOADER_ENABLED", 22 | "RENV_AUTOLOADER_ENABLED", 23 | "RENV_ACTIVATE_PROJECT" 24 | ) 25 | 26 | for (envvar in envvars) { 27 | envval <- Sys.getenv(envvar, unset = NA) 28 | if (!is.na(envval)) 29 | return(tolower(envval) %in% c("true", "t", "1")) 30 | } 31 | 32 | # enable by default 33 | TRUE 34 | 35 | }) 36 | 37 | if (!enabled) 38 | return(FALSE) 39 | 40 | # avoid recursion 41 | if (identical(getOption("renv.autoloader.running"), TRUE)) { 42 | warning("ignoring recursive attempt to run renv autoloader") 43 | return(invisible(TRUE)) 44 | } 45 | 46 | # signal that we're loading renv during R startup 47 | options(renv.autoloader.running = TRUE) 48 | on.exit(options(renv.autoloader.running = NULL), add = TRUE) 49 | 50 | # signal that we've consented to use renv 51 | options(renv.consent = TRUE) 52 | 53 | # load the 'utils' package eagerly -- this ensures that renv shims, which 54 | # mask 'utils' packages, will come first on the search path 55 | library(utils, lib.loc = .Library) 56 | 57 | # unload renv if it's already been laoded 58 | if ("renv" %in% loadedNamespaces()) 59 | unloadNamespace("renv") 60 | 61 | # load bootstrap tools 62 | `%||%` <- function(x, y) { 63 | if (is.environment(x) || length(x)) x else y 64 | } 65 | 66 | bootstrap <- function(version, library) { 67 | 68 | # attempt to download renv 69 | tarball <- tryCatch(renv_bootstrap_download(version), error = identity) 70 | if (inherits(tarball, "error")) 71 | stop("failed to download renv ", version) 72 | 73 | # now attempt to install 74 | status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) 75 | if (inherits(status, "error")) 76 | stop("failed to install renv ", version) 77 | 78 | } 79 | 80 | renv_bootstrap_tests_running <- function() { 81 | getOption("renv.tests.running", default = FALSE) 82 | } 83 | 84 | renv_bootstrap_repos <- function() { 85 | 86 | # check for repos override 87 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) 88 | if (!is.na(repos)) 89 | return(repos) 90 | 91 | # check for lockfile repositories 92 | repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) 93 | if (!inherits(repos, "error") && length(repos)) 94 | return(repos) 95 | 96 | # if we're testing, re-use the test repositories 97 | if (renv_bootstrap_tests_running()) 98 | return(getOption("renv.tests.repos")) 99 | 100 | # retrieve current repos 101 | repos <- getOption("repos") 102 | 103 | # ensure @CRAN@ entries are resolved 104 | repos[repos == "@CRAN@"] <- getOption( 105 | "renv.repos.cran", 106 | "https://cloud.r-project.org" 107 | ) 108 | 109 | # add in renv.bootstrap.repos if set 110 | default <- c(FALLBACK = "https://cloud.r-project.org") 111 | extra <- getOption("renv.bootstrap.repos", default = default) 112 | repos <- c(repos, extra) 113 | 114 | # remove duplicates that might've snuck in 115 | dupes <- duplicated(repos) | duplicated(names(repos)) 116 | repos[!dupes] 117 | 118 | } 119 | 120 | renv_bootstrap_repos_lockfile <- function() { 121 | 122 | lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") 123 | if (!file.exists(lockpath)) 124 | return(NULL) 125 | 126 | lockfile <- tryCatch(renv_json_read(lockpath), error = identity) 127 | if (inherits(lockfile, "error")) { 128 | warning(lockfile) 129 | return(NULL) 130 | } 131 | 132 | repos <- lockfile$R$Repositories 133 | if (length(repos) == 0) 134 | return(NULL) 135 | 136 | keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) 137 | vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) 138 | names(vals) <- keys 139 | 140 | return(vals) 141 | 142 | } 143 | 144 | renv_bootstrap_download <- function(version) { 145 | 146 | # if the renv version number has 4 components, assume it must 147 | # be retrieved via github 148 | nv <- numeric_version(version) 149 | components <- unclass(nv)[[1]] 150 | 151 | # if this appears to be a development version of 'renv', we'll 152 | # try to restore from github 153 | dev <- length(components) == 4L 154 | 155 | # begin collecting different methods for finding renv 156 | methods <- c( 157 | renv_bootstrap_download_tarball, 158 | if (dev) 159 | renv_bootstrap_download_github 160 | else c( 161 | renv_bootstrap_download_cran_latest, 162 | renv_bootstrap_download_cran_archive 163 | ) 164 | ) 165 | 166 | for (method in methods) { 167 | path <- tryCatch(method(version), error = identity) 168 | if (is.character(path) && file.exists(path)) 169 | return(path) 170 | } 171 | 172 | stop("failed to download renv ", version) 173 | 174 | } 175 | 176 | renv_bootstrap_download_impl <- function(url, destfile) { 177 | 178 | mode <- "wb" 179 | 180 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 181 | fixup <- 182 | Sys.info()[["sysname"]] == "Windows" && 183 | substring(url, 1L, 5L) == "file:" 184 | 185 | if (fixup) 186 | mode <- "w+b" 187 | 188 | utils::download.file( 189 | url = url, 190 | destfile = destfile, 191 | mode = mode, 192 | quiet = TRUE 193 | ) 194 | 195 | } 196 | 197 | renv_bootstrap_download_cran_latest <- function(version) { 198 | 199 | spec <- renv_bootstrap_download_cran_latest_find(version) 200 | 201 | message("* Downloading renv ", version, " ... ", appendLF = FALSE) 202 | 203 | type <- spec$type 204 | repos <- spec$repos 205 | 206 | info <- tryCatch( 207 | utils::download.packages( 208 | pkgs = "renv", 209 | destdir = tempdir(), 210 | repos = repos, 211 | type = type, 212 | quiet = TRUE 213 | ), 214 | condition = identity 215 | ) 216 | 217 | if (inherits(info, "condition")) { 218 | message("FAILED") 219 | return(FALSE) 220 | } 221 | 222 | # report success and return 223 | message("OK (downloaded ", type, ")") 224 | info[1, 2] 225 | 226 | } 227 | 228 | renv_bootstrap_download_cran_latest_find <- function(version) { 229 | 230 | # check whether binaries are supported on this system 231 | binary <- 232 | getOption("renv.bootstrap.binary", default = TRUE) && 233 | !identical(.Platform$pkgType, "source") && 234 | !identical(getOption("pkgType"), "source") && 235 | Sys.info()[["sysname"]] %in% c("Darwin", "Windows") 236 | 237 | types <- c(if (binary) "binary", "source") 238 | 239 | # iterate over types + repositories 240 | for (type in types) { 241 | for (repos in renv_bootstrap_repos()) { 242 | 243 | # retrieve package database 244 | db <- tryCatch( 245 | as.data.frame( 246 | utils::available.packages(type = type, repos = repos), 247 | stringsAsFactors = FALSE 248 | ), 249 | error = identity 250 | ) 251 | 252 | if (inherits(db, "error")) 253 | next 254 | 255 | # check for compatible entry 256 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ] 257 | if (nrow(entry) == 0) 258 | next 259 | 260 | # found it; return spec to caller 261 | spec <- list(entry = entry, type = type, repos = repos) 262 | return(spec) 263 | 264 | } 265 | } 266 | 267 | # if we got here, we failed to find renv 268 | fmt <- "renv %s is not available from your declared package repositories" 269 | stop(sprintf(fmt, version)) 270 | 271 | } 272 | 273 | renv_bootstrap_download_cran_archive <- function(version) { 274 | 275 | name <- sprintf("renv_%s.tar.gz", version) 276 | repos <- renv_bootstrap_repos() 277 | urls <- file.path(repos, "src/contrib/Archive/renv", name) 278 | destfile <- file.path(tempdir(), name) 279 | 280 | message("* Downloading renv ", version, " ... ", appendLF = FALSE) 281 | 282 | for (url in urls) { 283 | 284 | status <- tryCatch( 285 | renv_bootstrap_download_impl(url, destfile), 286 | condition = identity 287 | ) 288 | 289 | if (identical(status, 0L)) { 290 | message("OK") 291 | return(destfile) 292 | } 293 | 294 | } 295 | 296 | message("FAILED") 297 | return(FALSE) 298 | 299 | } 300 | 301 | renv_bootstrap_download_tarball <- function(version) { 302 | 303 | # if the user has provided the path to a tarball via 304 | # an environment variable, then use it 305 | tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) 306 | if (is.na(tarball)) 307 | return() 308 | 309 | # allow directories 310 | info <- file.info(tarball, extra_cols = FALSE) 311 | if (identical(info$isdir, TRUE)) { 312 | name <- sprintf("renv_%s.tar.gz", version) 313 | tarball <- file.path(tarball, name) 314 | } 315 | 316 | # bail if it doesn't exist 317 | if (!file.exists(tarball)) 318 | return() 319 | 320 | fmt <- "* Bootstrapping with tarball at path '%s'." 321 | msg <- sprintf(fmt, tarball) 322 | message(msg) 323 | 324 | tarball 325 | 326 | } 327 | 328 | renv_bootstrap_download_github <- function(version) { 329 | 330 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") 331 | if (!identical(enabled, "TRUE")) 332 | return(FALSE) 333 | 334 | # prepare download options 335 | pat <- Sys.getenv("GITHUB_PAT") 336 | if (nzchar(Sys.which("curl")) && nzchar(pat)) { 337 | fmt <- "--location --fail --header \"Authorization: token %s\"" 338 | extra <- sprintf(fmt, pat) 339 | saved <- options("download.file.method", "download.file.extra") 340 | options(download.file.method = "curl", download.file.extra = extra) 341 | on.exit(do.call(base::options, saved), add = TRUE) 342 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { 343 | fmt <- "--header=\"Authorization: token %s\"" 344 | extra <- sprintf(fmt, pat) 345 | saved <- options("download.file.method", "download.file.extra") 346 | options(download.file.method = "wget", download.file.extra = extra) 347 | on.exit(do.call(base::options, saved), add = TRUE) 348 | } 349 | 350 | message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) 351 | 352 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) 353 | name <- sprintf("renv_%s.tar.gz", version) 354 | destfile <- file.path(tempdir(), name) 355 | 356 | status <- tryCatch( 357 | renv_bootstrap_download_impl(url, destfile), 358 | condition = identity 359 | ) 360 | 361 | if (!identical(status, 0L)) { 362 | message("FAILED") 363 | return(FALSE) 364 | } 365 | 366 | message("OK") 367 | return(destfile) 368 | 369 | } 370 | 371 | renv_bootstrap_install <- function(version, tarball, library) { 372 | 373 | # attempt to install it into project library 374 | message("* Installing renv ", version, " ... ", appendLF = FALSE) 375 | dir.create(library, showWarnings = FALSE, recursive = TRUE) 376 | 377 | # invoke using system2 so we can capture and report output 378 | bin <- R.home("bin") 379 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" 380 | r <- file.path(bin, exe) 381 | 382 | args <- c( 383 | "--vanilla", "CMD", "INSTALL", "--no-multiarch", 384 | "-l", shQuote(path.expand(library)), 385 | shQuote(path.expand(tarball)) 386 | ) 387 | 388 | output <- system2(r, args, stdout = TRUE, stderr = TRUE) 389 | message("Done!") 390 | 391 | # check for successful install 392 | status <- attr(output, "status") 393 | if (is.numeric(status) && !identical(status, 0L)) { 394 | header <- "Error installing renv:" 395 | lines <- paste(rep.int("=", nchar(header)), collapse = "") 396 | text <- c(header, lines, output) 397 | writeLines(text, con = stderr()) 398 | } 399 | 400 | status 401 | 402 | } 403 | 404 | renv_bootstrap_platform_prefix <- function() { 405 | 406 | # construct version prefix 407 | version <- paste(R.version$major, R.version$minor, sep = ".") 408 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") 409 | 410 | # include SVN revision for development versions of R 411 | # (to avoid sharing platform-specific artefacts with released versions of R) 412 | devel <- 413 | identical(R.version[["status"]], "Under development (unstable)") || 414 | identical(R.version[["nickname"]], "Unsuffered Consequences") 415 | 416 | if (devel) 417 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") 418 | 419 | # build list of path components 420 | components <- c(prefix, R.version$platform) 421 | 422 | # include prefix if provided by user 423 | prefix <- renv_bootstrap_platform_prefix_impl() 424 | if (!is.na(prefix) && nzchar(prefix)) 425 | components <- c(prefix, components) 426 | 427 | # build prefix 428 | paste(components, collapse = "/") 429 | 430 | } 431 | 432 | renv_bootstrap_platform_prefix_impl <- function() { 433 | 434 | # if an explicit prefix has been supplied, use it 435 | prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) 436 | if (!is.na(prefix)) 437 | return(prefix) 438 | 439 | # if the user has requested an automatic prefix, generate it 440 | auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) 441 | if (auto %in% c("TRUE", "True", "true", "1")) 442 | return(renv_bootstrap_platform_prefix_auto()) 443 | 444 | # empty string on failure 445 | "" 446 | 447 | } 448 | 449 | renv_bootstrap_platform_prefix_auto <- function() { 450 | 451 | prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) 452 | if (inherits(prefix, "error") || prefix %in% "unknown") { 453 | 454 | msg <- paste( 455 | "failed to infer current operating system", 456 | "please file a bug report at https://github.com/rstudio/renv/issues", 457 | sep = "; " 458 | ) 459 | 460 | warning(msg) 461 | 462 | } 463 | 464 | prefix 465 | 466 | } 467 | 468 | renv_bootstrap_platform_os <- function() { 469 | 470 | sysinfo <- Sys.info() 471 | sysname <- sysinfo[["sysname"]] 472 | 473 | # handle Windows + macOS up front 474 | if (sysname == "Windows") 475 | return("windows") 476 | else if (sysname == "Darwin") 477 | return("macos") 478 | 479 | # check for os-release files 480 | for (file in c("/etc/os-release", "/usr/lib/os-release")) 481 | if (file.exists(file)) 482 | return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) 483 | 484 | # check for redhat-release files 485 | if (file.exists("/etc/redhat-release")) 486 | return(renv_bootstrap_platform_os_via_redhat_release()) 487 | 488 | "unknown" 489 | 490 | } 491 | 492 | renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { 493 | 494 | # read /etc/os-release 495 | release <- utils::read.table( 496 | file = file, 497 | sep = "=", 498 | quote = c("\"", "'"), 499 | col.names = c("Key", "Value"), 500 | comment.char = "#", 501 | stringsAsFactors = FALSE 502 | ) 503 | 504 | vars <- as.list(release$Value) 505 | names(vars) <- release$Key 506 | 507 | # get os name 508 | os <- tolower(sysinfo[["sysname"]]) 509 | 510 | # read id 511 | id <- "unknown" 512 | for (field in c("ID", "ID_LIKE")) { 513 | if (field %in% names(vars) && nzchar(vars[[field]])) { 514 | id <- vars[[field]] 515 | break 516 | } 517 | } 518 | 519 | # read version 520 | version <- "unknown" 521 | for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { 522 | if (field %in% names(vars) && nzchar(vars[[field]])) { 523 | version <- vars[[field]] 524 | break 525 | } 526 | } 527 | 528 | # join together 529 | paste(c(os, id, version), collapse = "-") 530 | 531 | } 532 | 533 | renv_bootstrap_platform_os_via_redhat_release <- function() { 534 | 535 | # read /etc/redhat-release 536 | contents <- readLines("/etc/redhat-release", warn = FALSE) 537 | 538 | # infer id 539 | id <- if (grepl("centos", contents, ignore.case = TRUE)) 540 | "centos" 541 | else if (grepl("redhat", contents, ignore.case = TRUE)) 542 | "redhat" 543 | else 544 | "unknown" 545 | 546 | # try to find a version component (very hacky) 547 | version <- "unknown" 548 | 549 | parts <- strsplit(contents, "[[:space:]]")[[1L]] 550 | for (part in parts) { 551 | 552 | nv <- tryCatch(numeric_version(part), error = identity) 553 | if (inherits(nv, "error")) 554 | next 555 | 556 | version <- nv[1, 1] 557 | break 558 | 559 | } 560 | 561 | paste(c("linux", id, version), collapse = "-") 562 | 563 | } 564 | 565 | renv_bootstrap_library_root_name <- function(project) { 566 | 567 | # use project name as-is if requested 568 | asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") 569 | if (asis) 570 | return(basename(project)) 571 | 572 | # otherwise, disambiguate based on project's path 573 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) 574 | paste(basename(project), id, sep = "-") 575 | 576 | } 577 | 578 | renv_bootstrap_library_root <- function(project) { 579 | 580 | prefix <- renv_bootstrap_profile_prefix() 581 | 582 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) 583 | if (!is.na(path)) 584 | return(paste(c(path, prefix), collapse = "/")) 585 | 586 | path <- renv_bootstrap_library_root_impl(project) 587 | if (!is.null(path)) { 588 | name <- renv_bootstrap_library_root_name(project) 589 | return(paste(c(path, prefix, name), collapse = "/")) 590 | } 591 | 592 | renv_bootstrap_paths_renv("library", project = project) 593 | 594 | } 595 | 596 | renv_bootstrap_library_root_impl <- function(project) { 597 | 598 | root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) 599 | if (!is.na(root)) 600 | return(root) 601 | 602 | type <- renv_bootstrap_project_type(project) 603 | if (identical(type, "package")) { 604 | userdir <- renv_bootstrap_user_dir() 605 | return(file.path(userdir, "library")) 606 | } 607 | 608 | } 609 | 610 | renv_bootstrap_validate_version <- function(version) { 611 | 612 | loadedversion <- utils::packageDescription("renv", fields = "Version") 613 | if (version == loadedversion) 614 | return(TRUE) 615 | 616 | # assume four-component versions are from GitHub; three-component 617 | # versions are from CRAN 618 | components <- strsplit(loadedversion, "[.-]")[[1]] 619 | remote <- if (length(components) == 4L) 620 | paste("rstudio/renv", loadedversion, sep = "@") 621 | else 622 | paste("renv", loadedversion, sep = "@") 623 | 624 | fmt <- paste( 625 | "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", 626 | "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", 627 | "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", 628 | sep = "\n" 629 | ) 630 | 631 | msg <- sprintf(fmt, loadedversion, version, remote) 632 | warning(msg, call. = FALSE) 633 | 634 | FALSE 635 | 636 | } 637 | 638 | renv_bootstrap_hash_text <- function(text) { 639 | 640 | hashfile <- tempfile("renv-hash-") 641 | on.exit(unlink(hashfile), add = TRUE) 642 | 643 | writeLines(text, con = hashfile) 644 | tools::md5sum(hashfile) 645 | 646 | } 647 | 648 | renv_bootstrap_load <- function(project, libpath, version) { 649 | 650 | # try to load renv from the project library 651 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) 652 | return(FALSE) 653 | 654 | # warn if the version of renv loaded does not match 655 | renv_bootstrap_validate_version(version) 656 | 657 | # load the project 658 | renv::load(project) 659 | 660 | TRUE 661 | 662 | } 663 | 664 | renv_bootstrap_profile_load <- function(project) { 665 | 666 | # if RENV_PROFILE is already set, just use that 667 | profile <- Sys.getenv("RENV_PROFILE", unset = NA) 668 | if (!is.na(profile) && nzchar(profile)) 669 | return(profile) 670 | 671 | # check for a profile file (nothing to do if it doesn't exist) 672 | path <- renv_bootstrap_paths_renv("profile", profile = FALSE) 673 | if (!file.exists(path)) 674 | return(NULL) 675 | 676 | # read the profile, and set it if it exists 677 | contents <- readLines(path, warn = FALSE) 678 | if (length(contents) == 0L) 679 | return(NULL) 680 | 681 | # set RENV_PROFILE 682 | profile <- contents[[1L]] 683 | if (!profile %in% c("", "default")) 684 | Sys.setenv(RENV_PROFILE = profile) 685 | 686 | profile 687 | 688 | } 689 | 690 | renv_bootstrap_profile_prefix <- function() { 691 | profile <- renv_bootstrap_profile_get() 692 | if (!is.null(profile)) 693 | return(file.path("profiles", profile, "renv")) 694 | } 695 | 696 | renv_bootstrap_profile_get <- function() { 697 | profile <- Sys.getenv("RENV_PROFILE", unset = "") 698 | renv_bootstrap_profile_normalize(profile) 699 | } 700 | 701 | renv_bootstrap_profile_set <- function(profile) { 702 | profile <- renv_bootstrap_profile_normalize(profile) 703 | if (is.null(profile)) 704 | Sys.unsetenv("RENV_PROFILE") 705 | else 706 | Sys.setenv(RENV_PROFILE = profile) 707 | } 708 | 709 | renv_bootstrap_profile_normalize <- function(profile) { 710 | 711 | if (is.null(profile) || profile %in% c("", "default")) 712 | return(NULL) 713 | 714 | profile 715 | 716 | } 717 | 718 | renv_bootstrap_path_absolute <- function(path) { 719 | 720 | substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( 721 | substr(path, 1L, 1L) %in% c(letters, LETTERS) && 722 | substr(path, 2L, 3L) %in% c(":/", ":\\") 723 | ) 724 | 725 | } 726 | 727 | renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { 728 | renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") 729 | root <- if (renv_bootstrap_path_absolute(renv)) NULL else project 730 | prefix <- if (profile) renv_bootstrap_profile_prefix() 731 | components <- c(root, renv, prefix, ...) 732 | paste(components, collapse = "/") 733 | } 734 | 735 | renv_bootstrap_project_type <- function(path) { 736 | 737 | descpath <- file.path(path, "DESCRIPTION") 738 | if (!file.exists(descpath)) 739 | return("unknown") 740 | 741 | desc <- tryCatch( 742 | read.dcf(descpath, all = TRUE), 743 | error = identity 744 | ) 745 | 746 | if (inherits(desc, "error")) 747 | return("unknown") 748 | 749 | type <- desc$Type 750 | if (!is.null(type)) 751 | return(tolower(type)) 752 | 753 | package <- desc$Package 754 | if (!is.null(package)) 755 | return("package") 756 | 757 | "unknown" 758 | 759 | } 760 | 761 | renv_bootstrap_user_dir <- function() { 762 | dir <- renv_bootstrap_user_dir_impl() 763 | path.expand(chartr("\\", "/", dir)) 764 | } 765 | 766 | renv_bootstrap_user_dir_impl <- function() { 767 | 768 | # use local override if set 769 | override <- getOption("renv.userdir.override") 770 | if (!is.null(override)) 771 | return(override) 772 | 773 | # use R_user_dir if available 774 | tools <- asNamespace("tools") 775 | if (is.function(tools$R_user_dir)) 776 | return(tools$R_user_dir("renv", "cache")) 777 | 778 | # try using our own backfill for older versions of R 779 | envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") 780 | for (envvar in envvars) { 781 | root <- Sys.getenv(envvar, unset = NA) 782 | if (!is.na(root)) 783 | return(file.path(root, "R/renv")) 784 | } 785 | 786 | # use platform-specific default fallbacks 787 | if (Sys.info()[["sysname"]] == "Windows") 788 | file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") 789 | else if (Sys.info()[["sysname"]] == "Darwin") 790 | "~/Library/Caches/org.R-project.R/R/renv" 791 | else 792 | "~/.cache/R/renv" 793 | 794 | } 795 | 796 | 797 | renv_json_read <- function(file = NULL, text = NULL) { 798 | 799 | text <- paste(text %||% read(file), collapse = "\n") 800 | 801 | # find strings in the JSON 802 | pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' 803 | locs <- gregexpr(pattern, text)[[1]] 804 | 805 | # if any are found, replace them with placeholders 806 | replaced <- text 807 | strings <- character() 808 | replacements <- character() 809 | 810 | if (!identical(c(locs), -1L)) { 811 | 812 | # get the string values 813 | starts <- locs 814 | ends <- locs + attr(locs, "match.length") - 1L 815 | strings <- substring(text, starts, ends) 816 | 817 | # only keep those requiring escaping 818 | strings <- grep("[[\\]{}:]", strings, perl = TRUE, value = TRUE) 819 | 820 | # compute replacements 821 | replacements <- sprintf('"\032%i\032"', seq_along(strings)) 822 | 823 | # replace the strings 824 | mapply(function(string, replacement) { 825 | replaced <<- sub(string, replacement, replaced, fixed = TRUE) 826 | }, strings, replacements) 827 | 828 | } 829 | 830 | # transform the JSON into something the R parser understands 831 | transformed <- replaced 832 | transformed <- gsub("[[{]", "list(", transformed) 833 | transformed <- gsub("[]}]", ")", transformed) 834 | transformed <- gsub(":", "=", transformed, fixed = TRUE) 835 | text <- paste(transformed, collapse = "\n") 836 | 837 | # parse it 838 | json <- parse(text = text, keep.source = FALSE, srcfile = NULL)[[1L]] 839 | 840 | # construct map between source strings, replaced strings 841 | map <- as.character(parse(text = strings)) 842 | names(map) <- as.character(parse(text = replacements)) 843 | 844 | # convert to list 845 | map <- as.list(map) 846 | 847 | # remap strings in object 848 | remapped <- renv_json_remap(json, map) 849 | 850 | # evaluate 851 | eval(remapped, envir = baseenv()) 852 | 853 | } 854 | 855 | renv_json_remap <- function(json, map) { 856 | 857 | # fix names 858 | if (!is.null(names(json))) { 859 | lhs <- match(names(json), names(map), nomatch = 0L) 860 | rhs <- match(names(map), names(json), nomatch = 0L) 861 | names(json)[rhs] <- map[lhs] 862 | } 863 | 864 | # fix values 865 | if (is.character(json)) 866 | return(map[[json]] %||% json) 867 | 868 | # handle true, false, null 869 | if (is.name(json)) { 870 | text <- as.character(json) 871 | if (text == "true") 872 | return(TRUE) 873 | else if (text == "false") 874 | return(FALSE) 875 | else if (text == "null") 876 | return(NULL) 877 | } 878 | 879 | # recurse 880 | if (is.recursive(json)) { 881 | for (i in seq_along(json)) { 882 | json[i] <- list(renv_json_remap(json[[i]], map)) 883 | } 884 | } 885 | 886 | json 887 | 888 | } 889 | 890 | # load the renv profile, if any 891 | renv_bootstrap_profile_load(project) 892 | 893 | # construct path to library root 894 | root <- renv_bootstrap_library_root(project) 895 | 896 | # construct library prefix for platform 897 | prefix <- renv_bootstrap_platform_prefix() 898 | 899 | # construct full libpath 900 | libpath <- file.path(root, prefix) 901 | 902 | # attempt to load 903 | if (renv_bootstrap_load(project, libpath, version)) 904 | return(TRUE) 905 | 906 | # load failed; inform user we're about to bootstrap 907 | prefix <- paste("# Bootstrapping renv", version) 908 | postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") 909 | header <- paste(prefix, postfix) 910 | message(header) 911 | 912 | # perform bootstrap 913 | bootstrap(version, libpath) 914 | 915 | # exit early if we're just testing bootstrap 916 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) 917 | return(TRUE) 918 | 919 | # try again to load 920 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { 921 | message("* Successfully installed and loaded renv ", version, ".") 922 | return(renv::load()) 923 | } 924 | 925 | # failed to download or load renv; warn the user 926 | msg <- c( 927 | "Failed to find an renv installation: the project will not be loaded.", 928 | "Use `renv::activate()` to re-initialize the project." 929 | ) 930 | 931 | warning(paste(msg, collapse = "\n"), call. = FALSE) 932 | 933 | }) 934 | -------------------------------------------------------------------------------- /renv/settings.dcf: -------------------------------------------------------------------------------- 1 | external.libraries: 2 | ignored.packages: 3 | package.dependency.fields: Imports, Depends, LinkingTo 4 | r.version: 5 | snapshot.type: implicit 6 | use.cache: TRUE 7 | vcs.ignore.library: TRUE 8 | vcs.ignore.local: TRUE 9 | -------------------------------------------------------------------------------- /submission.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'How to build a package with "Rmd First" method' 3 | author: "Sébastien Rochette" 4 | date: "28/01/2021" 5 | output: html_document 6 | --- 7 | 8 | ## The title of the tutorial 9 | 10 | How to build a package with "Rmd First" method 11 | 12 | ## Abstract 13 | 14 | "Rmd First" method can reduce mental load when building packages by keeping users in a natural environment, using a tool they know: a RMarkdown document. 15 | 16 | The step between writing your own R code to analyze some data and refactoring it into a well-documented, ready-to-share R package seems unreachable to many R users. 17 | The package structure is sometimes perceived as useful only for building general-purpose tools for data analysis to be shared on official platforms. 18 | However, packages can be used for a broader range of purposes, from internal use to open-source sharing. 19 | Because packages are designed for robustness and enforce helpful standards for documentation and testing, the package structure provides a useful framework for refactoring analyses and preparing them to go into production. 20 | The following approach to write a development or an analysis inside a Rmd, will significantly reduce the work to transform a Rmd into a package : 21 | 22 | - _Design_ : define the goal of your next steps and the tools needed to reach them 23 | - _Prototype_ : use some small examples to prototype your script in Rmd 24 | - _Build_ : Build your script as functions and document your work to be able to use them, in the future, on real-life datasets 25 | - _Strengthen_ : Create tests to assure stability of your code and follow modifications through time 26 | - _Deploy_ : Transform as a well-structured package to deploy and share with your community 27 | 28 | During this tutorial, we will work through the steps of Rmd Driven Development to persuade attendees that their experience writing R code means that they already know how to build a package. They only need to be in a safe environment to find it out, which will be what we propose. 29 | We will take advantage of all existing tools such as {devtools}, {testthat}, {attachment} and {usethis} that ease package development from Rmd to building a package. 30 | The recent package [{fusen}](https://thinkr-open.github.io/fusen), which "inflates a package from a simple flat Rmd", will be presented to further reduce the step between well-designed Rmd and package deployment. 31 | Attendees will leave this workshop having built their first package with the "Rmd First" method and with the skills and tools to build more packages on their own. 32 | 33 | ## The broad topic it covers 34 | 35 | - R Packages: building packages, CRAN submission and package maintenance 36 | - Reproducibility and best practices 37 | 38 | ## The learning goals 39 | 40 | By the end of the tutorial participants should: 41 | 42 | - understand the methodology proposed by Rmd Driven Development 43 | - be able to refactor their code into correctly formatted functions 44 | - understand the structure of a package 45 | - be able to build a documented and tested R package 46 | - know how to share their work with the community on GitHub 47 | 48 | ## Time zone preference and time slot (please mention at least three different time zones you are comfortable with) 49 | 50 | - 1:00pm - 4:00pm UTC 51 | - 2:00pm - 5:00pm UTC 52 | - 3:00pm - 6:00pm UTC 53 | 54 | ## Length of the tutorial 55 | 56 | Tutorial will be 3 hours length. 57 | It will be divided in 3 times 1 hour: ~25’ presentation + 2’ quizz + 28’ exercises + 5’ break 58 | 59 | ## Language in which the tutorial can be taught. 60 | 61 | The tutorial will be taught in English. 62 | However, there will be a possibility for help in French during exercises sessions. 63 | 64 | ## The intended audience and method of online engagement with the audience 65 | 66 | The course will alternate between two formats of instruction: 67 | 68 | - Plenary room : Lecture, presenting slides 69 | - Breakout rooms (if possible): Exercises time. 5 attendees by room (6 rooms). Instructors are not needed in all 6 rooms, but we want to be able to discuss with some, without bothering everyone. Instructors will move from a room to the other and may be summoned over Slack. Teaching assistants may be needed. 70 | 71 | The tutorial is built as a private course. 72 | 73 | - There will only be 30 participants for 3 instructors. 74 | - Attendees are expected to participate and to answer questions. 75 | - Instructors will make sure this participation will be in a safe environment, in plain group and in small groups during exercises. 76 | - Instructors will ask questions to individuals to be sure no one is left behind. 77 | - Attendees should expect to share their screen individually or to the group so that we can help. 78 | - Instructors will try to make the course active and exciting. Attendees are expected to help in this way. 79 | 80 | A chat platform (Slack or equivalent) will be open in parallel to allow chat assistance, attendees interactions and information or resources sharing. 81 | 82 | ## If there exists, a link to the Tutorial materials and/or web page. 83 | 84 | - https://github.com/statnmap/user2021.rmdd 85 | 86 | ## Prerequisites / requirements 87 | 88 | ### Prerequisites 89 | 90 | Upper-beginner to Intermediate. 91 | Attendees should already have experience with R and be able to: 92 | 93 | - Manipulate rectangular data with {dplyr}: select, filter, mutate, group_by, summarize 94 | - Work with RMarkdown documents 95 | - Understand the meaning of this line of code and how to use it: 96 | ``` 97 | my_mean <- function(x, na.rm = TRUE) { sum(x, na.rm = na.rm) / length(x) } 98 | ``` 99 | 100 | ### Requirements 101 | 102 | - The tutorial will be taught using the [ThinkR e-learning platform, named CRUZ](https://rtask.thinkr.fr/remote-trainings-and-certification/). 103 | Here is a presentation of the platform that will be provided: https://thinkr.fr/Take_a_tour_on_CRUZ.pdf 104 | 105 | - The platform provided by ThinkR is online. No installation is required on attendees computers. 106 | - Attendees will only receive their credentials the day before the tutorial. They will be able to log on the e-learning platform after receiving their credentials. 107 | - All attendees will have their own sessions with all required packages and course material already installed 108 | 109 | - Required equipment 110 | + A computer 111 | + A correct internet connection (You can test your internet connection: we recommend a download value higher than 6 Mb/s) 112 | + A microphone (*compulsory, the default computer mic is perfect*), a webcam if the learner wishes and has one (*possibly the computer’s one if available*), headphones to ensure the learner’s comfort – the ideal being a headset with a microphone 113 | + Good mood 🙂 114 | 115 | 116 | ## Material sharing (license), recording consent 117 | 118 | - Material will be shared on GitHub : https://github.com/statnmap/user2021.rmdd 119 | - Instructors agree to be recorded. Attendees will be notified when recording is on, in particular during plenary room sessions. Recording will be stopped (or deleted) during exercises time 120 | 121 | 122 | ## A brief biography of the instructors 123 | 124 | - Sébastien Rochette (@statnmap) is R trainer and consultant at [ThinkR](https://rtask.thinkr.fr). 125 | He participates in the development of open-source R packages proposed on GitHub by ThinkR and himself, including {fusen} and {attachment}. He also has created multiple internal packages for ThinkR and different clients. 126 | He gave different presentations and tutorials on package development with the 'Rmd first' method as summed up in ["Rmd first: When development starts with documentation"](https://rtask.thinkr.fr/when-development-starts-with-documentation/) and blogs about R [on his website](https://statnmap.com). 127 | He is co-author of the book ["Engineering Production-Grade Shiny Apps"](https://engineering-shiny.org/) that promotes an adapted RMDD method for Shiny application using {golem}. 128 | 129 | - Emily Riederer (@emilyriederer) is a Senior Analytics Manager at Capital One where she leads a team building analytics infrastrucutre in R. Emily is a proponent of [R Markdown Driven Development](https://emilyriederer.netlify.app/post/rmarkdown-driven-development/) and a co-author of the [R Markdown Cookbook](https://bookdown.org/yihui/rmarkdown-cookbook/). She also maintains the {projmgr} and {convo} R packages, and frequently blogs about R [on her website](emily.rbind.io). 130 | -------------------------------------------------------------------------------- /teach-package-dev-rmdfirst.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | --------------------------------------------------------------------------------