From 7572078c1f4343dd153d75ceea5c6f70535e7f0e Mon Sep 17 00:00:00 2001 From: froggleston Date: Mon, 11 Nov 2024 12:49:49 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20carpentr?= =?UTF-8?q?ies/pegboard@bad0be19a12f0c6545801b276ddf26c945f8bfd1=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/intro-lesson.html | 2 +- articles/intro-xml.html | 2 +- articles/validation.html | 2 +- news/index.html | 2 +- pkgdown.yml | 2 +- reference/Episode.html | 2 +- reference/make_link_table.html | 28 ++++++++++++++-------------- reference/validate_links.html | 28 ++++++++++++++-------------- search.json | 2 +- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/articles/intro-lesson.html b/articles/intro-lesson.html index 6d87715..956bfc8 100644 --- a/articles/intro-lesson.html +++ b/articles/intro-lesson.html @@ -410,7 +410,7 @@

Methods Summaries and Validation## # ℹ 3 more variables: error <int>, images <int>, links <int>

Validation will auto-check everything and return the results as data frames. You can find more information abou the specific checks by -reading vignette("validation", package = "pegboard").

+reading vignette("validation", package = "pegboard").

Details of the individual functions can be found via ?validate_links(), ?validate_divs(), and ?validate_headings().

diff --git a/articles/intro-xml.html b/articles/intro-xml.html index 061f390..1302632 100644 --- a/articles/intro-xml.html +++ b/articles/intro-xml.html @@ -195,7 +195,7 @@

Motivating Example#> #> {% include setup-r.md %} child_from_include(setup_file) -#> /tmp/RtmpY1fgUy/file1b97ca0ff71.md +#> /tmp/Rtmp3r8ivU/file1b6e43337776.md writeLines(readLines(fs::path_ext_set(setup_file, "Rmd"))) # show the file
#> ## Setup Instructions
 #> 
diff --git a/articles/validation.html b/articles/validation.html
index 0fc5f93..a249e56 100644
--- a/articles/validation.html
+++ b/articles/validation.html
@@ -150,7 +150,7 @@ 
     
loop <- fs::path(lesson_fragment(), "_episodes", "14-looping-data-sets.md")
 make_link_table(Episode$new(loop))
-#>    scheme            server       port user
-#> 1   https   docs.python.org         NA     
-#> 2   https   docs.python.org         NA     
-#> 3   https   docs.python.org         NA     
-#> 4   https pandas.pydata.org         NA     
-#> 5   https   docs.python.org         NA     
-#> 9   https   carpentries.org         NA     
-#> 10                                  NA     
-#> 6                                22021     
-#> 7                           1177610896     
-#> 11  https   carpentries.org         NA     
-#> 12                                  NA     
-#> 13                          1309757824     
-#> 8                                22021     
+#>    scheme            server        port user
+#> 1   https   docs.python.org          NA     
+#> 2   https   docs.python.org          NA     
+#> 3   https   docs.python.org          NA     
+#> 4   https pandas.pydata.org          NA     
+#> 5   https   docs.python.org          NA     
+#> 9   https   carpentries.org          NA     
+#> 10                                   NA     
+#> 6                                 22010     
+#> 7                            2122065360     
+#> 11  https   carpentries.org          NA     
+#> 12                                   NA     
+#> 13                          -2132804248     
+#> 8                                 22010     
 #>                                                             path query
 #> 1                                           /3/library/glob.html      
 #> 2                                           /3/library/glob.html      
diff --git a/reference/validate_links.html b/reference/validate_links.html
index 05fda22..4620a79 100644
--- a/reference/validate_links.html
+++ b/reference/validate_links.html
@@ -234,20 +234,20 @@ 

Examples#> [22] "internal_file" "internal_well_formed" "all_reachable" #> [25] "img_alt_text" "descriptive" "link_length" v -#> scheme server port user -#> 1 https docs.python.org NA -#> 2 https docs.python.org NA -#> 3 https docs.python.org NA -#> 4 https pandas.pydata.org NA -#> 5 https docs.python.org NA -#> 9 https carpentries.org NA -#> 10 NA -#> 6 40 -#> 7 50 -#> 11 https carpentries.org NA -#> 12 NA -#> 13 1348819536 -#> 8 41 +#> scheme server port user +#> 1 https docs.python.org NA +#> 2 https docs.python.org NA +#> 3 https docs.python.org NA +#> 4 https pandas.pydata.org NA +#> 5 https docs.python.org NA +#> 9 https carpentries.org NA +#> 10 NA +#> 6 22010 +#> 7 -2082140592 +#> 11 https carpentries.org NA +#> 12 NA +#> 13 2122065360 +#> 8 22010 #> path query #> 1 /3/library/glob.html #> 2 /3/library/glob.html diff --git a/search.json b/search.json index 85f71ef..78437e1 100644 --- a/search.json +++ b/search.json @@ -1 +1 @@ -[{"path":[]},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"members, contributors, leaders pledge make participation community harassment-free experience everyone, regardless age, body size, visible invisible disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, religion, sexual identity orientation. pledge act interact ways contribute open, welcoming, diverse, inclusive, healthy community.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes positive environment community include: Demonstrating empathy kindness toward people respectful differing opinions, viewpoints, experiences Giving gracefully accepting constructive feedback Accepting responsibility apologizing affected mistakes, learning experience Focusing best just us individuals, overall community Examples unacceptable behavior include: use sexualized language imagery, sexual attention advances kind Trolling, insulting derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical email address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement-responsibilities","dir":"","previous_headings":"","what":"Enforcement Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Community leaders responsible clarifying enforcing standards acceptable behavior take appropriate fair corrective action response behavior deem inappropriate, threatening, offensive, harmful. Community leaders right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, communicate reasons moderation decisions appropriate.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within community spaces, also applies individual officially representing community public spaces. Examples representing community include using official e-mail address, posting via official social media account, acting appointed representative online offline event.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported community leaders responsible enforcement [INSERT CONTACT METHOD]. complaints reviewed investigated promptly fairly. community leaders obligated respect privacy security reporter incident.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement-guidelines","dir":"","previous_headings":"","what":"Enforcement Guidelines","title":"Contributor Covenant Code of Conduct","text":"Community leaders follow Community Impact Guidelines determining consequences action deem violation Code Conduct:","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_1-correction","dir":"","previous_headings":"Enforcement Guidelines","what":"1. Correction","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Use inappropriate language behavior deemed unprofessional unwelcome community. Consequence: private, written warning community leaders, providing clarity around nature violation explanation behavior inappropriate. public apology may requested.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_2-warning","dir":"","previous_headings":"Enforcement Guidelines","what":"2. Warning","title":"Contributor Covenant Code of Conduct","text":"Community Impact: violation single incident series actions. Consequence: warning consequences continued behavior. interaction people involved, including unsolicited interaction enforcing Code Conduct, specified period time. includes avoiding interactions community spaces well external channels like social media. Violating terms may lead temporary permanent ban.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_3-temporary-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"3. Temporary Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: serious violation community standards, including sustained inappropriate behavior. Consequence: temporary ban sort interaction public communication community specified period time. public private interaction people involved, including unsolicited interaction enforcing Code Conduct, allowed period. Violating terms may lead permanent ban.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_4-permanent-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"4. Permanent Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Demonstrating pattern violation community standards, including sustained inappropriate behavior, harassment individual, aggression toward disparagement classes individuals. Consequence: permanent ban sort public interaction within community.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 2.0, available https://www.contributor-covenant.org/version/2/0/ code_of_conduct.html. Community Impact Guidelines inspired Mozilla’s code conduct enforcement ladder. answers common questions code conduct, see FAQ https://www.contributor-covenant.org/faq. Translations available https:// www.contributor-covenant.org/translations.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":null,"dir":"","previous_headings":"","what":"Contributing to pegboard","title":"Contributing to pegboard","text":"outlines propose change pegboard. detailed info contributing , tidyverse packages, please see development contributing guide.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"fixing-typos","dir":"","previous_headings":"","what":"Fixing typos","title":"Contributing to pegboard","text":"can fix typos, spelling mistakes, grammatical errors documentation directly using GitHub web interface, long changes made source file. generally means ’ll need edit roxygen2 comments .R, .Rd file. can find .R file generates .Rd reading comment first line.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"bigger-changes","dir":"","previous_headings":"","what":"Bigger changes","title":"Contributing to pegboard","text":"want make bigger change, ’s good idea first file issue make sure someone team agrees ’s needed. ’ve found bug, please file issue illustrates bug minimal reprex (also help write unit test, needed).","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"pull-request-process","dir":"","previous_headings":"Bigger changes","what":"Pull request process","title":"Contributing to pegboard","text":"Fork package clone onto computer. haven’t done , recommend using usethis::create_from_github(\"\", fork = TRUE). Install development dependences devtools::install_dev_deps(), make sure package passes R CMD check running devtools::check(). R CMD check doesn’t pass cleanly, ’s good idea ask help continuing. Create Git branch pull request (PR). recommend using usethis::pr_init(\"brief-description--change\"). Make changes, commit git, create PR running usethis::pr_push(), following prompts browser. title PR briefly describe change. body PR contain Fixes #issue-number. user-facing changes, add bullet top NEWS.md (.e. just first header). Follow style described https://style.tidyverse.org/news.html.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"code-style","dir":"","previous_headings":"Bigger changes","what":"Code style","title":"Contributing to pegboard","text":"New code follow tidyverse style guide. can use styler package apply styles, please don’t restyle code nothing PR. use roxygen2, Markdown syntax, documentation. use testthat unit tests. Contributions test cases included easier accept.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"code-of-conduct","dir":"","previous_headings":"","what":"Code of Conduct","title":"Contributing to pegboard","text":"Please note pegboard project released Contributor Code Conduct. contributing project agree abide terms.","code":""},{"path":"https://carpentries.github.io/pegboard/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2020 Carpentries Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":null,"dir":"","previous_headings":"","what":"Getting help with pegboard","title":"Getting help with pegboard","text":"Thanks using pegboard! filing issue, places explore pieces put together make process smooth possible.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"make-a-reprex","dir":"","previous_headings":"","what":"Make a reprex","title":"Getting help with pegboard","text":"Start making minimal reproducible example using reprex package. haven’t heard used reprex , ’re treat! Seriously, reprex make R-question-asking endeavors easier (pretty insane ROI five ten minutes ’ll take learn ’s ). additional reprex pointers, check Get help! section tidyverse site.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"where-to-ask","dir":"","previous_headings":"","what":"Where to ask?","title":"Getting help with pegboard","text":"Armed reprex, next step figure ask. ’s question: start community.rstudio.com, /StackOverflow. people answer questions. ’s bug: ’re right place, file issue. ’re sure: let community help figure ! problem bug feature request, can easily return report . opening new issue, sure search issues pull requests make sure bug hasn’t reported /already fixed development version. default, search pre-populated :issue :open. can edit qualifiers (e.g. :pr, :closed) needed. example, ’d simply remove :open search issues repo, open closed.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"what-happens-next","dir":"","previous_headings":"","what":"What happens next?","title":"Getting help with pegboard","text":"efficient possible, development tidyverse packages tends bursty, shouldn’t worry don’t get immediate response. Typically don’t look repo sufficient quantity issues accumulates, ’s burst intense activity focus efforts. makes development efficient avoids expensive context switching problems, cost taking longer get back . process makes good reprex particularly important might multiple months initial report start working . can’t reproduce bug, can’t fix !","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Introduction to the Episode Object","text":"{pegboard} package facilitates analysis manipulation Markdown R Markdown files translating XML back . extends {tinkr} package (see vignette(\"tinkr\", package = \"tinkr\")) providing additional methods specific Carpentries-style lessons. two R6 classes defined {pegboard}: pegboard::Episode objects contain XML data, YAML metadata extra fields define child parent files particular episode. inherit tinkr::yarn R6 class. pegboard::Lesson objects contain lists Episode objects categorised “episodes”, “extra”, “children”. vignette discussing structure Episode objects, query contents {xml2} package, use methods active bindings get information , extract, manipulate anything inside Markdown R Markdown document.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"reading-markdown-content","dir":"Articles","previous_headings":"","what":"Reading Markdown Content","title":"Introduction to the Episode Object","text":"Episode object starts Markdown file. particular {pegboard}, assume Markdown file written using Pandoc syntax (superset CommonMark). can markdown file, us explore Episode object offer us, let’s take example R Markdown file present fragment Carpentries Workbench lesson package. using {xml2} package explore object {fs} package help constructing file paths. lesson fragment looks like. fragment ’s main purpose used examples tests, contains basic structure lesson want. can retrieve lesson_fragment() function, loads example data pegboard. take lesson fragment read first episode initialization method, Episode$new(), followed $confirm_sandpaper(), confirmation episode created work {sandpaper}, user interface build engine Carpentries Workbench (information non-workbench content, see section Jekyll Lesson Markdown Content) $protect_math() prevent special characters LaTeX math escaped. print Episode object, ’m going get long list methods, fields active bindings (functions act like fields) printed: actual XML content $body field. contains data markdown document, XML form. want see contents look like, can use $show(), $head(), $tail() methods (note: $show() method print entire markdown document).","code":"library(\"pegboard\") library(\"xml2\") library(\"fs\") ## /home/runner/work/_temp/Library/pegboard/sandpaper-fragment ## ├── config.yaml ## ├── episodes ## │ ├── intro.Rmd ## │ └── nope.md ## ├── index.md ## ├── instructors ## │ └── a.md ## ├── learners ## │ └── setup.md ## ├── profiles ## │ └── b.md ## └── site ## └── README.md lsn <- lesson_fragment(\"sandpaper-fragment\") # Read in the intro.Rmd document as an `Episode` object intro_path <- path(lsn, \"episodes\", \"intro.Rmd\") intro <- Episode$new(intro_path)$confirm_sandpaper()$protect_math() intro ## ## Inherits from: ## Public: ## add_md: function (md, where = 0L) ## body: xml_document, xml_node ## build_parents: ## challenges: active binding ## children: ## clone: function (deep = FALSE) ## code: active binding ## confirm_sandpaper: function () ## error: active binding ## get_blocks: function (type = NULL, level = 1L) ## get_challenge_graph: function (recurse = TRUE) ## get_divs: function (type = NULL, include = FALSE) ## get_images: function (process = FALSE) ## get_protected: function (type = NULL) ## get_yaml: function () ## handout: function (path = NULL, solutions = FALSE) ## has_children: active binding ## has_parents: active binding ## head: function (n = 6L) ## headings: active binding ## images: active binding ## initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, ## isolate_blocks: function () ## keypoints: active binding ## label_divs: function () ## lesson: active binding ## links: active binding ## md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) ## move_keypoints: function () ## move_objectives: function () ## move_questions: function () ## name: active binding ## ns: http://commonmark.org/xml/1.0 ## objectives: active binding ## output: active binding ## parents: ## path: /home/runner/work/_temp/Library/pegboard/sandpaper-fragm ... ## protect_curly: function () ## protect_math: function () ## protect_unescaped: function () ## questions: active binding ## remove_error: function () ## remove_output: function () ## reset: function () ## show: function (n = TRUE) ## show_problems: active binding ## solutions: active binding ## summary: function () ## tags: active binding ## tail: function (n = 6L) ## unblock: function (token = \"#'\", force = FALSE) ## use_dovetail: function () ## use_sandpaper: function (rmd = FALSE, yml = list()) ## validate_divs: function (warn = TRUE) ## validate_headings: function (verbose = TRUE, warn = TRUE) ## validate_links: function (warn = TRUE) ## warning: active binding ## write: function (path = NULL, format = \"md\", edit = FALSE) ## yaml: --- title: \"Using RMarkdown\" teaching: 10 exercises: 2 --- ## Private: ## clear_yaml_item: function (what) ## deep_clone: function (name, value) ## encoding: UTF-8 ## md_lines: function (path = NULL, stylesheet = NULL) ## mutations: TRUE FALSE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE ## problems: list ## record_problem: function (x) ## sourcepos: TRUE intro$body ## {xml_document} ## ## [1] ## [2] \\n \\n \\n ## [6] ## [7] \\n \\n \\n ## [11] \\n \\n \\n ## [16] \\n \\n \\n ## ... intro$head(10) ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? intro$tail(10) ## Cool, right? ## ## ::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use `.Rmd` files for lessons even if you don't need to generate any code ## - Run `sandpaper::check_lesson()` to identify any issues with your lesson ## - Run `sandpaper::build_lesson()` to preview your lesson locally ## ## :::::::::::::::::::::::::::::::::::::::::::::::: intro$show() ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## This is the new Carpentries template. It is written in [RMarkdown][r-markdown], ## which is a variant of Markdown that allows you to render code inside the ## lesson. Please refer to the [lesson ## example](https://carpentries.github.io/lesson-example) for full documentation. ## ## What you need to know is that there are three block quotes required for a valid ## Carpentries lesson template: ## ## 1. `questions` are displayed at the beginning of the episode to prime the ## learner for the content. ## 2. `objectives` are the learning objectives for an episode displayed with ## the questions. ## 3. `keypoints` are displayed at the end of the episode to reinforce the ## objectives. ## ## ::::::::::::::::::::::::::::::::::::: challenge ## ## ## Challenge 1: Can you do it? ## ## What is the output of this command? ## ## ```{r, eval=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ``` ## ## :::::::::::::::::::::::: solution ## ## ## Output ## ## ```{r, echo=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ``` ## ## :::::::::::::::::::::::::::::::::: ## ## ## Challenge 2: how do you nest solutions within challenge blocks? ## ## :::::::::::::::::::::::: solution ## ## You can add a line with at least three colons and a `solution` tag. ## ## ::::::::::::::::::::::::::::::::: ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Figures ## ## You can also include figures: ## ## ```{r pyramid} ## pie( ## c(Sky = 78, \"Sunny side of pyramid\" = 17, \"Shady side of pyramid\" = 5), ## init.angle = 315, ## col = c(\"deepskyblue\", \"yellow\", \"yellow3\"), ## border = FALSE ## ) ## ``` ## ## ## Math ## ## One of our episodes contains $\\LaTeX$ equations when describing how to create ## dynamic reports with {knitr}, so we now use mathjax to describe this: ## ## `$\\alpha = \\dfrac{1}{(1 - \\beta)^2}$` becomes: $\\alpha = \\dfrac{1}{(1 - \\beta)^2}$ ## ## Cool, right? ## ## ::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use `.Rmd` files for lessons even if you don't need to generate any code ## - Run `sandpaper::check_lesson()` to identify any issues with your lesson ## - Run `sandpaper::build_lesson()` to preview your lesson locally ## ## ::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"file-information","dir":"Articles","previous_headings":"","what":"File information","title":"Introduction to the Episode Object","text":"information file relationship files, can use following active bindings, useful working Episodes lesson context.","code":"intro$path ## /home/runner/work/_temp/Library/pegboard/sandpaper-fragment/episodes/intro.Rmd intro$name ## [1] \"intro.Rmd\" intro$lesson ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" # NOTE: relationships to other episodes are automatically handled in the # Lesson context intro$has_parents ## [1] FALSE intro$has_children ## [1] FALSE intro$children # separate documents processed as if they were part of this document ## character(0) intro$parents # the immediate documents that would require this document to build ## character(0) intro$build_parents # the final documents that would require this document to build ## character(0)"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"accessing-markdown-elements","dir":"Articles","previous_headings":"","what":"Accessing Markdown Elements","title":"Introduction to the Episode Object","text":"Episode object centered around $body item, contains XML representation document. possible find markdown elements XPath statments: However, useful elements want know , implemented active bindings methods: Much summarized $summary() method:","code":"xml2::xml_find_all(intro$body, \".//md:link\", ns = intro$ns) ## {xml_nodeset (1)} ## [1] ## [1] \\n \\n ... ## [2] \\n \\n ... ## [3] \\n \\n < ... # headings where level 2 headings are equivalent to sections intro$headings ## {xml_nodeset (6)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ` tags ## {xml_nodeset (0)} intro$links ## {xml_nodeset (1)} ## [1] ls -larth /path/to/folder <\/code_block> There is a code chunk here that will produce a plot, but not show the code: ```{r chunky, echo=FALSE, fig.alt=\"a plot of y = mx + b for m = 1 and b = 0\"} plot(1:10, type = \"l\") ``` plot(1:10, type = \"l\") <\/code_block>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"manipulation","dir":"Articles","previous_headings":"","what":"Manipulation","title":"Introduction to the Episode Object","text":"everything centers around $body element extracted {xml2}, ’s possible manipulate elements document. One thing possible can add new content document using $add_md() method, add markdown element paragraph document. example, can add information pegboard new code block first heading: can also manipulate existing elements. example, let’s say wanted make sure R code chunks named. can querying manipulating code blocks: can see chunks now names, proof rendering:","code":"intro$head(26) # first 26 lines ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## This is the new Carpentries template. It is written in [RMarkdown][r-markdown], ## which is a variant of Markdown that allows you to render code inside the ## lesson. Please refer to the [lesson ## example](https://carpentries.github.io/lesson-example) for full documentation. intro$body # first heading is item 11 ## {xml_document} ## ## [1] ## [2] \\n \\n \\n ## [6] ## [7] \\n \\n \\n ## [11] \\n \\n \\n ## [16] \\n \\n \\n ## ... cb <- c(\"You can clone the **{pegboard} package**: ```sh git clone https://github.com/carpentries/pegboard.git ``` \") intro$add_md(cb, where = 11) intro$head(26) # code block has been added ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## You can clone the **{pegboard} package**: ## ## ```sh ## git clone https://github.com/carpentries/pegboard.git ## ``` intro$code ## {xml_nodeset (4)} ## [1] git clone https://gith ... ## [2] git clone https://gith ... ## [2] git clone https://gith ... ## [2] } replaced class definitions key/value pairs. always appear relevant block lead code blocks looked like : Moreover, achieve special callout blocks, used blockquotes given special classes (accessbility -blocks semantic HTML) nesting block quotes looked like : One biggest challenges authors , unless used editor like vim emacs, difficult write prefixed blockquote characters keeping track IALs belonged block.","code":"~~~ ls -larth /path/to/dir ~~~ {: .language-bash} > ## Challenge > > How do you list all files in a directory in reverse order by the time it was > last updated? > > > ## Solution > > > > ~~~ > > ls -larth /path/to/dir > > ~~~ > > {: .language-bash} > {: .solution} {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"special-methods-and-active-bindings","dir":"Articles","previous_headings":"Jekyll Lesson Markdown Content","what":"Special methods and active bindings","title":"Introduction to the Episode Object","text":"Episodes written Jekyll syntax special functions active bindings allow analyzed transformed Workbench episodes. example lesson fragment: Notice questions, objectives, keypoints yaml frontmatter. accessor returns list instead node, compatibility Jekyll lessons: Even though challenges formatted differently, accessors still return correctly: can also get block quotes using $get_blocks() method. NOTE: extract block quotes (including ktag attributes. One things advantageous blockquotes analyze pathway blockquotes figure comonly written lesson. $get_challenge_graph() creates data frame describes relationships: might notice attribute called ktag. Jekyll-formatted episode read , IAL tags processed placed attribute called ktag (kramdown tag), accessible via $tags active binding. needed commonmark know process postfix tags important translation commonmark syntax:","code":"library(\"pegboard\") library(\"xml2\") library(\"fs\") lf <- lesson_fragment() ep <- Episode$new(path(lf, \"_episodes\", \"14-looping-data-sets.md\")) # show relevant sections of head and tail ep$head(29) ## --- ## title: \"Looping Over Data Sets\" ## teaching: 5 ## exercises: 10 ## questions: ## - \"How can I process many data sets with a single command?\" ## objectives: ## - \"Be able to read and write globbing expressions that match sets of files.\" ## - \"Use glob to create lists of files.\" ## - \"Write for loops to perform operations on files given their names in a list.\" ## keypoints: ## - \"Use a `for` loop to process files given a list of their names.\" ## - \"Use `glob.glob` to find sets of files whose names match a pattern.\" ## - \"Use `glob` and `for` to process batches of files.\" ## --- ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ## ## ``` ## import pandas as pd ## for filename in ['data/gapminder_gdp_africa.csv', 'data/gapminder_gdp_asia.csv']: ## data = pd.read_csv(filename, index_col='country') ## print(filename, data.min()) ## ``` ## {: .language-python} ep$tail(53) ## ## > ## Comparing Data ## > ## > Write a program that reads in the regional data sets ## > and plots the average GDP per capita for each region over time ## > in a single chart. ## > ## > > ## Solution ## > > ## > > This solution builds a useful legend by using the string [`split`](https://docs.python.org/3/library/stdtypes.html#str.split) method to ## > > extract the `region` from the path 'data/gapminder\\_gdp\\_a\\_specific\\_region.csv'. The [`pathlib module`] ## > > also provides useful abstractions for file and path manipulation like returning the name of a file ## > > without the file extension. ## > > ## > > ``` ## > > import glob ## > > import pandas as pd ## > > import matplotlib.pyplot as plt ## > > fig, ax = plt.subplots(1,1) ## > > for filename in glob.glob('data/gapminder_gdp*.csv'): ## > > dataframe = pd.read_csv(filename) ## > > # extract from the filename, expected to be in the format 'data/gapminder_gdp_.csv'. ## > > # we will split the string using the split method and `_` as our separator, ## > > # retrieve the last string in the list that split returns (`.csv`), ## > > # and then remove the `.csv` extension from that string. ## > > region = filename.split('_')[-1][:-4] ## > > dataframe.mean().plot(ax=ax, label=region) ## > > plt.legend() ## > > plt.show() ## > > ``` ## > > {: .language-python} ## > {: .solution} ## {: .challenge} ## ## ### ZNK test links and images ## ## \"books ## ## \"books ## ## Link to [Home]({{ page.root }}/index.html) and to [shell]({{ site.swc_pages }}/shell-novice) ## ## ![Carpentries logo](https://carpentries.org/assets/img/TheCarpentries.svg) ## ## ![Non-working image](../no-workie.svg) ## ## ![Non-working image with jekyll syntax]({{ page.root }}/no-workie.svg) ## ## This text includes a [link that isn't parsed correctly by commonmark]({{ page.root }}{% link index.md %}) ## . The rest of the text should be properly parsed. ## ## {% include links.md %} ep$questions ## [1] \"How can I process many data sets with a single command?\" ep$objectives ## [1] \"Be able to read and write globbing expressions that match sets of files.\" ## [2] \"Use glob to create lists of files.\" ## [3] \"Write for loops to perform operations on files given their names in a list.\" ep$keypoints ## [1] \"Use a `for` loop to process files given a list of their names.\" ## [2] \"Use `glob.glob` to find sets of files whose names match a pattern.\" ## [3] \"Use `glob` and `for` to process batches of files.\" ep$challenges ## {xml_nodeset (3)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n from the filename, expected to be in the format 'data/gapminder_gdp_.csv'. ## # we will split the string using the split method and `_` as our separator, ## # retrieve the last string in the list that split returns (`.csv`), ## # and then remove the `.csv` extension from that string. ## region = filename.split('_')[-1][:-4] ## dataframe.mean().plot(ax=ax, label=region) ## plt.legend() ## plt.show() ## ``` ## ## ::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## ### ZNK test links and images ## ## \"books ## ## \"books ## ## Link to [Home](index.html) and to [shell](https://swcarpentry.github.io/shell-novice) ## ## ![](https://carpentries.org/assets/img/TheCarpentries.svg){alt='Carpentries logo'} ## ## ![](no-workie.svg){alt='Non-working image'} ## ## ![](no-workie.svg){alt='Non-working image with jekyll syntax'} ## ## This text includes a [link that isn't parsed correctly by commonmark](index.md) ## . The rest of the text should be properly parsed. ## ## ## ## :::::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use a `for` loop to process files given a list of their names. ## - Use `glob.glob` to find sets of files whose names match a pattern. ## - Use `glob` and `for` to process batches of files. ## ## ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"transformation-tip","dir":"Articles","previous_headings":"Jekyll Lesson Markdown Content > Transformation","what":"Transformation tip!","title":"Introduction to the Episode Object","text":"times lesson authors forget tag block quote correct type tag make callout block. case, block quote remain unconverted lesson. example let’s say block quote top lesson defined prerequisites, author accidentally new line blockquote IAL tag, meaning blockquote processed: Notice block quote picked blockquote, special block quote. set ktag attribute block quote “{: .prereq}”, recognised special blockquote, can translated. Now can convert block fenced div $unblock()","code":"# add a prerequisite block after the questions and objectives untranslated_block <- \" > ## Barnaby > > - a barn > - a bee > {: .prereq} \" ep$add_md(untranslated_block, where = 10) ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## ## {: .prereq} ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ep$get_blocks(\".prereq\") ## {xml_nodeset (0)} ep$get_blocks() ## {xml_nodeset (1)} ## [1] \\n \\n Barn ... # remove the orphan prereq tag: orphan_tag <- xml2::xml_find_all(ep$body, \".//md:paragraph[md:text[contains(text(),'.prereq}')]]\", ns = ep$ns) xml2::xml_remove(orphan_tag) ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ## ## ```python # set the attribute of the block quote: xml2::xml_set_attr(ep$get_blocks(), \"ktag\", \"{: .prereq}\") ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## {: .prereq} ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ep$get_blocks(\".prereq\") ## {xml_nodeset (1)} ## [1] \\n \\n A Brief Word About History and Jekyll","what":"Folder Structure","title":"Introduction to the Lesson Object","text":"folder structure lessons built Jekyll one content tooling lived side--side. folder structure looked something like : {pegboard} first written, initially assumed folder structure, R Markdown regular Markdown episodes lived different folders (often , outputs R Markdown files lived inside _episodes/ folder. main method organising episodes numbers embedded name files. Workbench developed, clear folder structure needed change, needed keep compatibility old lessons want ensure people can independently convert old style lessons new style, thus added jekyll parameter Lesson object initializer method, set jekyll = TRUE default keep backwards compatibility.","code":"# . # ├── Gemfile # ├── Makefile # ├── _config.yml # ├── _episodes/ # │ └── 01-intro.md # ├── _episodes_rmd/ # ├── _extras/ # │ ├── a.md # │ └── b.md # ├── _includes/ # ├── _layouts/ # ├── aio.md # ├── assets/ # ├── bin/ # ├── fig/ # ├── index.md # ├── reference.md # ├── requirements.txt # └── setup.md"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"creating-a-new-lesson-object","dir":"Articles","previous_headings":"","what":"Creating a New Lesson Object","title":"Introduction to the Lesson Object","text":"Lesson object invoked Lesson$new(), method. , demonstrate Workbench lesson. folder structure workbench lesson: read , Workbench lesson, need specify jekyll = FALSE register div tags ensure lesson treated like Workbench lesson. Lesson printing shows subset methods named similarly methods active bindings Episode class. inherited, rather implemented across Episode objects. Episode objects parsed one three elements: “episodes”, “children”, “extra” (NOTE: “extra” slot may superceded elements better match folder structure lessons). Notice one episode $episodes item, directory tree , see two. config.yaml file, defines order episodes: episodes/nope.Rmd listed, read . useful avoid reading content files incomplete correctly formatted.","code":"# . # ├── config.yaml # ├── episodes # │ ├── intro.Rmd # │ └── nope.md # ├── index.md # ├── instructors # │ └── a.md # ├── learners # │ └── setup.md # ├── profiles # │ └── b.md # └── site # └── README.md library(\"pegboard\") library(\"glue\") library(\"yaml\") library(\"xml2\") library(\"fs\") wbfragment <- lesson_fragment(\"sandpaper-fragment\") print(wbfragment) # path to the lesson ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" wb_lesson <- Lesson$new(wbfragment, jekyll = FALSE) print(wb_lesson) ## ## Public: ## blocks: function (type = NULL, level = 0, path = FALSE) ## built: NULL ## challenges: function (path = FALSE, graph = FALSE, recurse = TRUE) ## children: NULL ## clone: function (deep = FALSE) ## episodes: list ## extra: list ## files: active binding ## get: function (element = NULL, collection = \"episodes\") ## handout: function (path = NULL, solution = FALSE) ## has_children: active binding ## initialize: function (path = \".\", rmd = FALSE, jekyll = TRUE, ...) ## isolate_blocks: function () ## load_built: function () ## n_problems: active binding ## overview: FALSE ## path: /home/runner/work/_temp/Library/pegboard/sandpaper-fragment ## reset: function () ## rmd: FALSE ## sandpaper: TRUE ## show_problems: active binding ## solutions: function (path = FALSE) ## summary: function (collection = \"episodes\") ## thin: function (verbose = TRUE) ## trace_lineage: function (episode_path) ## validate_divs: function () ## validate_headings: function (verbose = TRUE) ## validate_links: function () ## Private: ## deep_clone: function (name, value) lapply(wb_lesson$episodes, class) ## $intro.Rmd ## [1] \"Episode\" \"yarn\" \"R6\" lapply(wb_lesson$children, class) ## list() lapply(wb_lesson$extra, class) ## $index.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $a.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $setup.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $b.md ## [1] \"Episode\" \"yarn\" \"R6\" read_yaml(path(wbfragment, \"config.yaml\"))$episodes ## [1] \"intro.Rmd\""},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"file-information","dir":"Articles","previous_headings":"","what":"File Information","title":"Introduction to the Lesson Object","text":"Lesson object contains information file information:","code":"# what is the root path for the lesson? wb_lesson$path ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" # what episode files exist? wb_lesson$files ## intro.Rmd ## \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment/episodes/intro.Rmd\" # do any of the files have children (Workbench lessons only)? wb_lesson$has_children ## [1] FALSE"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"accessors","dir":"Articles","previous_headings":"","what":"Accessors","title":"Introduction to the Lesson Object","text":"mentioned earlier, many methods Lesson object wrappers methods Episode objects. challenges, solutions obvious ones. rest elements (active bindings), need use $get() method. example, wanted code blocks episodes extra content, use: Similarly, links headings use:","code":"wb_lesson$challenges() ## $intro.Rmd ## $intro.Rmd$`div-3-challenge` ## {xml_nodeset (12)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ## 1 intro.Rmd 6 6 6 1 2 3 0 0 ## # ℹ 3 more variables: error , images , links wb_lesson$summary(collection = c(\"episodes\", \"extra\")) ## # A tibble: 5 × 12 ## page sections headings callouts challenges solutions code output warning ## ## 1 intro.Rmd 6 6 6 1 2 3 0 0 ## 2 index.md 0 0 0 0 0 0 0 0 ## 3 a.md 0 0 0 0 0 0 0 0 ## 4 setup.md 2 2 3 0 2 0 0 0 ## 5 b.md 0 0 0 0 0 0 0 0 ## # ℹ 3 more variables: error , images , links divs <- wb_lesson$validate_divs() print(divs) ## episodes path div pb_label pos ## div-1-questions intro.Rmd episodes/intro.Rmd questions div-1-questions 7 ## div-2-objectives intro.Rmd episodes/intro.Rmd objectives div-2-objectives 13 ## div-3-challenge intro.Rmd episodes/intro.Rmd challenge div-3-challenge 37 ## div-4-solution intro.Rmd episodes/intro.Rmd solution div-4-solution 47 ## div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 60 ## div-6-keypoints intro.Rmd episodes/intro.Rmd keypoints div-6-keypoints 90 ## div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 ## div-2-solution setup.md learners/setup.md solution div-2-solution 14 ## div-3-solution setup.md learners/setup.md solution div-3-solution 22 ## is_known ## div-1-questions TRUE ## div-2-objectives TRUE ## div-3-challenge TRUE ## div-4-solution TRUE ## div-5-solution TRUE ## div-6-keypoints TRUE ## div-1-instructor TRUE ## div-2-solution TRUE ## div-3-solution TRUE headings <- wb_lesson$validate_headings() print(headings) ## episodes heading ## 1 intro.Rmd Introduction ## 2 intro.Rmd Challenge 1: Can you do it? ## 3 intro.Rmd Output ## 4 intro.Rmd Challenge 2: how do you nest solutions within challenge blocks? ## 5 intro.Rmd Figures ## 6 intro.Rmd Math ## 7 setup.md For Windows ## 8 setup.md For MacOS ## level pos node first_heading_is_second_level greater_than_first_level ## 1 2 20 ## ## ::warning file=learners/setup.md,line=18:: [needs HTTPS]: [the PuTTY terminal](http://example.com/putty) ## ::warning file=learners/setup.md,line=26:: [needs HTTPS]: [Terminal.app](http://example.com/terminal) print(links) ## episodes scheme server port user path query ## 1 intro.Rmd https carpentries.github.io NA /lesson-example ## 2 setup.md http example.com NA /putty ## 3 setup.md http example.com NA /terminal ## fragment orig text alt ## 1 https://carpentries.github.io/lesson-example lesson example ## 2 http://example.com/putty the PuTTY terminal ## 3 http://example.com/terminal Terminal.app ## title type rel anchor sourcepos filepath parents node ## 1 link FALSE 25 episodes/intro.Rmd FALSE 18 learners/setup.md FALSE 26 learners/setup.md ## 1 intro.Rmd 3 0 0 0 0 ## 2 site/built/a.md 0 0 0 0 0 ## 3 site/built/b.md 0 0 0 0 0 ## 4 site/built/index.md 0 0 0 0 0 ## 5 site/built/intro.md 3 1 1 0 0 ## 6 site/built/setup.md 0 0 0 0 0"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"handouts","dir":"Articles","previous_headings":"","what":"Handouts","title":"Introduction to the Lesson Object","text":"another method wrapped Episode method, combines output single file prepends Episode title section:","code":"writeLines(wb_lesson$handout()) ## ## Using RMarkdown ## ## ## Challenge 1: Can you do it? ## ## What is the output of this command? ## ## ```{r, eval=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ```"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"accessing-other-episode-methods","dir":"Articles","previous_headings":"","what":"Accessing other Episode methods","title":"Introduction to the Lesson Object","text":"pegboard::Episode methods listed , need manually iterate Episode objects. example, wanted extract instructor notes lesson, use purrr::map() wanted get specific thing body document, use functions {xml2} xml2::xml_find_first() xml2::xml_find_all(). , looking first first text element fenced-div element: information constructing XPath queries working XML data, can read vignette(\"intro-xml\", package = \"pegboard\")","code":"purrr::map(c(wb_lesson$episodes, wb_lesson$extra), function(ep) ep$get_divs(\"instructor\")) ## $intro.Rmd ## named list() ## ## $index.md ## named list() ## ## $a.md ## named list() ## ## $setup.md ## $setup.md$`div-1-instructor` ## {xml_nodeset (3)} ## [1] \\n \\n \\n } replaced class definitions key/value pairs. always appear relevant block lead code blocks looked like : Moreover, achieve special callout blocks, used blockquotes given special classes (accessbility -blocks semantic HTML) nesting block quotes looked like : One biggest challenges authors , unless used editor like vim emacs, difficult write prefixed blockquote characters keeping track IALs belonged block.","code":"~~~ ls -larth /path/to/dir ~~~ {: .language-bash} > ## Challenge > > How do you list all files in a directory in reverse order by the time it was > last updated? > > > ## Solution > > > > ~~~ > > ls -larth /path/to/dir > > ~~~ > > {: .language-bash} > {: .solution} {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"methods","dir":"Articles","previous_headings":"Jekyll Lessons","what":"Methods","title":"Introduction to the Lesson Object","text":"methods specific lessons built Jekyll. particular, n_problems show_problems active binding useful determining anything went wrong parsing kramdown syntax, $isolate_blocks() method used strip non-blockquote content, $blocks() method returned block quote filters types, $rmd field indicator lesson used R Markdown. mentioned , Jekyll uses special block quotes format callout blocks. $challenges() $solutions() methods recognise return block quotes: blocks, can use $blocks() method:","code":"jekyll <- Lesson$new(lesson_fragment(\"lesson-fragment\"), jekyll = TRUE) jekyll$n_problems ## 10-lunch.md 12-for-loops.md 14-looping-data-sets.md ## 0 0 0 ## 17-scope.md ## 0 rmd <- Lesson$new(lesson_fragment(\"rmd-lesson\"), jekyll = TRUE) ## could not find _episodes/, using _episodes_rmd/ as the source rmd$n_problems ## 01-test.Rmd ## 0 jekyll$challenges() ## $`10-lunch.md` ## {xml_nodeset (0)} ## ## $`12-for-loops.md` ## {xml_nodeset (7)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ## Setup Instructions #> #> ### Python #> #> {% include setup-python.md%} #> #> ### R #> #> {% include setup-r.md %} child_from_include(setup_file) #> ℹ /tmp/RtmpY1fgUy/file1b97ca0ff71.md writeLines(readLines(fs::path_ext_set(setup_file, \"Rmd\"))) # show the file #> ## Setup Instructions #> #> ### Python #> #> ```{r include-setup-python, child='files/setup-python.md'} #> ``` #> #> ### R #> #> ```{r include-setup-r, child='files/setup-r.md'} #> ```"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"working-with-xml-data","dir":"Articles","previous_headings":"","what":"Working with XML data","title":"Working with XML data","text":"Episode object contains field (can think field list element) called $body, contains {xml2} document. core Episode object every function works way field.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-memory-of-xml-objects","dir":"Articles","previous_headings":"Working with XML data","what":"The memory of XML objects","title":"Working with XML data","text":"casual R user (even experienced), way use package may seem little strange. R, functions side effects, vast majority methods Episode object modify object way XML data handled R {xml2} package. Normally R, pass data function, make copy data apply function copy data: working XML R, {xml2} package unparalleled, leads surprising outcomes modify content within XML object, modifying object place: gets bit stranger consider code, y x exactly object shown fact manipulate y, x also modified: can even extract child elements XML document manipulate reflected parent. example, extract second child document, apply cool=\"verified\" attribute child, reflected parent document. persistance lends well using {R6} package creating objects work object-oriented way (methods belong classes instead way around). familiar Python methods work, mostly familiar {R6} objects behave. worthwhile read {R6} introduction vignette want understand program modify package. example , notice use xml2::xml_child() extract child nodes, real power XML comes searching items using XPath syntax traversing XML nodes able one following get child called “c” next section cover bit XPath provide resources practice learn comes handy quickly traverse XML nodes without relying loops.","code":"x <- 1:10 f <- function(x) { # insert 99 after the fourth position in a vector return(append(x, 99, after = 4)) } print(f(x)) #> [1] 1 2 3 4 99 5 6 7 8 9 10 # note that x is not modified print(x) #> [1] 1 2 3 4 5 6 7 8 9 10 x <- xml2::read_xml(\"<\/b><\/a>\") print(x) #> {xml_document} #> #> [1] f <- function(x, new = \"c\") { xml2::xml_add_child(x, new, .where = xml2::xml_length(x)) return(x) } y <- f(x) # note that x and y are identical print(x) #> {xml_document} #> #> [1] #> [2] print(y) #> {xml_document} #> #> [1] #> [2] f(y, \"d\") #> {xml_document} #> #> [1] #> [2] #> [3] print(y) #> {xml_document} #> #> [1] #> [2] #> [3] print(x) #> {xml_document} #> #> [1] #> [2] #> [3] child <- xml2::xml_child(x, 2) xml2::xml_set_attr(child, \"cool\", \"verified\") print(child) #> {xml_node} #> #> NULL print(x) #> {xml_document} #> #> [1] #> [2] #> [3] print(y) #> {xml_document} #> #> [1] #> [2] #> [3] xml2::xml_find_first(x, \".//c\") #> {xml_node} #> xml2::xml_find_first(x, \"/a/c\") #> {xml_node} #> "},{"path":[]},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-structure-of-xpath","dir":"Articles","previous_headings":"Using XPath to parse XML","what":"The structure of XPath","title":"Working with XML data","text":"section, talk XPath syntax, non-exhaustive. Unfortunately, good tutorials web far , can help: MDN XPath Axes good knowing navigate among nodes MDN XPath functions good knowing filter node matches w3schools tutorial XPath actually one best , excpetion rule. tutorial, trust content w3schools (aligned web consortium). XPath tester like regex tester allow try complex queries visual manner. ’s important remember XML document tree-like structure similar directories folders computer. example, look source directory structure package, see folder called R/ nested folder called tests/testhat/. started root directory package, list R files R/ folder ls R/*.R similarly, wanted list R files tests/testthat/ folder, us ls tests/testthat/*.R. respect, XPath similar syntax: enter next level nesting, add slash (/). example, let’s take look file structure look like XML form: XPath syntax find files R testthat folders started root: R/file tests/testthat/file. However, XPath one advantage normal command line syntax doesn’t : can short-cut paths, wanted find files given folder, can use double slash (//) recursively search nesting. habit, normally use precede slashes dot (.) can sure start node variable: course, method finds files, wanted filter , can use bracket notation create filters selection based ext attribute, prefixed @. bracket notation, add brackets node selection condition. case, want test extension ‘R’, use [@ext='R']: scheme, ’ve put file names text nodes, can use bracket notation XPath functions filter files contain “one” wanted extract source files contain “one”, also use parent:: XPath axis: Note used slash (/) instead square brackets parent, get parent back: see, many times, XPath query can get kind hairy, often like compose different parts programming {glue}: next section, discuss extract manipulate XML comes Markdown namespaces.","code":" one<\/file> two<\/file> <\/R> test-data<\/file> <\/data> test-one<\/file> test-two<\/file> <\/testthat> <\/tests> <\/ROOT> xml2::xml_find_all(xml, \"R/file\") #> {xml_nodeset (2)} #> [1] one<\/file> #> [2] two<\/file> xml2::xml_find_all(xml, \"tests/testthat/file\") #> {xml_nodeset (2)} #> [1] test-one<\/file> #> [2] test-two<\/file> xml2::xml_find_all(xml, \".//file\") #> {xml_nodeset (5)} #> [1] one<\/file> #> [2] two<\/file> #> [3] test-data<\/file> #> [4] test-one<\/file> #> [5] test-two<\/file> xml2::xml_find_all(xml, \".//file[@ext='R']\") #> {xml_nodeset (4)} #> [1] one<\/file> #> [2] two<\/file> #> [3] test-one<\/file> #> [4] test-two<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')]\") #> {xml_nodeset (2)} #> [1] one<\/file> #> [2] test-one<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')][parent::R]\") #> {xml_nodeset (1)} #> [1] one<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')]/parent::R\") #> {xml_nodeset (1)} #> [1] \\n one<\/file>\\n two<\/file>\\n<\/R> predicate <- \"[@ext='R'][contains(text(), 'one')]\" XPath <- glue::glue(\".//file{predicate}/parent::R\") xml2::xml_find_all(xml, XPath) #> {xml_nodeset (1)} #> [1] \\n one<\/file>\\n two<\/file>\\n<\/R>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"xml-data-from-markdown-using-namespaces","dir":"Articles","previous_headings":"","what":"XML data from Markdown using namespaces","title":"Working with XML data","text":"XML markdown transformation fully handled {commonmark} package, convenient commonmark::markdown_xml() function. example, following markdown processed: bunch example markdown text list can see successfully parsed markdown paragraph list various elements within.","code":"This is a bunch of [example markdown](https://example.com 'for example') text - this - is - a **list** md <- c(\"This is a bunch of [example markdown](https://example.com 'for example') text\", \"\", \"- this\", \"- is\", \"- a **list**\" ) xml_txt <- commonmark::markdown_xml(paste(md, collapse = \"\\n\")) class(xml_txt) #> [1] \"character\" writeLines(xml_txt) #> #> #> #> #> This is a bunch of <\/text> #> #> example markdown<\/text> #> <\/link> #> text<\/text> #> <\/paragraph> #> #> #> #> this<\/text> #> <\/paragraph> #> <\/item> #> #> #> is<\/text> #> <\/paragraph> #> <\/item> #> #> #> a <\/text> #> #> list<\/text> #> <\/strong> #> <\/paragraph> #> <\/item> #> <\/list> #> <\/document>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-default-namespace","dir":"Articles","previous_headings":"XML data from Markdown using namespaces","what":"The default namespace","title":"Working with XML data","text":"Now ’s catch: commonmark markdown always starts basic skeleton root node . xmlns attribute defines default XML namespace: many XML applications, namespaces come prefixes, defined xmlns attribute (e.g. xmlns:svg=\"http://www.w3.org/2000/svg\"). node namespace, needs selected namespace prefix like : .//svg:circle. default namespaces, rule applies, question becomes: know namespace prefix ? {xml2}, default namespace always begins d1 increments new namespaces added. can inspect namespace xml2::xml_ns(): Thus, XPath query use select paragraph .//d1:paragraph: course, default namespace {xml2} drawbacks adding new nodes duplicate namespace different identifier, one way avoided {tinkr} (package basic conversion) define namespace prefix function can use querying: ’s also important remember nodes require namespace prefix, wanted select paragraphs inside list, need specify use .//md:list//md:paragraph:","code":"#> #> #> #> #> MARKDOWN CONTENT HERE #> #> <\/document> xml <- xml2::read_xml(xml_txt) xml2::xml_ns(xml) #> d1 <-> http://commonmark.org/xml/1.0 # with namespace prefix xml2::xml_find_all(xml, \".//d1:paragraph\") #> {xml_nodeset (4)} #> [1] \\n This is a bunch of <\/text>\\n < ... #> [2] \\n this<\/text>\\n<\/paragraph> #> [3] \\n is<\/text>\\n<\/paragraph> #> [4] \\n a <\/text>\\n \\n md <-> http://commonmark.org/xml/1.0 xml2::xml_find_all(xml, \".//md:paragraph\", ns = tinkr::md_ns()) #> {xml_nodeset (4)} #> [1] \\n This is a bunch of <\/text>\\n < ... #> [2] \\n this<\/text>\\n<\/paragraph> #> [3] \\n is<\/text>\\n<\/paragraph> #> [4] \\n a <\/text>\\n \\n {xml_nodeset (3)} #> [1] \\n this<\/text>\\n<\/paragraph> #> [2] \\n is<\/text>\\n<\/paragraph> #> [3] \\n a <\/text>\\n \\n XML node defined pegboard namespace. sandwich nodes want query allow us use tinkr::find_between() search specific tags: automated get_divs() internal function:","code":"This is markdown with fenced divs ::: discussion This is a discussion ::: ::: spoiler This is a spoiler that is hidden by default ::: md <- 'This is markdown with fenced divs ::: discussion This is a discussion ::: ::: spoiler This is a spoiler that is hidden by default ::: ' fences <- xml2::read_xml(commonmark::markdown_xml(md)) fences #> {xml_document} #> #> [1] \\n This is markdown with fenced di ... #> [2] \\n ::: discussion<\/text>\\n<\/paragr ... #> [3] \\n This is a discussion<\/text>\\n<\/ ... #> [4] \\n :::<\/text>\\n<\/paragraph> #> [5] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [6] \\n This is a spoiler that is hidde ... #> [7] \\n :::<\/text>\\n<\/paragraph> pb <- asNamespace(\"pegboard\") pb$label_div_tags(fences) fences #> {xml_document} #> #> [1] \\n This is markdown with fenced d ... #> [2] #> [3] \\n ::: discussion<\/text>\\n<\/parag ... #> [4] \\n This is a discussion<\/text>\\n< ... #> [5] \\n :::<\/text>\\n<\/paragraph> #> [6] #> [7] #> [8] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [9] \\n This is a spoiler that is hidd ... #> [10] \\n :::<\/text>\\n<\/paragraph> #> [11] ns <- pb$get_ns() ns # both md and pegboard namespaces #> md <-> http://commonmark.org/xml/1.0 #> pb <-> http://carpentries.org/pegboard/ tinkr::find_between(fences, ns = ns, pattern = \"pb:dtag[@label='div-1-discussion']\") #> {xml_nodeset (3)} #> [1] \\n ::: discussion<\/text>\\n<\/paragr ... #> [2] \\n This is a discussion<\/text>\\n<\/ ... #> [3] \\n :::<\/text>\\n<\/paragraph> pb$get_divs(fences) #> $`div-1-discussion` #> {xml_nodeset (3)} #> [1] \\n ::: discussion<\/text>\\n<\/paragr ... #> [2] \\n This is a discussion<\/text>\\n<\/ ... #> [3] \\n :::<\/text>\\n<\/paragraph> #> #> $`div-2-spoiler` #> {xml_nodeset (3)} #> [1] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [2] \\n This is a spoiler that is hidde ... #> [3] \\n :::<\/text>\\n<\/paragraph>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"conclusion","dir":"Articles","previous_headings":"","what":"Conclusion","title":"Working with XML data","text":"short introduction using XML {pegboard}. now basics structure XML , use XPath (resources), use XPath namespaces, use namespaces {pegboard} allow us parse specific items. good idea practices working XPath useful working XML representations markdown documents, also heavily used post-processing HTML {pkgdown} {sandpaper} packages.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Validation of Lesson Elements","text":"package designed parse structure Markdown R Markdown files inside Carpentries-style lesson. ensure consistent lesson structure, built-validators inspect headings, links, callout sections. document help become familiar output validators can used update lesson. Lesson authors contributors likely see output validators need interact directly. example, lesson contains mal-formed links headings: can see informative actionable output produced allow lesson authors make targeted changes files. next sections detail can work output methods.","code":"library(pegboard) lsn <- Lesson$new(lesson_fragment()) # validation lsn$validate_divs() lsn$validate_links() #| ! There were errors in 4/14 images #| ◌ Some linked internal files do not exist #| ◌ Images need alt-text #| #| ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #| ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg lsn$validate_headings(verbose = FALSE) #| ! There were errors in 13/37 headings #| ◌ Headings must be unique #| #| #| ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated)"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"link-validation","dir":"Articles","previous_headings":"","what":"Link Validation","title":"Validation of Lesson Elements","text":"validation methods produce messages (aka stderr) user, also produce data frame output contains detailed information link tests passed pass. can find tests run links accessing help page validate_links typing ?validate_links R console. want inspect data frame, can assign new variable: data frame combined output three sources: output [xml2::url_parse()] source data containing original source file (filepath), line number (pos), XML node (node) tests performed logical vectors, can extracted programmatically , can see nodes pass tests using link_tests vector, internal vector defining inline messages printed failed test, filter output: context, document looks like positions:","code":"links <- lsn$validate_links() #| ! There were errors in 4/14 images #| ◌ Some linked internal files do not exist #| ◌ Images need alt-text #| #| ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #| ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg str(links, max.level = 1) #| 'data.frame': 14 obs. of 28 variables: #| $ episodes : chr \"12-for-loops.md\" \"14-looping-data-sets.md\" \"14-looping-data-sets.m\".. #| $ scheme : chr \"https\" \"https\" \"https\" \"https\" ... #| $ server : chr \"docs.python.org\" \"docs.python.org\" \"docs.python.org\" \"docs.python.\".. #| $ port : int NA NA NA NA NA NA NA NA 21994 2140680360 ... #| $ user : chr \"\" \"\" \"\" \"\" ... #| $ path : chr \"/3/library/stdtypes.html\" \"/3/library/glob.html\" \"/3/library/glob.\".. #| $ query : chr \"\" \"\" \"\" \"\" ... #| $ fragment : chr \"range\" \"glob.glob\" \"\" \"\" ... #| $ orig : chr \"https://docs.python.org/3/library/stdtypes.html#range\" \"https://do\".. #| $ text : chr \"range\" \"glob.glob\" \"glob\" \"glob\" ... #| $ alt : chr NA NA NA NA ... #| $ title : chr \"\" \"\" \"\" \"\" ... #| $ type : chr \"link\" \"link\" \"link\" \"link\" ... #| $ rel : chr NA NA NA NA ... #| $ anchor : logi FALSE FALSE FALSE FALSE FALSE FALSE ... #| $ sourcepos : int 135 51 57 58 140 163 189 191 193 193 ... #| $ filepath : 'fs_path' chr \"_episodes/12-for-loops.md\" \"_episodes/14-looping-data-se\".. #| $ parents :List of 14 #| $ node :List of 14 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ known_protocol : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ enforce_https : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_anchor : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_file : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_well_formed: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ all_reachable : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ img_alt_text : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ descriptive : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ link_length : logi TRUE TRUE TRUE TRUE TRUE TRUE ... # get the subset of rows that did not pass all the tests invalid <- !apply(links[names(link_tests)], MARGIN = 1L, all) # return the nodes links$node[invalid] #| [[1]] #| {html_node} #| \"books #| #| [[2]] #| {xml_node} #| #| [1] Carpentries logo<\/text> #| #| [[3]] #| {xml_node} #| #| [1] Non-working image<\/text> #| #| [[4]] #| {xml_node} #| #| [1] Non-working image with jekyll syntax<\/text> #| \"books #| #| \"books #| #| Link to [Home]({{ page.root }}/index.html) and to [shell]({{ site.swc_pages }}/shell-novice) #| #| ![Carpentries logo](https://carpentries.org/assets/img/TheCarpentries.svg) #| #| ![Non-working image](../no-workie.svg) #| #| ![Non-working image with jekyll syntax]({{ page.root }}/no-workie.svg) #| #| This text includes a [link that isn't parsed correctly by commonmark]({{ page.root }}{% link index.md %}) #| . The rest of the text should be properly parsed. #| #| {% include links.md %}"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"fenced-div-validation","dir":"Articles","previous_headings":"","what":"Fenced Div Validation","title":"Validation of Lesson Elements","text":"Validation fenced divs (aka callout blocks) moment checks whether section divs encouter lessons ones expect, avoid issues div class mis-typed. divs expect object pegboard::KNOWN_DIVS: callout, objectives, questions, challenge, prereq, checklist, solution, hint, discussion, testimonial, keypoints, instructor, spoiler, tab, group-tab, caution. example lesson old styles repository, fenced divs, can use lesson fragment {sandpaper}: Notice message produced indicating divs lesson fragment okay. look data frame produced, can see six divs: invalid div names lesson, reported. example, lesson right now, improper fenced div classes, add invalid fenced div (via add_md() method tinkr::yarn() class), able find quickly: can see table is_known column now FALSE value:","code":"snd <- Lesson$new(lesson_fragment(name = \"sandpaper-fragment\"), jekyll = FALSE) snd_divs <- snd$validate_divs() snd_divs #| episodes path div pb_label pos is_known #| div-1-questions intro.Rmd episodes/intro.Rmd questions div-1-questions 7 TRUE #| div-2-objectives intro.Rmd episodes/intro.Rmd objectives div-2-objectives 13 TRUE #| div-3-challenge intro.Rmd episodes/intro.Rmd challenge div-3-challenge 37 TRUE #| div-4-solution intro.Rmd episodes/intro.Rmd solution div-4-solution 47 TRUE #| div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 60 TRUE #| div-6-keypoints intro.Rmd episodes/intro.Rmd keypoints div-6-keypoints 90 TRUE #| div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 TRUE #| div-2-solution setup.md learners/setup.md solution div-2-solution 14 TRUE #| div-3-solution setup.md learners/setup.md solution div-3-solution 22 TRUE our_div <- c(\"::: exercise\", \"\\nthis is an invalid div\\n\", \":::\") snd$episodes[[\"intro.Rmd\"]]$add_md(our_div) snd_divs <- snd$validate_divs() #| ! There were errors in 1/10 fenced divs #| ◌ The Carpentries Workbench knows the following div types callout, objectives, questions, challenge, prereq, checklist, solution, hint, discussion, testimonial, keypoints, instructor, spoiler, tab, group-tab, caution #| #| ::warning file=episodes/intro.Rmd,line=NA:: [unknown div] exercise snd_divs #| episodes path div pb_label pos is_known #| div-1-exercise intro.Rmd episodes/intro.Rmd exercise div-1-exercise NA FALSE #| div-2-questions intro.Rmd episodes/intro.Rmd questions div-2-questions 7 TRUE #| div-3-objectives intro.Rmd episodes/intro.Rmd objectives div-3-objectives 13 TRUE #| div-4-challenge intro.Rmd episodes/intro.Rmd challenge div-4-challenge 37 TRUE #| div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 47 TRUE #| div-6-solution intro.Rmd episodes/intro.Rmd solution div-6-solution 60 TRUE #| div-7-keypoints intro.Rmd episodes/intro.Rmd keypoints div-7-keypoints 90 TRUE #| div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 TRUE #| div-2-solution setup.md learners/setup.md solution div-2-solution 14 TRUE #| div-3-solution setup.md learners/setup.md solution div-3-solution 22 TRUE"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"heading-validation","dir":"Articles","previous_headings":"","what":"Heading Validation","title":"Validation of Lesson Elements","text":"NOTE: rethinking exact specifications heading validation time Validation headings operate similarly links produces data frame along message output can inspected manipulated. can find accessing help documentation validate_headings typing ?validate_headings R console. particular data frame fewer rows fewer moving parts headings links, indeed important. process getting subset invalid headings similar: use heading_tests vector pegboard subset rows failed:","code":"headings <- lsn$validate_headings(verbose = TRUE) #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"For Loops\" #| ├─## A for loop executes commands once for each value in a collection. #| ├─## A for loop is made up of a collection, a loop variable, and a body. #| ├─## The first line of the for loop must end with a colon, and the body must be indented. #| ├─## Loop variables can be called anything. #| ├─## The body of a loop can contain many statements. #| ├─## Use range to iterate over a sequence of numbers. #| ├─## The Accumulator pattern turns many values into one. #| ├─## Classifying Errors #| ├─## Solution (duplicated) #| ├─## Tracing Execution #| ├─## Solution (duplicated) #| ├─## Reversing a String #| ├─## Solution (duplicated) #| ├─## Practice Accumulating #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Cumulative Sum #| ├─## Solution (duplicated) #| ├─## Identifying Variable Name Errors #| ├─## Solution (duplicated) #| ├─## Identifying Item Errors #| └─## Solution (duplicated) #| ──────────────────────────────────────────────────────────────────────────────────────────────────── #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"Looping Over Data Sets\" #| ├─## Use a for loop to process files given a list of their names. #| ├─## Use glob.glob to find sets of files whose names match a pattern. #| ├─## Use glob and for to process batches of files. #| ├─## Determining Matches #| ├─## Solution (duplicated) #| ├─## Minimum File Size #| ├─## Solution (duplicated) #| ├─## Comparing Data #| └─## Solution (duplicated) #| └─### ZNK test links and images #| ──────────────────────────────────────────────────────────────────────────────────────────────────── #| ! There were errors in 13/37 headings #| ◌ Headings must be unique #| #| #| ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) str(headings, max.level = 1) #| 'data.frame': 37 obs. of 11 variables: #| $ episodes : chr \"12-for-loops.md\" \"12-for-loops.md\" \"12-for-loops.md\" \"12-\".. #| $ heading : chr \"A for loop executes commands once for each value in a col\".. #| $ level : int 2 2 2 2 2 2 2 2 2 2 ... #| $ pos : int 21 54 67 101 113 133 155 180 183 189 ... #| $ node :List of 37 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ first_heading_is_second_level: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ greater_than_first_level : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_sequential : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ have_names : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_unique : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ path : chr \"_episodes/12-for-loops.md\" \"_episodes/12-for-loops.md\" \"_\".. # get the subset of rows that did not pass all the tests invalid <- !apply(headings[names(heading_tests)], MARGIN = 1L, all) # return the nodes headings$node[invalid] #| [[1]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[2]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[3]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[4]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[5]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[6]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[7]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[8]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[9]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[10]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[11]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[12]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[13]] #| {xml_node} #| #| [1] Solution<\/text>"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"internal-testing","dir":"Articles","previous_headings":"","what":"Internal testing","title":"Validation of Lesson Elements","text":"testing, created documents extreme cases links headings failed show features examples:","code":"ex <- here::here(\"tests/testthat/examples\") lnk <- Episode$new(fs::path(ex, \"link-test.md\")) hd <- Episode$new(fs::path(ex, \"validation-headings.md\"))"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"links","dir":"Articles","previous_headings":"Internal testing","what":"Links","title":"Validation of Lesson Elements","text":"links example several mistakes covering possibilities:","code":"lnk$show() #| --- #| title: Link Tests #| --- #| #| ## Internal links {#internal} #| #| ### :crystal\\_ball: Heading with Emoji #| #| ### Heading with long name that has a label {#label-1} #| #| ### Another heading with a long name that has a label {#label-2} #| #| ### Heading with a class, but no label {.challenge} #| #| ### Heading with class and a label {.solution #label-3} #| #| This is a [link to the Heading with Emoji](#heading-with-emoji) and a [link to #| label 1][rel-label-1] and a [link](#label-2) and [this link](#label-2). #| #| This link goes to [the heading with class and a label](#label-3). #| #| This link is [absolutely incorrect](#bad-fragment) #| #| This [relative link goes to label 1][rel-label-1] #| #| ## Cross-Lesson links {#cross-lesson} #| #| This [link will go to the image test][rel-image], but [this link is #| wrong](incorrect-link.html). #| #| [This link also goes to image test](image-test) and [*this* link goes to #| image test as well](./image-test.html) #| [This link also goes to image test, but with a slash](image-test/), though this #| may not work for us because it implies that there is an `index.html` hiding in #| there. #| #| This link [should be a relative link](rel-image). #| This link [is a relative link that works][rel-image] #| #| This link [goes to an internal nested file](files/thing.txt), but this internal #| link [does not exist](files/ohno.txt) #| #| ## Invalid protocols #| #| This is a [link with a typo](gttps://example.com) #| #| This is a [bitcoin link](bitcoin:FAKE-EXAMPLE) #| and this is a [javascript example](javascript:alert%28%27JavaScript%20Link!%27%29), #| both of which should never appear in lessons. #| #| ## HTTP links #| #| This [link uses http, which is no bueno](http://example.com) #| #| ## Link text #| #| If we have [link text that is informative](https://example.com/link-text#good), #| it will pass. #| #| If we have links like #| [this][bad-link-text] #| [link][bad-link-text] #| [this link][bad-link-text] #| [a link][bad-link-text] #| [link to][bad-link-text] #| [here][bad-link-text] #| [here for][bad-link-text] #| [click here for][bad-link-text] #| [over here for][bad-link-text] #| [more][bad-link-text] #| [more about][bad-link-text] #| [for more about][bad-link-text] #| [for more info about][bad-link-text] #| [for more information about][bad-link-text] #| [read more about][bad-link-text] #| [read more][bad-link-text] #| [read on][bad-link-text] #| [read on about][bad-link-text], #| [a][bad-link-text], #| [][bad-link-text] #| they will fail, but [link text that is descriptive][1], albiet with a numeric #| anchor will work. #| #| ## Spans #| #| This is an [internal span]{#spanny style='color: red'} that we might want to #| link to. #| #| [definition list]{#deffy .anchored} #| : This is a definition list item that has an anchor #| #| We have examples of [spans](#spanny) and [definition lists](#deffy). #| We also have an example of a [missing anchor pointing to float](#floaty) #| #| [rel-label-1]: #label-1 #| [rel-image]: image-test.html #| [bad-link-text]: https://example.com/link-text#bad #| [1]: https://example.com/link-text#descriptive lnk$validate_links() #| ! There were errors in 31/45 links #| ◌ Links must have a known URL protocol (e.g. https, ftp, mailto). See for a list of acceptable protocols. #| ◌ Links must use HTTPS #| ◌ Some link anchors for relative links (e.g. [anchor]: link) are missing #| ◌ Some linked internal files do not exist #| ◌ Some links were incorrectly formatted #| ◌ Avoid uninformative link phrases #| ◌ Avoid single-letter or missing link text #| #| ::warning file=link-test.md,line=18:: [uninformative link text]: [link](#label-2) #| ::warning file=link-test.md,line=18:: [uninformative link text]: [this link](#label-2) #| ::warning file=link-test.md,line=22:: [missing anchor]: [absolutely incorrect](#bad-fragment) #| ::warning file=link-test.md,line=29:: [missing file]: [this link is wrong](incorrect-link.html) #| ::warning file=link-test.md,line=37:: [incorrect formatting]: [should be a relative link][rel-image] -> [should be a relative link](rel-image) #| ::warning file=link-test.md,line=41:: [missing file]: [does not exist](files/ohno.txt) #| ::warning file=link-test.md,line=45:: [invalid protocol]: gttps [needs HTTPS]: [link with a typo](gttps://example.com) #| ::warning file=link-test.md,line=47:: [invalid protocol]: bitcoin [needs HTTPS]: [bitcoin link](bitcoin:FAKE-EXAMPLE) #| ::warning file=link-test.md,line=48:: [invalid protocol]: javascript [needs HTTPS]: [javascript example](javascript:alert%28%27JavaScript%20Link!%27%29) #| ::warning file=link-test.md,line=53:: [needs HTTPS]: [link uses http, which is no bueno](http://example.com) #| ::warning file=link-test.md,line=61:: [uninformative link text]: [this](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=62:: [uninformative link text]: [link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=63:: [uninformative link text]: [this link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=64:: [uninformative link text]: [a link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=65:: [uninformative link text]: [link to](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=66:: [uninformative link text]: [here](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=67:: [uninformative link text]: [here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=68:: [uninformative link text]: [click here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=69:: [uninformative link text]: [over here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=70:: [uninformative link text]: [more](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=71:: [uninformative link text]: [more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=72:: [uninformative link text]: [for more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=73:: [uninformative link text]: [for more info about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=74:: [uninformative link text]: [for more information about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=75:: [uninformative link text]: [read more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=76:: [uninformative link text]: [read more](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=77:: [uninformative link text]: [read on](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=78:: [uninformative link text]: [read on about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=79:: [link text too short]: [a](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=80:: [link text too short]: [](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=93:: [missing anchor]: [missing anchor pointing to float](#floaty)"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"headings","dir":"Articles","previous_headings":"Internal testing","what":"Headings","title":"Validation of Lesson Elements","text":"headings example also several mistakes, demonstrates value visual heading tree displayed output verbose = TRUE","code":"hd$show() #| --- #| title: \"Errors in Headings\" #| --- #| #| # First heading throws an error #| #| ### This heading throws another error #| #| ## This heading is okay #| #| ## This heading is okay #| #| The above heading is not okay #| #| ### This heading is okay #| #| ## #| #| The abve heading doesn't make sense #| #| ## This last heading is okay hd$validate_headings(verbose = TRUE) #| ! There were errors in 5/7 headings #| ◌ First heading must be level 2 #| ◌ Level 1 headings are not allowed #| ◌ Headings must be sequential #| ◌ Headings must be named #| ◌ Headings must be unique #| #| #| ::warning file=validation-headings.md,line=5:: (must be level 2) (first level heading) #| ::warning file=validation-headings.md,line=7:: (non-sequential heading jump) #| ::warning file=validation-headings.md,line=9:: (duplicated) #| ::warning file=validation-headings.md,line=11:: (duplicated) #| ::warning file=validation-headings.md,line=18:: (no name) #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"Errors in Headings\" #| ├─# First heading throws an error (must be level 2) (first level heading) #| │ ├─### This heading throws another error (non-sequential heading jump) #| │ ├─## This heading is okay (duplicated) #| │ ├─## This heading is okay (duplicated) #| │ │ └─### This heading is okay #| │ ├─## (no name) #| │ └─## This last heading is okay #| ────────────────────────────────────────────────────────────────────────────────────────────────────"},{"path":"https://carpentries.github.io/pegboard/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Robert Davey. Author, maintainer. Erin Becker. Author. Zhian N. Kamvar. Author. Toby Hodges. Contributor. Erin Becker. Contributor. Kelly Barnes. Contributor.","code":""},{"path":"https://carpentries.github.io/pegboard/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Davey R, Becker E, Kamvar Z (2024). pegboard: Explore Manipulate Markdown Curricula Carpentries. R package version 0.7.7, https://carpentries.github.io/pegboard.","code":"@Manual{, title = {pegboard: Explore and Manipulate Markdown Curricula from the Carpentries}, author = {Robert Davey and Erin Becker and Zhian N. Kamvar}, year = {2024}, note = {R package version 0.7.7}, url = {https://carpentries.github.io/pegboard}, }"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"pegboard-parse-source-files-in-the-carpentries-workbench-","dir":"","previous_headings":"","what":"The Carpentries Lesson Validator","title":"The Carpentries Lesson Validator","text":"[pegboard] tempered hardboard pre-drilled evenly spaced holes. holes used accept pegs hooks support various items, tools workshop. https://en.wikipedia.org/wiki/Pegboard {pegboard} package part Carpentries Workbench ’s main functionality parse Markdown R Markdown documents XML representations (via {tinkr}). using XML, able easily arrange parse elements lessons makes two things possible: parse validate lessons structural markdown elements translate markdown syntax Carpentries-style materials styles lesson infrastructure (Jekyll-based) Workbench (Pandoc-based) (see lesson transition tool details) two {R6} objects package: Episode: stores xml content single Markdown R Markdown file. extends tinkr::yarn class. See vignette(\"intro-episode\", package = \"pegboard\") info. Lesson: stores publishable markdown content Episodes within lesson. See vignette(\"intro-episode\", package = \"pegboard\") info. One simple usage getting summary content episode. Let’s investigate contents “Episode Structure” episode Workbench documentation:","code":"library(\"pegboard\") library(\"withr\") # Download the file we need ------------------------------------ src <- \"https://raw.githubusercontent.com/carpentries/sandpaper-docs/main/episodes/episodes.Rmd\" tmp <- local_tempfile(fileext = \".Rmd\") download.file(src, tmp) # Load episode ep <- Episode$new(tmp) # Summary ------------------------------------------------------------- # confirm that we are using sandpaper and get a summary of the contents ep$confirm_sandpaper()$summary() #| sections headings callouts challenges solutions code output warning error images links #| 17 35 28 7 6 35 1 0 0 3 21 # Validation ---------------------------------------------------------- # NOTE: a lot of invalid links because files do not exist outside of # the lesson context lnk <- ep$validate_links() #| ! There were errors in 12/22 links and images #| ◌ Some linked internal files do not exist #| #| fileccef6278e384.Rmd:38 [missing file]: [next episode](editing.md) #| fileccef6278e384.Rmd:51 [missing file]: [the Introduction](introduction.md) #| fileccef6278e384.Rmd:203 [missing file]: [The Workbench Component Guide](component-guide.md) #| fileccef6278e384.Rmd:771 [missing file]: [the setup page](../learners/setup.md) #| fileccef6278e384.Rmd:787 [missing file]: [another episode (e.g. introduction)](introduction.md) #| fileccef6278e384.Rmd:788 [missing file]: [the home page](../index.md) #| fileccef6278e384.Rmd:789 [missing file]: [the setup page](../learners/setup.md) #| fileccef6278e384.Rmd:790 [missing file]: [the \"line length\" section in the style guide](../learners/style.md#line-length) #| fileccef6278e384.Rmd:796 [missing file]: [the style guide](../learners/style.md) #| fileccef6278e384.Rmd:816 [missing file]: [internal links](../episodes/episodes.Rmd#internal-links) #| fileccef6278e384.Rmd:851 [missing file]: [Hex sticker for The Carpentries](fig/carpentries-hex-blue.svg) #| fileccef6278e384.Rmd:893 [missing file]: [Example of Wrapped Alt Text (with apologies to William Carlos Williams)](fig/freezer.png) str(lnk, max.level = 1) #| 'data.frame': 24 obs. of 27 variables: #| $ scheme : chr \"\" \"\" \"\" \"\" ... #| $ server : chr \"\" \"\" \"\" \"\" ... #| $ port : int NA NA NA NA NA NA NA NA NA NA ... #| $ user : chr \"\" \"\" \"\" \"\" ... #| $ path : chr \"editing.md\" \"introduction.md\" \"\" \"component-guide.md\" ... #| $ query : chr \"\" \"\" \"\" \"\" ... #| $ fragment : chr \"\" \"\" \"callout-blocks\" \"\" ... #| $ orig : chr \"editing.md\" \"introduction.md\" \"#callout-blocks\" \"component-guide.md\" ... #| $ text : chr \"next episode\" \"the Introduction\" \"the next section\" \"The Workbench Component Guide\" ... #| $ alt : chr NA NA NA NA ... #| $ title : chr \"\" \"\" \"\" \"\" ... #| $ type : chr \"link\" \"link\" \"link\" \"link\" ... #| $ rel : chr NA NA NA NA ... #| $ anchor : logi FALSE FALSE FALSE FALSE FALSE FALSE ... #| $ sourcepos : int 38 51 168 203 320 329 536 541 621 737 ... #| $ filepath : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... #| $ parents :List of 24 #| $ node :List of 24 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ known_protocol : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ enforce_https : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_anchor : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_file : logi FALSE FALSE TRUE FALSE TRUE TRUE ... #| $ internal_well_formed: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ all_reachable : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ img_alt_text : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ descriptive : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ link_length : logi TRUE TRUE TRUE TRUE TRUE TRUE ... hdg <- ep$validate_headings() str(hdg, max.level = 1) #| 'data.frame': 35 obs. of 10 variables: #| $ heading : chr \"Introduction\" \"Buoyant Barnacle\" \"Creating A New Episode\" \"What is the .Rmd extension?\" ... #| $ level : int 2 3 2 3 2 3 3 3 2 3 ... #| $ pos : int 29 48 63 80 117 126 143 156 196 200 ... #| $ node :List of 35 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ first_heading_is_second_level: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ greater_than_first_level : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_sequential : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ have_names : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_unique : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ path : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... div <- ep$validate_divs() str(div, max.level = 1) #| 'data.frame': 28 obs. of 5 variables: #| $ path : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... #| $ div : chr \"questions\" \"objectives\" \"prereq\" \"callout\" ... #| $ pb_label: chr \"div-1-questions\" \"div-2-objectives\" \"div-3-prereq\" \"div-4-callout\" ... #| $ pos : int 9 20 46 78 141 198 226 245 255 274 ... #| $ is_known: logi TRUE TRUE TRUE TRUE TRUE TRUE ..."},{"path":"https://carpentries.github.io/pegboard/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"The Carpentries Lesson Validator","text":"{pegboard} currently CRAN, can installed Carpentries Universe (updated every hour) following commands:","code":"options(repos = c( carpentries = \"https://carpentries.r-universe.dev/\", CRAN = \"https://cran.rstudio.com/\" )) install.packages(\"pegboard\")"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"example","dir":"","previous_headings":"","what":"Example","title":"The Carpentries Lesson Validator","text":"use {pegboard} context Workbench, need lesson handy. don’t one, can use get_lesson() function, use {gert} clone lesson repository computer. (NOTE: file last run 2023-11-22 11:15:17.770234)","code":"library(\"pegboard\") library(\"purrr\") library(\"xml2\") library(\"fs\") d <- fs::file_temp(pattern = \"PBREADME\") rng <- get_lesson(\"swcarpentry/r-novice-gapminder\", path = d, jekyll = FALSE) rng #| #| Public: #| blocks: function (type = NULL, level = 0, path = FALSE) #| built: NULL #| challenges: function (path = FALSE, graph = FALSE, recurse = TRUE) #| children: NULL #| clone: function (deep = FALSE) #| episodes: list #| extra: list #| files: active binding #| get: function (element = NULL, collection = \"episodes\") #| handout: function (path = NULL, solution = FALSE) #| has_children: active binding #| initialize: function (path = \".\", rmd = FALSE, jekyll = TRUE, ...) #| isolate_blocks: function () #| load_built: function () #| n_problems: active binding #| overview: FALSE #| path: /tmp/Rtmp40TO0e/PBREADMEccef2b02e45e/swcarpentry--r-novi ... #| reset: function () #| rmd: FALSE #| sandpaper: TRUE #| show_problems: active binding #| solutions: function (path = FALSE) #| summary: function (collection = \"episodes\") #| thin: function (verbose = TRUE) #| trace_lineage: function (episode_path) #| validate_divs: function () #| validate_headings: function (verbose = TRUE) #| validate_links: function () #| Private: #| deep_clone: function (name, value) # Get a summary of all the elements in each episode rng$summary() #| # A tibble: 16 × 12 #| page sections headings callouts challenges solutions code output warning error images links #| #| 1 01-rstudio-intro.Rmd 28 28 19 5 5 47 1 0 0 2 7 #| 2 02-project-intro.Rmd 12 19 12 5 1 4 0 0 0 1 3 #| 3 03-seeking-help.Rmd 15 15 11 3 3 12 0 0 0 0 7 #| 4 04-data-structures-part1.Rmd 2 50 31 9 15 77 0 0 0 0 1 #| 5 05-data-structures-part2.Rmd 15 15 12 4 4 32 0 0 0 0 3 #| 6 06-data-subsetting.Rmd 33 34 26 8 8 76 0 0 0 2 0 #| 7 07-control-flow.Rmd 15 15 17 5 5 36 0 0 0 0 2 #| 8 08-plot-ggplot2.Rmd 20 20 18 6 6 23 0 0 0 0 12 #| 9 09-vectorization.Rmd 11 11 14 4 4 24 0 0 0 0 1 #| 10 10-functions.Rmd 20 21 19 5 5 28 0 0 0 0 12 #| 11 11-writing-data.Rmd 6 6 7 2 2 11 0 0 0 0 0 #| 12 12-plyr.Rmd 8 8 10 3 3 17 0 0 0 2 1 #| 13 13-dplyr.Rmd 18 18 11 3 3 30 0 0 0 3 6 #| 14 14-tidyr.Rmd 10 10 9 3 3 16 0 0 0 4 5 #| 15 15-knitr-markdown.Rmd 22 22 13 4 4 9 0 0 0 2 18 #| 16 16-wrap-up.Rmd 9 9 4 0 0 1 0 0 0 0 1 # Validate lesson elements rng$validate_links() rng$validate_divs() rng$validate_headings() # this is not run by default in sandpaper lessons #| # Episode: \"Data Structures\" #| ├─### Tip: Editing Text files in R (must be level 2) #| ├─### Check your data for factors #| ├─### Data Types #| ├─### Vectors and Type Coercion #| ├─### Discussion 1 #| ├─### Discussion 1 #| ├─### Challenge 1 #| │ └─#### Copy the code template #| ├─### Instructions for the tasks #| │ └─#### 1. Print the data #| ├─### Tip 1.1 #| ├─### Solution to Challenge 1.1 #| │ └─#### 2. Overview of the data types #| ├─### Tip 1.2 #| ├─### Solution to Challenge 1.2 #| │ └─#### 3. Which data type do we need? #| ├─### Tip 1.3 #| ├─### Solution to Challenge 1.3 #| │ └─#### 4. Correct the problematic value #| ├─### Tip 1.4 #| ├─### Solution to challenge 1.4 #| │ └─#### 5. Convert the column \"weight\" to the correct data type #| ├─### Tip 1.5 #| ├─### Solution to Challenge 1.5 #| ├─### Some basic vector functions #| ├─### Challenge 2 #| ├─### Solution to Challenge 2 #| ├─### Lists #| ├─## Names #| │ ├─### Accessing vectors and lists by name #| │ ├─### Accessing and changing names #| │ ├─### Challenge 3 #| │ ├─### Solution to Challenge 3 #| │ ├─### Challenge 4 #| │ └─### Solution to Challenge 4 #| └─## Data frames #| ├─### Challenge 5 #| ├─### Solution to Challenge 5 #| ├─### Tip: Renaming data frame columns #| ├─### Matrices #| ├─### Challenge 6 #| ├─### Solution to Challenge 6 #| ├─### Challenge 7 #| ├─### Solution to Challenge 7 #| ├─### Challenge 8 #| ├─### Solution to Challenge 8 #| ├─### Challenge 9 #| └─### Solution to Challenge 9 #| # Episode: \"Vectorization\" #| ├─## Challenge 1 #| ├─## Solution to challenge 1 #| ├─## Challenge 2 #| ├─## Solution to challenge 2 #| ├─## Tip: some useful functions for logical vectors #| ├─## Tip: element-wise vs. matrix multiplication #| ├─## Challenge 3 #| ├─## Solution to challenge 3 #| ├─## Challenge 4 (duplicated) #| ├─## Challenge 4 (duplicated) #| └─## Tip: Operations on vectors of unequal length #| # Episode: \"Functions Explained\" #| ├─## What is a function? #| ├─## Defining a function #| ├─## Tip (duplicated) #| ├─## Challenge 1 #| ├─## Solution to challenge 1 #| ├─## Combining functions #| ├─## Challenge 2 #| ├─## Solution to challenge 2 #| ├─## Interlude: Defensive Programming #| │ └─### Checking conditions with stopifnot() #| ├─## Challenge 3 #| ├─## Solution to challenge 3 #| ├─## More on combining functions #| ├─## Tip: Pass by value #| ├─## Tip: Function scope #| ├─## Challenge 4 #| ├─## Solution to challenge 4 #| ├─## Challenge 5 #| ├─## Solution to challenge 5 #| ├─## Tip (duplicated) #| └─## Tip: Testing and documenting"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"manipulation","dir":"","previous_headings":"Example","what":"Manipulation","title":"The Carpentries Lesson Validator","text":"XML contents lesson contained within $body element Episode object anything XML document retained within object (see {tinkr} documentation details):","code":"ep1 <- rng$episodes[[1]] ep1$body #| {xml_document} #| #| [1] #| [2] \\n ::::::::::::::::::::::::::::::::::::::: objectives<\/text>\\n<\/paragraph> #| [3] \\n \\n \\n Describe the purpose and use of each pane in RStudio<\/text>\\n <\/paragraph>\\n <\/item>\\n \\n ::::::::::::::::::::::::::::::::::::::::::::::::::<\/text>\\n<\/paragraph> #| [5] #| [6] #| [7] \\n :::::::::::::::::::::::::::::::::::::::: questions<\/text>\\n<\/paragraph> #| [8] \\n \\n \\n How to find your way around RStudio?<\/text>\\n <\/paragraph>\\n <\/item>\\n \\ ... #| [9] \\n ::::::::::::::::::::::::::::::::::::::::::::::::::<\/text>\\n<\/paragraph> #| [10] #| [11] #| [12] \\n Before Starting The Workshop<\/text>\\n<\/heading> #| [13] \\n Please ensure you have the latest version of R and RStudio installed on your machine. This is important, as some packages used in the workshop may not install correctly (or at all) if R is not up to dat ... #| [14] \\n \\n \\n \\n Download and inst ... #| [15] \\n Why use R and R studio?<\/text>\\n<\/heading> #| [16] \\n Welcome to the R portion of the Software Carpentry workshop!<\/text>\\n<\/paragraph> #| [17] \\n Science is a multi-step process: once you've designed an experiment and collected<\/text>\\n \\n data, the real fun begins with analysis! Thr ... #| [18] \\n Although we could use a spreadsheet in Microsoft Excel or Google sheets to analyze our data, these tools are limited in their flexibility and accessibility. Critically, they also are difficult to share ... #| [19] \\n Therefore, this lesson will teach you how to begin exploring your data using R and RStudio. The R program is available for Windows, Mac, and Linux operating systems, and is a freely-available where you ... #| [20] \\n However, to make using R easier, we will use the program RStudio, which we also downloaded above. RStudio is a free, open-source, Integrated Development<\/text>\\n \\n #| [1] NEW CONTENT<\/text> xml2::xml_set_attr(ep1$headings[[1]], \"level\", \"2\") ep1$head(20) #| --- #| title: Introduction to R and RStudio #| teaching: 45 #| exercises: 10 #| source: Rmd #| --- #| #| ## NEW CONTENT #| #| Hello! This is **new markdown content** generated via the #| [{pegboard}](https://carpentries.github.io/pegboard) package that will #| appear above the objectives block! #| #| ::::::::::::::::::::::::::::::::::::::: objectives #| #| - Describe the purpose and use of each pane in RStudio #| - Locate buttons and options in RStudio #| - Define a variable #| - Assign data to a variable #| - Manage a workspace in an interactive R session ep1$headings[[1]] # the first heading is now level 2 #| {xml_node} #| #| [1] NEW CONTENT<\/text> # write the file ep1$write(fs::path_dir(ep1$path), format = \"Rmd\") readLines(ep1$path, 20) #| [1] \"---\" \"title: Introduction to R and RStudio\" \"teaching: 45\" \"exercises: 10\" #| [5] \"source: Rmd\" \"---\" \"\" \"## NEW CONTENT\" #| [9] \"\" \"Hello! This is **new markdown content** generated via the\" \"[{pegboard}](https://carpentries.github.io/pegboard) package that will\" \"appear above the objectives block!\" #| [13] \"\" \"::::::::::::::::::::::::::::::::::::::: objectives\" \"\" \"- Describe the purpose and use of each pane in RStudio\" #| [17] \"- Locate buttons and options in RStudio\" \"- Define a variable\" \"- Assign data to a variable\" \"- Manage a workspace in an interactive R session\""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":null,"dir":"Reference","previous_headings":"","what":"Class representing XML source of a Carpentries episode — Episode","title":"Class representing XML source of a Carpentries episode — Episode","text":"Wrapper around xml document manipulate inspect Carpentries episodes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode class superclass tinkr::yarn(), transforms (commonmark-formatted) Markdown XML back . extension Episode class provides support Pandoc kramdown flavours Markdown. Read class vignette(\"intro-episode\", package = \"pegboard\").","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Class representing XML source of a Carpentries episode — Episode","text":"current XLST spec tinkr support kramdown, Carpentries Episodes styled , thus block tags destructively modified conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"super-class","dir":"Reference","previous_headings":"","what":"Super class","title":"Class representing XML source of a Carpentries episode — Episode","text":"tinkr::yarn -> Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"public-fields","dir":"Reference","previous_headings":"","what":"Public fields","title":"Class representing XML source of a Carpentries episode — Episode","text":"children [character] vector absolute paths child files exist. parents [character] vector absolute paths immediate parent files exist build_parents [character] vector absolute paths final parent files trigger child file build","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"active-bindings","dir":"Reference","previous_headings":"","what":"Active bindings","title":"Class representing XML source of a Carpentries episode — Episode","text":"show_problems [list] list problems occurred parsing episode headings [xml_nodeset] headings document links [xml_nodeset] links (images) document images [xml_nodeset] image sources document tags [xml_nodeset] kramdown tags episode questions [character] questions episode keypoints [character] keypoints episode objectives [character] objectives episode challenges [xml_nodeset] challenges blocks episode solutions [xml_nodeset] solutions blocks episode output [xml_nodeset] output blocks episode error [xml_nodeset] error blocks episode warning [xml_nodeset] warning blocks episode code [xml_nodeset] code blocks episode name [character] name source file without path lesson [character] path lesson episode has_children [logical] indicator presence child files (TRUE) absence (FALSE) has_parents [logical] indicator presence parent files (TRUE) absence (FALSE)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"methods","dir":"Reference","previous_headings":"","what":"Methods","title":"Class representing XML source of a Carpentries episode — Episode","text":"tinkr::yarn$add_md() tinkr::yarn$get_protected() tinkr::yarn$md_vec() tinkr::yarn$protect_curly() tinkr::yarn$protect_math() tinkr::yarn$protect_unescaped()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"public-methods","dir":"Reference","previous_headings":"","what":"Public methods","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode$new() Episode$confirm_sandpaper() Episode$get_blocks() Episode$get_images() Episode$label_divs() Episode$get_divs() Episode$get_yaml() Episode$use_dovetail() Episode$use_sandpaper() Episode$remove_error() Episode$remove_output() Episode$move_objectives() Episode$move_keypoints() Episode$move_questions() Episode$get_challenge_graph() Episode$show() Episode$head() Episode$tail() Episode$write() Episode$handout() Episode$reset() Episode$isolate_blocks() Episode$unblock() Episode$summary() Episode$validate_headings() Episode$validate_divs() Episode$validate_links() Episode$clone()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-new-","dir":"Reference","previous_headings":"","what":"Method new()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create new Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$new( path = NULL, process_tags = TRUE, fix_links = TRUE, fix_liquid = FALSE, parents = NULL, ... )"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path [character] path markdown episode file disk process_tags [logical] TRUE (default), kramdown tags processed attributes parent nodes. FALSE, tags treated text fix_links [logical] TRUE (default), links pointing liquid tags (e.g. {{ page.root }}) included links (supplied call {\\% import links.md \\%}) appropriately processed valid links. fix_liquid [logical] defaults FALSE, means data immediately passed tinkr::yarn. TRUE, liquid variables relative links spaces removed allow commonmark parser interpret links. parents [list] list Episode objects represent immediate parents child ... arguments passed tinkr::yarn tinkr::to_xml()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"new Episode object extracted XML data","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$name scope$lesson scope$challenges"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-confirm-sandpaper-","dir":"Reference","previous_headings":"","what":"Method confirm_sandpaper()","title":"Class representing XML source of a Carpentries episode — Episode","text":"enforce episode sandpaper episode withtout going conversion steps. default Episodes pegboard assumed generated using Jekyll kramdown syntax. bit kludge bypass normal checks kramdown syntax just assume pandoc syntax","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-1","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$confirm_sandpaper()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-blocks-","dir":"Reference","previous_headings":"","what":"Method get_blocks()","title":"Class representing XML source of a Carpentries episode — Episode","text":"return block_quote elements within Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-2","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_blocks(type = NULL, level = 1L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-1","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 1, represents block_quotes nested within block quotes. Increase nubmer increase level nesting.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-1","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"[xml_nodeset] blocks episode given tag level.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-1","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) # get all the challenges scope$get_blocks(\".challenge\") # get the solutions scope$get_blocks(\".solution\", level = 2) \\dontrun{ # download the source files for r-novice-gampinder into a Lesson object rng <- get_lesson(\"swcarpentry/r-novice-gapminder\") dsp1 <- rng$episodes[[\"04-data-structures-part1.md\"]] # There are 9 blocks in total dsp1$get_blocks() # One is a callout block dsp1$get_blocks(\".callout\") # One is a discussion block dsp1$get_blocks(\".discussion\") # Seven are Challenge blocks dsp1$get_blocks(\".challenge\") # There are eight solution blocks: dsp1$get_blocks(\".solution\", level = 2L) }"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-images-","dir":"Reference","previous_headings":"","what":"Method get_images()","title":"Class representing XML source of a Carpentries episode — Episode","text":"fetch image sources optionally process easier parsing. default version function equivalent active binding $images.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-3","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_images(process = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-2","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"process TRUE, images processed via internal function process_images(), add alt attribute, available extract img nodes HTML blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-2","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"xml_nodelist","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-2","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$get_images() loop$get_images(process = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-label-divs-","dir":"Reference","previous_headings":"","what":"Method label_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"label div elements within Episode extract $get_divs()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-4","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$label_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-divs-","dir":"Reference","previous_headings":"","what":"Method get_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"return div elements within Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-5","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_divs(type = NULL, include = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-3","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"type type div tag (e.g. 'challenge' 'solution') include \\[logical\\] TRUE, div tags included output. Defaults FALSE, return text div tags.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-yaml-","dir":"Reference","previous_headings":"","what":"Method get_yaml()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Extract yaml metadata episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-6","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_yaml()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-use-dovetail-","dir":"Reference","previous_headings":"","what":"Method use_dovetail()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Ammend add setup code block use {dovetail} convert lesson use dovetail R package processing specialized block quotes two things: convert lesson md Rmd add setup chunk following code setup chunk, one created. setup chunk, source knitr_fig_path calls removed.","code":"library('dovetail') source(dvt_opts())"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-7","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$use_dovetail()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-use-sandpaper-","dir":"Reference","previous_headings":"","what":"Method use_sandpaper()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Use sandpaper package processing convert lesson use {sandpaper} R package processing lesson instead Jekyll (default). following effects: code blocks marked liquid tags (e.g. {: .language-r} converted standard code blocks Rmarkdown chunks (language information top code block) rmarkdown used lesson contains python code, library('reticulate') added setup chunk lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-8","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$use_sandpaper(rmd = FALSE, yml = list())"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-4","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"rmd TRUE, lessons converted RMarkdown documents yml list derived yml file episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-remove-error-","dir":"Reference","previous_headings":"","what":"Method remove_error()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove error blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-9","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$remove_error()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-remove-output-","dir":"Reference","previous_headings":"","what":"Method remove_output()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove output blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-10","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$remove_output()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-objectives-","dir":"Reference","previous_headings":"","what":"Method move_objectives()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move objectives yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-11","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_objectives()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-keypoints-","dir":"Reference","previous_headings":"","what":"Method move_keypoints()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move keypoints yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-12","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_keypoints()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-questions-","dir":"Reference","previous_headings":"","what":"Method move_questions()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move questions yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-13","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_questions()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-challenge-graph-","dir":"Reference","previous_headings":"","what":"Method get_challenge_graph()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create graph top-level elements challenges.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-14","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_challenge_graph(recurse = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-5","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"recurse TRUE (default), content solutions included graph; FALSE keep solutions block_quote elements.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-3","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame four columns representing elements within challenges Episode: Block: sequential number challenge block : inward elements : outward elements pos: position markdown document Note three special node names: challenge: start end challenge block solution: start solution block lesson: start lesson block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-3","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$get_challenge_graph()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-show-","dir":"Reference","previous_headings":"","what":"Method show()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-15","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$show(n = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-6","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n subset elements show, default TRUE lines","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-4","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-4","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$head() scope$tail() scope$show()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-head-","dir":"Reference","previous_headings":"","what":"Method head()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show first n lines markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-16","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$head(n = 6L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-7","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n number lines show top","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-5","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-tail-","dir":"Reference","previous_headings":"","what":"Method tail()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show first n lines markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-17","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$tail(n = 6L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-8","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n number lines show top","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-6","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-write-","dir":"Reference","previous_headings":"","what":"Method write()","title":"Class representing XML source of a Carpentries episode — Episode","text":"write episode disk markdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-18","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$write(path = NULL, format = \"md\", edit = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-9","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path path write file . Defaults empty directory temporary folder format one \"md\" (default) \"xml\". create file correct extension path edit TRUE, file open editor. Defaults FALSE.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-7","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"episode object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-5","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$write()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-handout-","dir":"Reference","previous_headings":"","what":"Method handout()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create trimmed-RMarkdown document strips prose contains important code chunks challenge blocks without solutions.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-19","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$handout(path = NULL, solutions = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-10","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path (handout) path R Markdown file write. NULL, file written lines output returned. solutions TRUE, include solutions output. Defaults FALSE, removes solution blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-8","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector path = NULL, otherwise, called side effect creating file.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-6","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) e <- lsn$episodes[[1]] cat(e$handout()) cat(e$handout(solution = TRUE))"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-reset-","dir":"Reference","previous_headings":"","what":"Method reset()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Re-read episode disk","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-20","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$reset()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-9","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"episode object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-7","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) xml2::xml_text(scope$tags[1]) xml2::xml_set_text(scope$tags[1], \"{: .code}\") xml2::xml_text(scope$tags[1]) scope$reset() xml2::xml_text(scope$tags[1])"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-isolate-blocks-","dir":"Reference","previous_headings":"","what":"Method isolate_blocks()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove elements except within block quotes kramdown tag. Note destructive process.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-21","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$isolate_blocks()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-10","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-8","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$body # a full document with block quotes and code blocks, etc scope$isolate_blocks()$body # only one challenge block_quote"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-unblock-","dir":"Reference","previous_headings":"","what":"Method unblock()","title":"Class representing XML source of a Carpentries episode — Episode","text":"convert challenge blocks roxygen-like code blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-22","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$unblock(token = \"#'\", force = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-11","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"token token use indicate non-code, Defaults \"#'\" force force conversion even conversion already taken place","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-11","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-9","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc loop$get_blocks() # all the blocks in the episode loop$unblock() loop$get_blocks() # no blocks loop$code # now there are two blocks with challenge tags"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-summary-","dir":"Reference","previous_headings":"","what":"Method summary()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Get high-level summary elements episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-23","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$summary()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-12","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame counts following elements per page: sections: level 2 headings headings: headings callouts: callouts challenges: subset callouts solutions: subset callouts code: code block elements (excluding inline code) output: subset code displayed output warnining: subset code displayed warning error: subset code displayed error images: images markdown HTML links: links markdown HTML","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-headings-","dir":"Reference","previous_headings":"","what":"Method validate_headings()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation headings document. validate following aspects headings: first heading starts level 2 (first_heading_is_second_level) greater level 1 (greater_than_first_level) increse sequentially (e.g. jumps 2 4) (are_sequential) names (have_names) unique hierarchy (are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-24","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_headings(verbose = TRUE, warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-12","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"verbose TRUE (default), message rule broken issued stderr. FALSE, silent. warn TRUE (default), warning issued failures tests.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-13","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame variable number rows follwoing columns: episode filename episode heading text heading level heading level pos position heading document node XML node represents heading (next five columns tests listed ) path path file. row data frame represents individual heading across Lesson. See validate_headings() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-10","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"# Example: There are multiple headings called \"Solution\" that are not # nested within a higher-level heading and will throw an error loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_headings()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-divs-","dir":"Reference","previous_headings":"","what":"Method validate_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation divs document. validate following aspects divs. See validate_divs() details. divs known type (is_known)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-25","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_divs(warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-13","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"warn TRUE (default), warning message divs determined invalid. Set FALSE want table processing later.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-14","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"logical TRUE valid divs FALSE invalid divs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-11","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-links-","dir":"Reference","previous_headings":"","what":"Method validate_links()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation links images document. validate following aspects links. See validate_links() details. External links use HTTPS (enforce_https) Internal links exist (internal_okay) External links reachable (all_reachable) (planned) Images alt text (img_alt_text) Link text descriptive (descriptive) Link text single letter (link_length)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-26","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_links(warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-14","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"warn TRUE (default), warning message links determined invalid. Set FALSE want table processing later.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-15","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"logical TRUE valid links FALSE invalid links.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-12","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-clone-","dir":"Reference","previous_headings":"","what":"Method clone()","title":"Class representing XML source of a Carpentries episode — Episode","text":"objects class cloneable method.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-27","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$clone(deep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-15","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"deep Whether make deep clone.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"## ------------------------------------------------ ## Method `Episode$new` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$name #> [1] \"17-scope.md\" scope$lesson #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" scope$challenges #> {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (0)} if (FALSE) { # \\dontrun{ # download the source files for r-novice-gampinder into a Lesson object rng <- get_lesson(\"swcarpentry/r-novice-gapminder\") dsp1 <- rng$episodes[[\"04-data-structures-part1.md\"]] # There are 9 blocks in total dsp1$get_blocks() # One is a callout block dsp1$get_blocks(\".callout\") # One is a discussion block dsp1$get_blocks(\".discussion\") # Seven are Challenge blocks dsp1$get_blocks(\".challenge\") # There are eight solution blocks: dsp1$get_blocks(\".solution\", level = 2L) } # } ## ------------------------------------------------ ## Method `Episode$get_images` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$get_images() #> {xml_nodeset (5)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... #> [5] {xml_nodeset (5)} #> [1] \"boo [2] \"books [3] [4] \\ ... #> [5] Block from to pos level #> 1 1 challenge heading 45:1-60:14 1 #> 2 1 heading paragraph 45:3-45:34 1 #> 3 1 paragraph code_block 47:3-48:68 1 #> 4 1 code_block lesson 50:3-58:5 1 #> 5 2 challenge heading 62:1-95:14 1 #> 6 2 heading paragraph 62:3-62:27 1 #> 7 2 paragraph list 64:3-64:55 1 #> 8 2 list code_block 66:3-72:1 1 #> 9 2 code_block lesson 73:3-93:5 1 ## ------------------------------------------------ ## Method `Episode$show` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$head() #> --- #> title: \"Variable Scope\" #> teaching: 10 #> exercises: 10 #> questions: #> - \"How do function calls actually work?\" scope$tail() #> > #> > KeyError: 'Friday' #> > ``` #> > {: .error} #> {: .challenge} #> scope$show() #> --- #> title: \"Variable Scope\" #> teaching: 10 #> exercises: 10 #> questions: #> - \"How do function calls actually work?\" #> - \"How can I determine where errors occurred?\" #> objectives: #> - \"Identify local and global variables.\" #> - \"Identify parameters as local variables.\" #> - \"Read a traceback and determine the file, function, and line number on which the error occurred, the type of error, and the error message.\" #> keypoints: #> - \"The scope of a variable is the part of a program that can 'see' that variable.\" #> --- #> #> ## The scope of a variable is the part of a program that can 'see' that variable. #> #> - There are only so many sensible names for variables. #> - People using functions shouldn't have to worry about #> what variable names the author of the function used. #> - People writing functions shouldn't have to worry about #> what variable names the function's caller uses. #> - The part of a program in which a variable is visible is called its *scope*. #> #> ``` #> pressure = 103.9 #> #> def adjust(t): #> temperature = t * 1.43 / pressure #> return temperature #> ``` #> {: .language-python} #> #> - `pressure` is a *global variable*. #> - Defined outside any particular function. #> - Visible everywhere. #> - `t` and `temperature` are *local variables* in `adjust`. #> - Defined in the function. #> - Not visible in the main program. #> - Remember: a function parameter is a variable #> that is automatically assigned a value when the function is called. #> #> ``` #> print('adjusted:', adjust(0.9)) #> print('temperature after call:', temperature) #> ``` #> {: .language-python} #> #> ``` #> adjusted: 0.01238691049085659 #> ``` #> {: .output} #> #> ``` #> Traceback (most recent call last): #> File \"/Users/swcarpentry/foo.py\", line 8, in #> print('temperature after call:', temperature) #> NameError: name 'temperature' is not defined #> ``` #> {: .error} #> #> > ## Local and Global Variable Use #> > #> > Trace the values of all variables in this program as it is executed. #> > (Use '---' as the value of variables before and after they exist.) #> > #> > ``` #> > limit = 100 #> > #> > def clip(value): #> > return min(max(0.0, value), limit) #> > #> > value = -22.5 #> > print(clip(value)) #> > ``` #> > {: .language-python} #> {: .challenge} #> #> > ## Reading Error Messages #> > #> > Read the traceback below, and identify the following: #> > #> > 1. How many levels does the traceback have? #> > 2. What is the file name where the error occurred? #> > 3. What is the function name where the error occurred? #> > 4. On which line number in this function did the error occur? #> > 5. What is the type of error? #> > 6. What is the error message? #> > #> > ``` #> > --------------------------------------------------------------------------- #> > KeyError Traceback (most recent call last) #> > in () #> > 1 import errors_02 #> > ----> 2 errors_02.print_friday_message() #> > #> > /Users/ghopper/thesis/code/errors_02.py in print_friday_message() #> > 13 #> > 14 def print_friday_message(): #> > ---> 15 print_message(\"Friday\") #> > #> > /Users/ghopper/thesis/code/errors_02.py in print_message(day) #> > 9 \"sunday\": \"Aw, the weekend is almost over.\" #> > 10 } #> > ---> 11 print(messages[day]) #> > 12 #> > 13 #> > #> > KeyError: 'Friday' #> > ``` #> > {: .error} #> {: .challenge} #> ## ------------------------------------------------ ## Method `Episode$write` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$write() #> Creating temporary directory '/tmp/Rtmp3tPmlj/dir16b131de6084' ## ------------------------------------------------ ## Method `Episode$handout` ## ------------------------------------------------ lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) e <- lsn$episodes[[1]] cat(e$handout()) #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` cat(e$handout(solution = TRUE)) #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::: solution #> #> ## Output #> #> ```{r, echo=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::::::::::::: #> #> ## Challenge 2: how do you nest solutions within challenge blocks? #> #> :::::::::::::::::::::::: solution #> #> You can add a line with at least three colons and a `solution` tag. ## ------------------------------------------------ ## Method `Episode$reset` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" xml2::xml_set_text(scope$tags[1], \"{: .code}\") #> {xml_nodeset (1)} #> [1] ktag=\"{: .language-python}\" xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" scope$reset() xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" ## ------------------------------------------------ ## Method `Episode$isolate_blocks` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] \\n [5] [6] [7] [8] \\n [9] \\n {xml_document} #> #> [1] \\n [2] \\n {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$get_blocks() # all the blocks in the episode #> {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (0)} loop$code # now there are two blocks with challenge tags #> {xml_nodeset (11)} #> [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] ! There were errors in 3/10 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ──────────────────────────────────────────────────────────────────────────────── ## ------------------------------------------------ ## Method `Episode$validate_divs` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_divs() ## ------------------------------------------------ ## Method `Episode$validate_links` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_links() #> ! There were errors in 4/13 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":null,"dir":"Reference","previous_headings":"","what":"Class to contain a single Lesson by the Carpentries — Lesson","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wrapper several Episode class objects.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"class contains keeps track relationships Episode objects contained within Carpentries Workbench Carpentries styles lessons. Read use class vignette(\"intro-lesson\", package = \"pegboard\")","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"public-fields","dir":"Reference","previous_headings":"","what":"Public fields","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [character] path Lesson directory episodes [list] list Episode class objects representing episodes lesson. built [list] list Episode class objects representing markdown artefacts rendered RMarkdown files. extra [list] list Episode class objects representing extra markdown components including index, setup, information learners, information instructors, learner profiles. processed jekyll lessons. children [list] list Episode class objects representing child files needed components built processed jekyll lessons. sandpaper [logical] TRUE, episodes lesson written pandoc flavoured markdown. FALSE indicate jekyll-based lesson written kramdown. rmd [logical] TRUE, episodes represent RMarkdown files, default FALSE markdown files (deprecated unused). overview [logical] TRUE, lesson overview lesson necessarly contain episodes. Defaults FALSE","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"active-bindings","dir":"Reference","previous_headings":"","what":"Active bindings","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"n_problems number problems per episode show_problems contents problems per episode files source files episode has_children logical indicating presence (TRUE) absence (FALSE) child files within main files lesson","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"public-methods","dir":"Reference","previous_headings":"","what":"Public methods","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson$new() Lesson$load_built() Lesson$get() Lesson$summary() Lesson$blocks() Lesson$challenges() Lesson$solutions() Lesson$thin() Lesson$reset() Lesson$isolate_blocks() Lesson$handout() Lesson$validate_headings() Lesson$validate_divs() Lesson$validate_links() Lesson$trace_lineage() Lesson$clone()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-new-","dir":"Reference","previous_headings":"","what":"Method new()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"create new Lesson object directory","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$new(path = \".\", rmd = FALSE, jekyll = TRUE, ...)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [character] path lesson directory. must folder called _episodes within contains markdown episodes. Defaults current working directory. rmd [logical] TRUE, imported files source RMarkdown files. Defaults FALSE, reads rendered markdown files. jekyll [logical] TRUE (default), structure lesson assumed derived carpentries/styles repository. FALSE, structure assumed sandpaper lesson extra content learners, instructors, profiles populated. ... arguments passed Episode$new","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"new Lesson object contains list Episode objects $episodes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$path frg$episodes"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-load-built-","dir":"Reference","previous_headings":"","what":"Method load_built()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"read markdown content generated RMarkdown sources load load memory","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-1","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$load_built()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-get-","dir":"Reference","previous_headings":"","what":"Method get()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"getter various active bindings Episode class objects. practice syntactic sugar around purrr::map(l$episodes, ~.x$element)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-2","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$get(element = NULL, collection = \"episodes\")"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-1","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"element [character] defined element active bindings Episode class. Defaults NULL, return nothing. Elements exist Episode class return NULL collection [character] one \"episodes\" (default), \"extra\", \"built\". Select TRUE collect information files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-1","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$get(\"error\") # error code blocks frg$get(\"links\") # links"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-summary-","dir":"Reference","previous_headings":"","what":"Method summary()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"summary element counts episode. can useful assessing broad overview lesson dynamics","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-3","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$summary(collection = \"episodes\")"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-2","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"collection [character] one \"episodes\" (default), \"extra\", \"built\". Select TRUE collect information files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-2","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$summary() # episode summary (default)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-blocks-","dir":"Reference","previous_headings":"","what":"Method blocks()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather blocks lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-4","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$blocks(type = NULL, level = 0, path = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-3","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 0, represents block_quotes within document regardless nesting level. path [logical] TRUE, names element equivalent path. default FALSE, gives name episode. body XML body carpentries lesson (xml2 object)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-challenges-","dir":"Reference","previous_headings":"","what":"Method challenges()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather challenges lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-5","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$challenges(path = FALSE, graph = FALSE, recurse = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-4","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [logical] TRUE, names element equivalent path. default FALSE, gives name episode. graph [logical] TRUE, output data frame representing directed graph elements within challenges. See get_challenge_graph() method Episode. recurse [logical] graph = TRUE, include solutions output. See Episode details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-solutions-","dir":"Reference","previous_headings":"","what":"Method solutions()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather solutions lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-6","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$solutions(path = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-5","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [logical] TRUE, names element equivalent path. default FALSE, gives name episode.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-thin-","dir":"Reference","previous_headings":"","what":"Method thin()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Remove episodes challenges","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-7","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$thin(verbose = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-6","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose [logical] TRUE (default), names episode removed reported. Set FALSE remove behavior.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-1","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-3","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$thin()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-reset-","dir":"Reference","previous_headings":"","what":"Method reset()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Re-read Episodes disk","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-8","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$reset()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-2","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-4","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$episodes[[1]]$body frg$isolate_blocks()$episodes[[1]]$body # empty frg$reset()$episodes[[1]]$body # reset"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-isolate-blocks-","dir":"Reference","previous_headings":"","what":"Method isolate_blocks()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Remove elements except within block quotes kramdown tag. Note destructive process.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-9","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$isolate_blocks()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-3","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-5","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$isolate_blocks()$body # only one challenge block_quote"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-handout-","dir":"Reference","previous_headings":"","what":"Method handout()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"create handout episodes lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-10","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$handout(path = NULL, solution = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-7","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path path R Markdown file written. NULL (default), file written lines output document returned. solution TRUE solutions retained. Defaults FALSE","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-4","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path = NULL, character vector, otherwise, object returned.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-6","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) cat(lsn$handout()) cat(lsn$handout(solution = TRUE))"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-headings-","dir":"Reference","previous_headings":"","what":"Method validate_headings()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate heading elements meet minimum accessibility requirements. See internal validate_headings() deails. validate following aspects headings: first heading starts level 2 (first_heading_is_second_level) greater level 1 (greater_than_first_level) increse sequentially (e.g. jumps 2 4) (are_sequential) names (have_names) unique hierarchy (are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-11","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_headings(verbose = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-8","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE, heading tree printed console warnings assocated validators","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-5","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"data frame variable number rows follwoing columns: episode filename episode heading text heading level heading level pos position heading document node XML node represents heading (next five columns tests listed ) path path file. row data frame represents individual heading across Lesson. See validate_headings() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-7","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_headings()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-divs-","dir":"Reference","previous_headings":"","what":"Method validate_divs()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate divs known. See internal validate_divs() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"validation-variables","dir":"Reference","previous_headings":"","what":"Validation variables","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"divs known (is_known)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-12","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-9","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE (default), failed tests printed console message giving information document failing divs appear.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-6","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wide data frame five rows number columns equal number episodes lesson extra column indicating type validation. See method Episode class details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-8","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-links-","dir":"Reference","previous_headings":"","what":"Method validate_links()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate links images valid accessible. See internal validate_links() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"validation-variables-1","dir":"Reference","previous_headings":"","what":"Validation variables","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"External links use HTTPS (enforce_https) Internal links exist (internal_okay) External links reachable (all_reachable) (planned) Images alt text (img_alt_text) Link text descriptive (descriptive) Link text single letter (link_length)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-13","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-10","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE (default), failed tests printed console message giving information document failing links/images appear.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-7","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wide data frame five rows number columns equal number episodes lesson extra column indicating type validation. See method Episode class details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-9","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-trace-lineage-","dir":"Reference","previous_headings":"","what":"Method trace_lineage()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"find children single source file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-14","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$trace_lineage(episode_path)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-11","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"episode_path path episode extra file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-8","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"character vector full lineage files starting single source file. Note: assumes sandpaper lesson child files. child files, return path","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-10","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frag <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(frag, jekyll = FALSE) lsn$has_children # TRUE lsn$episodes[[1]]$children # first episode shows 1 immediate child lsn$trace_lineage(lsn$files[[1]]) # find recursive children of 1st episode"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-clone-","dir":"Reference","previous_headings":"","what":"Method clone()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"objects class cloneable method.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-15","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$clone(deep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-12","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"deep Whether make deep clone.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"## ------------------------------------------------ ## Method `Lesson$new` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$path #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" frg$episodes #> $`10-lunch.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- layout: break title: \"Lunch\" teaching: 0 exercises: ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`12-for-loops.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"For Loops\" teaching: 10 exercises: 15 questi ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`14-looping-data-sets.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"Looping Over Data Sets\" teaching: 5 exercise ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`17-scope.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"Variable Scope\" teaching: 10 exercises: 10 q ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> ## ------------------------------------------------ ## Method `Lesson$get` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$get(\"error\") # error code blocks #> $`10-lunch.md` #> {xml_nodeset (0)} #> #> $`12-for-loops.md` #> {xml_nodeset (2)} #> [1] [2] #> $`14-looping-data-sets.md` #> {xml_nodeset (0)} #> #> $`17-scope.md` #> {xml_nodeset (2)} #> [1] [2] frg$get(\"links\") # links #> $`10-lunch.md` #> {xml_nodeset (0)} #> #> $`12-for-loops.md` #> {xml_nodeset (1)} #> [1] #> $`14-looping-data-sets.md` #> {xml_nodeset (8)} #> [1] [2] [3] [4] [5] [6] \\ ... #> [7] [8] #> $`17-scope.md` #> {xml_nodeset (0)} #> ## ------------------------------------------------ ## Method `Lesson$summary` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$summary() # episode summary (default) #> ! Summary not guaranteed for styles-based lessons #> # A tibble: 4 × 12 #> page sections headings callouts challenges solutions code output warning #> #> 1 10-lunch… 0 0 0 0 0 0 0 0 #> 2 12-for-l… 24 24 7 7 10 32 4 0 #> 3 14-loopi… 9 10 3 3 3 11 4 0 #> 4 17-scope… 3 3 2 2 0 6 1 0 #> # ℹ 3 more variables: error , images , links ## ------------------------------------------------ ## Method `Lesson$thin` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$thin() #> Removing 1 episode: 10-lunch.md ## ------------------------------------------------ ## Method `Lesson$reset` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$episodes[[1]]$body #> {xml_document} #> #> [1] \\n [2] \\n {xml_document} #> frg$reset()$episodes[[1]]$body # reset #> {xml_document} #> #> [1] \\n [2] \\n NULL ## ------------------------------------------------ ## Method `Lesson$handout` ## ------------------------------------------------ lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) cat(lsn$handout()) #> ## Using RMarkdown #> #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` cat(lsn$handout(solution = TRUE)) #> ## Using RMarkdown #> #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::: solution #> #> ## Output #> #> ```{r, echo=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::::::::::::: #> #> ## Challenge 2: how do you nest solutions within challenge blocks? #> #> :::::::::::::::::::::::: solution #> #> You can add a line with at least three colons and a `solution` tag. ## ------------------------------------------------ ## Method `Lesson$validate_headings` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_headings() #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “For Loops” #> ├─## A for loop executes commands once for each value in a collection. #> ├─## A for loop is made up of a collection, a loop variable, and a body. #> ├─## The first line of the for loop must end with a colon, and the body must be #> ├─## Loop variables can be called anything. #> ├─## The body of a loop can contain many statements. #> ├─## Use range to iterate over a sequence of numbers. #> ├─## The Accumulator pattern turns many values into one. #> ├─## Classifying Errors #> ├─## Solution (duplicated) #> ├─## Tracing Execution #> ├─## Solution (duplicated) #> ├─## Reversing a String #> ├─## Solution (duplicated) #> ├─## Practice Accumulating #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Cumulative Sum #> ├─## Solution (duplicated) #> ├─## Identifying Variable Name Errors #> ├─## Solution (duplicated) #> ├─## Identifying Item Errors #> └─## Solution (duplicated) #> ──────────────────────────────────────────────────────────────────────────────── #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ──────────────────────────────────────────────────────────────────────────────── #> ! There were errors in 13/37 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) ## ------------------------------------------------ ## Method `Lesson$validate_divs` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_divs() ## ------------------------------------------------ ## Method `Lesson$validate_links` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_links() #> ! There were errors in 4/14 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg ## ------------------------------------------------ ## Method `Lesson$trace_lineage` ## ------------------------------------------------ frag <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(frag, jekyll = FALSE) lsn$has_children # TRUE #> [1] TRUE lsn$episodes[[1]]$children # first episode shows 1 immediate child #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd lsn$trace_lineage(lsn$files[[1]]) # find recursive children of 1st episode #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":null,"dir":"Reference","previous_headings":"","what":"Add a pegboard node before or after a node — add_pegboard_nodes","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"nodes namespace \"http://carpentries.org/pegboard/\"","code":""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"","code":"add_pegboard_nodes(node, df)"},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"node single node df data frame generated make_div_pairs()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"NULL, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if a node is after another node — after_thing","title":"Check if a node is after another node — after_thing","text":"Check node another node","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if a node is after another node — after_thing","text":"","code":"after_thing(body, thing = \"code_block\")"},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if a node is after another node — after_thing","text":"body XML node thing name XML node node , defaults \"code_block\"","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if a node is after another node — after_thing","text":"single boolean value indicating node single sibling code block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":null,"dir":"Reference","previous_headings":"","what":"test if the children of a given nodeset are kramdown blocks — are_blocks","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"test children given nodeset kramdown blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"","code":"are_blocks(krams)"},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"krams nodeset","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"boolean vector equal length nodeset","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":null,"dir":"Reference","previous_headings":"","what":"Clean the div tags from an xml document — clean_div_tags","title":"Clean the div tags from an xml document — clean_div_tags","text":"Clean div tags xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Clean the div tags from an xml document — clean_div_tags","text":"","code":"clean_div_tags(body)"},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Clean the div tags from an xml document — clean_div_tags","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Clean the div tags from an xml document — clean_div_tags","text":"TRUE divs detected cleaned, FALSE divs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Clean the div tags from an xml document — clean_div_tags","text":"Commonmark knows raw HTML looks like read HTML block, escaping tag. every HTML tag preceded blank line, :
\\n\\n<\/div> becomes two html_block elements However, element preceded non-html element, becomes part html element.
\\n<\/div> becomes single html_block element: Sometimes, process can gobble text markdown instead HTML, function find multiple tags HTML blocks separates different blocks.","code":" <div class='hello'>\\n <\/html_block> </div>\\n <\/html_block> <div class='hello'>\\n</div>\\n <\/html_block>"},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Clean the div tags from an xml document — clean_div_tags","text":"","code":"txt <- \"
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ```
```{r} It's not that challenging ``` <\/div>
We just have to try harder and use `
` tags ```{r} cat('better faster stronger with
') ``` <\/div> <\/div>
## Good divs <\/div> \" library(purrr) library(xml2) f <- tempfile() writeLines(txt, f) ex <- tinkr::to_xml(f) xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (5)} #> [1] <div class='challenge'>\\n## Challe ... #> [2] <div class='solution'>\\n```{r}\\nIt ... #> [3] </div>\\n</div>\\n<\/html_block> #> [4] <div class='good'>\\n<\/html_block> #> [5] </div>\\n<\/html_block> pegboard:::clean_div_tags(ex$body) #> [1] TRUE xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (8)} #> [1] &l ... #> [2] &l ... #> [3] &l ... #> [4] &l ... #> [5] &l ... #> [6] &l ... #> [7] <div class='good'>\\n<\/html_block> #> [8] </div>\\n<\/html_block> pegboard:::label_div_tags(ex$body) xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (8)} #> [1] &l ... #> [2] &l ... #> [3] &l ... #> [4] &l ... #> [5] &l ... #> [6] &l ... #> [7] <div class='good'>\\n<\/html_block> #> [8] </div>\\n<\/html_block>"},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":null,"dir":"Reference","previous_headings":"","what":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"Sometimes pandoc fenced divs bunched together, makes difficult track pairs. separates different paragraph elements can track ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"","code":"clean_fenced_divs(body)"},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"DEPRECATED.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"","code":"txt <- \"::::::: challenge ## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` ::::: solution :::: ```{r} It's not that challenging ``` :::: ::: solution :::::::: We just have to try harder and use `
` tags ```{r} cat('better faster stronger with
') ``` What if we include some `:::` code in here or ::: like this ::::: ::::: ::: good ## Good divs :::\" f <- tempfile() writeLines(txt, f) ex <- tinkr::to_xml(f, sourcepos = TRUE) ex$body #> {xml_document} #> #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] [7] \\n [8] [9] <img src='htt ... #> [10] \\n [11] \\n [12] \\n [13] \\n [14] \\n [1] \"::::::: challenge\" \"::::: solution ::::\" \"::::\" #> [4] \"::: solution ::::::::\" \":::::\" \":::::\" #> [7] \"::: good\" \":::\" pegboard:::clean_fenced_divs(ex$body) xml2::xml_text(xml2::xml_find_all(ex$body, predicate)) #> [1] \"::::::: challenge\" \"::::: solution ::::\" \"::::\" #> [4] \"::: solution ::::::::\" \":::::\" \":::::\" #> [7] \"::: good\" \":::\""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":null,"dir":"Reference","previous_headings":"","what":"Issue a warning via CLI if it exists or send a message — issue_warning","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"allows us control messages emitted continue keep CLI suggested package.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"","code":"issue_warning( msg = NULL, cli = has_cli(), what = NULL, url = NULL, n = NULL, N = NULL, infos = list(), reports = list(), ... ) pb_message(..., domain = NULL, appendLF = TRUE) line_report(msg = \"\", path, pos, sep = \"\\t\", type = \"warning\") append_labels(l, i = TRUE, e = \"\", cli = FALSE, f = \"style_inverse\") message_muffler(expr, keep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"msg message glue CLI string. Defaults NULL cli TRUE, stylizes e f name specific element report error url url extra information help. n number elements errored N number total elements infos information errors shown user reports reported errors. ... named arguments evaluated message via glue CLI domain see gettext. NA, messages translated, see also note stop. appendLF logical: messages given character string newline appended? path path file report pos position error sep character use separate human message line number type (used context CI ) type warning thrown (defaults warning) l vector/list characters index elements append e new element append element f function cli transform e expr R expression. keep TRUE, messages kept list. Defautls FALSE cli message discarded.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"nothing, invisibly; used side-effect , l, appended keep = FALSE, output expr, keep = TRUE, list elements val = expr msg = s","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"vast majority code function copied directly message() function.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"","code":"pegboard:::pb_message(\"hello\") #> hello x <- letters[1:5] x2 <- pegboard:::append_labels(x, c(1, 3), \"appended\", cli = requireNamespace(\"cli\", quietly = TRUE), f = \"col_cyan\" ) writeLines(glue::glue(\"[{x}]->[{x2}]\")) #> [a]->[a appended] #> [b]->[b] #> [c]->[c appended] #> [d]->[d] #> [e]->[e] pegboard:::message_muffler({ cli::cli_text(\"hello there! I'm staying in!\") pegboard:::pb_message(\"normal looking message that's not getting through\") message(\"this message makes it out!\") runif(1) }) #> this message makes it out! #> [1] 0.08075014 pegboard:::message_muffler({ cli::cli_text(\"hello there! I'm staying in!\") pegboard:::pb_message(\"normal looking message that's not getting through\") message(\"this message makes it out!\") runif(1) }, keep = TRUE) #> this message makes it out! #> $val #> [1] 0.834333 #> #> $msg #> $msg[[1]] #> > #> #> $msg[[2]] #> > #> #>"},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":null,"dir":"Reference","previous_headings":"","what":"Collect and append validation messages — collect_labels","title":"Collect and append validation messages — collect_labels","text":"Given data frame containing results validation tests, append column labels describes failure.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Collect and append validation messages — collect_labels","text":"","code":"collect_labels(VAL, cli = FALSE, msg = heading_tests)"},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Collect and append validation messages — collect_labels","text":"VAL data frame containing results tests cli indicator use cli package format warnings msg named vector template messages provide test formatted glue package.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Collect and append validation messages — collect_labels","text":"","code":"# As an example, consider a data frame where you have observations in rows # and the results of individual tests in columns: set.seed(2023-11-16) dat <- data.frame( name = letters[1:10], rank = sample(1:3, 10, replace = TRUE), A = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)), B = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)), C = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)) ) dat #> name rank A B C #> 1 a 1 TRUE FALSE TRUE #> 2 b 1 FALSE FALSE TRUE #> 3 c 3 FALSE TRUE TRUE #> 4 d 1 TRUE TRUE TRUE #> 5 e 2 TRUE TRUE TRUE #> 6 f 2 FALSE TRUE TRUE #> 7 g 3 TRUE FALSE TRUE #> 8 h 2 TRUE TRUE FALSE #> 9 i 2 TRUE FALSE TRUE #> 10 j 3 FALSE TRUE TRUE # you can see what the results of the tests were, but it would be a good # idea to have a lookup table describing what these results mean dat_tests <- c( A = \"[missing widget]: {name}\", B = \"[incorrect rank]: {rank}\", C = \"[something else]\" ) # collect_labels will create the output you need: pb <- asNamespace(\"pegboard\") res <- pb$collect_labels(dat, msg = dat_tests) res #> name rank A B C labels #> 1 a 1 TRUE FALSE TRUE [incorrect rank]: 1 #> 2 b 1 FALSE FALSE TRUE [missing widget]: b [incorrect rank]: 1 #> 3 c 3 FALSE TRUE TRUE [missing widget]: c #> 4 d 1 TRUE TRUE TRUE #> 5 e 2 TRUE TRUE TRUE #> 6 f 2 FALSE TRUE TRUE [missing widget]: f #> 7 g 3 TRUE FALSE TRUE [incorrect rank]: 3 #> 8 h 2 TRUE TRUE FALSE [something else] #> 9 i 2 TRUE FALSE TRUE [incorrect rank]: 2 #> 10 j 3 FALSE TRUE TRUE [missing widget]: j writeLines(res$labels) #> [incorrect rank]: 1 #> [missing widget]: b [incorrect rank]: 1 #> [missing widget]: c #> #> #> [missing widget]: f #> [incorrect rank]: 3 #> [something else] #> [incorrect rank]: 2 #> [missing widget]: j if (requireNamespace(\"cli\", quietly = TRUE)) { # you can also specify cli to TRUE to format with CLI res <- pb$collect_labels(dat, cli = TRUE, msg = dat_tests) writeLines(res$labels) } #> [incorrect rank]: 1 #> [missing widget]: b [incorrect rank]: 1 #> [missing widget]: c #> #> #> [missing widget]: f #> [incorrect rank]: 3 #> [something else] #> [incorrect rank]: 2 #> [missing widget]: j"},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":null,"dir":"Reference","previous_headings":"","what":"Add labels to div tags in the form of a ","title":"Add labels to div tags in the form of a ","text":"Add labels div tags form \"dtag\" node paired \"label\" attribute.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add labels to div tags in the form of a ","text":"","code":"label_div_tags(body) find_div_tags(body) clear_div_labels(body)"},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add labels to div tags in the form of a ","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add labels to div tags in the form of a ","text":"label_div_tags(): document, modified clear_div_labels(): document, modified find_div_tags(): node list","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add labels to div tags in the form of a ","text":"","code":"txt <- \"# Example with a mix of div tags > PLEASE NEVER DO THE LESSONS THIS WAY > > I AM LITERALLY JUST TESTING A TERRIBLE EXAMPLE. --------------------------------------------------------------------------------
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` :::: solution ```{r} It's not that challenging ``` :::
We just have to try harder and use `
` tags :::::: callout ```{r} cat('better faster stronger with
') ``` :::: :::::: discussion ::::: <\/div> <\/div>
## Good divs <\/div> \" tmp <- tempfile() writeLines(txt, tmp) ex <- tinkr::to_xml(tmp) ex$body #> {xml_document} #> #> [1] \\n Example with a mix of ... #> [2] \\n \\n PLEASE NEVE ... #> [3] #> [4] <div class='challenge'>\\n## Chall ... #> [5] \\n do that challenging thing.<\/te ... #> [6] cat('it might be c ... #> [7] \\n :::: solution<\/text>\\n<\/paragr ... #> [8] It's not that chal ... #> [9] \\n :::<\/text>\\n<\/paragraph> #> [10] <div class='solution'>\\nWe just h ... #> [11] \\n :::::: callout<\/text>\\n<\/parag ... #> [12] cat('better faster ... #> [13] \\n ::::<\/text>\\n \\n ... #> [14] </div>\\n</div>\\n<\/html_block> #> [15] <div class='good'>\\n<\/html_block> #> [16] \\n Good divs<\/text>\\n<\/he ... #> [17] </div>\\n<\/html_block> pegboard:::label_div_tags(ex$body) ex$body #> {xml_document} #> #> [1] \\n Example with a mix of ... #> [2] \\n \\n PLEASE NEVE ... #> [3] #> [4] #> [5] & ... #> [6] \\n [7] \\n do that challenging thing.<\/te ... #> [8] cat('it might be c ... #> [9] #> [10] \\n :::: solution<\/text>\\n<\/paragr ... #> [11] It's not that chal ... #> [12] \\n :::<\/text>\\n<\/paragraph> #> [13] #> [14] #> [15] & ... #> [16] \\n [17] #> [18] \\n :::::: callout<\/text>\\n<\/parag ... #> [19] cat('better faster ... #> [20] #> ... pegboard:::clear_div_labels(ex$body)"},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":null,"dir":"Reference","previous_headings":"","what":"elevate all children of a node — elevate_children","title":"elevate all children of a node — elevate_children","text":"elevate children node","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"elevate all children of a node — elevate_children","text":"","code":"elevate_children(parent, remove = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"elevate all children of a node — elevate_children","text":"parent xml node (notably block quote) remove logical value. TRUE (default), parent node removed document.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"elevate all children of a node — elevate_children","text":"elevated nodes, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"elevate all children of a node — elevate_children","text":"","code":"if (FALSE) { # \\dontrun{ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) # get all the challenges (2 blocks) scope$get_blocks(\".challenge\") b1 <- scope$get_blocks(\".challenge\")[[1]] elevate_children(b1) # now there is only one block: scope$get_blocks(\".challenge\") } # }"},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":null,"dir":"Reference","previous_headings":"","what":"Find nodes between two nodes with a given dtag — find_between_tags","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"Find nodes two nodes given dtag","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"","code":"find_between_tags( tag, body, ns = \"pb\", find = \"dtag[@label='{tag}']\", include = FALSE )"},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"tag integer representing unique dtag attribute body xml document ns namespace body find xpath element search (without namespace tag) include TRUE, tags included output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"nodeset tags dtag attribute matching tag","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$unblock() # removing blockquotes and replacing with div tags # find all the div tags ns <- pegboard:::get_ns(loop$body) tags <- xml2::xml_find_all(loop$body, \".//pb:dtag\", ns) tags <- xml2::xml_attr(tags, \"label\") tags #> [1] \"div-1-challenge\" \"div-2-solution\" \"div-2-solution\" \"div-1-challenge\" #> [5] \"div-3-challenge\" \"div-4-solution\" \"div-4-solution\" \"div-3-challenge\" #> [9] \"div-5-challenge\" \"div-6-solution\" \"div-6-solution\" \"div-5-challenge\" # grab the contents of the first div tag pegboard:::find_between_tags(tags[[1]], loop$body) #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n --- #> title: \"Using RMarkdown\" #> teaching: 10 #> exercises: 2 #> --- #> #> :::::::::::::::::::::::::::::::::::::: questions #> #> - How do you write a lesson using RMarkdown and `{sandpaper}`? #> #> :::::::::::::::::::::::::::::::::::::::::::::::: #> #> ::::::::::::::::::::::::::::::::::::: objectives #> #> - Explain how to use markdown with the new lesson template #> - Demonstrate how to include pieces of code, figures, and nested challenge blocks #> #> :::::::::::::::::::::::::::::::::::::::::::::::: #> #> ```{r cat-child, child=\"files/cat.Rmd\"} #> ``` pb$find_children(intro) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd # this is identical to the `$children` element of an Episode object ep <- Episode$new(fs::path(ex, \"episodes\", \"intro.Rmd\")) ep$children #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd # Loading the child document reveals another child child <- Episode$new(ep$children[[1]]) child$children #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/files/session.Rmd child$show() #> Here is a picture of a kitten: #> #> ![I hope you have a good day](https://placekitten.com/300/300){alt='a random cute kitten'} #> #> ```{r sessionInfo(), child=\"files/session.Rmd\"} #> ``` #> # `trace_children()` ------------------------------------------------------- # In the context of the lesson, we can find all the descendants lsn <- Lesson$new(ex, jekyll = FALSE) pb$trace_children(ep, lsn) #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\" # This is the same as using the method of the same name in the Lesson object # using the path to the episode lsn$trace_lineage(ep$path) #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\" # show the children purrr::walk(lsn$children, function(ep) { message(\"----\", ep$path, \"----\") ep$show() } ) #> ----/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd---- #> Here is a picture of a kitten: #> #> ![I hope you have a good day](https://placekitten.com/300/300){alt='a random cute kitten'} #> #> ```{r sessionInfo(), child=\"files/session.Rmd\"} #> ``` #> #> ----/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd---- #>
#> Here is the sesion information for this build<\/summary> #> #> ```{r session-info} #> sessioninfo::session_info() #> ``` #> #> <\/details> #>"},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":null,"dir":"Reference","previous_headings":"","what":"Make paired labels for opening and closing div tags — find_div_pairs","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"Make paired labels opening closing div tags","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"","code":"find_div_pairs(divs, close = div_close_regex())"},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"close regex valid closing tag nodes character vector div open close tags","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"integer vector pairs labels opening closing tag. Note labels produced cumulative sum node depths.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"","code":"nodes <- c( \"
\", \"
\" , \"<\/div>\", \"
\", \"
\", \"<\/div>\", \"<\/div>\", \"<\/div>\") pegboard:::find_div_pairs(nodes) #> [1] 1 2 2 3 4 4 3 1"},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":null,"dir":"Reference","previous_headings":"","what":"Find the level of the current node releative to the document — find_node_level","title":"Find the level of the current node releative to the document — find_node_level","text":"Find level current node releative document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find the level of the current node releative to the document — find_node_level","text":"","code":"find_node_level(node)"},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find the level of the current node releative to the document — find_node_level","text":"node XML node object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find the level of the current node releative to the document — find_node_level","text":"number indicating nested current node . 0 represents document , 1 represents child elements document, etc.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Find and fix unresolved template links within an Episode XML body — fix_links","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"Links like [link text]({{ page.root }}/destination.html) parsed correctly commonmark parser output text. Use find missing links transform link image elements.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"","code":"fix_links(body) find_broken_links(body) fix_broken_links(fragments) make_link_patterns(ns = \"md:\") get_link_fragment_nodes(node) fix_broken_link(nodes) links_within_text_regex() text_to_links(txt, ns = NULL, type, sourcepos = NULL) make_link(txt, pattern, type = \"rel_link\") find_between_nodes(a, b, include = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"body XML document. ns namespace object node node determined text representation link destination txt text derived xml2::xml_text() type either \"image\" \"link\". sourcepos defaults NULL. NULL, sourcepos attribute text node(s) applied new nodes. pattern regular expression used splitting link surrounding text.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"fix_links(): modified body find_broken_link(): list element represents fragmented link. Inside element two elements: parent: parent paragraph node link nodes: series four five nodes make link text get_link_fragments(): preceding three four nodes, text link alt text image. text_to_links(): ns NULL: character vector XML text nodes, otherwise, new XML text nodes. get_link_fragments(): preceding three four nodes, text link alt text image.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"find_broken_links() uses pattern generated make_link_patterns() search potential links. fix_broken_links() uses output find_broken_links() replace node fragments links. make_link_patterns() generator create XPath query search liquid markup following closing bracket. get_link_fragment_nodes(): Get source link node fragments fix_broken_link() takes set nodes comprises single link recomposes link image node. links_within_text_regex(): finding different types links within markdown text can challenging involves characters used regex grouping character classes. general, want two things text get back document: split links text identify parts resulting vector links. way, can convert links links text text. text_to_links(): Splits links away text returns nodeset insert make_link(): makes link depending link type","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"motivation","dir":"Reference","previous_headings":"","what":"Motivation","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"Jekyll implements liquid template language, can break syntax expected commonmark. syntax appears link context, link rendred text. Carpentries Lessons created 2023 use Jekyll templating embedded many links. order convert pre-workbench lesson use Workbench, need make sure links accurately represented avoid invalid syntax broken links sneaking lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"implementation-details","dir":"Reference","previous_headings":"","what":"Implementation Details","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"example, valid line link looks like [Home](index.html) text appear XML : However, link uses liquid templating variable : [Home]({{ page.root }}/index.html) text, appear XML Note: nodes asis elements tinkr protecting square brackets. run fix_links(), nodes collapsed link: can transform link replace liquid templating something makes sense sandpaper.","code":"... Home<\/link> and other text<\/text> ... ... [<\/text> Home<\/text> ]<\/text> ({{ page.root }}/index.html) and other text<\/text> ... ... Home<\/link> and other text<\/text> ..."},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"","code":"loop <- fs::path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") e <- Episode$new(loop, fix_links = FALSE) e$links # five links #> {xml_nodeset (5)} #> [1] [2] [3] [4] [5] {xml_nodeset (4)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... # fix_links() --------------------------------------------------------------- e$body <- asNamespace(\"pegboard\")$fix_links(e$body) e$links # eight links #> {xml_nodeset (8)} #> [1] [2] [3] [4] [5] [6] \\ ... #> [7] [8] {xml_nodeset (5)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... #> [5] .//md:text[@asis][text()=']']/following-sibling::md:text[(contains(text(), '({{') and contains(text(), '}}'))] # links_within_text_regex() ------------------------------------------------- helpers <- pegboard:::links_within_text_regex() helpers #> to_split #> \"(? find_links #> \"(? res #> 1 text ![image text](a.png #> 2 with #> 3 a link](b.org #> 4 and text grepl(helpers[\"find_links\"], res, perl = TRUE) #> [1] TRUE FALSE TRUE FALSE # text_to_links() ----------------------------------------------------------- txt <- \"Some text [and _a link_]({{ page.root }}/link.to#thing), some other text.\" pegboard:::text_to_links(txt, type = \"link\") #> [1] \"Some text <\/text>\" #> [2] \"and _a link_<\/text><\/link>\" #> [3] \", \\nsome other text.<\/text>\" md <- c(md = \"http://commonmark.org/xml/1.0\") class(md) <- \"xml_namespace\" pegboard:::text_to_links(txt, md, \"link\") #> {xml_nodeset (3)} #> [1] Some text <\/text> #> [2] \\n and _a link_< ... #> [3] , \\nsome other text.<\/text>"},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":null,"dir":"Reference","previous_headings":"","what":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"Liquid syntax wraps variables double moustache braces may may spaces within moustaches. example, get link page root, use page.root make readable. However, violates expectation commonmark parser makes think “oh, just ordinary text”.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"","code":"fix_liquid_relative_link(path, encoding = \"UTF-8\")"},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"path path MD file encoding encoding text, defaults UTF-8","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"function fixes issue removing spaces within braces.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"function perform transformation three node types:","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"","code":"fix_sandpaper_links(body, yml = list(), path = NULL, known = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"body XML document yml list key/value pairs derived _config.yml file path path current episode known character vector known episodes lesson, relative lesson root.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"body, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"image link html_node transformation remove relative paths (\"../\") replace Jekyll templating (e.g. \" page.root \" \" site.swc_pages \" either nothing link software carpentry, respectively.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"absolutely comprehensive links fail converted. happens, please report issue: https://github.com/carpentries/pegboard/issues/new/","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"","code":"loop <- fs::path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") e <- Episode$new(loop) pegboard:::make_link_table(e)$orig #> [1] \"https://docs.python.org/3/library/glob.html#glob.glob\" #> [2] \"https://docs.python.org/3/library/glob.html\" #> [3] \"https://docs.python.org/3/library/glob.html\" #> [4] \"https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html\" #> [5] \"https://docs.python.org/3/library/stdtypes.html#str.split\" #> [6] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [7] \"../no-workie.svg\" #> [8] \"{{ page.root }}/index.html\" #> [9] \"{{ site.swc_pages }}/shell-novice\" #> [10] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [11] \"../no-workie.svg\" #> [12] \"{{ page.root }}/no-workie.svg\" #> [13] \"{{ page.root }}{% link index.md %}\" e$use_sandpaper() pegboard:::make_link_table(e)$orig #> [1] \"https://docs.python.org/3/library/glob.html#glob.glob\" #> [2] \"https://docs.python.org/3/library/glob.html\" #> [3] \"https://docs.python.org/3/library/glob.html\" #> [4] \"https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html\" #> [5] \"https://docs.python.org/3/library/stdtypes.html#str.split\" #> [6] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [7] \"no-workie.svg\" #> [8] \"index.html\" #> [9] \"https://swcarpentry.github.io/shell-novice\" #> [10] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [11] \"no-workie.svg\" #> [12] \"no-workie.svg\" #> [13] \"index.md\""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":null,"dir":"Reference","previous_headings":"","what":"Gather blocks from the XML body of a carpentries lesson — get_blocks","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"search XML document block_quotes specified type level extract nodeset.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"","code":"get_blocks(body, type = NULL, level = 0)"},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"body XML body carpentries lesson (xml2 object) type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 1, represents block_quotes nested within block quotes. Increase nubmer increase level nesting.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"xml nodeset object element representing blockquote matched input criteria.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"moment, blocks returned specified level. select type = \".solution\", level = 1, receive blocks contain solution blocks even though blocks almost always nested within blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"","code":"frg <- Lesson$new(lesson_fragment()) # Find all the blocks in the get_blocks(frg$episodes[[\"17-scope.md\"]]$body) #> {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n loop$reset() get_challenges(loop$use_dovetail()$unblock()$body, \"chunk\") #> {xml_nodeset (3)} #> [1] [2] [3] \".","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get code blocks from xml document — get_code","text":"xml nodeset object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get code blocks from xml document — get_code","text":"uses XPath function fn:starts-() search code block automatically includes opening brace, regular expressions allowed. used $code, $output, $error elements Episode class.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get code blocks from xml document — get_code","text":"","code":"e <- Episode$new(fs::path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) get_code(e$body) #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (1)} #> [1] {xml_nodeset (2)} #> [1] [2] elements containing div tags grab first tag pair filter div tag class (type) grab elements tags","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/get_divs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get paired div blocks — get_divs","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$unblock() # removing blockquotes and replacing with div tags pegboard:::get_divs(loop$body, 'challenge') # all challenge blocks #> $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n pegboard:::get_divs(loop$body, 'solution') # all solution blocks #> $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n "},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":null,"dir":"Reference","previous_headings":"","what":"Get images from an Episode/yarn object — get_images","title":"Get images from an Episode/yarn object — get_images","text":"Get images Episode/yarn object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get images from an Episode/yarn object — get_images","text":"","code":"get_images(yrn, process = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get images from an Episode/yarn object — get_images","text":"yrn Episode/yarn object process TRUE (default), images processed via process_images() add alt attribute extract images HTML blocks. FALSE present nodes found XPath search.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get images from an Episode/yarn object — get_images","text":"xml_nodelist","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get images from an Episode/yarn object — get_images","text":"Markdown users can write images either markdown HTML. write images HTML, commonmark XML parser recognises generic \"HTML blocks\" found just searching .//md:image. function searches md:html_block md:html_inline image content can extract downstream analysis.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get images from an Episode/yarn object — get_images","text":"","code":"tmp <- tempfile() on.exit(unlink(tmp)) txt <- ' ![a kitten](https://placekitten.com/200/200){alt=\"a pretty kitten\"} an inline html image of a kitten ' writeLines(txt, tmp) ep <- Episode$new(tmp) ep$show() #> ![a kitten](https://placekitten.com/200/200){alt=\"a pretty kitten\"} #> #> #> #> #> #> an inline html image of a kitten #> # without process = TRUE, images in HTML elements are not converted ep$get_images() #> {xml_nodeset (3)} #> [1] [2] <img src=\"https: ... #> [3] <img src=\"http ... # setting process = TRUE will extract the HTML elements for analysis # (e.g to detect alt text) ep$get_images(process = TRUE) #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n loop$reset() get_solutions(loop$use_dovetail()$unblock()$body, \"chunk\") #> {xml_nodeset (3)} #> [1] [2] [3] [1] 1 2 2 1 x <- c(\"(\", \"(\", \")\", \"(\", \"(\", \")\", \")\", \")\") pegboard:::label_pairs(x, 4) #> [1] 1 2 2 3 4 4 3 1"},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":null,"dir":"Reference","previous_headings":"","what":"Example Lesson Fragments — lesson_fragment","title":"Example Lesson Fragments — lesson_fragment","text":"Partial lessons mainly used testing demonstration purposes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Example Lesson Fragments — lesson_fragment","text":"","code":"lesson_fragment(name = \"lesson-fragment\")"},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Example Lesson Fragments — lesson_fragment","text":"name name lesson fragment. Can one : lesson-fragment rmd-lesson sandpaper-fragment sandpaper-fragment child","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Example Lesson Fragments — lesson_fragment","text":"path lesson fragment whose contents : lesson-fragment contains one _episodes directory three files: \"10-lunch.md\", \"14-looping-data-sets.md\", \"17-scope.md\" rmd-fragment contains one episode _episodes_rmd called 01-test.Rmd. sandpaper-fragment contains trimmed-Workbench lesson R Markdown content pre-built sandpaper-fragment--child contains much content sandpaper-fragment, episodes/index.Rmd file references child documents.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Example Lesson Fragments — lesson_fragment","text":"lesson-fragment example taken python novice gapminder lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Example Lesson Fragments — lesson_fragment","text":"","code":"lesson_fragment() #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" lesson_fragment(\"rmd-lesson\") #> [1] \"/home/runner/work/_temp/Library/pegboard/rmd-lesson\" lesson_fragment(\"sandpaper-fragment\") #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" lesson_fragment(\"sandpaper-fragment-with-child\") #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child\""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"Liquid code blocks generally codified ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"","code":"liquid_to_commonmark(block, make_rmd = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"block code block make_rmd TRUE, language wrapped curly braces evaluated RMarkdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"node, invisibly.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":": .language-python However, simpler syntax can use: take code block convert longer use liquid tag (added \"ktag\" attribute \"kramdown\" tag)","code":"print(\"code goes \" + \"here\") print(\"code goes \" + \"here\")"},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"","code":"frg1 <- Lesson$new(lesson_fragment()) frg2 <- frg1$clone(deep = TRUE) py1 <- get_code(frg1$episodes[[\"17-scope.md\"]]$body, \".language\") py2 <- get_code(frg2$episodes[[\"17-scope.md\"]]$body, \".language\") py1 #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] [2] [3] [1] TRUE purrr::map2(children, lsn$children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] FALSE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] FALSE #> # read children takes in a list of children episodes and appends that list # with the descendants # given a full list of children, it will return the same list these_children <- pb$read_children(lsn$episodes[[1]], children) purrr::map2(these_children, children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] TRUE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] TRUE #> # given a partial list, it will append to it new_children <- pb$read_children(lsn$episodes[[1]], children[1]) purrr::map2(new_children, children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] TRUE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] FALSE #>"},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":null,"dir":"Reference","previous_headings":"","what":"Create an xml document that contains two html_block elements that contain div tags. — make_div","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"Create xml document contains two html_block elements contain div tags.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"","code":"make_div(what, fenced = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"class block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"xml document commonmark namespace","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"","code":"cha <- pegboard:::make_div(\"challenge\") cha #> {xml_document} #> #> [1] \\n ::::::::::::::::::::::::::::::: ... #> [2] \\n ::::::::::::::::::::::::::::::: ... cat(pegboard:::xml_to_md(cha)) #> :::::::::::::::::::::::::::::::::::::::: challenge #> #> ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a data frame describing the divs associated with nodes. — make_div_pairs","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"Native fenced divs may several tags grouped single element. order mark pairs, need account tags exist nodes. function creates ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"","code":"make_div_pairs(nodes, path = NULL, yaml = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"nodes nodelist containing native div fenced div tags html_block paragraphs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"list data frames node following columns: node: numeric index node div: text individual div element, stripped context label: label div pair (div-label-class) pos: position label relative associated node","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"","code":"txt <- \"# Example with a mix of div tags > PLEASE NEVER DO THE LESSONS THIS WAY > > I AM LITERALLY JUST TESTING A TERRIBLE EXAMPLE. --------------------------------------------------------------------------------
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` :::: solution ```{r} It's not that challenging ``` :::
We just have to try harder and use `
` tags :::::: callout ```{r} cat('better faster stronger with
') ``` :::: :::::: discussion ::::: <\/div> <\/div>
## Good divs <\/div> \" tmp <- tempfile() writeLines(txt, tmp) ex <- tinkr::to_xml(tmp) pegboard:::clean_div_tags(ex$body) #> [1] TRUE nodes <- pegboard:::find_div_tags(ex$body) divs <- pegboard:::make_div_pairs(nodes) do.call(\"rbind\", divs) #> node div line label pos #> 1 1
NA div-1-challenge before #> 2 2 :::: solution NA div-2-solution before #> 3 3 ::: NA div-2-solution after #> 4 4
NA div-3-solution before #> 5 5 :::::: callout NA div-4-callout before #> 6.6 6 :::: NA div-4-callout after #> 6.7 6 :::::: discussion NA div-5-discussion before #> 6.8 6 ::::: NA div-5-discussion after #> 7 7 <\/div> NA div-3-solution after #> 8 8 <\/div> NA div-1-challenge after #> 9 9
NA div-6-good before #> 10 10 <\/div> NA div-6-good after"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a table of divs in an episode — make_div_table","title":"Create a table of divs in an episode — make_div_table","text":"Create table divs episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a table of divs in an episode — make_div_table","text":"","code":"make_div_table(yrn)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a table of divs in an episode — make_div_table","text":"yrn tinkr::yarn Episode object.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a table of divs in an episode — make_div_table","text":"data frame following columns: path: path file, relative lesson div: type div pb_label: label div line: line number div label","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a table for headings — make_heading_table","title":"Create a table for headings — make_heading_table","text":"Create table headings","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a table for headings — make_heading_table","text":"","code":"make_heading_table(headings, offset = 5L)"},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a table for headings — make_heading_table","text":"headings xml_nodeset object text \"level\" attributes offest offset yaml header (artifact tinkr), defaults 5L, two fences plus title, teaching, exercises.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a table for headings — make_heading_table","text":"data frame three columns: heading text heading level heading level pos position heading document node node containing heading","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a table for headings — make_heading_table","text":"","code":"path <- file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") loop <- Episode$new(path) pegboard:::make_heading_table(loop$headings, offset = length(loop$yaml)) #> heading level pos #> 1 Use a for loop to process files given a list of their names. 2 17 #> 2 Use glob.glob to find sets of files whose names match a pattern. 2 51 #> 3 Use glob and for to process batches of files. 2 84 #> 4 Determining Matches 2 110 #> 5 Solution 2 119 #> 6 Minimum File Size 2 125 #> 7 Solution 2 143 #> 8 Comparing Data 2 157 #> 9 Solution 2 162 #> 10 ZNK test links and images 3 187 #> node #> 1 2 3 4 5 6 7 8 9 10 scheme server port user #> 1 https docs.python.org NA #> 2 https docs.python.org NA #> 3 https docs.python.org NA #> 4 https pandas.pydata.org NA #> 5 https docs.python.org NA #> 9 https carpentries.org NA #> 10 NA #> 6 22021 #> 7 1177610896 #> 11 https carpentries.org NA #> 12 NA #> 13 1309757824 #> 8 22021 #> path query #> 1 /3/library/glob.html #> 2 /3/library/glob.html #> 3 /3/library/glob.html #> 4 /pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 /3/library/stdtypes.html #> 9 /assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 #> 7 #> 11 /assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 #> 8 #> fragment #> 1 glob.glob #> 2 #> 3 #> 4 #> 5 str.split #> 9 #> 10 #> 6 #> 7 #> 11 #> 12 #> 13 #> 8 #> orig #> 1 https://docs.python.org/3/library/glob.html#glob.glob #> 2 https://docs.python.org/3/library/glob.html #> 3 https://docs.python.org/3/library/glob.html #> 4 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 https://docs.python.org/3/library/stdtypes.html#str.split #> 9 https://carpentries.org/assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 {{ page.root }}/index.html #> 7 {{ site.swc_pages }}/shell-novice #> 11 https://carpentries.org/assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 {{ page.root }}/no-workie.svg #> 8 {{ page.root }}{% link index.md %} #> text alt title type #> 1 glob.glob link #> 2 glob link #> 3 glob link #> 4 shape method link #> 5 split link #> 9 books as clubs img #> 10 books as clubs img #> 6 Home link #> 7 shell link #> 11 Carpentries logo image #> 12 Non-working image image #> 13 Non-working image with jekyll syntax image #> 8 link that isn't parsed correctly by commonmark link #> rel anchor sourcepos filepath parents node #> 1 FALSE 51 _episodes/14-looping-data-sets.md 2 FALSE 57 _episodes/14-looping-data-sets.md 3 FALSE 58 _episodes/14-looping-data-sets.md 4 FALSE 140 _episodes/14-looping-data-sets.md 5 FALSE 163 _episodes/14-looping-data-sets.md 9 FALSE 189 _episodes/14-looping-data-sets.md 10 FALSE 191 _episodes/14-looping-data-sets.md 6 FALSE 193 _episodes/14-looping-data-sets.md 7 FALSE 193 _episodes/14-looping-data-sets.md 11 FALSE 195 _episodes/14-looping-data-sets.md 12 FALSE 197 _episodes/14-looping-data-sets.md 13 FALSE 199 _episodes/14-looping-data-sets.md 8 FALSE 201 _episodes/14-looping-data-sets.md {xml_nodeset (2)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... lop$get_blocks(level = 1) #> {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (0)} # add tags pegboard:::label_div_tags(lop$body) lop$get_divs() #> $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n xml2::xml_text(lop$get_divs()[[1]]) #> [1] \"::::::::::::::::::::::::::::::::::::::: challenge\" #> [2] \"Determining Matches\" #> [3] \"Which of these files is not matched by the expression glob.glob('data/*as*.csv')?\" #> [4] \"data/gapminder_gdp_africa.csvdata/gapminder_gdp_americas.csvdata/gapminder_gdp_asia.csv1 and 2 are not matched.\" #> [5] \"::::::::::::::: solution\" #> [6] \"Solution\" #> [7] \"1 is not matched by the glob.\" #> [8] \":::::::::::::::::::::::::\" #> [9] \"::::::::::::::::::::::::::::::::::::::::::::::::::\""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":null,"dir":"Reference","previous_headings":"","what":"Set the alt text for a nodeset of images — set_alt_attr","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"finds attribute curly braces image declaration, extracts alt text, adds attribute image, useful parsing XML, affect rendering.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"","code":"set_alt_attr(images, xpath, ns)"},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"images nodeset images xpath XPath expression finds first curly brace immediately node. ns namespace XML","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"nodeset, invisibly.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"function assumes images entering curly brace following.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":null,"dir":"Reference","previous_headings":"","what":"add the kramdown tags as attributes of special blocks — set_ktag_block","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"add kramdown tags attributes special blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"","code":"set_ktag_block(tags)"},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"tags tags function kramdown_tags()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"Kramdown bit weird uses tags trail elements like code blocks block quotes. follow block quotes, commonmark parse part block quote. problematic per-se run common situation Carpentries' curriculum: nested block quotes parsed commonmark, three tags end parsed part 2nd-level block quote: function take block quote elements add \"ktag\" attribute represents value tag. parsed xslt style sheet tags properly appended.","code":"> # Challenge 1 > > Some text here > > > # Solution 1 > > > > ~~~ > > print(\"hello world!\") > > ~~~ > > {: .language-pyton} > {: .solution} {: .challenge} ... > > ~~~ > > {: .language-pyton} > > {: .solution} > > {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":null,"dir":"Reference","previous_headings":"","what":"Test for the existence of a file — test_file_existence","title":"Test for the existence of a file — test_file_existence","text":"Test existence file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Test for the existence of a file — test_file_existence","text":"","code":"test_file_existence(paths, home)"},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Test for the existence of a file — test_file_existence","text":"paths relative paths tested home root directory paths","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Test for the existence of a file — test_file_existence","text":"logical vector length paths indicating file exists _anywhere lesson infrastructure","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Test for the existence of a file — test_file_existence","text":"function detects existence files relative current folder taking account references built site. understand needed consider Workbench Jekyll takes contents source folders pools flat file structure website. , possible write links like [link](resource.html) [link](../learners/resource.md) continue valid.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Test for the existence of a file — test_file_existence","text":"","code":"pb <- asNamespace(\"pegboard\") # Example: validation of links in a sandpaper context ----------------------- fs::dir_tree(lesson_fragment(\"sandpaper-fragment\")) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment #> ├── config.yaml #> ├── episodes #> │ ├── intro.Rmd #> │ └── nope.md #> ├── index.md #> ├── instructors #> │ └── a.md #> ├── learners #> │ └── setup.md #> ├── profiles #> │ └── b.md #> └── site #> ├── DESCRIPTION #> ├── README.md #> ├── _pkgdown.yaml #> └── built #> ├── a.md #> ├── b.md #> ├── config.yaml #> ├── fig #> │ └── intro-rendered-pyramid-1.png #> ├── index.md #> ├── intro.md #> ├── md5sum.txt #> └── setup.md links <- c( \"../episodes/fig/missing.png\", # does not exist \"../index.md\", # exists \"../instructors/a.md\", # exists \"../episodes/intro.Rmd\", # exists \"setup.md\", # exists \"intro.html\" # exists ) home <- fs::path(lesson_fragment(\"sandpaper-fragment\"), \"learners\") # show the resulting vector with our paths relative to the \"learners\" folder setNames(pb$test_file_existence(links, home), links) #> ../episodes/fig/missing.png ../index.md #> FALSE TRUE #> ../instructors/a.md ../episodes/intro.Rmd #> TRUE TRUE #> setup.md intro.html #> TRUE TRUE # Example: validation of links in a sandpaper context with children --------- # in this context, the references must be relative to the _parent_ file # for this example, the home folder is the parent of the child, which is # obtained from the `$build_parent` element in the child file. To demonstrate # this, I will first load the lesson context <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(context, jekyll = FALSE) fs::dir_tree(context) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child #> ├── config.yaml #> ├── episodes #> │ ├── files #> │ │ ├── cat.Rmd #> │ │ └── session.Rmd #> │ ├── intro.Rmd #> │ └── nope.md #> ├── index.md #> ├── instructors #> │ └── a.md #> ├── learners #> │ └── setup.md #> ├── profiles #> │ └── b.md #> └── site #> ├── DESCRIPTION #> ├── README.md #> ├── _pkgdown.yaml #> └── built #> ├── a.md #> ├── b.md #> ├── config.yaml #> ├── fig #> │ └── intro-rendered-pyramid-1.png #> ├── index.md #> ├── intro.md #> ├── md5sum.txt #> └── setup.md links <- c( \"../episodes/fig/missing.png\", # does not exist \"../index.md\", # exists \"../instructors/a.md\", # exists \"intro.Rmd\", # exists \"../learners/setup.md\", # does not exist \"intro.html\" # exists ) # in practice, we check that the episode has parents: lsn$episodes[[1]]$has_parents # episodes do not have parents #> [1] FALSE lsn$children[[2]]$has_parents # but children do! #> [1] TRUE # The \"home\" path in the context of a child document is the _build parent_, # which is the parent that will eventually contain the output of the child. # in the case of this lesson, both child files are used in the intro.Rmd, # even though `cat.Rmd` is the parent of `session.Rmd` setNames(lsn$get(\"parents\", \"children\"), fs::path_file(names(lsn$children))) #> $cat.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> #> $session.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> # They both show that `intro.Rmd` is the build parent setNames(lsn$get(\"build_parents\", \"children\"), fs::path_file(names(lsn$children))) #> $cat.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> #> $session.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> # show the links as if they existed in the `session.Rmd` file home <- lsn$children[[2]]$build_parents setNames(pb$test_file_existence(links, home), links) #> ../episodes/fig/missing.png ../index.md #> FALSE TRUE #> ../instructors/a.md intro.Rmd #> TRUE TRUE #> ../learners/setup.md intro.html #> TRUE TRUE # Example: validation of links in a Jekyll context -------------------------- fs::dir_tree(lesson_fragment()) #> /home/runner/work/_temp/Library/pegboard/lesson-fragment #> ├── _config.yml #> └── _episodes #> ├── 10-lunch.md #> ├── 12-for-loops.md #> ├── 14-looping-data-sets.md #> └── 17-scope.md links <- c( \"../non-existent.md\", # does not exist \"../_config.yml\", # exists \"../_episodes/10-lunch.md\", # exists \"10-lunch.html\" # exists in built site ) # set the home folder to be the \"_extras\" folder home <- fs::path(lesson_fragment(), \"_extras\") # show the resulting vector with our paths setNames(pb$test_file_existence(links, home), links) #> ../non-existent.md ../_config.yml ../_episodes/10-lunch.md #> FALSE TRUE TRUE #> 10-lunch.html #> TRUE"},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":null,"dir":"Reference","previous_headings":"","what":"Throw a validation report as a single message — throw_heading_warnings","title":"Throw a validation report as a single message — throw_heading_warnings","text":"Collapse variable number validation reports single message can formatted CLI GitHub.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Throw a validation report as a single message — throw_heading_warnings","text":"","code":"throw_heading_warnings(VAL) throw_div_warnings(VAL) throw_link_warnings(VAL)"},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Throw a validation report as a single message — throw_heading_warnings","text":"VAL [data.frame] validation report derived one validate functions.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Throw a validation report as a single message — throw_heading_warnings","text":"NULL, invisibly. used side-effect formatting issuing messages via issue_warning().","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Throw a validation report as a single message — throw_heading_warnings","text":"One key features pegboard ability parse validate markdown elements. functions provide standard way creating reports user based whether CLI GitHub. prerequisites functions input data frame (generated actual validation function) internal set known templating vectors contain templates test show actual error along general information can help correct error (see ).","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"input-data-frame","dir":"Reference","previous_headings":"","what":"Input Data Frame","title":"Throw a validation report as a single message — throw_heading_warnings","text":"validations initially reported data frame following properties: one row per element columns indicate parsed attributes element, source file, source position, actual element XML node object. boolean columns indicate tests element, used collect_labels() add \"labels\" column data.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"templating-vectors","dir":"Reference","previous_headings":"","what":"Templating vectors","title":"Throw a validation report as a single message — throw_heading_warnings","text":"vectors come two forms [thing]_tests [thing]_info (e.g. validate_links(), link_tests link_info). named vectors match boolean columns data frame produced validation function. [thing]_tests vector contains templates describes error shows text caused error. [thing]_info contains general information address particular error. example, one common link error link descriptive (e.g. link text says \"click \"). column VAL data frame contains result test called \"descriptive\", look values link info tests vectors: throw_*_warnings() functions detect errors, use info tests vectors construct composite message.","code":"link_info[\"descriptive\"] #> descriptive #> \"Avoid uninformative link phrases \" link_tests[\"descriptive\"] #> descriptive #> \"[uninformative link text]: [{text}]({orig})\""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"process","dir":"Reference","previous_headings":"","what":"Process","title":"Throw a validation report as a single message — throw_heading_warnings","text":"throw_*_warnings() functions basic procedure (indeed consolidated single function future) pass data collect_labels(), parse [thing]_tests templating vector label failing element VAL appropriate failure message gather source information failure pass failures [thing]_info elements matched unique failures issue_warning()","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert a given block quote to dovetail template — to_dovetail","title":"Convert a given block quote to dovetail template — to_dovetail","text":"dovetail package allows people write block quotes code blocks formatted roxygen2 syntax. internal function takes block quote element, elevates child elements, converts block quote code block uses custom xslt stylesheet render children block roxygen-formatted text code.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert a given block quote to dovetail template — to_dovetail","text":"","code":"to_dovetail(block, token = \"#'\")"},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert a given block quote to dovetail template — to_dovetail","text":"block block quote element token token use indicate markdown text code","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert a given block quote to dovetail template — to_dovetail","text":"block, converted code block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert a given block quote to dovetail template — to_dovetail","text":"","code":"if (FALSE) { # \\dontrun{ frg <- Lesson$new(lesson_fragment()) blo <- frg$episodes$`14-looping-data-sets.md`$get_blocks()[[2]] to_dovetail(blo) cat(xml2::xml_text(blo)) } # }"},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":null,"dir":"Reference","previous_headings":"","what":"Trim div fences from output — trim_fence","title":"Trim div fences from output — trim_fence","text":"Trim div fences output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Trim div fences from output — trim_fence","text":"","code":"trim_fence(nodes)"},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Trim div fences from output — trim_fence","text":"nodes xml_nodeset whose first last node div fences","code":""},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Trim div fences from output — trim_fence","text":"nodeset without div fences","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"Convert Jekyll-based lesson sandpaper-based lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"","code":"use_sandpaper(body, rmd = TRUE, yml = list(), path = NULL, known_paths = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"body xml body episode rmd TRUE, chunks converted RMarkdown chunks yml list derived _config.yml file defines site variables. path path source body. Defaults NULL. used conjunction known_paths known_paths character vector known paths lesson. used determine correct path files lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"Jekyll episode littered kramdown inline attribute tags liquid-formatted links. Converting sandpaper means following: links using liquid formatting (e.g. [text]({{ site.path }}/01-episode/) replaced relative counterparts ([text](01-episode.md). include statements links.md base_path.md removed image attributes kramdown : removed code blocks kramdown inline attribute tag converted commonmark via internal liquid_to_commonmark(). Lesson template-specific code removed setup chunk R Markdown files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate Callout Blocks for sandpaper episodes — validate_divs","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"Carpentries Workbench uses pandoc fenced divs create special blocks within lesson learners instructors provide breaks narrative flow focus specific tasks caveats. fenced divs look something like :","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"","code":"validate_divs(yrn) div_is_known(div_table) KNOWN_DIVS div_tests div_info"},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"object class character length 16. object class character length 1. object class character length 1.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"yrn tinkr::yarn Episode object. div_table data frame derived make_div_table()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"data frame following columns: div: type div label: label div line: line number div label is_known: logical value div known type (TRUE) (FALSE)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"Lessons created Carpentries Workbench expected following fenced divs: objectives (top) questions (top) keypoints (bottom) following fenced divs can occur lesson, required: prereq callout caution challenge solution (nested inside challenge) hint (nested inside challenge) discussion checklist testimonial tab (can contain text, images, code blocks) group-tab (can contain text, images, code blocks) div names produce structure resulting DOM, special visual styling.","code":"::: callout ### Hello! This is a callout block :::"},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate headings — validate_headings","title":"Validate headings — validate_headings","text":"validate following aspects headings:","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate headings — validate_headings","text":"","code":"validate_headings(headings, title = NULL, offset = 5L) heading_tests heading_info headings_first_heading_is_second_level(VAL) headings_greater_than_first_level(VAL) headings_are_sequential(VAL) headings_have_names(VAL) headings_are_unique(VAL)"},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate headings — validate_headings","text":"object class character length 5. object class character length 5.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate headings — validate_headings","text":"headings object xml_nodelist. title title document offset number lines offset position (equal size yaml header). VAL data frame contains results make_heading_table() logical columns match name test.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate headings — validate_headings","text":"list two elements: data frame contains results make_heading_table() logical columns test FALSE indicates failed test given heading. data frame can printed tree show_heading_tree()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Validate headings — validate_headings","text":"first heading starts level 2 (first_heading_is_second_level) greater level 1 (all_are_greater_than_first_level) increse sequentially (e.g. jumps 2 4) (all_are_sequential) names (all_have_names) unique hierarchy (all_are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Validate headings — validate_headings","text":"internal function implemented Episode Lesson classes.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Validate headings — validate_headings","text":"","code":"l <- Lesson$new(lesson_fragment()) e <- l$episodes[[3]] # Our headings validators run a series of tests on headings and return a data # frame with information about the headings along with the results of the # tests v <- pegboard:::validate_headings(e$headings, e$get_yaml()$title, length(e$yaml)) names(v) #> [1] \"results\" \"tree\" v$results #> heading level pos #> 1 Use a for loop to process files given a list of their names. 2 17 #> 2 Use glob.glob to find sets of files whose names match a pattern. 2 51 #> 3 Use glob and for to process batches of files. 2 84 #> 4 Determining Matches 2 110 #> 5 Solution 2 119 #> 6 Minimum File Size 2 125 #> 7 Solution 2 143 #> 8 Comparing Data 2 157 #> 9 Solution 2 162 #> 10 ZNK test links and images 3 187 #> node first_heading_is_second_level greater_than_first_level #> 1 2 3 4 5 6 7 8 9 10 are_sequential have_names are_unique #> 1 TRUE TRUE TRUE #> 2 TRUE TRUE TRUE #> 3 TRUE TRUE TRUE #> 4 TRUE TRUE TRUE #> 5 TRUE TRUE FALSE #> 6 TRUE TRUE TRUE #> 7 TRUE TRUE FALSE #> 8 TRUE TRUE TRUE #> 9 TRUE TRUE FALSE #> 10 TRUE TRUE TRUE v$results$path <- fs::path_rel(e$path, e$lesson) # The validator does not produce any warnings or messages, but this data # frame can be passed on to other functions that will throw them for us. We # have a function that will throw a warning/message for each heading that # fails the tests. These messages are controlled by `heading_tests` and # `heading_info`. pegboard:::heading_tests #> first_heading_is_second_level greater_than_first_level #> \"(must be level 2)\" \"(first level heading)\" #> are_sequential have_names #> \"(non-sequential heading jump)\" \"(no name)\" #> are_unique #> \"(duplicated)\" pegboard:::heading_info #> first_heading_is_second_level greater_than_first_level #> \"First heading must be level 2\" \"Level 1 headings are not allowed\" #> are_sequential have_names #> \"Headings must be sequential\" \"Headings must be named\" #> are_unique #> \"Headings must be unique\" pegboard:::throw_heading_warnings(v$results) #> ! There were errors in 3/10 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) # Because the headings are best understood in tree form we have a utility # that will print the heading tree with the associated errors: pegboard:::show_heading_tree(v$tree) #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ────────────────────────────────────────────────────────────────────────────────"},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate Links in a markdown document — validate_links","title":"Validate Links in a markdown document — validate_links","text":"function validate links throw error markdown documents. include links images respect robots.txt websites.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate Links in a markdown document — validate_links","text":"","code":"validate_links(yrn) allowed_uri_protocols link_known_protocol(VAL) link_enforce_https(VAL) link_all_reachable(VAL) link_img_alt_text(VAL) link_length(VAL) link_descriptive(VAL) link_source_list(lt) link_internal_anchor(VAL, source_list, headings, body) link_internal_file(VAL, source_list, root) link_internal_well_formed(VAL, source_list) link_tests link_info"},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate Links in a markdown document — validate_links","text":"allowed_uri_protocols character string length 23 link_tests character string length 9 containing templates use output validate_links() formatting. link_info character string length 9 gives information informative links additional context failures.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate Links in a markdown document — validate_links","text":"yrn tinkr::yarn Episode object. lt output make_link_table() source_list output link_source_list headings xml_nodeset headings body xml_document root root path folder containing file containing paths ultimate parent files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate Links in a markdown document — validate_links","text":"data frame parsed information xml2::url_parse() columns logical values indicating tests passed.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"link-validity","dir":"Reference","previous_headings":"","what":"Link Validity","title":"Validate Links in a markdown document — validate_links","text":"links must resolve specific location. exist, link invalid. moment, can local links.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"external-links","dir":"Reference","previous_headings":"","what":"External links","title":"Validate Links in a markdown document — validate_links","text":"links must start valid secure protocol. Allowed protocols taken allowed protocols Wordpress: http, https, ftp, ftps, mailto, news, irc, irc6, ircs, gopher, nntp, feed, telnet, mms, rtsp, sms, svn, tel, fax, xmpp, webcal, urn Misspellings unsupported protocols (e.g. javascript: bitcoin: flagged). addition, enforce use HTTPS HTTP.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"cross-lesson-links","dir":"Reference","previous_headings":"","what":"Cross-lesson links","title":"Validate Links in a markdown document — validate_links","text":"links protocol, resolve HTML version page correct capitalisation.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"anchors-aka-fragments-","dir":"Reference","previous_headings":"","what":"Anchors (aka fragments)","title":"Validate Links in a markdown document — validate_links","text":"Anchors located end URLs start # sign. used indicate section documenation span id.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"accessibility-a-y-","dir":"Reference","previous_headings":"","what":"Accessibility (a11y)","title":"Validate Links in a markdown document — validate_links","text":"Accessibillity ensures links accurate descriptive people slow connections use screen reader technology.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"alt-text-for-images-","dir":"Reference","previous_headings":"","what":"Alt-text (for images)","title":"Validate Links in a markdown document — validate_links","text":"images must associated alt-text. pandoc, acheived writing alt attribute curly braces image: ![image caption](link){alt='alt text'}: https://webaim.org/techniques/alttext/","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"descriptive-text","dir":"Reference","previous_headings":"","what":"Descriptive text","title":"Validate Links in a markdown document — validate_links","text":"links must descriptive text associated , beneficial screen readers scanning links page list full \"link\", \"link\", \"link\": https://webaim.org/techniques/hypertext/link_text#uninformative","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"text-length","dir":"Reference","previous_headings":"","what":"Text length","title":"Validate Links in a markdown document — validate_links","text":"Link text length must greater 1: https://webaim.org/techniques/hypertext/link_text#link_length","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Validate Links in a markdown document — validate_links","text":"moment, currently test links reachable. feature planned future. function internal. Please use methods Episode Lesson classes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Validate Links in a markdown document — validate_links","text":"","code":"l <- Lesson$new(lesson_fragment()) e <- l$episodes[[3]] # Our link validators run a series of tests on links and images and return a # data frame with information about the links (via xml2::url_parse), along # with the results of the tests v <- asNamespace('pegboard')$validate_links(e) names(v) #> [1] \"scheme\" \"server\" \"port\" #> [4] \"user\" \"path\" \"query\" #> [7] \"fragment\" \"orig\" \"text\" #> [10] \"alt\" \"title\" \"type\" #> [13] \"rel\" \"anchor\" \"sourcepos\" #> [16] \"filepath\" \"parents\" \"node\" #> [19] \"known_protocol\" \"enforce_https\" \"internal_anchor\" #> [22] \"internal_file\" \"internal_well_formed\" \"all_reachable\" #> [25] \"img_alt_text\" \"descriptive\" \"link_length\" v #> scheme server port user #> 1 https docs.python.org NA #> 2 https docs.python.org NA #> 3 https docs.python.org NA #> 4 https pandas.pydata.org NA #> 5 https docs.python.org NA #> 9 https carpentries.org NA #> 10 NA #> 6 40 #> 7 50 #> 11 https carpentries.org NA #> 12 NA #> 13 1348819536 #> 8 41 #> path query #> 1 /3/library/glob.html #> 2 /3/library/glob.html #> 3 /3/library/glob.html #> 4 /pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 /3/library/stdtypes.html #> 9 /assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 #> 7 #> 11 /assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 #> 8 #> fragment #> 1 glob.glob #> 2 #> 3 #> 4 #> 5 str.split #> 9 #> 10 #> 6 #> 7 #> 11 #> 12 #> 13 #> 8 #> orig #> 1 https://docs.python.org/3/library/glob.html#glob.glob #> 2 https://docs.python.org/3/library/glob.html #> 3 https://docs.python.org/3/library/glob.html #> 4 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 https://docs.python.org/3/library/stdtypes.html#str.split #> 9 https://carpentries.org/assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 {{ page.root }}/index.html #> 7 {{ site.swc_pages }}/shell-novice #> 11 https://carpentries.org/assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 {{ page.root }}/no-workie.svg #> 8 {{ page.root }}{% link index.md %} #> text alt title type #> 1 glob.glob link #> 2 glob link #> 3 glob link #> 4 shape method link #> 5 split link #> 9 books as clubs img #> 10 books as clubs img #> 6 Home link #> 7 shell link #> 11 Carpentries logo image #> 12 Non-working image image #> 13 Non-working image with jekyll syntax image #> 8 link that isn't parsed correctly by commonmark link #> rel anchor sourcepos filepath parents node #> 1 FALSE 51 _episodes/14-looping-data-sets.md 2 FALSE 57 _episodes/14-looping-data-sets.md 3 FALSE 58 _episodes/14-looping-data-sets.md 4 FALSE 140 _episodes/14-looping-data-sets.md 5 FALSE 163 _episodes/14-looping-data-sets.md 9 FALSE 189 _episodes/14-looping-data-sets.md 10 FALSE 191 _episodes/14-looping-data-sets.md 6 FALSE 193 _episodes/14-looping-data-sets.md 7 FALSE 193 _episodes/14-looping-data-sets.md 11 FALSE 195 _episodes/14-looping-data-sets.md 12 FALSE 197 _episodes/14-looping-data-sets.md 13 FALSE 199 _episodes/14-looping-data-sets.md 8 FALSE 201 _episodes/14-looping-data-sets.md known_protocol enforce_https internal_anchor internal_file #> 1 TRUE TRUE TRUE TRUE #> 2 TRUE TRUE TRUE TRUE #> 3 TRUE TRUE TRUE TRUE #> 4 TRUE TRUE TRUE TRUE #> 5 TRUE TRUE TRUE TRUE #> 9 TRUE TRUE TRUE TRUE #> 10 TRUE TRUE TRUE FALSE #> 6 TRUE TRUE TRUE TRUE #> 7 TRUE TRUE TRUE TRUE #> 11 TRUE TRUE TRUE TRUE #> 12 TRUE TRUE TRUE FALSE #> 13 TRUE TRUE TRUE TRUE #> 8 TRUE TRUE TRUE TRUE #> internal_well_formed all_reachable img_alt_text descriptive link_length #> 1 TRUE TRUE TRUE TRUE TRUE #> 2 TRUE TRUE TRUE TRUE TRUE #> 3 TRUE TRUE TRUE TRUE TRUE #> 4 TRUE TRUE TRUE TRUE TRUE #> 5 TRUE TRUE TRUE TRUE TRUE #> 9 TRUE TRUE TRUE TRUE TRUE #> 10 TRUE TRUE TRUE TRUE TRUE #> 6 TRUE TRUE TRUE TRUE TRUE #> 7 TRUE TRUE TRUE TRUE TRUE #> 11 TRUE TRUE FALSE TRUE TRUE #> 12 TRUE TRUE FALSE TRUE TRUE #> 13 TRUE TRUE FALSE TRUE TRUE #> 8 TRUE TRUE TRUE TRUE TRUE # URL protocols ----------------------------------------------------------- # To avoid potentially malicious situations, we have an explicit list of # allwed URI protocols, which can be found in the `allowed_uri_protocols` # character vector: asNamespace('pegboard')$allowed_uri_protocols #> [1] \"\" \"http\" \"https\" \"ftp\" \"ftps\" \"mailto\" \"news\" \"irc\" #> [9] \"irc6\" \"ircs\" \"gopher\" \"nntp\" \"feed\" \"telnet\" \"mms\" \"rtsp\" #> [17] \"sms\" \"svn\" \"tel\" \"fax\" \"xmpp\" \"webcal\" \"urn\" # note that we make an additional check for the http protocol. # Creating Warnings from the table ---------------------------------------- # The validator does not produce any warnings or messages, but this data # frame can be passed on to other functions that will throw them for us. We # have a function that will throw a warning/message for each link that # fails the tests. These messages are controlled by `link_tests` and # `link_info`. asNamespace('pegboard')$link_tests #> known_protocol #> \"[invalid protocol]: {scheme}\" #> enforce_https #> \"[needs HTTPS]: [{text}]({orig})\" #> internal_anchor #> \"[missing anchor]: [{text}]({orig})\" #> internal_file #> \"[missing file{format_parents(parents)}]: [{text}]({orig})\" #> internal_well_formed #> \"[incorrect formatting]: [{text}][{orig}] -> [{text}]({orig})\" #> all_reachable #> \"\" #> img_alt_text #> \"[image missing alt-text]: {orig}\" #> descriptive #> \"[uninformative link text]: [{text}]({orig})\" #> link_length #> \"[link text too short]: [{text}]({orig})\" asNamespace('pegboard')$link_info #> known_protocol #> \"Links must have a known URL protocol (e.g. https, ftp, mailto). See for a list of acceptable protocols.\" #> enforce_https #> \"Links must use HTTPS \" #> internal_anchor #> \"Some link anchors for relative links (e.g. [anchor]: link) are missing\" #> internal_file #> \"Some linked internal files do not exist \" #> internal_well_formed #> \"Some links were incorrectly formatted\" #> all_reachable #> \"\" #> img_alt_text #> \"Images need alt-text \" #> descriptive #> \"Avoid uninformative link phrases \" #> link_length #> \"Avoid single-letter or missing link text \" asNamespace('pegboard')$throw_link_warnings(v) #> ! There were errors in 4/13 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg"},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert xml to markdown — xml_to_md","title":"Convert xml to markdown — xml_to_md","text":"Convert xml markdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert xml to markdown — xml_to_md","text":"","code":"xml_to_md(body, stylesheet = \"xml2md_gfm_kramdown.xsl\", newlines = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert xml to markdown — xml_to_md","text":"body xml document stylesheet name stylesheet passed get_stylesheet newlines logical indicating newlines (aka softbreaks) inserted elements (defaults FALSE, meaning separator added elements).","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert xml to markdown — xml_to_md","text":"character vector length 1","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert xml to markdown — xml_to_md","text":"","code":"cha <- pegboard:::make_div(\"challenge\") sol <- pegboard:::make_div(\"solution\") xml2::xml_add_child(cha, xml2::xml_child(sol, 1), .where = 1) xml2::xml_add_child(cha, xml2::xml_child(sol, 2), .where = 2) cat(pegboard:::xml_to_md(cha)) #> :::::::::::::::::::::::::::::::::::::::: challenge #> #> :::::::::::::::: solution #> #> ::::::::::::::::::::::::: #> #> ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-7","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.7 (2024-11-11)","text":"Add support validation caution fenced divs (fixed: @froggleston #160)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-6","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.6 (2024-06-25)","text":"Hotfix {tinkr} upcoming bump 0.3.0 changes yarn$show() arguments: https://github.com/ropensci/tinkr/pull/108. (reported @froggleston https://github.com/carpentries/pegboard/issues/156, fixed: @froggleston, #157) Remove support checks Windows R 3.6","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-5","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.5 (2024-04-10)","text":"Add support tabbed content lessons (reported: @astroDimitrios, implemented: @astroDimitrios, @froggleston, https://github.com/carpentries/pegboard/pull/148https://github.com/carpentries/sandpaper/pull/571, https://github.com/carpentries/varnish/pull/121, ).","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-4","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.4 (2024-03-06)","text":"Hotfix R 4.3.3 bump results trailing commas glue function causing argument errors: https://github.com/tidyverse/glue/issues/320 (reported: @ns-rse, #149; fixed: @Bisaloo, #150). Required sandpaper CSS fix","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-7-3","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.7.3 (2023-11-22)","text":"New vignette(\"intro-lesson\", package = \"pegboard\") provides information working pegboard::Lesson objects. Documentation Episode Lesson objects updated bit descriptive point vignettes.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-3","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.3 (2023-11-22)","text":"Episode$unblock() method gains force argument allow method run even previously run.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-7-2","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.7.2 (2023-11-17)","text":"Snapshot update testthat 3.2.0","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-2","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.2 (2023-11-17)","text":"validate_links() now differentiates links images reporting (reported: @joelnitta, #143; fixed: @zkamvar, #144)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-7-2","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.7.2 (2023-11-17)","text":"Two vignettes added XML Episode class Documentation validation reporting added","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-071-2023-10-03","dir":"Changelog","previous_headings":"","what":"pegboard 0.7.1 (2023-10-03)","title":"pegboard 0.7.1 (2023-10-03)","text":"child chunk options fail context longer cause failure. (reported: @trhallam, https://github.com/carpentries/workbench/issues/74, #139; fixed: @zkamvar, #140)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-070-2023-10-02","dir":"Changelog","previous_headings":"","what":"pegboard 0.7.0 (2023-10-02)","title":"pegboard 0.7.0 (2023-10-02)","text":"release introduces automated processing {knitr} child files, enables automatically available validation processing.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.0 (2023-10-02)","text":"Episode class objects gain children, parents, build_parents fields contain known relationships files. children parents represent immediate relationships build_parents represent distant ancestor object trigger build. Note parents fields populated Episode context Lesson object. Lesson class objects gain children field list stores Episode objects derived child files. Episode objects gain $has_parents active binding reporting object parent object. used context Lesson. Episode Lesson objects gain $has_children active binding, reporting child episodes lesson episode. Lesson objects gain $trace_lineage() method return absolute paths child files source path given episode exist. make_link_table() now new column called parents contains list column parents () files checked $validate_links(), $validate_divs(), $validate_headings() now process child files default. Note $validate_links() report missing files relative build parents.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-7-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.7.0 (2023-10-02)","text":"$load_built() method now load built markdown content, just episodes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-6-1","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.6.1 (2023-09-06)","text":"$validate_divs() method now recognises spoiler class fenced divs allow optional/expandable items automatically shown learner (implemented: @tobyhodges, #134)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-6-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.6.0 (2023-08-29)","text":"Workshop overview pages now able processed Lesson objects. Jekyll- based lessons, directory name must end -workshop (standard workshop overview lessons without episodes), sandpaper- based lessons, config.yaml file must contain overview: true tag (reported: @zkamvar, #118; fixed: @zkamvar, #132, reviewed @klbarnes20). pages indicated $overview field Lesson object. lessons workshop overview lessons, nothing change.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-6-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.6.0 (2023-08-29)","text":"Lessons underwent incomplete conversion Jekyll sandpaper now appropriate error message provided.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.3 (2023-07-08)","text":"$validate_links() longer throws error HTML images embedded comments (reported: @beastyblacksmith, #130; fixed: @zkamvar, #131, reviewed @ErinBecker) (transition) $move_objectives() $move_questions() methods longer place blocks second element markdown. originally implemented thought {dovetail} solution lesson infrastructure (thus needed setup chunk blocks). (transition) liquid-formatted links markdown inside now parsed correctly. leads lessons accurately transitioned use {sandpaper} (reported: @uschille, https://github.com/carpentries/lesson-transition/issues/46; fixed: @zkamvar, #121) (transition) images kramdown attributes new line now accurately transitioned use {sandpaper} (reported: @uschille, https://github.com/carpentries/lesson-transition/issues/46; fixed: @zkamvar, #121)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-5-3","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.5.3 (2023-07-08)","text":"failing test due workbench transition fixed (reported: @zkamvar, #125; fixed: @zkamvar, #127)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-2","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.2 (2023-04-05)","text":"README file longer run validation generally part website often , creates distractions.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-1","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.1 (2023-03-31)","text":"Fenced divs attributes now properly parsed (@zkamvar, #115).","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-5-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.5.0 (2023-03-31)","text":"Lesson object validators now validate non-episode files (reported: @zkamvar #110; fixed: @zkamvar #113). $validate_links() now respect links anchors spans. validators longer truncate GitHub actions (reported: @zkamvar #111, fixed: @zkamvar: #114). validators provide full context invalid links (just link text, link text).","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-5-0","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.5.0 (2023-03-31)","text":"tinkr’s minimum version set 0.2.0 recognise release CRAN bring new bugfixes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-4-3","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.4.3 (2023-01-26)","text":"$validate_links() now checks URL protocol external link matches known list protocols. match (e.g. javascript: bitcoin:) flagged. (@zkamvar #109)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-4-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.4.3 (2023-01-26)","text":"bug attributes following image cause missing alt text reported fixed. (discovered: @dpshelio @karenword; reported: @zkamvar #106; fixed: @zkamvar #108). fix also makes alt text parsing validation robust bug unknown protocol recognised invalid fixed. (discovered: @ndporter; reported: @zkamvar, #107; fixed: @zkamvar, #109)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"internals-0-4-3","dir":"Changelog","previous_headings":"","what":"INTERNALS","title":"pegboard 0.4.3 (2023-01-26)","text":"New internal function find_between_nodes() get nodes two sibling nodes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-4-2","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.4.2 (2023-01-10)","text":"test depended upstream resource fixed. Tests modified account new case image fixing.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-4-2","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.4.2 (2023-01-10)","text":"Internal fix_links() function improved documentation.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-4-1","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.4.1 (2023-01-06)","text":"test dependend upstream resource fixed.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-4-0","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.4.0 (2023-01-06)","text":"{tinkr} minimum version upgraded 0.1.0.9000 address square bracket protection implemented version.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-4-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.4.0 (2023-01-06)","text":"Jekyll links spaces processed correctly. broken update {tinkr} (reported: @zkamvar, #100; fixed: @zkamvar, #102)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-4-0","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.4.0 (2023-01-06)","text":"GitHub workflows updated run weekly.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-3-2","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.3.2 (2022-09-14)","text":"Soft dependencty {cli} recommended 0.3.4 prevent reporting issues (see #97) Soft dependencies ggraph, ggplot2, tidygraph removed. dependencies needed producing now---date survey document","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-3-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.3.1 (2022-08-16)","text":"preparation {tinkr} 0.1.0, changes path default stylesheet, using tinkr::stylesheet() convenience function access .","code":""},{"path":[]},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"episode-class-objects-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Episode class objects","title":"pegboard 0.3.0 (2022-05-25)","text":"$summary() method can summarise counts elements episode. fixes $error $output active bindings new $warning active binding show code blocks warning class.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"lesson-class-objects-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Lesson class objects","title":"pegboard 0.3.0 (2022-05-25)","text":"new public field “built” contain XML representations markdown files built RMarkdown files sandpaper lessons. new public field “sandpaper” boolean indicates lesson can built sandpaper. new $load_built() method load built files exist sandpaper lesson. new $get() method get element Episode class object contained within. new $summary() method call $summary() method Episode class object.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"messages-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Messages","title":"pegboard 0.3.0 (2022-05-25)","text":"muffle_messages() internal function muffle messages originate {cli} {pegboard} packages. {cli} package available, messages class pbMessage, allow end users/package authors catch manipulate messages originate {pegboard}","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"transformation-0-2-7","dir":"Changelog","previous_headings":"","what":"TRANSFORMATION","title":"pegboard 0.2.7 (unreleased, no user-visible changes)","text":"make_pandoc_alt() (internal converter function) longer create alt text caption contains URL. messes downstream validation image links. fix_sandpaper_links() now also fixes links use {{ site.baseurl }}.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-6","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.6 (2022-05-11)","text":"internal function text_to_links() now processes unescaped ampersands internal function find_lesson_links() longer expects links strictly paragraph elements.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-2-5","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.2.5 (2022-05-10)","text":"validate_links() longer flag alt=\"\" errors. indicate decorative images. said, rare lessons, just case ’s needed. Source: https://webaim.org/techniques/alttext/#decorative","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-2-4","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.2.4 (2022-02-25)","text":"{fs} package needs >= 1.5.0 (#83, @sstevens2)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.3 (2022-02-23)","text":"footnotes trailing newline longer accidentally appended relative link anchors getOption('sandpaper.links') NULL.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-2-2","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.2.2 (2022-02-23)","text":"getOption(\"sandpaper.links\") NULL (context {sandpaper} lesson) valid file, appended file read via Episode$new()","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-2","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.2 (2022-02-23)","text":"$validate_links() longer throws warnings short uninformative text link anchors (@zkamvar, #81)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-2-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.2.1 (2022-02-18)","text":"inline messages link validation errors verbose (@tobyhodges, #79)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-2-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.2.0 (2022-02-17)","text":"validate_divs() validate divs Episode ones expect.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-1-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.1.1 (2022-02-02)","text":"Correct mis-attribution LICENSE","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-010-2022-02-01","dir":"Changelog","previous_headings":"","what":"pegboard 0.1.0 (2022-02-01)","title":"pegboard 0.1.0 (2022-02-01)","text":"soft release {pegboard} coincide first announcement Carpentries Workbench.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"imports-0-1-0","dir":"Changelog","previous_headings":"","what":"IMPORTS","title":"pegboard 0.1.0 (2022-02-01)","text":"{lifecycle} longer imported package. using , makes sense leave production.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-1-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.1.0 (2022-02-01)","text":"get_list_block() now select last block multiple “keypoints” blocks (@zkamvar, #75) get_list_block() now throw warning block contain list elements (@zkamvar, #74)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9034","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9034","text":"get_stylesheet() now escapes spaces normalizes windows path tinkr stylesheet embedding (@zkamvar, #72)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9033","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9033","text":"$move_*() methods longer create redundant heading fenced div (@zkamvar, #26)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-0-0-9033","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.0.0.9033","text":"pkgdown site updated complete. div family functions uses roxygen family tag complete.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9032","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9032","text":"$use_sandpaper() method Episode objects now remove “root” “layout” yaml directives (@zkamvar, #68)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9031","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9031","text":"Images attributes added now post-processed use_sandpaper() retain original attributes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9030","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9030","text":"replace relative_root_path nothing instead ., fixes bug introduced 0.0.0.9028.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9029","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9029","text":"fix jekyll-based lessons using base_path.html define relative_root_path now corrected longer include directives links.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9028","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9028","text":"fix jekyll-based lesson auto-detection RMD lessons error pure Rmd lessons","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9027","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9027","text":"Jekyll-based lessons now auto-detect read R Markdown content exists. rmd flag Lesson initializer now nothing.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9026","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9026","text":"now use _config.yml file parse site-specific liquid template links fix #60","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9025","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9025","text":"RMarkdown episodes setup chunk without specifying includes now considered valid setup chunks can chunks converted.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9024","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9024","text":"Episode$handout() create trimmed-R Markdown document challenge blocks code chunks purl = TRUE, can passed knitr::purl() processing R code handout. Lesson$handout() create concatenated version Episode$handout().","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-0-0-9023","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.0.0.9023","text":"validation messages revamped consistent across messages. validation methods Episode Lesson now return data frames contain detailed information element tests passed failed downstream analysis. Importantly, contain column called “node”, points exact XML node containing link/image/heading inspection/manipulation. validation reporting longer grouped error link validation information switched show error message problematic aspect/fix heading validation now works continuous integration functions longer rely dplyr installed","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9022","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9022","text":"Episode class now gains $confirm_sandpaper() method bypass assumption Episodes start kramdown-formatted documents attempt label divs episode (warning success). Lesson class now run $confirm_sandpaper() method markdown files jekyll = FALSE. Lesson$new() now default current working directory.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-0-0-9022","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.0.0.9022","text":"internal get_list_block() longer auto-label divs.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9021","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9021","text":"Link validation now checks general uninformative link text empty links (@zkamvar, #49) make_link_table() treat linebreaks link text space character.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9020","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9020","text":"Lesson class now $validate_links() $validate_headings() methods. (@zkamvar, #48)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009019","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9019","title":"pegboard 0.0.0.9019","text":"NOTE: (@zkamvar, #44)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9019","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9019","text":"Episode class now $links $images active bindings extracts links images (markdown HTML) document. make_link_table() creates table links parsed via xml2::url_parse() additional information caption alternative text (images). Episode class now $validate_links() method, validate links images common errors using https unresolved relative links. Episode$use_sandpaper() now converts images use alt text captions. Images ![alt](link) converted ![](link){alt='alt'} pandoc uses everything square brackets caption text. NOTE: now makes copy XML document.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fixes-0-0-0-9019","dir":"Changelog","previous_headings":"","what":"BUG FIXES","title":"pegboard 0.0.0.9019","text":"Episode$new() gains argument fix_liquid, fixes liquid variables relative links passed {tinkr} (https://github.com/carpentries/pegboard/issues/46) Post-processed links via fix_links() retains sourcepos attribute (fixed e5508cc9c9a3821381293bdac12647edfbc0608e). Episode$lesson longer assumes episode inside sub-folder (fixed 63432ef83ecc41a6aab53fe768e8eaec107278d5).","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009018","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9018","title":"pegboard 0.0.0.9018","text":"Episode$validate_headings() now properly displays duplicated headings. (@zkamvar, #45)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009017","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9017","title":"pegboard 0.0.0.9017","text":"Lesson class now respects order contents config.yaml (#42 via #43)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009016","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9016","title":"pegboard 0.0.0.9016","text":"Episode class now $headings active binding $validate_headings() method validate headings (#23 via #41) now use {testthat} 3e tests Cloning Episode object now reliable","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009015","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9015","title":"pegboard 0.0.0.9015","text":"Episode class now sub-class tinkr::yarn class gains show(), head(), tail(), protect_math() methods.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009014","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9014","title":"pegboard 0.0.0.9014","text":"Innocent block quotes sullied ruthless kramdown postfix operators kept block quotes instead failing $unblock() conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009013","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9013","title":"pegboard 0.0.0.9013","text":"omnipresent {% include links.md %} now removed sandpaper conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009012","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9012","title":"pegboard 0.0.0.9012","text":"Lesson class now work {sandpaper} (#24) new parameter jekyll Episode class gains new slot called extras handle sandpaper non-episodic things better error message thrown Episode$label_divs().","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009011","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9011","title":"pegboard 0.0.0.9011","text":"Swap {git2r} dependency {gert}, smoother interface matches dependencies {sandpaper}.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009010","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9010","title":"pegboard 0.0.0.9010","text":"Missing questions, objectives, keypoints longer fail cryptic error. informative warning thrown empty character vector returned. addresses issue {sandpaper}: https://github.com/carpentries/sandpaper/issues/79 URI pegboard tags now “http://carpentries.org/pegboard/”, fixes https://github.com/carpentries/pegboard/issues/18","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009009","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9009","title":"pegboard 0.0.0.9009","text":"Several Bug fixes, see https://github.com/carpentries/pegboard/pull/21 details. Travis hopefully banished","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009008","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9008","title":"pegboard 0.0.0.9008","text":"$label_divs() longer modifies fenced divs. @dtag labels attached html_block paragraph elements now replaced elements live within custom namespace called “pegboard”. allows us avoid manipulating document paragraph structure case fenced divs. $get_divs() now includes div tags/fences output. Internally, namespace handling gotten marginally better default namespace prefix modified md:. fenced divs longer manipulated labelling. new test expectation, expect_moved_yaml() tests yaml element successfully moved body document.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009007","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9007","title":"pegboard 0.0.0.9007","text":"$keypoints $objectives now available act like $questions $move_*() methods now add h2 header block $move_*() methods use pandoc syntax instead html div blocks. Internal changes creation elements longer relies complex namespace juggling","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009006","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9006","title":"pegboard 0.0.0.9006","text":"$label_divs() method now label div tags episode $move_* methods now auto-label div tags $questions field now returns questions block yaml header character vector.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009005","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9005","title":"pegboard 0.0.0.9005","text":"pandoc-style fenced divs now processed native div tags @dtag labels now format div-{n}-{class} {n} sequential number document {class} type div. labelling @dtags straightforward label tags sequentially.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009004","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9004","title":"pegboard 0.0.0.9004","text":"changes version largely enhancements handling div tags conversion. See #9 details $unblock() defaults converting div tags unless $use_sandpaper() called. $unblock() auto-name divs {class}-div-{number} $move_* functions now name html_blocks $get_divs() returns div tags named list $challenges now find either blocks, divs code, depending mutations $soltuions challenges (see ) $use_dovetail() warn user body empty $use_sandpaper() ","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009003","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9003","title":"pegboard 0.0.0.9003","text":"Jekyll-specific relative links now converted part use_sandpaper().","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-function-0-0-0-9003","dir":"Changelog","previous_headings":"","what":"NEW FUNCTION","title":"pegboard 0.0.0.9003","text":"fix_sandpaper_links() fix relative paths jekyll-specific links inside lessons yet otherwise converted.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009002","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9002","title":"pegboard 0.0.0.9002","text":"version introduces conversions work together can chained convert episode old Jekyll style new {sandpaper} style. Things still much development though. conversions sandpaper dovetail clearly separated Episode class understands conversions performed private logical vector tracks changes. pkgdown site now built automatically github actions","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-episode-methods-0-0-0-9002","dir":"Changelog","previous_headings":"","what":"NEW EPISODE METHODS","title":"pegboard 0.0.0.9002","text":"use_dovetail() inserts setup chunk top file use_sandpaper() converts chunks liquid/kramdown syntax commonmark RMD syntax move_*() generate dovetail block just plain div block depending whether use_dovetail() called. remove_output() says tin remove_error() removes error code blocks $output $error can now grab output error chunks converted via use_sandpaper()","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009001","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9001","title":"pegboard 0.0.0.9001","text":"Added NEWS.md file track changes package. Dependencies {yaml} {commonmark} now explicit Added methods Episode class move questions, objectives, keypoints YAML lesson body.","code":""}] +[{"path":[]},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"members, contributors, leaders pledge make participation community harassment-free experience everyone, regardless age, body size, visible invisible disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, religion, sexual identity orientation. pledge act interact ways contribute open, welcoming, diverse, inclusive, healthy community.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes positive environment community include: Demonstrating empathy kindness toward people respectful differing opinions, viewpoints, experiences Giving gracefully accepting constructive feedback Accepting responsibility apologizing affected mistakes, learning experience Focusing best just us individuals, overall community Examples unacceptable behavior include: use sexualized language imagery, sexual attention advances kind Trolling, insulting derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical email address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement-responsibilities","dir":"","previous_headings":"","what":"Enforcement Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Community leaders responsible clarifying enforcing standards acceptable behavior take appropriate fair corrective action response behavior deem inappropriate, threatening, offensive, harmful. Community leaders right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, communicate reasons moderation decisions appropriate.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within community spaces, also applies individual officially representing community public spaces. Examples representing community include using official e-mail address, posting via official social media account, acting appointed representative online offline event.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported community leaders responsible enforcement [INSERT CONTACT METHOD]. complaints reviewed investigated promptly fairly. community leaders obligated respect privacy security reporter incident.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"enforcement-guidelines","dir":"","previous_headings":"","what":"Enforcement Guidelines","title":"Contributor Covenant Code of Conduct","text":"Community leaders follow Community Impact Guidelines determining consequences action deem violation Code Conduct:","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_1-correction","dir":"","previous_headings":"Enforcement Guidelines","what":"1. Correction","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Use inappropriate language behavior deemed unprofessional unwelcome community. Consequence: private, written warning community leaders, providing clarity around nature violation explanation behavior inappropriate. public apology may requested.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_2-warning","dir":"","previous_headings":"Enforcement Guidelines","what":"2. Warning","title":"Contributor Covenant Code of Conduct","text":"Community Impact: violation single incident series actions. Consequence: warning consequences continued behavior. interaction people involved, including unsolicited interaction enforcing Code Conduct, specified period time. includes avoiding interactions community spaces well external channels like social media. Violating terms may lead temporary permanent ban.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_3-temporary-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"3. Temporary Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: serious violation community standards, including sustained inappropriate behavior. Consequence: temporary ban sort interaction public communication community specified period time. public private interaction people involved, including unsolicited interaction enforcing Code Conduct, allowed period. Violating terms may lead permanent ban.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"id_4-permanent-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"4. Permanent Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Demonstrating pattern violation community standards, including sustained inappropriate behavior, harassment individual, aggression toward disparagement classes individuals. Consequence: permanent ban sort public interaction within community.","code":""},{"path":"https://carpentries.github.io/pegboard/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 2.0, available https://www.contributor-covenant.org/version/2/0/ code_of_conduct.html. Community Impact Guidelines inspired Mozilla’s code conduct enforcement ladder. answers common questions code conduct, see FAQ https://www.contributor-covenant.org/faq. Translations available https:// www.contributor-covenant.org/translations.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":null,"dir":"","previous_headings":"","what":"Contributing to pegboard","title":"Contributing to pegboard","text":"outlines propose change pegboard. detailed info contributing , tidyverse packages, please see development contributing guide.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"fixing-typos","dir":"","previous_headings":"","what":"Fixing typos","title":"Contributing to pegboard","text":"can fix typos, spelling mistakes, grammatical errors documentation directly using GitHub web interface, long changes made source file. generally means ’ll need edit roxygen2 comments .R, .Rd file. can find .R file generates .Rd reading comment first line.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"bigger-changes","dir":"","previous_headings":"","what":"Bigger changes","title":"Contributing to pegboard","text":"want make bigger change, ’s good idea first file issue make sure someone team agrees ’s needed. ’ve found bug, please file issue illustrates bug minimal reprex (also help write unit test, needed).","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"pull-request-process","dir":"","previous_headings":"Bigger changes","what":"Pull request process","title":"Contributing to pegboard","text":"Fork package clone onto computer. haven’t done , recommend using usethis::create_from_github(\"\", fork = TRUE). Install development dependences devtools::install_dev_deps(), make sure package passes R CMD check running devtools::check(). R CMD check doesn’t pass cleanly, ’s good idea ask help continuing. Create Git branch pull request (PR). recommend using usethis::pr_init(\"brief-description--change\"). Make changes, commit git, create PR running usethis::pr_push(), following prompts browser. title PR briefly describe change. body PR contain Fixes #issue-number. user-facing changes, add bullet top NEWS.md (.e. just first header). Follow style described https://style.tidyverse.org/news.html.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"code-style","dir":"","previous_headings":"Bigger changes","what":"Code style","title":"Contributing to pegboard","text":"New code follow tidyverse style guide. can use styler package apply styles, please don’t restyle code nothing PR. use roxygen2, Markdown syntax, documentation. use testthat unit tests. Contributions test cases included easier accept.","code":""},{"path":"https://carpentries.github.io/pegboard/CONTRIBUTING.html","id":"code-of-conduct","dir":"","previous_headings":"","what":"Code of Conduct","title":"Contributing to pegboard","text":"Please note pegboard project released Contributor Code Conduct. contributing project agree abide terms.","code":""},{"path":"https://carpentries.github.io/pegboard/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2020 Carpentries Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":null,"dir":"","previous_headings":"","what":"Getting help with pegboard","title":"Getting help with pegboard","text":"Thanks using pegboard! filing issue, places explore pieces put together make process smooth possible.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"make-a-reprex","dir":"","previous_headings":"","what":"Make a reprex","title":"Getting help with pegboard","text":"Start making minimal reproducible example using reprex package. haven’t heard used reprex , ’re treat! Seriously, reprex make R-question-asking endeavors easier (pretty insane ROI five ten minutes ’ll take learn ’s ). additional reprex pointers, check Get help! section tidyverse site.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"where-to-ask","dir":"","previous_headings":"","what":"Where to ask?","title":"Getting help with pegboard","text":"Armed reprex, next step figure ask. ’s question: start community.rstudio.com, /StackOverflow. people answer questions. ’s bug: ’re right place, file issue. ’re sure: let community help figure ! problem bug feature request, can easily return report . opening new issue, sure search issues pull requests make sure bug hasn’t reported /already fixed development version. default, search pre-populated :issue :open. can edit qualifiers (e.g. :pr, :closed) needed. example, ’d simply remove :open search issues repo, open closed.","code":""},{"path":"https://carpentries.github.io/pegboard/SUPPORT.html","id":"what-happens-next","dir":"","previous_headings":"","what":"What happens next?","title":"Getting help with pegboard","text":"efficient possible, development tidyverse packages tends bursty, shouldn’t worry don’t get immediate response. Typically don’t look repo sufficient quantity issues accumulates, ’s burst intense activity focus efforts. makes development efficient avoids expensive context switching problems, cost taking longer get back . process makes good reprex particularly important might multiple months initial report start working . can’t reproduce bug, can’t fix !","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Introduction to the Episode Object","text":"{pegboard} package facilitates analysis manipulation Markdown R Markdown files translating XML back . extends {tinkr} package (see vignette(\"tinkr\", package = \"tinkr\")) providing additional methods specific Carpentries-style lessons. two R6 classes defined {pegboard}: pegboard::Episode objects contain XML data, YAML metadata extra fields define child parent files particular episode. inherit tinkr::yarn R6 class. pegboard::Lesson objects contain lists Episode objects categorised “episodes”, “extra”, “children”. vignette discussing structure Episode objects, query contents {xml2} package, use methods active bindings get information , extract, manipulate anything inside Markdown R Markdown document.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"reading-markdown-content","dir":"Articles","previous_headings":"","what":"Reading Markdown Content","title":"Introduction to the Episode Object","text":"Episode object starts Markdown file. particular {pegboard}, assume Markdown file written using Pandoc syntax (superset CommonMark). can markdown file, us explore Episode object offer us, let’s take example R Markdown file present fragment Carpentries Workbench lesson package. using {xml2} package explore object {fs} package help constructing file paths. lesson fragment looks like. fragment ’s main purpose used examples tests, contains basic structure lesson want. can retrieve lesson_fragment() function, loads example data pegboard. take lesson fragment read first episode initialization method, Episode$new(), followed $confirm_sandpaper(), confirmation episode created work {sandpaper}, user interface build engine Carpentries Workbench (information non-workbench content, see section Jekyll Lesson Markdown Content) $protect_math() prevent special characters LaTeX math escaped. print Episode object, ’m going get long list methods, fields active bindings (functions act like fields) printed: actual XML content $body field. contains data markdown document, XML form. want see contents look like, can use $show(), $head(), $tail() methods (note: $show() method print entire markdown document).","code":"library(\"pegboard\") library(\"xml2\") library(\"fs\") ## /home/runner/work/_temp/Library/pegboard/sandpaper-fragment ## ├── config.yaml ## ├── episodes ## │ ├── intro.Rmd ## │ └── nope.md ## ├── index.md ## ├── instructors ## │ └── a.md ## ├── learners ## │ └── setup.md ## ├── profiles ## │ └── b.md ## └── site ## └── README.md lsn <- lesson_fragment(\"sandpaper-fragment\") # Read in the intro.Rmd document as an `Episode` object intro_path <- path(lsn, \"episodes\", \"intro.Rmd\") intro <- Episode$new(intro_path)$confirm_sandpaper()$protect_math() intro ## ## Inherits from: ## Public: ## add_md: function (md, where = 0L) ## body: xml_document, xml_node ## build_parents: ## challenges: active binding ## children: ## clone: function (deep = FALSE) ## code: active binding ## confirm_sandpaper: function () ## error: active binding ## get_blocks: function (type = NULL, level = 1L) ## get_challenge_graph: function (recurse = TRUE) ## get_divs: function (type = NULL, include = FALSE) ## get_images: function (process = FALSE) ## get_protected: function (type = NULL) ## get_yaml: function () ## handout: function (path = NULL, solutions = FALSE) ## has_children: active binding ## has_parents: active binding ## head: function (n = 6L) ## headings: active binding ## images: active binding ## initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, ## isolate_blocks: function () ## keypoints: active binding ## label_divs: function () ## lesson: active binding ## links: active binding ## md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) ## move_keypoints: function () ## move_objectives: function () ## move_questions: function () ## name: active binding ## ns: http://commonmark.org/xml/1.0 ## objectives: active binding ## output: active binding ## parents: ## path: /home/runner/work/_temp/Library/pegboard/sandpaper-fragm ... ## protect_curly: function () ## protect_math: function () ## protect_unescaped: function () ## questions: active binding ## remove_error: function () ## remove_output: function () ## reset: function () ## show: function (n = TRUE) ## show_problems: active binding ## solutions: active binding ## summary: function () ## tags: active binding ## tail: function (n = 6L) ## unblock: function (token = \"#'\", force = FALSE) ## use_dovetail: function () ## use_sandpaper: function (rmd = FALSE, yml = list()) ## validate_divs: function (warn = TRUE) ## validate_headings: function (verbose = TRUE, warn = TRUE) ## validate_links: function (warn = TRUE) ## warning: active binding ## write: function (path = NULL, format = \"md\", edit = FALSE) ## yaml: --- title: \"Using RMarkdown\" teaching: 10 exercises: 2 --- ## Private: ## clear_yaml_item: function (what) ## deep_clone: function (name, value) ## encoding: UTF-8 ## md_lines: function (path = NULL, stylesheet = NULL) ## mutations: TRUE FALSE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE ## problems: list ## record_problem: function (x) ## sourcepos: TRUE intro$body ## {xml_document} ## ## [1] ## [2] \\n \\n \\n ## [6] ## [7] \\n \\n \\n ## [11] \\n \\n \\n ## [16] \\n \\n \\n ## ... intro$head(10) ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? intro$tail(10) ## Cool, right? ## ## ::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use `.Rmd` files for lessons even if you don't need to generate any code ## - Run `sandpaper::check_lesson()` to identify any issues with your lesson ## - Run `sandpaper::build_lesson()` to preview your lesson locally ## ## :::::::::::::::::::::::::::::::::::::::::::::::: intro$show() ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## This is the new Carpentries template. It is written in [RMarkdown][r-markdown], ## which is a variant of Markdown that allows you to render code inside the ## lesson. Please refer to the [lesson ## example](https://carpentries.github.io/lesson-example) for full documentation. ## ## What you need to know is that there are three block quotes required for a valid ## Carpentries lesson template: ## ## 1. `questions` are displayed at the beginning of the episode to prime the ## learner for the content. ## 2. `objectives` are the learning objectives for an episode displayed with ## the questions. ## 3. `keypoints` are displayed at the end of the episode to reinforce the ## objectives. ## ## ::::::::::::::::::::::::::::::::::::: challenge ## ## ## Challenge 1: Can you do it? ## ## What is the output of this command? ## ## ```{r, eval=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ``` ## ## :::::::::::::::::::::::: solution ## ## ## Output ## ## ```{r, echo=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ``` ## ## :::::::::::::::::::::::::::::::::: ## ## ## Challenge 2: how do you nest solutions within challenge blocks? ## ## :::::::::::::::::::::::: solution ## ## You can add a line with at least three colons and a `solution` tag. ## ## ::::::::::::::::::::::::::::::::: ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Figures ## ## You can also include figures: ## ## ```{r pyramid} ## pie( ## c(Sky = 78, \"Sunny side of pyramid\" = 17, \"Shady side of pyramid\" = 5), ## init.angle = 315, ## col = c(\"deepskyblue\", \"yellow\", \"yellow3\"), ## border = FALSE ## ) ## ``` ## ## ## Math ## ## One of our episodes contains $\\LaTeX$ equations when describing how to create ## dynamic reports with {knitr}, so we now use mathjax to describe this: ## ## `$\\alpha = \\dfrac{1}{(1 - \\beta)^2}$` becomes: $\\alpha = \\dfrac{1}{(1 - \\beta)^2}$ ## ## Cool, right? ## ## ::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use `.Rmd` files for lessons even if you don't need to generate any code ## - Run `sandpaper::check_lesson()` to identify any issues with your lesson ## - Run `sandpaper::build_lesson()` to preview your lesson locally ## ## ::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"file-information","dir":"Articles","previous_headings":"","what":"File information","title":"Introduction to the Episode Object","text":"information file relationship files, can use following active bindings, useful working Episodes lesson context.","code":"intro$path ## /home/runner/work/_temp/Library/pegboard/sandpaper-fragment/episodes/intro.Rmd intro$name ## [1] \"intro.Rmd\" intro$lesson ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" # NOTE: relationships to other episodes are automatically handled in the # Lesson context intro$has_parents ## [1] FALSE intro$has_children ## [1] FALSE intro$children # separate documents processed as if they were part of this document ## character(0) intro$parents # the immediate documents that would require this document to build ## character(0) intro$build_parents # the final documents that would require this document to build ## character(0)"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"accessing-markdown-elements","dir":"Articles","previous_headings":"","what":"Accessing Markdown Elements","title":"Introduction to the Episode Object","text":"Episode object centered around $body item, contains XML representation document. possible find markdown elements XPath statments: However, useful elements want know , implemented active bindings methods: Much summarized $summary() method:","code":"xml2::xml_find_all(intro$body, \".//md:link\", ns = intro$ns) ## {xml_nodeset (1)} ## [1] ## [1] \\n \\n ... ## [2] \\n \\n ... ## [3] \\n \\n < ... # headings where level 2 headings are equivalent to sections intro$headings ## {xml_nodeset (6)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ` tags ## {xml_nodeset (0)} intro$links ## {xml_nodeset (1)} ## [1] ls -larth /path/to/folder <\/code_block> There is a code chunk here that will produce a plot, but not show the code: ```{r chunky, echo=FALSE, fig.alt=\"a plot of y = mx + b for m = 1 and b = 0\"} plot(1:10, type = \"l\") ``` plot(1:10, type = \"l\") <\/code_block>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"manipulation","dir":"Articles","previous_headings":"","what":"Manipulation","title":"Introduction to the Episode Object","text":"everything centers around $body element extracted {xml2}, ’s possible manipulate elements document. One thing possible can add new content document using $add_md() method, add markdown element paragraph document. example, can add information pegboard new code block first heading: can also manipulate existing elements. example, let’s say wanted make sure R code chunks named. can querying manipulating code blocks: can see chunks now names, proof rendering:","code":"intro$head(26) # first 26 lines ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## This is the new Carpentries template. It is written in [RMarkdown][r-markdown], ## which is a variant of Markdown that allows you to render code inside the ## lesson. Please refer to the [lesson ## example](https://carpentries.github.io/lesson-example) for full documentation. intro$body # first heading is item 11 ## {xml_document} ## ## [1] ## [2] \\n \\n \\n ## [6] ## [7] \\n \\n \\n ## [11] \\n \\n \\n ## [16] \\n \\n \\n ## ... cb <- c(\"You can clone the **{pegboard} package**: ```sh git clone https://github.com/carpentries/pegboard.git ``` \") intro$add_md(cb, where = 11) intro$head(26) # code block has been added ## --- ## title: \"Using RMarkdown\" ## teaching: 10 ## exercises: 2 ## --- ## ## :::::::::::::::::::::::::::::::::::::: questions ## ## - How do you write a lesson using RMarkdown and `{sandpaper}`? ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ::::::::::::::::::::::::::::::::::::: objectives ## ## - Explain how to use markdown with the new lesson template ## - Demonstrate how to include pieces of code, figures, and nested challenge blocks ## ## :::::::::::::::::::::::::::::::::::::::::::::::: ## ## ## Introduction ## ## You can clone the **{pegboard} package**: ## ## ```sh ## git clone https://github.com/carpentries/pegboard.git ## ``` intro$code ## {xml_nodeset (4)} ## [1] git clone https://gith ... ## [2] git clone https://gith ... ## [2] git clone https://gith ... ## [2] } replaced class definitions key/value pairs. always appear relevant block lead code blocks looked like : Moreover, achieve special callout blocks, used blockquotes given special classes (accessbility -blocks semantic HTML) nesting block quotes looked like : One biggest challenges authors , unless used editor like vim emacs, difficult write prefixed blockquote characters keeping track IALs belonged block.","code":"~~~ ls -larth /path/to/dir ~~~ {: .language-bash} > ## Challenge > > How do you list all files in a directory in reverse order by the time it was > last updated? > > > ## Solution > > > > ~~~ > > ls -larth /path/to/dir > > ~~~ > > {: .language-bash} > {: .solution} {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"special-methods-and-active-bindings","dir":"Articles","previous_headings":"Jekyll Lesson Markdown Content","what":"Special methods and active bindings","title":"Introduction to the Episode Object","text":"Episodes written Jekyll syntax special functions active bindings allow analyzed transformed Workbench episodes. example lesson fragment: Notice questions, objectives, keypoints yaml frontmatter. accessor returns list instead node, compatibility Jekyll lessons: Even though challenges formatted differently, accessors still return correctly: can also get block quotes using $get_blocks() method. NOTE: extract block quotes (including ktag attributes. One things advantageous blockquotes analyze pathway blockquotes figure comonly written lesson. $get_challenge_graph() creates data frame describes relationships: might notice attribute called ktag. Jekyll-formatted episode read , IAL tags processed placed attribute called ktag (kramdown tag), accessible via $tags active binding. needed commonmark know process postfix tags important translation commonmark syntax:","code":"library(\"pegboard\") library(\"xml2\") library(\"fs\") lf <- lesson_fragment() ep <- Episode$new(path(lf, \"_episodes\", \"14-looping-data-sets.md\")) # show relevant sections of head and tail ep$head(29) ## --- ## title: \"Looping Over Data Sets\" ## teaching: 5 ## exercises: 10 ## questions: ## - \"How can I process many data sets with a single command?\" ## objectives: ## - \"Be able to read and write globbing expressions that match sets of files.\" ## - \"Use glob to create lists of files.\" ## - \"Write for loops to perform operations on files given their names in a list.\" ## keypoints: ## - \"Use a `for` loop to process files given a list of their names.\" ## - \"Use `glob.glob` to find sets of files whose names match a pattern.\" ## - \"Use `glob` and `for` to process batches of files.\" ## --- ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ## ## ``` ## import pandas as pd ## for filename in ['data/gapminder_gdp_africa.csv', 'data/gapminder_gdp_asia.csv']: ## data = pd.read_csv(filename, index_col='country') ## print(filename, data.min()) ## ``` ## {: .language-python} ep$tail(53) ## ## > ## Comparing Data ## > ## > Write a program that reads in the regional data sets ## > and plots the average GDP per capita for each region over time ## > in a single chart. ## > ## > > ## Solution ## > > ## > > This solution builds a useful legend by using the string [`split`](https://docs.python.org/3/library/stdtypes.html#str.split) method to ## > > extract the `region` from the path 'data/gapminder\\_gdp\\_a\\_specific\\_region.csv'. The [`pathlib module`] ## > > also provides useful abstractions for file and path manipulation like returning the name of a file ## > > without the file extension. ## > > ## > > ``` ## > > import glob ## > > import pandas as pd ## > > import matplotlib.pyplot as plt ## > > fig, ax = plt.subplots(1,1) ## > > for filename in glob.glob('data/gapminder_gdp*.csv'): ## > > dataframe = pd.read_csv(filename) ## > > # extract from the filename, expected to be in the format 'data/gapminder_gdp_.csv'. ## > > # we will split the string using the split method and `_` as our separator, ## > > # retrieve the last string in the list that split returns (`.csv`), ## > > # and then remove the `.csv` extension from that string. ## > > region = filename.split('_')[-1][:-4] ## > > dataframe.mean().plot(ax=ax, label=region) ## > > plt.legend() ## > > plt.show() ## > > ``` ## > > {: .language-python} ## > {: .solution} ## {: .challenge} ## ## ### ZNK test links and images ## ## \"books ## ## \"books ## ## Link to [Home]({{ page.root }}/index.html) and to [shell]({{ site.swc_pages }}/shell-novice) ## ## ![Carpentries logo](https://carpentries.org/assets/img/TheCarpentries.svg) ## ## ![Non-working image](../no-workie.svg) ## ## ![Non-working image with jekyll syntax]({{ page.root }}/no-workie.svg) ## ## This text includes a [link that isn't parsed correctly by commonmark]({{ page.root }}{% link index.md %}) ## . The rest of the text should be properly parsed. ## ## {% include links.md %} ep$questions ## [1] \"How can I process many data sets with a single command?\" ep$objectives ## [1] \"Be able to read and write globbing expressions that match sets of files.\" ## [2] \"Use glob to create lists of files.\" ## [3] \"Write for loops to perform operations on files given their names in a list.\" ep$keypoints ## [1] \"Use a `for` loop to process files given a list of their names.\" ## [2] \"Use `glob.glob` to find sets of files whose names match a pattern.\" ## [3] \"Use `glob` and `for` to process batches of files.\" ep$challenges ## {xml_nodeset (3)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n from the filename, expected to be in the format 'data/gapminder_gdp_.csv'. ## # we will split the string using the split method and `_` as our separator, ## # retrieve the last string in the list that split returns (`.csv`), ## # and then remove the `.csv` extension from that string. ## region = filename.split('_')[-1][:-4] ## dataframe.mean().plot(ax=ax, label=region) ## plt.legend() ## plt.show() ## ``` ## ## ::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## ### ZNK test links and images ## ## \"books ## ## \"books ## ## Link to [Home](index.html) and to [shell](https://swcarpentry.github.io/shell-novice) ## ## ![](https://carpentries.org/assets/img/TheCarpentries.svg){alt='Carpentries logo'} ## ## ![](no-workie.svg){alt='Non-working image'} ## ## ![](no-workie.svg){alt='Non-working image with jekyll syntax'} ## ## This text includes a [link that isn't parsed correctly by commonmark](index.md) ## . The rest of the text should be properly parsed. ## ## ## ## :::::::::::::::::::::::::::::::::::::::: keypoints ## ## - Use a `for` loop to process files given a list of their names. ## - Use `glob.glob` to find sets of files whose names match a pattern. ## - Use `glob` and `for` to process batches of files. ## ## ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/articles/intro-episode.html","id":"transformation-tip","dir":"Articles","previous_headings":"Jekyll Lesson Markdown Content > Transformation","what":"Transformation tip!","title":"Introduction to the Episode Object","text":"times lesson authors forget tag block quote correct type tag make callout block. case, block quote remain unconverted lesson. example let’s say block quote top lesson defined prerequisites, author accidentally new line blockquote IAL tag, meaning blockquote processed: Notice block quote picked blockquote, special block quote. set ktag attribute block quote “{: .prereq}”, recognised special blockquote, can translated. Now can convert block fenced div $unblock()","code":"# add a prerequisite block after the questions and objectives untranslated_block <- \" > ## Barnaby > > - a barn > - a bee > {: .prereq} \" ep$add_md(untranslated_block, where = 10) ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## ## {: .prereq} ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ep$get_blocks(\".prereq\") ## {xml_nodeset (0)} ep$get_blocks() ## {xml_nodeset (1)} ## [1] \\n \\n Barn ... # remove the orphan prereq tag: orphan_tag <- xml2::xml_find_all(ep$body, \".//md:paragraph[md:text[contains(text(),'.prereq}')]]\", ns = ep$ns) xml2::xml_remove(orphan_tag) ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ## ## ```python # set the attribute of the block quote: xml2::xml_set_attr(ep$get_blocks(), \"ktag\", \"{: .prereq}\") ep$head(31) ## --- ## title: Looping Over Data Sets ## teaching: 5 ## exercises: 10 ## --- ## ## ::::::::::::::::::::::::::::::::::::::: objectives ## ## - Be able to read and write globbing expressions that match sets of files. ## - Use glob to create lists of files. ## - Write for loops to perform operations on files given their names in a list. ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## :::::::::::::::::::::::::::::::::::::::: questions ## ## - How can I process many data sets with a single command? ## ## :::::::::::::::::::::::::::::::::::::::::::::::::: ## ## > ## Barnaby ## > ## > - a barn ## > - a bee ## {: .prereq} ## ## ## Use a `for` loop to process files given a list of their names. ## ## - A filename is a character string. ## - And lists can contain character strings. ep$get_blocks(\".prereq\") ## {xml_nodeset (1)} ## [1] \\n \\n A Brief Word About History and Jekyll","what":"Folder Structure","title":"Introduction to the Lesson Object","text":"folder structure lessons built Jekyll one content tooling lived side--side. folder structure looked something like : {pegboard} first written, initially assumed folder structure, R Markdown regular Markdown episodes lived different folders (often , outputs R Markdown files lived inside _episodes/ folder. main method organising episodes numbers embedded name files. Workbench developed, clear folder structure needed change, needed keep compatibility old lessons want ensure people can independently convert old style lessons new style, thus added jekyll parameter Lesson object initializer method, set jekyll = TRUE default keep backwards compatibility.","code":"# . # ├── Gemfile # ├── Makefile # ├── _config.yml # ├── _episodes/ # │ └── 01-intro.md # ├── _episodes_rmd/ # ├── _extras/ # │ ├── a.md # │ └── b.md # ├── _includes/ # ├── _layouts/ # ├── aio.md # ├── assets/ # ├── bin/ # ├── fig/ # ├── index.md # ├── reference.md # ├── requirements.txt # └── setup.md"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"creating-a-new-lesson-object","dir":"Articles","previous_headings":"","what":"Creating a New Lesson Object","title":"Introduction to the Lesson Object","text":"Lesson object invoked Lesson$new(), method. , demonstrate Workbench lesson. folder structure workbench lesson: read , Workbench lesson, need specify jekyll = FALSE register div tags ensure lesson treated like Workbench lesson. Lesson printing shows subset methods named similarly methods active bindings Episode class. inherited, rather implemented across Episode objects. Episode objects parsed one three elements: “episodes”, “children”, “extra” (NOTE: “extra” slot may superceded elements better match folder structure lessons). Notice one episode $episodes item, directory tree , see two. config.yaml file, defines order episodes: episodes/nope.Rmd listed, read . useful avoid reading content files incomplete correctly formatted.","code":"# . # ├── config.yaml # ├── episodes # │ ├── intro.Rmd # │ └── nope.md # ├── index.md # ├── instructors # │ └── a.md # ├── learners # │ └── setup.md # ├── profiles # │ └── b.md # └── site # └── README.md library(\"pegboard\") library(\"glue\") library(\"yaml\") library(\"xml2\") library(\"fs\") wbfragment <- lesson_fragment(\"sandpaper-fragment\") print(wbfragment) # path to the lesson ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" wb_lesson <- Lesson$new(wbfragment, jekyll = FALSE) print(wb_lesson) ## ## Public: ## blocks: function (type = NULL, level = 0, path = FALSE) ## built: NULL ## challenges: function (path = FALSE, graph = FALSE, recurse = TRUE) ## children: NULL ## clone: function (deep = FALSE) ## episodes: list ## extra: list ## files: active binding ## get: function (element = NULL, collection = \"episodes\") ## handout: function (path = NULL, solution = FALSE) ## has_children: active binding ## initialize: function (path = \".\", rmd = FALSE, jekyll = TRUE, ...) ## isolate_blocks: function () ## load_built: function () ## n_problems: active binding ## overview: FALSE ## path: /home/runner/work/_temp/Library/pegboard/sandpaper-fragment ## reset: function () ## rmd: FALSE ## sandpaper: TRUE ## show_problems: active binding ## solutions: function (path = FALSE) ## summary: function (collection = \"episodes\") ## thin: function (verbose = TRUE) ## trace_lineage: function (episode_path) ## validate_divs: function () ## validate_headings: function (verbose = TRUE) ## validate_links: function () ## Private: ## deep_clone: function (name, value) lapply(wb_lesson$episodes, class) ## $intro.Rmd ## [1] \"Episode\" \"yarn\" \"R6\" lapply(wb_lesson$children, class) ## list() lapply(wb_lesson$extra, class) ## $index.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $a.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $setup.md ## [1] \"Episode\" \"yarn\" \"R6\" ## ## $b.md ## [1] \"Episode\" \"yarn\" \"R6\" read_yaml(path(wbfragment, \"config.yaml\"))$episodes ## [1] \"intro.Rmd\""},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"file-information","dir":"Articles","previous_headings":"","what":"File Information","title":"Introduction to the Lesson Object","text":"Lesson object contains information file information:","code":"# what is the root path for the lesson? wb_lesson$path ## [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" # what episode files exist? wb_lesson$files ## intro.Rmd ## \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment/episodes/intro.Rmd\" # do any of the files have children (Workbench lessons only)? wb_lesson$has_children ## [1] FALSE"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"accessors","dir":"Articles","previous_headings":"","what":"Accessors","title":"Introduction to the Lesson Object","text":"mentioned earlier, many methods Lesson object wrappers methods Episode objects. challenges, solutions obvious ones. rest elements (active bindings), need use $get() method. example, wanted code blocks episodes extra content, use: Similarly, links headings use:","code":"wb_lesson$challenges() ## $intro.Rmd ## $intro.Rmd$`div-3-challenge` ## {xml_nodeset (12)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ## 1 intro.Rmd 6 6 6 1 2 3 0 0 ## # ℹ 3 more variables: error , images , links wb_lesson$summary(collection = c(\"episodes\", \"extra\")) ## # A tibble: 5 × 12 ## page sections headings callouts challenges solutions code output warning ## ## 1 intro.Rmd 6 6 6 1 2 3 0 0 ## 2 index.md 0 0 0 0 0 0 0 0 ## 3 a.md 0 0 0 0 0 0 0 0 ## 4 setup.md 2 2 3 0 2 0 0 0 ## 5 b.md 0 0 0 0 0 0 0 0 ## # ℹ 3 more variables: error , images , links divs <- wb_lesson$validate_divs() print(divs) ## episodes path div pb_label pos ## div-1-questions intro.Rmd episodes/intro.Rmd questions div-1-questions 7 ## div-2-objectives intro.Rmd episodes/intro.Rmd objectives div-2-objectives 13 ## div-3-challenge intro.Rmd episodes/intro.Rmd challenge div-3-challenge 37 ## div-4-solution intro.Rmd episodes/intro.Rmd solution div-4-solution 47 ## div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 60 ## div-6-keypoints intro.Rmd episodes/intro.Rmd keypoints div-6-keypoints 90 ## div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 ## div-2-solution setup.md learners/setup.md solution div-2-solution 14 ## div-3-solution setup.md learners/setup.md solution div-3-solution 22 ## is_known ## div-1-questions TRUE ## div-2-objectives TRUE ## div-3-challenge TRUE ## div-4-solution TRUE ## div-5-solution TRUE ## div-6-keypoints TRUE ## div-1-instructor TRUE ## div-2-solution TRUE ## div-3-solution TRUE headings <- wb_lesson$validate_headings() print(headings) ## episodes heading ## 1 intro.Rmd Introduction ## 2 intro.Rmd Challenge 1: Can you do it? ## 3 intro.Rmd Output ## 4 intro.Rmd Challenge 2: how do you nest solutions within challenge blocks? ## 5 intro.Rmd Figures ## 6 intro.Rmd Math ## 7 setup.md For Windows ## 8 setup.md For MacOS ## level pos node first_heading_is_second_level greater_than_first_level ## 1 2 20 ## ## ::warning file=learners/setup.md,line=18:: [needs HTTPS]: [the PuTTY terminal](http://example.com/putty) ## ::warning file=learners/setup.md,line=26:: [needs HTTPS]: [Terminal.app](http://example.com/terminal) print(links) ## episodes scheme server port user path query ## 1 intro.Rmd https carpentries.github.io NA /lesson-example ## 2 setup.md http example.com NA /putty ## 3 setup.md http example.com NA /terminal ## fragment orig text alt ## 1 https://carpentries.github.io/lesson-example lesson example ## 2 http://example.com/putty the PuTTY terminal ## 3 http://example.com/terminal Terminal.app ## title type rel anchor sourcepos filepath parents node ## 1 link FALSE 25 episodes/intro.Rmd FALSE 18 learners/setup.md FALSE 26 learners/setup.md ## 1 intro.Rmd 3 0 0 0 0 ## 2 site/built/a.md 0 0 0 0 0 ## 3 site/built/b.md 0 0 0 0 0 ## 4 site/built/index.md 0 0 0 0 0 ## 5 site/built/intro.md 3 1 1 0 0 ## 6 site/built/setup.md 0 0 0 0 0"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"handouts","dir":"Articles","previous_headings":"","what":"Handouts","title":"Introduction to the Lesson Object","text":"another method wrapped Episode method, combines output single file prepends Episode title section:","code":"writeLines(wb_lesson$handout()) ## ## Using RMarkdown ## ## ## Challenge 1: Can you do it? ## ## What is the output of this command? ## ## ```{r, eval=FALSE} ## paste(\"This\", \"new\", \"template\", \"looks\", \"good\") ## ```"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"accessing-other-episode-methods","dir":"Articles","previous_headings":"","what":"Accessing other Episode methods","title":"Introduction to the Lesson Object","text":"pegboard::Episode methods listed , need manually iterate Episode objects. example, wanted extract instructor notes lesson, use purrr::map() wanted get specific thing body document, use functions {xml2} xml2::xml_find_first() xml2::xml_find_all(). , looking first first text element fenced-div element: information constructing XPath queries working XML data, can read vignette(\"intro-xml\", package = \"pegboard\")","code":"purrr::map(c(wb_lesson$episodes, wb_lesson$extra), function(ep) ep$get_divs(\"instructor\")) ## $intro.Rmd ## named list() ## ## $index.md ## named list() ## ## $a.md ## named list() ## ## $setup.md ## $setup.md$`div-1-instructor` ## {xml_nodeset (3)} ## [1] \\n \\n \\n } replaced class definitions key/value pairs. always appear relevant block lead code blocks looked like : Moreover, achieve special callout blocks, used blockquotes given special classes (accessbility -blocks semantic HTML) nesting block quotes looked like : One biggest challenges authors , unless used editor like vim emacs, difficult write prefixed blockquote characters keeping track IALs belonged block.","code":"~~~ ls -larth /path/to/dir ~~~ {: .language-bash} > ## Challenge > > How do you list all files in a directory in reverse order by the time it was > last updated? > > > ## Solution > > > > ~~~ > > ls -larth /path/to/dir > > ~~~ > > {: .language-bash} > {: .solution} {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/articles/intro-lesson.html","id":"methods","dir":"Articles","previous_headings":"Jekyll Lessons","what":"Methods","title":"Introduction to the Lesson Object","text":"methods specific lessons built Jekyll. particular, n_problems show_problems active binding useful determining anything went wrong parsing kramdown syntax, $isolate_blocks() method used strip non-blockquote content, $blocks() method returned block quote filters types, $rmd field indicator lesson used R Markdown. mentioned , Jekyll uses special block quotes format callout blocks. $challenges() $solutions() methods recognise return block quotes: blocks, can use $blocks() method:","code":"jekyll <- Lesson$new(lesson_fragment(\"lesson-fragment\"), jekyll = TRUE) jekyll$n_problems ## 10-lunch.md 12-for-loops.md 14-looping-data-sets.md ## 0 0 0 ## 17-scope.md ## 0 rmd <- Lesson$new(lesson_fragment(\"rmd-lesson\"), jekyll = TRUE) ## could not find _episodes/, using _episodes_rmd/ as the source rmd$n_problems ## 01-test.Rmd ## 0 jekyll$challenges() ## $`10-lunch.md` ## {xml_nodeset (0)} ## ## $`12-for-loops.md` ## {xml_nodeset (7)} ## [1] \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n ## Setup Instructions #> #> ### Python #> #> {% include setup-python.md%} #> #> ### R #> #> {% include setup-r.md %} child_from_include(setup_file) #> ℹ /tmp/Rtmp3r8ivU/file1b6e43337776.md writeLines(readLines(fs::path_ext_set(setup_file, \"Rmd\"))) # show the file #> ## Setup Instructions #> #> ### Python #> #> ```{r include-setup-python, child='files/setup-python.md'} #> ``` #> #> ### R #> #> ```{r include-setup-r, child='files/setup-r.md'} #> ```"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"working-with-xml-data","dir":"Articles","previous_headings":"","what":"Working with XML data","title":"Working with XML data","text":"Episode object contains field (can think field list element) called $body, contains {xml2} document. core Episode object every function works way field.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-memory-of-xml-objects","dir":"Articles","previous_headings":"Working with XML data","what":"The memory of XML objects","title":"Working with XML data","text":"casual R user (even experienced), way use package may seem little strange. R, functions side effects, vast majority methods Episode object modify object way XML data handled R {xml2} package. Normally R, pass data function, make copy data apply function copy data: working XML R, {xml2} package unparalleled, leads surprising outcomes modify content within XML object, modifying object place: gets bit stranger consider code, y x exactly object shown fact manipulate y, x also modified: can even extract child elements XML document manipulate reflected parent. example, extract second child document, apply cool=\"verified\" attribute child, reflected parent document. persistance lends well using {R6} package creating objects work object-oriented way (methods belong classes instead way around). familiar Python methods work, mostly familiar {R6} objects behave. worthwhile read {R6} introduction vignette want understand program modify package. example , notice use xml2::xml_child() extract child nodes, real power XML comes searching items using XPath syntax traversing XML nodes able one following get child called “c” next section cover bit XPath provide resources practice learn comes handy quickly traverse XML nodes without relying loops.","code":"x <- 1:10 f <- function(x) { # insert 99 after the fourth position in a vector return(append(x, 99, after = 4)) } print(f(x)) #> [1] 1 2 3 4 99 5 6 7 8 9 10 # note that x is not modified print(x) #> [1] 1 2 3 4 5 6 7 8 9 10 x <- xml2::read_xml(\"<\/b><\/a>\") print(x) #> {xml_document} #> #> [1] f <- function(x, new = \"c\") { xml2::xml_add_child(x, new, .where = xml2::xml_length(x)) return(x) } y <- f(x) # note that x and y are identical print(x) #> {xml_document} #> #> [1] #> [2] print(y) #> {xml_document} #> #> [1] #> [2] f(y, \"d\") #> {xml_document} #> #> [1] #> [2] #> [3] print(y) #> {xml_document} #> #> [1] #> [2] #> [3] print(x) #> {xml_document} #> #> [1] #> [2] #> [3] child <- xml2::xml_child(x, 2) xml2::xml_set_attr(child, \"cool\", \"verified\") print(child) #> {xml_node} #> #> NULL print(x) #> {xml_document} #> #> [1] #> [2] #> [3] print(y) #> {xml_document} #> #> [1] #> [2] #> [3] xml2::xml_find_first(x, \".//c\") #> {xml_node} #> xml2::xml_find_first(x, \"/a/c\") #> {xml_node} #> "},{"path":[]},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-structure-of-xpath","dir":"Articles","previous_headings":"Using XPath to parse XML","what":"The structure of XPath","title":"Working with XML data","text":"section, talk XPath syntax, non-exhaustive. Unfortunately, good tutorials web far , can help: MDN XPath Axes good knowing navigate among nodes MDN XPath functions good knowing filter node matches w3schools tutorial XPath actually one best , excpetion rule. tutorial, trust content w3schools (aligned web consortium). XPath tester like regex tester allow try complex queries visual manner. ’s important remember XML document tree-like structure similar directories folders computer. example, look source directory structure package, see folder called R/ nested folder called tests/testhat/. started root directory package, list R files R/ folder ls R/*.R similarly, wanted list R files tests/testthat/ folder, us ls tests/testthat/*.R. respect, XPath similar syntax: enter next level nesting, add slash (/). example, let’s take look file structure look like XML form: XPath syntax find files R testthat folders started root: R/file tests/testthat/file. However, XPath one advantage normal command line syntax doesn’t : can short-cut paths, wanted find files given folder, can use double slash (//) recursively search nesting. habit, normally use precede slashes dot (.) can sure start node variable: course, method finds files, wanted filter , can use bracket notation create filters selection based ext attribute, prefixed @. bracket notation, add brackets node selection condition. case, want test extension ‘R’, use [@ext='R']: scheme, ’ve put file names text nodes, can use bracket notation XPath functions filter files contain “one” wanted extract source files contain “one”, also use parent:: XPath axis: Note used slash (/) instead square brackets parent, get parent back: see, many times, XPath query can get kind hairy, often like compose different parts programming {glue}: next section, discuss extract manipulate XML comes Markdown namespaces.","code":" one<\/file> two<\/file> <\/R> test-data<\/file> <\/data> test-one<\/file> test-two<\/file> <\/testthat> <\/tests> <\/ROOT> xml2::xml_find_all(xml, \"R/file\") #> {xml_nodeset (2)} #> [1] one<\/file> #> [2] two<\/file> xml2::xml_find_all(xml, \"tests/testthat/file\") #> {xml_nodeset (2)} #> [1] test-one<\/file> #> [2] test-two<\/file> xml2::xml_find_all(xml, \".//file\") #> {xml_nodeset (5)} #> [1] one<\/file> #> [2] two<\/file> #> [3] test-data<\/file> #> [4] test-one<\/file> #> [5] test-two<\/file> xml2::xml_find_all(xml, \".//file[@ext='R']\") #> {xml_nodeset (4)} #> [1] one<\/file> #> [2] two<\/file> #> [3] test-one<\/file> #> [4] test-two<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')]\") #> {xml_nodeset (2)} #> [1] one<\/file> #> [2] test-one<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')][parent::R]\") #> {xml_nodeset (1)} #> [1] one<\/file> xml2::xml_find_all(xml, \".//file[@ext='R'][contains(text(), 'one')]/parent::R\") #> {xml_nodeset (1)} #> [1] \\n one<\/file>\\n two<\/file>\\n<\/R> predicate <- \"[@ext='R'][contains(text(), 'one')]\" XPath <- glue::glue(\".//file{predicate}/parent::R\") xml2::xml_find_all(xml, XPath) #> {xml_nodeset (1)} #> [1] \\n one<\/file>\\n two<\/file>\\n<\/R>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"xml-data-from-markdown-using-namespaces","dir":"Articles","previous_headings":"","what":"XML data from Markdown using namespaces","title":"Working with XML data","text":"XML markdown transformation fully handled {commonmark} package, convenient commonmark::markdown_xml() function. example, following markdown processed: bunch example markdown text list can see successfully parsed markdown paragraph list various elements within.","code":"This is a bunch of [example markdown](https://example.com 'for example') text - this - is - a **list** md <- c(\"This is a bunch of [example markdown](https://example.com 'for example') text\", \"\", \"- this\", \"- is\", \"- a **list**\" ) xml_txt <- commonmark::markdown_xml(paste(md, collapse = \"\\n\")) class(xml_txt) #> [1] \"character\" writeLines(xml_txt) #> #> #> #> #> This is a bunch of <\/text> #> #> example markdown<\/text> #> <\/link> #> text<\/text> #> <\/paragraph> #> #> #> #> this<\/text> #> <\/paragraph> #> <\/item> #> #> #> is<\/text> #> <\/paragraph> #> <\/item> #> #> #> a <\/text> #> #> list<\/text> #> <\/strong> #> <\/paragraph> #> <\/item> #> <\/list> #> <\/document>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"the-default-namespace","dir":"Articles","previous_headings":"XML data from Markdown using namespaces","what":"The default namespace","title":"Working with XML data","text":"Now ’s catch: commonmark markdown always starts basic skeleton root node . xmlns attribute defines default XML namespace: many XML applications, namespaces come prefixes, defined xmlns attribute (e.g. xmlns:svg=\"http://www.w3.org/2000/svg\"). node namespace, needs selected namespace prefix like : .//svg:circle. default namespaces, rule applies, question becomes: know namespace prefix ? {xml2}, default namespace always begins d1 increments new namespaces added. can inspect namespace xml2::xml_ns(): Thus, XPath query use select paragraph .//d1:paragraph: course, default namespace {xml2} drawbacks adding new nodes duplicate namespace different identifier, one way avoided {tinkr} (package basic conversion) define namespace prefix function can use querying: ’s also important remember nodes require namespace prefix, wanted select paragraphs inside list, need specify use .//md:list//md:paragraph:","code":"#> #> #> #> #> MARKDOWN CONTENT HERE #> #> <\/document> xml <- xml2::read_xml(xml_txt) xml2::xml_ns(xml) #> d1 <-> http://commonmark.org/xml/1.0 # with namespace prefix xml2::xml_find_all(xml, \".//d1:paragraph\") #> {xml_nodeset (4)} #> [1] \\n This is a bunch of <\/text>\\n < ... #> [2] \\n this<\/text>\\n<\/paragraph> #> [3] \\n is<\/text>\\n<\/paragraph> #> [4] \\n a <\/text>\\n \\n md <-> http://commonmark.org/xml/1.0 xml2::xml_find_all(xml, \".//md:paragraph\", ns = tinkr::md_ns()) #> {xml_nodeset (4)} #> [1] \\n This is a bunch of <\/text>\\n < ... #> [2] \\n this<\/text>\\n<\/paragraph> #> [3] \\n is<\/text>\\n<\/paragraph> #> [4] \\n a <\/text>\\n \\n {xml_nodeset (3)} #> [1] \\n this<\/text>\\n<\/paragraph> #> [2] \\n is<\/text>\\n<\/paragraph> #> [3] \\n a <\/text>\\n \\n XML node defined pegboard namespace. sandwich nodes want query allow us use tinkr::find_between() search specific tags: automated get_divs() internal function:","code":"This is markdown with fenced divs ::: discussion This is a discussion ::: ::: spoiler This is a spoiler that is hidden by default ::: md <- 'This is markdown with fenced divs ::: discussion This is a discussion ::: ::: spoiler This is a spoiler that is hidden by default ::: ' fences <- xml2::read_xml(commonmark::markdown_xml(md)) fences #> {xml_document} #> #> [1] \\n This is markdown with fenced di ... #> [2] \\n ::: discussion<\/text>\\n<\/paragr ... #> [3] \\n This is a discussion<\/text>\\n<\/ ... #> [4] \\n :::<\/text>\\n<\/paragraph> #> [5] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [6] \\n This is a spoiler that is hidde ... #> [7] \\n :::<\/text>\\n<\/paragraph> pb <- asNamespace(\"pegboard\") pb$label_div_tags(fences) fences #> {xml_document} #> #> [1] \\n This is markdown with fenced d ... #> [2] #> [3] \\n ::: discussion<\/text>\\n<\/parag ... #> [4] \\n This is a discussion<\/text>\\n< ... #> [5] \\n :::<\/text>\\n<\/paragraph> #> [6] #> [7] #> [8] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [9] \\n This is a spoiler that is hidd ... #> [10] \\n :::<\/text>\\n<\/paragraph> #> [11] ns <- pb$get_ns() ns # both md and pegboard namespaces #> md <-> http://commonmark.org/xml/1.0 #> pb <-> http://carpentries.org/pegboard/ tinkr::find_between(fences, ns = ns, pattern = \"pb:dtag[@label='div-1-discussion']\") #> {xml_nodeset (3)} #> [1] \\n ::: discussion<\/text>\\n<\/paragr ... #> [2] \\n This is a discussion<\/text>\\n<\/ ... #> [3] \\n :::<\/text>\\n<\/paragraph> pb$get_divs(fences) #> $`div-1-discussion` #> {xml_nodeset (3)} #> [1] \\n ::: discussion<\/text>\\n<\/paragr ... #> [2] \\n This is a discussion<\/text>\\n<\/ ... #> [3] \\n :::<\/text>\\n<\/paragraph> #> #> $`div-2-spoiler` #> {xml_nodeset (3)} #> [1] \\n ::: spoiler<\/text>\\n<\/paragraph> #> [2] \\n This is a spoiler that is hidde ... #> [3] \\n :::<\/text>\\n<\/paragraph>"},{"path":"https://carpentries.github.io/pegboard/articles/intro-xml.html","id":"conclusion","dir":"Articles","previous_headings":"","what":"Conclusion","title":"Working with XML data","text":"short introduction using XML {pegboard}. now basics structure XML , use XPath (resources), use XPath namespaces, use namespaces {pegboard} allow us parse specific items. good idea practices working XPath useful working XML representations markdown documents, also heavily used post-processing HTML {pkgdown} {sandpaper} packages.","code":""},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"Validation of Lesson Elements","text":"package designed parse structure Markdown R Markdown files inside Carpentries-style lesson. ensure consistent lesson structure, built-validators inspect headings, links, callout sections. document help become familiar output validators can used update lesson. Lesson authors contributors likely see output validators need interact directly. example, lesson contains mal-formed links headings: can see informative actionable output produced allow lesson authors make targeted changes files. next sections detail can work output methods.","code":"library(pegboard) lsn <- Lesson$new(lesson_fragment()) # validation lsn$validate_divs() lsn$validate_links() #| ! There were errors in 4/14 images #| ◌ Some linked internal files do not exist #| ◌ Images need alt-text #| #| ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #| ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg lsn$validate_headings(verbose = FALSE) #| ! There were errors in 13/37 headings #| ◌ Headings must be unique #| #| #| ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated)"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"link-validation","dir":"Articles","previous_headings":"","what":"Link Validation","title":"Validation of Lesson Elements","text":"validation methods produce messages (aka stderr) user, also produce data frame output contains detailed information link tests passed pass. can find tests run links accessing help page validate_links typing ?validate_links R console. want inspect data frame, can assign new variable: data frame combined output three sources: output [xml2::url_parse()] source data containing original source file (filepath), line number (pos), XML node (node) tests performed logical vectors, can extracted programmatically , can see nodes pass tests using link_tests vector, internal vector defining inline messages printed failed test, filter output: context, document looks like positions:","code":"links <- lsn$validate_links() #| ! There were errors in 4/14 images #| ◌ Some linked internal files do not exist #| ◌ Images need alt-text #| #| ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #| ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #| ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg str(links, max.level = 1) #| 'data.frame': 14 obs. of 28 variables: #| $ episodes : chr \"12-for-loops.md\" \"14-looping-data-sets.md\" \"14-looping-data-sets.m\".. #| $ scheme : chr \"https\" \"https\" \"https\" \"https\" ... #| $ server : chr \"docs.python.org\" \"docs.python.org\" \"docs.python.org\" \"docs.python.\".. #| $ port : int NA NA NA NA NA NA NA NA 21985 1155927432 ... #| $ user : chr \"\" \"\" \"\" \"\" ... #| $ path : chr \"/3/library/stdtypes.html\" \"/3/library/glob.html\" \"/3/library/glob.\".. #| $ query : chr \"\" \"\" \"\" \"\" ... #| $ fragment : chr \"range\" \"glob.glob\" \"\" \"\" ... #| $ orig : chr \"https://docs.python.org/3/library/stdtypes.html#range\" \"https://do\".. #| $ text : chr \"range\" \"glob.glob\" \"glob\" \"glob\" ... #| $ alt : chr NA NA NA NA ... #| $ title : chr \"\" \"\" \"\" \"\" ... #| $ type : chr \"link\" \"link\" \"link\" \"link\" ... #| $ rel : chr NA NA NA NA ... #| $ anchor : logi FALSE FALSE FALSE FALSE FALSE FALSE ... #| $ sourcepos : int 135 51 57 58 140 163 189 191 193 193 ... #| $ filepath : 'fs_path' chr \"_episodes/12-for-loops.md\" \"_episodes/14-looping-data-se\".. #| $ parents :List of 14 #| $ node :List of 14 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ known_protocol : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ enforce_https : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_anchor : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_file : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_well_formed: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ all_reachable : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ img_alt_text : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ descriptive : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ link_length : logi TRUE TRUE TRUE TRUE TRUE TRUE ... # get the subset of rows that did not pass all the tests invalid <- !apply(links[names(link_tests)], MARGIN = 1L, all) # return the nodes links$node[invalid] #| [[1]] #| {html_node} #| \"books #| #| [[2]] #| {xml_node} #| #| [1] Carpentries logo<\/text> #| #| [[3]] #| {xml_node} #| #| [1] Non-working image<\/text> #| #| [[4]] #| {xml_node} #| #| [1] Non-working image with jekyll syntax<\/text> #| \"books #| #| \"books #| #| Link to [Home]({{ page.root }}/index.html) and to [shell]({{ site.swc_pages }}/shell-novice) #| #| ![Carpentries logo](https://carpentries.org/assets/img/TheCarpentries.svg) #| #| ![Non-working image](../no-workie.svg) #| #| ![Non-working image with jekyll syntax]({{ page.root }}/no-workie.svg) #| #| This text includes a [link that isn't parsed correctly by commonmark]({{ page.root }}{% link index.md %}) #| . The rest of the text should be properly parsed. #| #| {% include links.md %}"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"fenced-div-validation","dir":"Articles","previous_headings":"","what":"Fenced Div Validation","title":"Validation of Lesson Elements","text":"Validation fenced divs (aka callout blocks) moment checks whether section divs encouter lessons ones expect, avoid issues div class mis-typed. divs expect object pegboard::KNOWN_DIVS: callout, objectives, questions, challenge, prereq, checklist, solution, hint, discussion, testimonial, keypoints, instructor, spoiler, tab, group-tab, caution. example lesson old styles repository, fenced divs, can use lesson fragment {sandpaper}: Notice message produced indicating divs lesson fragment okay. look data frame produced, can see six divs: invalid div names lesson, reported. example, lesson right now, improper fenced div classes, add invalid fenced div (via add_md() method tinkr::yarn() class), able find quickly: can see table is_known column now FALSE value:","code":"snd <- Lesson$new(lesson_fragment(name = \"sandpaper-fragment\"), jekyll = FALSE) snd_divs <- snd$validate_divs() snd_divs #| episodes path div pb_label pos is_known #| div-1-questions intro.Rmd episodes/intro.Rmd questions div-1-questions 7 TRUE #| div-2-objectives intro.Rmd episodes/intro.Rmd objectives div-2-objectives 13 TRUE #| div-3-challenge intro.Rmd episodes/intro.Rmd challenge div-3-challenge 37 TRUE #| div-4-solution intro.Rmd episodes/intro.Rmd solution div-4-solution 47 TRUE #| div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 60 TRUE #| div-6-keypoints intro.Rmd episodes/intro.Rmd keypoints div-6-keypoints 90 TRUE #| div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 TRUE #| div-2-solution setup.md learners/setup.md solution div-2-solution 14 TRUE #| div-3-solution setup.md learners/setup.md solution div-3-solution 22 TRUE our_div <- c(\"::: exercise\", \"\\nthis is an invalid div\\n\", \":::\") snd$episodes[[\"intro.Rmd\"]]$add_md(our_div) snd_divs <- snd$validate_divs() #| ! There were errors in 1/10 fenced divs #| ◌ The Carpentries Workbench knows the following div types callout, objectives, questions, challenge, prereq, checklist, solution, hint, discussion, testimonial, keypoints, instructor, spoiler, tab, group-tab, caution #| #| ::warning file=episodes/intro.Rmd,line=NA:: [unknown div] exercise snd_divs #| episodes path div pb_label pos is_known #| div-1-exercise intro.Rmd episodes/intro.Rmd exercise div-1-exercise NA FALSE #| div-2-questions intro.Rmd episodes/intro.Rmd questions div-2-questions 7 TRUE #| div-3-objectives intro.Rmd episodes/intro.Rmd objectives div-3-objectives 13 TRUE #| div-4-challenge intro.Rmd episodes/intro.Rmd challenge div-4-challenge 37 TRUE #| div-5-solution intro.Rmd episodes/intro.Rmd solution div-5-solution 47 TRUE #| div-6-solution intro.Rmd episodes/intro.Rmd solution div-6-solution 60 TRUE #| div-7-keypoints intro.Rmd episodes/intro.Rmd keypoints div-7-keypoints 90 TRUE #| div-1-instructor setup.md learners/setup.md instructor div-1-instructor 6 TRUE #| div-2-solution setup.md learners/setup.md solution div-2-solution 14 TRUE #| div-3-solution setup.md learners/setup.md solution div-3-solution 22 TRUE"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"heading-validation","dir":"Articles","previous_headings":"","what":"Heading Validation","title":"Validation of Lesson Elements","text":"NOTE: rethinking exact specifications heading validation time Validation headings operate similarly links produces data frame along message output can inspected manipulated. can find accessing help documentation validate_headings typing ?validate_headings R console. particular data frame fewer rows fewer moving parts headings links, indeed important. process getting subset invalid headings similar: use heading_tests vector pegboard subset rows failed:","code":"headings <- lsn$validate_headings(verbose = TRUE) #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"For Loops\" #| ├─## A for loop executes commands once for each value in a collection. #| ├─## A for loop is made up of a collection, a loop variable, and a body. #| ├─## The first line of the for loop must end with a colon, and the body must be indented. #| ├─## Loop variables can be called anything. #| ├─## The body of a loop can contain many statements. #| ├─## Use range to iterate over a sequence of numbers. #| ├─## The Accumulator pattern turns many values into one. #| ├─## Classifying Errors #| ├─## Solution (duplicated) #| ├─## Tracing Execution #| ├─## Solution (duplicated) #| ├─## Reversing a String #| ├─## Solution (duplicated) #| ├─## Practice Accumulating #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Solution (duplicated) #| ├─## Cumulative Sum #| ├─## Solution (duplicated) #| ├─## Identifying Variable Name Errors #| ├─## Solution (duplicated) #| ├─## Identifying Item Errors #| └─## Solution (duplicated) #| ──────────────────────────────────────────────────────────────────────────────────────────────────── #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"Looping Over Data Sets\" #| ├─## Use a for loop to process files given a list of their names. #| ├─## Use glob.glob to find sets of files whose names match a pattern. #| ├─## Use glob and for to process batches of files. #| ├─## Determining Matches #| ├─## Solution (duplicated) #| ├─## Minimum File Size #| ├─## Solution (duplicated) #| ├─## Comparing Data #| └─## Solution (duplicated) #| └─### ZNK test links and images #| ──────────────────────────────────────────────────────────────────────────────────────────────────── #| ! There were errors in 13/37 headings #| ◌ Headings must be unique #| #| #| ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #| ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #| ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) str(headings, max.level = 1) #| 'data.frame': 37 obs. of 11 variables: #| $ episodes : chr \"12-for-loops.md\" \"12-for-loops.md\" \"12-for-loops.md\" \"12-\".. #| $ heading : chr \"A for loop executes commands once for each value in a col\".. #| $ level : int 2 2 2 2 2 2 2 2 2 2 ... #| $ pos : int 21 54 67 101 113 133 155 180 183 189 ... #| $ node :List of 37 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ first_heading_is_second_level: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ greater_than_first_level : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_sequential : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ have_names : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_unique : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ path : chr \"_episodes/12-for-loops.md\" \"_episodes/12-for-loops.md\" \"_\".. # get the subset of rows that did not pass all the tests invalid <- !apply(headings[names(heading_tests)], MARGIN = 1L, all) # return the nodes headings$node[invalid] #| [[1]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[2]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[3]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[4]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[5]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[6]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[7]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[8]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[9]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[10]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[11]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[12]] #| {xml_node} #| #| [1] Solution<\/text> #| #| [[13]] #| {xml_node} #| #| [1] Solution<\/text>"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"internal-testing","dir":"Articles","previous_headings":"","what":"Internal testing","title":"Validation of Lesson Elements","text":"testing, created documents extreme cases links headings failed show features examples:","code":"ex <- here::here(\"tests/testthat/examples\") lnk <- Episode$new(fs::path(ex, \"link-test.md\")) hd <- Episode$new(fs::path(ex, \"validation-headings.md\"))"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"links","dir":"Articles","previous_headings":"Internal testing","what":"Links","title":"Validation of Lesson Elements","text":"links example several mistakes covering possibilities:","code":"lnk$show() #| --- #| title: Link Tests #| --- #| #| ## Internal links {#internal} #| #| ### :crystal\\_ball: Heading with Emoji #| #| ### Heading with long name that has a label {#label-1} #| #| ### Another heading with a long name that has a label {#label-2} #| #| ### Heading with a class, but no label {.challenge} #| #| ### Heading with class and a label {.solution #label-3} #| #| This is a [link to the Heading with Emoji](#heading-with-emoji) and a [link to #| label 1][rel-label-1] and a [link](#label-2) and [this link](#label-2). #| #| This link goes to [the heading with class and a label](#label-3). #| #| This link is [absolutely incorrect](#bad-fragment) #| #| This [relative link goes to label 1][rel-label-1] #| #| ## Cross-Lesson links {#cross-lesson} #| #| This [link will go to the image test][rel-image], but [this link is #| wrong](incorrect-link.html). #| #| [This link also goes to image test](image-test) and [*this* link goes to #| image test as well](./image-test.html) #| [This link also goes to image test, but with a slash](image-test/), though this #| may not work for us because it implies that there is an `index.html` hiding in #| there. #| #| This link [should be a relative link](rel-image). #| This link [is a relative link that works][rel-image] #| #| This link [goes to an internal nested file](files/thing.txt), but this internal #| link [does not exist](files/ohno.txt) #| #| ## Invalid protocols #| #| This is a [link with a typo](gttps://example.com) #| #| This is a [bitcoin link](bitcoin:FAKE-EXAMPLE) #| and this is a [javascript example](javascript:alert%28%27JavaScript%20Link!%27%29), #| both of which should never appear in lessons. #| #| ## HTTP links #| #| This [link uses http, which is no bueno](http://example.com) #| #| ## Link text #| #| If we have [link text that is informative](https://example.com/link-text#good), #| it will pass. #| #| If we have links like #| [this][bad-link-text] #| [link][bad-link-text] #| [this link][bad-link-text] #| [a link][bad-link-text] #| [link to][bad-link-text] #| [here][bad-link-text] #| [here for][bad-link-text] #| [click here for][bad-link-text] #| [over here for][bad-link-text] #| [more][bad-link-text] #| [more about][bad-link-text] #| [for more about][bad-link-text] #| [for more info about][bad-link-text] #| [for more information about][bad-link-text] #| [read more about][bad-link-text] #| [read more][bad-link-text] #| [read on][bad-link-text] #| [read on about][bad-link-text], #| [a][bad-link-text], #| [][bad-link-text] #| they will fail, but [link text that is descriptive][1], albiet with a numeric #| anchor will work. #| #| ## Spans #| #| This is an [internal span]{#spanny style='color: red'} that we might want to #| link to. #| #| [definition list]{#deffy .anchored} #| : This is a definition list item that has an anchor #| #| We have examples of [spans](#spanny) and [definition lists](#deffy). #| We also have an example of a [missing anchor pointing to float](#floaty) #| #| [rel-label-1]: #label-1 #| [rel-image]: image-test.html #| [bad-link-text]: https://example.com/link-text#bad #| [1]: https://example.com/link-text#descriptive lnk$validate_links() #| ! There were errors in 31/45 links #| ◌ Links must have a known URL protocol (e.g. https, ftp, mailto). See for a list of acceptable protocols. #| ◌ Links must use HTTPS #| ◌ Some link anchors for relative links (e.g. [anchor]: link) are missing #| ◌ Some linked internal files do not exist #| ◌ Some links were incorrectly formatted #| ◌ Avoid uninformative link phrases #| ◌ Avoid single-letter or missing link text #| #| ::warning file=link-test.md,line=18:: [uninformative link text]: [link](#label-2) #| ::warning file=link-test.md,line=18:: [uninformative link text]: [this link](#label-2) #| ::warning file=link-test.md,line=22:: [missing anchor]: [absolutely incorrect](#bad-fragment) #| ::warning file=link-test.md,line=29:: [missing file]: [this link is wrong](incorrect-link.html) #| ::warning file=link-test.md,line=37:: [incorrect formatting]: [should be a relative link][rel-image] -> [should be a relative link](rel-image) #| ::warning file=link-test.md,line=41:: [missing file]: [does not exist](files/ohno.txt) #| ::warning file=link-test.md,line=45:: [invalid protocol]: gttps [needs HTTPS]: [link with a typo](gttps://example.com) #| ::warning file=link-test.md,line=47:: [invalid protocol]: bitcoin [needs HTTPS]: [bitcoin link](bitcoin:FAKE-EXAMPLE) #| ::warning file=link-test.md,line=48:: [invalid protocol]: javascript [needs HTTPS]: [javascript example](javascript:alert%28%27JavaScript%20Link!%27%29) #| ::warning file=link-test.md,line=53:: [needs HTTPS]: [link uses http, which is no bueno](http://example.com) #| ::warning file=link-test.md,line=61:: [uninformative link text]: [this](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=62:: [uninformative link text]: [link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=63:: [uninformative link text]: [this link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=64:: [uninformative link text]: [a link](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=65:: [uninformative link text]: [link to](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=66:: [uninformative link text]: [here](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=67:: [uninformative link text]: [here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=68:: [uninformative link text]: [click here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=69:: [uninformative link text]: [over here for](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=70:: [uninformative link text]: [more](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=71:: [uninformative link text]: [more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=72:: [uninformative link text]: [for more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=73:: [uninformative link text]: [for more info about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=74:: [uninformative link text]: [for more information about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=75:: [uninformative link text]: [read more about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=76:: [uninformative link text]: [read more](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=77:: [uninformative link text]: [read on](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=78:: [uninformative link text]: [read on about](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=79:: [link text too short]: [a](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=80:: [link text too short]: [](https://example.com/link-text#bad) #| ::warning file=link-test.md,line=93:: [missing anchor]: [missing anchor pointing to float](#floaty)"},{"path":"https://carpentries.github.io/pegboard/articles/validation.html","id":"headings","dir":"Articles","previous_headings":"Internal testing","what":"Headings","title":"Validation of Lesson Elements","text":"headings example also several mistakes, demonstrates value visual heading tree displayed output verbose = TRUE","code":"hd$show() #| --- #| title: \"Errors in Headings\" #| --- #| #| # First heading throws an error #| #| ### This heading throws another error #| #| ## This heading is okay #| #| ## This heading is okay #| #| The above heading is not okay #| #| ### This heading is okay #| #| ## #| #| The abve heading doesn't make sense #| #| ## This last heading is okay hd$validate_headings(verbose = TRUE) #| ! There were errors in 5/7 headings #| ◌ First heading must be level 2 #| ◌ Level 1 headings are not allowed #| ◌ Headings must be sequential #| ◌ Headings must be named #| ◌ Headings must be unique #| #| #| ::warning file=validation-headings.md,line=5:: (must be level 2) (first level heading) #| ::warning file=validation-headings.md,line=7:: (non-sequential heading jump) #| ::warning file=validation-headings.md,line=9:: (duplicated) #| ::warning file=validation-headings.md,line=11:: (duplicated) #| ::warning file=validation-headings.md,line=18:: (no name) #| ── Heading structure ─────────────────────────────────────────────────────────────────────────────── #| # Episode: \"Errors in Headings\" #| ├─# First heading throws an error (must be level 2) (first level heading) #| │ ├─### This heading throws another error (non-sequential heading jump) #| │ ├─## This heading is okay (duplicated) #| │ ├─## This heading is okay (duplicated) #| │ │ └─### This heading is okay #| │ ├─## (no name) #| │ └─## This last heading is okay #| ────────────────────────────────────────────────────────────────────────────────────────────────────"},{"path":"https://carpentries.github.io/pegboard/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Robert Davey. Author, maintainer. Erin Becker. Author. Zhian N. Kamvar. Author. Toby Hodges. Contributor. Erin Becker. Contributor. Kelly Barnes. Contributor.","code":""},{"path":"https://carpentries.github.io/pegboard/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Davey R, Becker E, Kamvar Z (2024). pegboard: Explore Manipulate Markdown Curricula Carpentries. R package version 0.7.7, https://carpentries.github.io/pegboard.","code":"@Manual{, title = {pegboard: Explore and Manipulate Markdown Curricula from the Carpentries}, author = {Robert Davey and Erin Becker and Zhian N. Kamvar}, year = {2024}, note = {R package version 0.7.7}, url = {https://carpentries.github.io/pegboard}, }"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"pegboard-parse-source-files-in-the-carpentries-workbench-","dir":"","previous_headings":"","what":"The Carpentries Lesson Validator","title":"The Carpentries Lesson Validator","text":"[pegboard] tempered hardboard pre-drilled evenly spaced holes. holes used accept pegs hooks support various items, tools workshop. https://en.wikipedia.org/wiki/Pegboard {pegboard} package part Carpentries Workbench ’s main functionality parse Markdown R Markdown documents XML representations (via {tinkr}). using XML, able easily arrange parse elements lessons makes two things possible: parse validate lessons structural markdown elements translate markdown syntax Carpentries-style materials styles lesson infrastructure (Jekyll-based) Workbench (Pandoc-based) (see lesson transition tool details) two {R6} objects package: Episode: stores xml content single Markdown R Markdown file. extends tinkr::yarn class. See vignette(\"intro-episode\", package = \"pegboard\") info. Lesson: stores publishable markdown content Episodes within lesson. See vignette(\"intro-episode\", package = \"pegboard\") info. One simple usage getting summary content episode. Let’s investigate contents “Episode Structure” episode Workbench documentation:","code":"library(\"pegboard\") library(\"withr\") # Download the file we need ------------------------------------ src <- \"https://raw.githubusercontent.com/carpentries/sandpaper-docs/main/episodes/episodes.Rmd\" tmp <- local_tempfile(fileext = \".Rmd\") download.file(src, tmp) # Load episode ep <- Episode$new(tmp) # Summary ------------------------------------------------------------- # confirm that we are using sandpaper and get a summary of the contents ep$confirm_sandpaper()$summary() #| sections headings callouts challenges solutions code output warning error images links #| 17 35 28 7 6 35 1 0 0 3 21 # Validation ---------------------------------------------------------- # NOTE: a lot of invalid links because files do not exist outside of # the lesson context lnk <- ep$validate_links() #| ! There were errors in 12/22 links and images #| ◌ Some linked internal files do not exist #| #| fileccef6278e384.Rmd:38 [missing file]: [next episode](editing.md) #| fileccef6278e384.Rmd:51 [missing file]: [the Introduction](introduction.md) #| fileccef6278e384.Rmd:203 [missing file]: [The Workbench Component Guide](component-guide.md) #| fileccef6278e384.Rmd:771 [missing file]: [the setup page](../learners/setup.md) #| fileccef6278e384.Rmd:787 [missing file]: [another episode (e.g. introduction)](introduction.md) #| fileccef6278e384.Rmd:788 [missing file]: [the home page](../index.md) #| fileccef6278e384.Rmd:789 [missing file]: [the setup page](../learners/setup.md) #| fileccef6278e384.Rmd:790 [missing file]: [the \"line length\" section in the style guide](../learners/style.md#line-length) #| fileccef6278e384.Rmd:796 [missing file]: [the style guide](../learners/style.md) #| fileccef6278e384.Rmd:816 [missing file]: [internal links](../episodes/episodes.Rmd#internal-links) #| fileccef6278e384.Rmd:851 [missing file]: [Hex sticker for The Carpentries](fig/carpentries-hex-blue.svg) #| fileccef6278e384.Rmd:893 [missing file]: [Example of Wrapped Alt Text (with apologies to William Carlos Williams)](fig/freezer.png) str(lnk, max.level = 1) #| 'data.frame': 24 obs. of 27 variables: #| $ scheme : chr \"\" \"\" \"\" \"\" ... #| $ server : chr \"\" \"\" \"\" \"\" ... #| $ port : int NA NA NA NA NA NA NA NA NA NA ... #| $ user : chr \"\" \"\" \"\" \"\" ... #| $ path : chr \"editing.md\" \"introduction.md\" \"\" \"component-guide.md\" ... #| $ query : chr \"\" \"\" \"\" \"\" ... #| $ fragment : chr \"\" \"\" \"callout-blocks\" \"\" ... #| $ orig : chr \"editing.md\" \"introduction.md\" \"#callout-blocks\" \"component-guide.md\" ... #| $ text : chr \"next episode\" \"the Introduction\" \"the next section\" \"The Workbench Component Guide\" ... #| $ alt : chr NA NA NA NA ... #| $ title : chr \"\" \"\" \"\" \"\" ... #| $ type : chr \"link\" \"link\" \"link\" \"link\" ... #| $ rel : chr NA NA NA NA ... #| $ anchor : logi FALSE FALSE FALSE FALSE FALSE FALSE ... #| $ sourcepos : int 38 51 168 203 320 329 536 541 621 737 ... #| $ filepath : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... #| $ parents :List of 24 #| $ node :List of 24 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ known_protocol : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ enforce_https : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_anchor : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ internal_file : logi FALSE FALSE TRUE FALSE TRUE TRUE ... #| $ internal_well_formed: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ all_reachable : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ img_alt_text : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ descriptive : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ link_length : logi TRUE TRUE TRUE TRUE TRUE TRUE ... hdg <- ep$validate_headings() str(hdg, max.level = 1) #| 'data.frame': 35 obs. of 10 variables: #| $ heading : chr \"Introduction\" \"Buoyant Barnacle\" \"Creating A New Episode\" \"What is the .Rmd extension?\" ... #| $ level : int 2 3 2 3 2 3 3 3 2 3 ... #| $ pos : int 29 48 63 80 117 126 143 156 196 200 ... #| $ node :List of 35 #| ..- attr(*, \"class\")= chr \"AsIs\" #| $ first_heading_is_second_level: logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ greater_than_first_level : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_sequential : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ have_names : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ are_unique : logi TRUE TRUE TRUE TRUE TRUE TRUE ... #| $ path : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... div <- ep$validate_divs() str(div, max.level = 1) #| 'data.frame': 28 obs. of 5 variables: #| $ path : chr \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" \"fileccef6278e384.Rmd\" ... #| $ div : chr \"questions\" \"objectives\" \"prereq\" \"callout\" ... #| $ pb_label: chr \"div-1-questions\" \"div-2-objectives\" \"div-3-prereq\" \"div-4-callout\" ... #| $ pos : int 9 20 46 78 141 198 226 245 255 274 ... #| $ is_known: logi TRUE TRUE TRUE TRUE TRUE TRUE ..."},{"path":"https://carpentries.github.io/pegboard/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"The Carpentries Lesson Validator","text":"{pegboard} currently CRAN, can installed Carpentries Universe (updated every hour) following commands:","code":"options(repos = c( carpentries = \"https://carpentries.r-universe.dev/\", CRAN = \"https://cran.rstudio.com/\" )) install.packages(\"pegboard\")"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"example","dir":"","previous_headings":"","what":"Example","title":"The Carpentries Lesson Validator","text":"use {pegboard} context Workbench, need lesson handy. don’t one, can use get_lesson() function, use {gert} clone lesson repository computer. (NOTE: file last run 2023-11-22 11:15:17.770234)","code":"library(\"pegboard\") library(\"purrr\") library(\"xml2\") library(\"fs\") d <- fs::file_temp(pattern = \"PBREADME\") rng <- get_lesson(\"swcarpentry/r-novice-gapminder\", path = d, jekyll = FALSE) rng #| #| Public: #| blocks: function (type = NULL, level = 0, path = FALSE) #| built: NULL #| challenges: function (path = FALSE, graph = FALSE, recurse = TRUE) #| children: NULL #| clone: function (deep = FALSE) #| episodes: list #| extra: list #| files: active binding #| get: function (element = NULL, collection = \"episodes\") #| handout: function (path = NULL, solution = FALSE) #| has_children: active binding #| initialize: function (path = \".\", rmd = FALSE, jekyll = TRUE, ...) #| isolate_blocks: function () #| load_built: function () #| n_problems: active binding #| overview: FALSE #| path: /tmp/Rtmp40TO0e/PBREADMEccef2b02e45e/swcarpentry--r-novi ... #| reset: function () #| rmd: FALSE #| sandpaper: TRUE #| show_problems: active binding #| solutions: function (path = FALSE) #| summary: function (collection = \"episodes\") #| thin: function (verbose = TRUE) #| trace_lineage: function (episode_path) #| validate_divs: function () #| validate_headings: function (verbose = TRUE) #| validate_links: function () #| Private: #| deep_clone: function (name, value) # Get a summary of all the elements in each episode rng$summary() #| # A tibble: 16 × 12 #| page sections headings callouts challenges solutions code output warning error images links #| #| 1 01-rstudio-intro.Rmd 28 28 19 5 5 47 1 0 0 2 7 #| 2 02-project-intro.Rmd 12 19 12 5 1 4 0 0 0 1 3 #| 3 03-seeking-help.Rmd 15 15 11 3 3 12 0 0 0 0 7 #| 4 04-data-structures-part1.Rmd 2 50 31 9 15 77 0 0 0 0 1 #| 5 05-data-structures-part2.Rmd 15 15 12 4 4 32 0 0 0 0 3 #| 6 06-data-subsetting.Rmd 33 34 26 8 8 76 0 0 0 2 0 #| 7 07-control-flow.Rmd 15 15 17 5 5 36 0 0 0 0 2 #| 8 08-plot-ggplot2.Rmd 20 20 18 6 6 23 0 0 0 0 12 #| 9 09-vectorization.Rmd 11 11 14 4 4 24 0 0 0 0 1 #| 10 10-functions.Rmd 20 21 19 5 5 28 0 0 0 0 12 #| 11 11-writing-data.Rmd 6 6 7 2 2 11 0 0 0 0 0 #| 12 12-plyr.Rmd 8 8 10 3 3 17 0 0 0 2 1 #| 13 13-dplyr.Rmd 18 18 11 3 3 30 0 0 0 3 6 #| 14 14-tidyr.Rmd 10 10 9 3 3 16 0 0 0 4 5 #| 15 15-knitr-markdown.Rmd 22 22 13 4 4 9 0 0 0 2 18 #| 16 16-wrap-up.Rmd 9 9 4 0 0 1 0 0 0 0 1 # Validate lesson elements rng$validate_links() rng$validate_divs() rng$validate_headings() # this is not run by default in sandpaper lessons #| # Episode: \"Data Structures\" #| ├─### Tip: Editing Text files in R (must be level 2) #| ├─### Check your data for factors #| ├─### Data Types #| ├─### Vectors and Type Coercion #| ├─### Discussion 1 #| ├─### Discussion 1 #| ├─### Challenge 1 #| │ └─#### Copy the code template #| ├─### Instructions for the tasks #| │ └─#### 1. Print the data #| ├─### Tip 1.1 #| ├─### Solution to Challenge 1.1 #| │ └─#### 2. Overview of the data types #| ├─### Tip 1.2 #| ├─### Solution to Challenge 1.2 #| │ └─#### 3. Which data type do we need? #| ├─### Tip 1.3 #| ├─### Solution to Challenge 1.3 #| │ └─#### 4. Correct the problematic value #| ├─### Tip 1.4 #| ├─### Solution to challenge 1.4 #| │ └─#### 5. Convert the column \"weight\" to the correct data type #| ├─### Tip 1.5 #| ├─### Solution to Challenge 1.5 #| ├─### Some basic vector functions #| ├─### Challenge 2 #| ├─### Solution to Challenge 2 #| ├─### Lists #| ├─## Names #| │ ├─### Accessing vectors and lists by name #| │ ├─### Accessing and changing names #| │ ├─### Challenge 3 #| │ ├─### Solution to Challenge 3 #| │ ├─### Challenge 4 #| │ └─### Solution to Challenge 4 #| └─## Data frames #| ├─### Challenge 5 #| ├─### Solution to Challenge 5 #| ├─### Tip: Renaming data frame columns #| ├─### Matrices #| ├─### Challenge 6 #| ├─### Solution to Challenge 6 #| ├─### Challenge 7 #| ├─### Solution to Challenge 7 #| ├─### Challenge 8 #| ├─### Solution to Challenge 8 #| ├─### Challenge 9 #| └─### Solution to Challenge 9 #| # Episode: \"Vectorization\" #| ├─## Challenge 1 #| ├─## Solution to challenge 1 #| ├─## Challenge 2 #| ├─## Solution to challenge 2 #| ├─## Tip: some useful functions for logical vectors #| ├─## Tip: element-wise vs. matrix multiplication #| ├─## Challenge 3 #| ├─## Solution to challenge 3 #| ├─## Challenge 4 (duplicated) #| ├─## Challenge 4 (duplicated) #| └─## Tip: Operations on vectors of unequal length #| # Episode: \"Functions Explained\" #| ├─## What is a function? #| ├─## Defining a function #| ├─## Tip (duplicated) #| ├─## Challenge 1 #| ├─## Solution to challenge 1 #| ├─## Combining functions #| ├─## Challenge 2 #| ├─## Solution to challenge 2 #| ├─## Interlude: Defensive Programming #| │ └─### Checking conditions with stopifnot() #| ├─## Challenge 3 #| ├─## Solution to challenge 3 #| ├─## More on combining functions #| ├─## Tip: Pass by value #| ├─## Tip: Function scope #| ├─## Challenge 4 #| ├─## Solution to challenge 4 #| ├─## Challenge 5 #| ├─## Solution to challenge 5 #| ├─## Tip (duplicated) #| └─## Tip: Testing and documenting"},{"path":"https://carpentries.github.io/pegboard/index.html","id":"manipulation","dir":"","previous_headings":"Example","what":"Manipulation","title":"The Carpentries Lesson Validator","text":"XML contents lesson contained within $body element Episode object anything XML document retained within object (see {tinkr} documentation details):","code":"ep1 <- rng$episodes[[1]] ep1$body #| {xml_document} #| #| [1] #| [2] \\n ::::::::::::::::::::::::::::::::::::::: objectives<\/text>\\n<\/paragraph> #| [3] \\n \\n \\n Describe the purpose and use of each pane in RStudio<\/text>\\n <\/paragraph>\\n <\/item>\\n \\n ::::::::::::::::::::::::::::::::::::::::::::::::::<\/text>\\n<\/paragraph> #| [5] #| [6] #| [7] \\n :::::::::::::::::::::::::::::::::::::::: questions<\/text>\\n<\/paragraph> #| [8] \\n \\n \\n How to find your way around RStudio?<\/text>\\n <\/paragraph>\\n <\/item>\\n \\ ... #| [9] \\n ::::::::::::::::::::::::::::::::::::::::::::::::::<\/text>\\n<\/paragraph> #| [10] #| [11] #| [12] \\n Before Starting The Workshop<\/text>\\n<\/heading> #| [13] \\n Please ensure you have the latest version of R and RStudio installed on your machine. This is important, as some packages used in the workshop may not install correctly (or at all) if R is not up to dat ... #| [14] \\n \\n \\n \\n Download and inst ... #| [15] \\n Why use R and R studio?<\/text>\\n<\/heading> #| [16] \\n Welcome to the R portion of the Software Carpentry workshop!<\/text>\\n<\/paragraph> #| [17] \\n Science is a multi-step process: once you've designed an experiment and collected<\/text>\\n \\n data, the real fun begins with analysis! Thr ... #| [18] \\n Although we could use a spreadsheet in Microsoft Excel or Google sheets to analyze our data, these tools are limited in their flexibility and accessibility. Critically, they also are difficult to share ... #| [19] \\n Therefore, this lesson will teach you how to begin exploring your data using R and RStudio. The R program is available for Windows, Mac, and Linux operating systems, and is a freely-available where you ... #| [20] \\n However, to make using R easier, we will use the program RStudio, which we also downloaded above. RStudio is a free, open-source, Integrated Development<\/text>\\n \\n #| [1] NEW CONTENT<\/text> xml2::xml_set_attr(ep1$headings[[1]], \"level\", \"2\") ep1$head(20) #| --- #| title: Introduction to R and RStudio #| teaching: 45 #| exercises: 10 #| source: Rmd #| --- #| #| ## NEW CONTENT #| #| Hello! This is **new markdown content** generated via the #| [{pegboard}](https://carpentries.github.io/pegboard) package that will #| appear above the objectives block! #| #| ::::::::::::::::::::::::::::::::::::::: objectives #| #| - Describe the purpose and use of each pane in RStudio #| - Locate buttons and options in RStudio #| - Define a variable #| - Assign data to a variable #| - Manage a workspace in an interactive R session ep1$headings[[1]] # the first heading is now level 2 #| {xml_node} #| #| [1] NEW CONTENT<\/text> # write the file ep1$write(fs::path_dir(ep1$path), format = \"Rmd\") readLines(ep1$path, 20) #| [1] \"---\" \"title: Introduction to R and RStudio\" \"teaching: 45\" \"exercises: 10\" #| [5] \"source: Rmd\" \"---\" \"\" \"## NEW CONTENT\" #| [9] \"\" \"Hello! This is **new markdown content** generated via the\" \"[{pegboard}](https://carpentries.github.io/pegboard) package that will\" \"appear above the objectives block!\" #| [13] \"\" \"::::::::::::::::::::::::::::::::::::::: objectives\" \"\" \"- Describe the purpose and use of each pane in RStudio\" #| [17] \"- Locate buttons and options in RStudio\" \"- Define a variable\" \"- Assign data to a variable\" \"- Manage a workspace in an interactive R session\""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":null,"dir":"Reference","previous_headings":"","what":"Class representing XML source of a Carpentries episode — Episode","title":"Class representing XML source of a Carpentries episode — Episode","text":"Wrapper around xml document manipulate inspect Carpentries episodes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode class superclass tinkr::yarn(), transforms (commonmark-formatted) Markdown XML back . extension Episode class provides support Pandoc kramdown flavours Markdown. Read class vignette(\"intro-episode\", package = \"pegboard\").","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Class representing XML source of a Carpentries episode — Episode","text":"current XLST spec tinkr support kramdown, Carpentries Episodes styled , thus block tags destructively modified conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"super-class","dir":"Reference","previous_headings":"","what":"Super class","title":"Class representing XML source of a Carpentries episode — Episode","text":"tinkr::yarn -> Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"public-fields","dir":"Reference","previous_headings":"","what":"Public fields","title":"Class representing XML source of a Carpentries episode — Episode","text":"children [character] vector absolute paths child files exist. parents [character] vector absolute paths immediate parent files exist build_parents [character] vector absolute paths final parent files trigger child file build","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"active-bindings","dir":"Reference","previous_headings":"","what":"Active bindings","title":"Class representing XML source of a Carpentries episode — Episode","text":"show_problems [list] list problems occurred parsing episode headings [xml_nodeset] headings document links [xml_nodeset] links (images) document images [xml_nodeset] image sources document tags [xml_nodeset] kramdown tags episode questions [character] questions episode keypoints [character] keypoints episode objectives [character] objectives episode challenges [xml_nodeset] challenges blocks episode solutions [xml_nodeset] solutions blocks episode output [xml_nodeset] output blocks episode error [xml_nodeset] error blocks episode warning [xml_nodeset] warning blocks episode code [xml_nodeset] code blocks episode name [character] name source file without path lesson [character] path lesson episode has_children [logical] indicator presence child files (TRUE) absence (FALSE) has_parents [logical] indicator presence parent files (TRUE) absence (FALSE)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"methods","dir":"Reference","previous_headings":"","what":"Methods","title":"Class representing XML source of a Carpentries episode — Episode","text":"tinkr::yarn$add_md() tinkr::yarn$get_protected() tinkr::yarn$md_vec() tinkr::yarn$protect_curly() tinkr::yarn$protect_math() tinkr::yarn$protect_unescaped()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"public-methods","dir":"Reference","previous_headings":"","what":"Public methods","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode$new() Episode$confirm_sandpaper() Episode$get_blocks() Episode$get_images() Episode$label_divs() Episode$get_divs() Episode$get_yaml() Episode$use_dovetail() Episode$use_sandpaper() Episode$remove_error() Episode$remove_output() Episode$move_objectives() Episode$move_keypoints() Episode$move_questions() Episode$get_challenge_graph() Episode$show() Episode$head() Episode$tail() Episode$write() Episode$handout() Episode$reset() Episode$isolate_blocks() Episode$unblock() Episode$summary() Episode$validate_headings() Episode$validate_divs() Episode$validate_links() Episode$clone()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-new-","dir":"Reference","previous_headings":"","what":"Method new()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create new Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$new( path = NULL, process_tags = TRUE, fix_links = TRUE, fix_liquid = FALSE, parents = NULL, ... )"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path [character] path markdown episode file disk process_tags [logical] TRUE (default), kramdown tags processed attributes parent nodes. FALSE, tags treated text fix_links [logical] TRUE (default), links pointing liquid tags (e.g. {{ page.root }}) included links (supplied call {\\% import links.md \\%}) appropriately processed valid links. fix_liquid [logical] defaults FALSE, means data immediately passed tinkr::yarn. TRUE, liquid variables relative links spaces removed allow commonmark parser interpret links. parents [list] list Episode objects represent immediate parents child ... arguments passed tinkr::yarn tinkr::to_xml()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"new Episode object extracted XML data","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$name scope$lesson scope$challenges"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-confirm-sandpaper-","dir":"Reference","previous_headings":"","what":"Method confirm_sandpaper()","title":"Class representing XML source of a Carpentries episode — Episode","text":"enforce episode sandpaper episode withtout going conversion steps. default Episodes pegboard assumed generated using Jekyll kramdown syntax. bit kludge bypass normal checks kramdown syntax just assume pandoc syntax","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-1","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$confirm_sandpaper()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-blocks-","dir":"Reference","previous_headings":"","what":"Method get_blocks()","title":"Class representing XML source of a Carpentries episode — Episode","text":"return block_quote elements within Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-2","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_blocks(type = NULL, level = 1L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-1","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 1, represents block_quotes nested within block quotes. Increase nubmer increase level nesting.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-1","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"[xml_nodeset] blocks episode given tag level.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-1","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) # get all the challenges scope$get_blocks(\".challenge\") # get the solutions scope$get_blocks(\".solution\", level = 2) \\dontrun{ # download the source files for r-novice-gampinder into a Lesson object rng <- get_lesson(\"swcarpentry/r-novice-gapminder\") dsp1 <- rng$episodes[[\"04-data-structures-part1.md\"]] # There are 9 blocks in total dsp1$get_blocks() # One is a callout block dsp1$get_blocks(\".callout\") # One is a discussion block dsp1$get_blocks(\".discussion\") # Seven are Challenge blocks dsp1$get_blocks(\".challenge\") # There are eight solution blocks: dsp1$get_blocks(\".solution\", level = 2L) }"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-images-","dir":"Reference","previous_headings":"","what":"Method get_images()","title":"Class representing XML source of a Carpentries episode — Episode","text":"fetch image sources optionally process easier parsing. default version function equivalent active binding $images.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-3","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_images(process = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-2","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"process TRUE, images processed via internal function process_images(), add alt attribute, available extract img nodes HTML blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-2","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"xml_nodelist","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-2","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$get_images() loop$get_images(process = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-label-divs-","dir":"Reference","previous_headings":"","what":"Method label_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"label div elements within Episode extract $get_divs()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-4","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$label_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-divs-","dir":"Reference","previous_headings":"","what":"Method get_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"return div elements within Episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-5","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_divs(type = NULL, include = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-3","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"type type div tag (e.g. 'challenge' 'solution') include \\[logical\\] TRUE, div tags included output. Defaults FALSE, return text div tags.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-yaml-","dir":"Reference","previous_headings":"","what":"Method get_yaml()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Extract yaml metadata episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-6","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_yaml()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-use-dovetail-","dir":"Reference","previous_headings":"","what":"Method use_dovetail()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Ammend add setup code block use {dovetail} convert lesson use dovetail R package processing specialized block quotes two things: convert lesson md Rmd add setup chunk following code setup chunk, one created. setup chunk, source knitr_fig_path calls removed.","code":"library('dovetail') source(dvt_opts())"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-7","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$use_dovetail()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-use-sandpaper-","dir":"Reference","previous_headings":"","what":"Method use_sandpaper()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Use sandpaper package processing convert lesson use {sandpaper} R package processing lesson instead Jekyll (default). following effects: code blocks marked liquid tags (e.g. {: .language-r} converted standard code blocks Rmarkdown chunks (language information top code block) rmarkdown used lesson contains python code, library('reticulate') added setup chunk lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-8","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$use_sandpaper(rmd = FALSE, yml = list())"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-4","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"rmd TRUE, lessons converted RMarkdown documents yml list derived yml file episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-remove-error-","dir":"Reference","previous_headings":"","what":"Method remove_error()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove error blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-9","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$remove_error()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-remove-output-","dir":"Reference","previous_headings":"","what":"Method remove_output()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove output blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-10","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$remove_output()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-objectives-","dir":"Reference","previous_headings":"","what":"Method move_objectives()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move objectives yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-11","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_objectives()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-keypoints-","dir":"Reference","previous_headings":"","what":"Method move_keypoints()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move keypoints yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-12","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_keypoints()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-move-questions-","dir":"Reference","previous_headings":"","what":"Method move_questions()","title":"Class representing XML source of a Carpentries episode — Episode","text":"move questions yaml item body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-13","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$move_questions()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-get-challenge-graph-","dir":"Reference","previous_headings":"","what":"Method get_challenge_graph()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create graph top-level elements challenges.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-14","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$get_challenge_graph(recurse = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-5","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"recurse TRUE (default), content solutions included graph; FALSE keep solutions block_quote elements.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-3","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame four columns representing elements within challenges Episode: Block: sequential number challenge block : inward elements : outward elements pos: position markdown document Note three special node names: challenge: start end challenge block solution: start solution block lesson: start lesson block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-3","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$get_challenge_graph()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-show-","dir":"Reference","previous_headings":"","what":"Method show()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-15","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$show(n = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-6","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n subset elements show, default TRUE lines","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-4","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-4","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$head() scope$tail() scope$show()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-head-","dir":"Reference","previous_headings":"","what":"Method head()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show first n lines markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-16","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$head(n = 6L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-7","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n number lines show top","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-5","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-tail-","dir":"Reference","previous_headings":"","what":"Method tail()","title":"Class representing XML source of a Carpentries episode — Episode","text":"show first n lines markdown contents screen","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-17","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$tail(n = 6L)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-8","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"n number lines show top","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-6","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector one line line output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-write-","dir":"Reference","previous_headings":"","what":"Method write()","title":"Class representing XML source of a Carpentries episode — Episode","text":"write episode disk markdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-18","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$write(path = NULL, format = \"md\", edit = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-9","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path path write file . Defaults empty directory temporary folder format one \"md\" (default) \"xml\". create file correct extension path edit TRUE, file open editor. Defaults FALSE.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-7","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"episode object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-5","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$write()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-handout-","dir":"Reference","previous_headings":"","what":"Method handout()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Create trimmed-RMarkdown document strips prose contains important code chunks challenge blocks without solutions.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-19","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$handout(path = NULL, solutions = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-10","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"path (handout) path R Markdown file write. NULL, file written lines output returned. solutions TRUE, include solutions output. Defaults FALSE, removes solution blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-8","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"character vector path = NULL, otherwise, called side effect creating file.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-6","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) e <- lsn$episodes[[1]] cat(e$handout()) cat(e$handout(solution = TRUE))"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-reset-","dir":"Reference","previous_headings":"","what":"Method reset()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Re-read episode disk","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-20","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$reset()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-9","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"episode object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-7","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) xml2::xml_text(scope$tags[1]) xml2::xml_set_text(scope$tags[1], \"{: .code}\") xml2::xml_text(scope$tags[1]) scope$reset() xml2::xml_text(scope$tags[1])"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-isolate-blocks-","dir":"Reference","previous_headings":"","what":"Method isolate_blocks()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Remove elements except within block quotes kramdown tag. Note destructive process.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-21","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$isolate_blocks()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-10","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-8","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$body # a full document with block quotes and code blocks, etc scope$isolate_blocks()$body # only one challenge block_quote"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-unblock-","dir":"Reference","previous_headings":"","what":"Method unblock()","title":"Class representing XML source of a Carpentries episode — Episode","text":"convert challenge blocks roxygen-like code blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-22","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$unblock(token = \"#'\", force = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-11","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"token token use indicate non-code, Defaults \"#'\" force force conversion even conversion already taken place","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-11","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-9","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc loop$get_blocks() # all the blocks in the episode loop$unblock() loop$get_blocks() # no blocks loop$code # now there are two blocks with challenge tags"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-summary-","dir":"Reference","previous_headings":"","what":"Method summary()","title":"Class representing XML source of a Carpentries episode — Episode","text":"Get high-level summary elements episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-23","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$summary()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-12","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame counts following elements per page: sections: level 2 headings headings: headings callouts: callouts challenges: subset callouts solutions: subset callouts code: code block elements (excluding inline code) output: subset code displayed output warnining: subset code displayed warning error: subset code displayed error images: images markdown HTML links: links markdown HTML","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-headings-","dir":"Reference","previous_headings":"","what":"Method validate_headings()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation headings document. validate following aspects headings: first heading starts level 2 (first_heading_is_second_level) greater level 1 (greater_than_first_level) increse sequentially (e.g. jumps 2 4) (are_sequential) names (have_names) unique hierarchy (are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-24","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_headings(verbose = TRUE, warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-12","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"verbose TRUE (default), message rule broken issued stderr. FALSE, silent. warn TRUE (default), warning issued failures tests.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-13","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"data frame variable number rows follwoing columns: episode filename episode heading text heading level heading level pos position heading document node XML node represents heading (next five columns tests listed ) path path file. row data frame represents individual heading across Lesson. See validate_headings() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-10","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"# Example: There are multiple headings called \"Solution\" that are not # nested within a higher-level heading and will throw an error loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_headings()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-divs-","dir":"Reference","previous_headings":"","what":"Method validate_divs()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation divs document. validate following aspects divs. See validate_divs() details. divs known type (is_known)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-25","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_divs(warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-13","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"warn TRUE (default), warning message divs determined invalid. Set FALSE want table processing later.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-14","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"logical TRUE valid divs FALSE invalid divs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-11","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-validate-links-","dir":"Reference","previous_headings":"","what":"Method validate_links()","title":"Class representing XML source of a Carpentries episode — Episode","text":"perform validation links images document. validate following aspects links. See validate_links() details. External links use HTTPS (enforce_https) Internal links exist (internal_okay) External links reachable (all_reachable) (planned) Images alt text (img_alt_text) Link text descriptive (descriptive) Link text single letter (link_length)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-26","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$validate_links(warn = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-14","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"warn TRUE (default), warning message links determined invalid. Set FALSE want table processing later.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"returns-15","dir":"Reference","previous_headings":"","what":"Returns","title":"Class representing XML source of a Carpentries episode — Episode","text":"logical TRUE valid links FALSE invalid links.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"examples-12","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"method-clone-","dir":"Reference","previous_headings":"","what":"Method clone()","title":"Class representing XML source of a Carpentries episode — Episode","text":"objects class cloneable method.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"usage-27","dir":"Reference","previous_headings":"","what":"Usage","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"Episode$clone(deep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"arguments-15","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class representing XML source of a Carpentries episode — Episode","text":"deep Whether make deep clone.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Episode.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class representing XML source of a Carpentries episode — Episode","text":"","code":"## ------------------------------------------------ ## Method `Episode$new` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$name #> [1] \"17-scope.md\" scope$lesson #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" scope$challenges #> {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (0)} if (FALSE) { # \\dontrun{ # download the source files for r-novice-gampinder into a Lesson object rng <- get_lesson(\"swcarpentry/r-novice-gapminder\") dsp1 <- rng$episodes[[\"04-data-structures-part1.md\"]] # There are 9 blocks in total dsp1$get_blocks() # One is a callout block dsp1$get_blocks(\".callout\") # One is a discussion block dsp1$get_blocks(\".discussion\") # Seven are Challenge blocks dsp1$get_blocks(\".challenge\") # There are eight solution blocks: dsp1$get_blocks(\".solution\", level = 2L) } # } ## ------------------------------------------------ ## Method `Episode$get_images` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$get_images() #> {xml_nodeset (5)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... #> [5] {xml_nodeset (5)} #> [1] \"boo [2] \"books [3] [4] \\ ... #> [5] Block from to pos level #> 1 1 challenge heading 45:1-60:14 1 #> 2 1 heading paragraph 45:3-45:34 1 #> 3 1 paragraph code_block 47:3-48:68 1 #> 4 1 code_block lesson 50:3-58:5 1 #> 5 2 challenge heading 62:1-95:14 1 #> 6 2 heading paragraph 62:3-62:27 1 #> 7 2 paragraph list 64:3-64:55 1 #> 8 2 list code_block 66:3-72:1 1 #> 9 2 code_block lesson 73:3-93:5 1 ## ------------------------------------------------ ## Method `Episode$show` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$head() #> --- #> title: \"Variable Scope\" #> teaching: 10 #> exercises: 10 #> questions: #> - \"How do function calls actually work?\" scope$tail() #> > #> > KeyError: 'Friday' #> > ``` #> > {: .error} #> {: .challenge} #> scope$show() #> --- #> title: \"Variable Scope\" #> teaching: 10 #> exercises: 10 #> questions: #> - \"How do function calls actually work?\" #> - \"How can I determine where errors occurred?\" #> objectives: #> - \"Identify local and global variables.\" #> - \"Identify parameters as local variables.\" #> - \"Read a traceback and determine the file, function, and line number on which the error occurred, the type of error, and the error message.\" #> keypoints: #> - \"The scope of a variable is the part of a program that can 'see' that variable.\" #> --- #> #> ## The scope of a variable is the part of a program that can 'see' that variable. #> #> - There are only so many sensible names for variables. #> - People using functions shouldn't have to worry about #> what variable names the author of the function used. #> - People writing functions shouldn't have to worry about #> what variable names the function's caller uses. #> - The part of a program in which a variable is visible is called its *scope*. #> #> ``` #> pressure = 103.9 #> #> def adjust(t): #> temperature = t * 1.43 / pressure #> return temperature #> ``` #> {: .language-python} #> #> - `pressure` is a *global variable*. #> - Defined outside any particular function. #> - Visible everywhere. #> - `t` and `temperature` are *local variables* in `adjust`. #> - Defined in the function. #> - Not visible in the main program. #> - Remember: a function parameter is a variable #> that is automatically assigned a value when the function is called. #> #> ``` #> print('adjusted:', adjust(0.9)) #> print('temperature after call:', temperature) #> ``` #> {: .language-python} #> #> ``` #> adjusted: 0.01238691049085659 #> ``` #> {: .output} #> #> ``` #> Traceback (most recent call last): #> File \"/Users/swcarpentry/foo.py\", line 8, in #> print('temperature after call:', temperature) #> NameError: name 'temperature' is not defined #> ``` #> {: .error} #> #> > ## Local and Global Variable Use #> > #> > Trace the values of all variables in this program as it is executed. #> > (Use '---' as the value of variables before and after they exist.) #> > #> > ``` #> > limit = 100 #> > #> > def clip(value): #> > return min(max(0.0, value), limit) #> > #> > value = -22.5 #> > print(clip(value)) #> > ``` #> > {: .language-python} #> {: .challenge} #> #> > ## Reading Error Messages #> > #> > Read the traceback below, and identify the following: #> > #> > 1. How many levels does the traceback have? #> > 2. What is the file name where the error occurred? #> > 3. What is the function name where the error occurred? #> > 4. On which line number in this function did the error occur? #> > 5. What is the type of error? #> > 6. What is the error message? #> > #> > ``` #> > --------------------------------------------------------------------------- #> > KeyError Traceback (most recent call last) #> > in () #> > 1 import errors_02 #> > ----> 2 errors_02.print_friday_message() #> > #> > /Users/ghopper/thesis/code/errors_02.py in print_friday_message() #> > 13 #> > 14 def print_friday_message(): #> > ---> 15 print_message(\"Friday\") #> > #> > /Users/ghopper/thesis/code/errors_02.py in print_message(day) #> > 9 \"sunday\": \"Aw, the weekend is almost over.\" #> > 10 } #> > ---> 11 print(messages[day]) #> > 12 #> > 13 #> > #> > KeyError: 'Friday' #> > ``` #> > {: .error} #> {: .challenge} #> ## ------------------------------------------------ ## Method `Episode$write` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$write() #> Creating temporary directory '/tmp/RtmpvjwUql/dir168757737362' ## ------------------------------------------------ ## Method `Episode$handout` ## ------------------------------------------------ lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) e <- lsn$episodes[[1]] cat(e$handout()) #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` cat(e$handout(solution = TRUE)) #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::: solution #> #> ## Output #> #> ```{r, echo=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::::::::::::: #> #> ## Challenge 2: how do you nest solutions within challenge blocks? #> #> :::::::::::::::::::::::: solution #> #> You can add a line with at least three colons and a `solution` tag. ## ------------------------------------------------ ## Method `Episode$reset` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" xml2::xml_set_text(scope$tags[1], \"{: .code}\") #> {xml_nodeset (1)} #> [1] ktag=\"{: .language-python}\" xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" scope$reset() xml2::xml_text(scope$tags[1]) #> [1] \"{: .language-python}\" ## ------------------------------------------------ ## Method `Episode$isolate_blocks` ## ------------------------------------------------ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) scope$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] \\n [5] [6] [7] [8] \\n [9] \\n {xml_document} #> #> [1] \\n [2] \\n {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$get_blocks() # all the blocks in the episode #> {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (0)} loop$code # now there are two blocks with challenge tags #> {xml_nodeset (11)} #> [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] ! There were errors in 3/10 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ──────────────────────────────────────────────────────────────────────────────── ## ------------------------------------------------ ## Method `Episode$validate_divs` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_divs() ## ------------------------------------------------ ## Method `Episode$validate_links` ## ------------------------------------------------ loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$validate_links() #> ! There were errors in 4/13 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":null,"dir":"Reference","previous_headings":"","what":"Class to contain a single Lesson by the Carpentries — Lesson","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wrapper several Episode class objects.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"class contains keeps track relationships Episode objects contained within Carpentries Workbench Carpentries styles lessons. Read use class vignette(\"intro-lesson\", package = \"pegboard\")","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"public-fields","dir":"Reference","previous_headings":"","what":"Public fields","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [character] path Lesson directory episodes [list] list Episode class objects representing episodes lesson. built [list] list Episode class objects representing markdown artefacts rendered RMarkdown files. extra [list] list Episode class objects representing extra markdown components including index, setup, information learners, information instructors, learner profiles. processed jekyll lessons. children [list] list Episode class objects representing child files needed components built processed jekyll lessons. sandpaper [logical] TRUE, episodes lesson written pandoc flavoured markdown. FALSE indicate jekyll-based lesson written kramdown. rmd [logical] TRUE, episodes represent RMarkdown files, default FALSE markdown files (deprecated unused). overview [logical] TRUE, lesson overview lesson necessarly contain episodes. Defaults FALSE","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"active-bindings","dir":"Reference","previous_headings":"","what":"Active bindings","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"n_problems number problems per episode show_problems contents problems per episode files source files episode has_children logical indicating presence (TRUE) absence (FALSE) child files within main files lesson","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"public-methods","dir":"Reference","previous_headings":"","what":"Public methods","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson$new() Lesson$load_built() Lesson$get() Lesson$summary() Lesson$blocks() Lesson$challenges() Lesson$solutions() Lesson$thin() Lesson$reset() Lesson$isolate_blocks() Lesson$handout() Lesson$validate_headings() Lesson$validate_divs() Lesson$validate_links() Lesson$trace_lineage() Lesson$clone()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-new-","dir":"Reference","previous_headings":"","what":"Method new()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"create new Lesson object directory","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$new(path = \".\", rmd = FALSE, jekyll = TRUE, ...)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [character] path lesson directory. must folder called _episodes within contains markdown episodes. Defaults current working directory. rmd [logical] TRUE, imported files source RMarkdown files. Defaults FALSE, reads rendered markdown files. jekyll [logical] TRUE (default), structure lesson assumed derived carpentries/styles repository. FALSE, structure assumed sandpaper lesson extra content learners, instructors, profiles populated. ... arguments passed Episode$new","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"new Lesson object contains list Episode objects $episodes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$path frg$episodes"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-load-built-","dir":"Reference","previous_headings":"","what":"Method load_built()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"read markdown content generated RMarkdown sources load load memory","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-1","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$load_built()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-get-","dir":"Reference","previous_headings":"","what":"Method get()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"getter various active bindings Episode class objects. practice syntactic sugar around purrr::map(l$episodes, ~.x$element)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-2","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$get(element = NULL, collection = \"episodes\")"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-1","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"element [character] defined element active bindings Episode class. Defaults NULL, return nothing. Elements exist Episode class return NULL collection [character] one \"episodes\" (default), \"extra\", \"built\". Select TRUE collect information files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-1","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$get(\"error\") # error code blocks frg$get(\"links\") # links"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-summary-","dir":"Reference","previous_headings":"","what":"Method summary()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"summary element counts episode. can useful assessing broad overview lesson dynamics","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-3","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$summary(collection = \"episodes\")"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-2","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"collection [character] one \"episodes\" (default), \"extra\", \"built\". Select TRUE collect information files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-2","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$summary() # episode summary (default)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-blocks-","dir":"Reference","previous_headings":"","what":"Method blocks()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather blocks lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-4","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$blocks(type = NULL, level = 0, path = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-3","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 0, represents block_quotes within document regardless nesting level. path [logical] TRUE, names element equivalent path. default FALSE, gives name episode. body XML body carpentries lesson (xml2 object)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-challenges-","dir":"Reference","previous_headings":"","what":"Method challenges()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather challenges lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-5","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$challenges(path = FALSE, graph = FALSE, recurse = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-4","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [logical] TRUE, names element equivalent path. default FALSE, gives name episode. graph [logical] TRUE, output data frame representing directed graph elements within challenges. See get_challenge_graph() method Episode. recurse [logical] graph = TRUE, include solutions output. See Episode details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-solutions-","dir":"Reference","previous_headings":"","what":"Method solutions()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Gather solutions lesson list xml_nodeset objects","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-6","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$solutions(path = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-5","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path [logical] TRUE, names element equivalent path. default FALSE, gives name episode.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-thin-","dir":"Reference","previous_headings":"","what":"Method thin()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Remove episodes challenges","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-7","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$thin(verbose = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-6","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose [logical] TRUE (default), names episode removed reported. Set FALSE remove behavior.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-1","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-3","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$thin()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-reset-","dir":"Reference","previous_headings":"","what":"Method reset()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Re-read Episodes disk","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-8","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$reset()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-2","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Lesson object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-4","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$episodes[[1]]$body frg$isolate_blocks()$episodes[[1]]$body # empty frg$reset()$episodes[[1]]$body # reset"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-isolate-blocks-","dir":"Reference","previous_headings":"","what":"Method isolate_blocks()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Remove elements except within block quotes kramdown tag. Note destructive process.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-9","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$isolate_blocks()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-3","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Episode object, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-5","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$isolate_blocks()$body # only one challenge block_quote"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-handout-","dir":"Reference","previous_headings":"","what":"Method handout()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"create handout episodes lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-10","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$handout(path = NULL, solution = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-7","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path path R Markdown file written. NULL (default), file written lines output document returned. solution TRUE solutions retained. Defaults FALSE","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-4","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"path = NULL, character vector, otherwise, object returned.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-6","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) cat(lsn$handout()) cat(lsn$handout(solution = TRUE))"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-headings-","dir":"Reference","previous_headings":"","what":"Method validate_headings()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate heading elements meet minimum accessibility requirements. See internal validate_headings() deails. validate following aspects headings: first heading starts level 2 (first_heading_is_second_level) greater level 1 (greater_than_first_level) increse sequentially (e.g. jumps 2 4) (are_sequential) names (have_names) unique hierarchy (are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-11","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_headings(verbose = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-8","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE, heading tree printed console warnings assocated validators","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-5","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"data frame variable number rows follwoing columns: episode filename episode heading text heading level heading level pos position heading document node XML node represents heading (next five columns tests listed ) path path file. row data frame represents individual heading across Lesson. See validate_headings() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-7","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_headings()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-divs-","dir":"Reference","previous_headings":"","what":"Method validate_divs()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate divs known. See internal validate_divs() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"validation-variables","dir":"Reference","previous_headings":"","what":"Validation variables","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"divs known (is_known)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-12","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-9","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE (default), failed tests printed console message giving information document failing divs appear.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-6","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wide data frame five rows number columns equal number episodes lesson extra column indicating type validation. See method Episode class details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-8","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_divs()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-validate-links-","dir":"Reference","previous_headings":"","what":"Method validate_links()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"Validate links images valid accessible. See internal validate_links() details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"validation-variables-1","dir":"Reference","previous_headings":"","what":"Validation variables","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"External links use HTTPS (enforce_https) Internal links exist (internal_okay) External links reachable (all_reachable) (planned) Images alt text (img_alt_text) Link text descriptive (descriptive) Link text single letter (link_length)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-13","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-10","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"verbose TRUE (default), failed tests printed console message giving information document failing links/images appear.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-7","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"wide data frame five rows number columns equal number episodes lesson extra column indicating type validation. See method Episode class details.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-9","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frg <- Lesson$new(lesson_fragment()) frg$validate_links()"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-trace-lineage-","dir":"Reference","previous_headings":"","what":"Method trace_lineage()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"find children single source file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-14","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$trace_lineage(episode_path)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-11","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"episode_path path episode extra file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"returns-8","dir":"Reference","previous_headings":"","what":"Returns","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"character vector full lineage files starting single source file. Note: assumes sandpaper lesson child files. child files, return path","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"examples-10","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"frag <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(frag, jekyll = FALSE) lsn$has_children # TRUE lsn$episodes[[1]]$children # first episode shows 1 immediate child lsn$trace_lineage(lsn$files[[1]]) # find recursive children of 1st episode"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"method-clone-","dir":"Reference","previous_headings":"","what":"Method clone()","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"objects class cloneable method.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"usage-15","dir":"Reference","previous_headings":"","what":"Usage","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"Lesson$clone(deep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"arguments-12","dir":"Reference","previous_headings":"","what":"Arguments","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"deep Whether make deep clone.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/Lesson.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Class to contain a single Lesson by the Carpentries — Lesson","text":"","code":"## ------------------------------------------------ ## Method `Lesson$new` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$path #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" frg$episodes #> $`10-lunch.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- layout: break title: \"Lunch\" teaching: 0 exercises: ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`12-for-loops.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"For Loops\" teaching: 10 exercises: 15 questi ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`14-looping-data-sets.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"Looping Over Data Sets\" teaching: 5 exercise ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> #> $`17-scope.md` #> #> Inherits from: #> Public: #> add_md: function (md, where = 0L) #> body: xml_document, xml_node #> build_parents: #> challenges: active binding #> children: #> clone: function (deep = FALSE) #> code: active binding #> confirm_sandpaper: function () #> error: active binding #> get_blocks: function (type = NULL, level = 1L) #> get_challenge_graph: function (recurse = TRUE) #> get_divs: function (type = NULL, include = FALSE) #> get_images: function (process = FALSE) #> get_protected: function (type = NULL) #> get_yaml: function () #> handout: function (path = NULL, solutions = FALSE) #> has_children: active binding #> has_parents: active binding #> head: function (n = 6L) #> headings: active binding #> images: active binding #> initialize: function (path = NULL, process_tags = TRUE, fix_links = TRUE, #> isolate_blocks: function () #> keypoints: active binding #> label_divs: function () #> lesson: active binding #> links: active binding #> md_vec: function (xpath = NULL, stylesheet_path = stylesheet()) #> move_keypoints: function () #> move_objectives: function () #> move_questions: function () #> name: active binding #> ns: http://commonmark.org/xml/1.0 #> objectives: active binding #> output: active binding #> parents: #> path: /home/runner/work/_temp/Library/pegboard/lesson-fragment ... #> protect_curly: function () #> protect_math: function () #> protect_unescaped: function () #> questions: active binding #> remove_error: function () #> remove_output: function () #> reset: function () #> show: function (n = TRUE) #> show_problems: active binding #> solutions: active binding #> summary: function () #> tags: active binding #> tail: function (n = 6L) #> unblock: function (token = \"#'\", force = FALSE) #> use_dovetail: function () #> use_sandpaper: function (rmd = FALSE, yml = list()) #> validate_divs: function (warn = TRUE) #> validate_headings: function (verbose = TRUE, warn = TRUE) #> validate_links: function (warn = TRUE) #> warning: active binding #> write: function (path = NULL, format = \"md\", edit = FALSE) #> yaml: --- title: \"Variable Scope\" teaching: 10 exercises: 10 q ... #> Private: #> clear_yaml_item: function (what) #> deep_clone: function (name, value) #> encoding: UTF-8 #> md_lines: function (path = NULL, stylesheet = NULL) #> mutations: FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE #> problems: list #> record_problem: function (x) #> sourcepos: TRUE #> ## ------------------------------------------------ ## Method `Lesson$get` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$get(\"error\") # error code blocks #> $`10-lunch.md` #> {xml_nodeset (0)} #> #> $`12-for-loops.md` #> {xml_nodeset (2)} #> [1] [2] #> $`14-looping-data-sets.md` #> {xml_nodeset (0)} #> #> $`17-scope.md` #> {xml_nodeset (2)} #> [1] [2] frg$get(\"links\") # links #> $`10-lunch.md` #> {xml_nodeset (0)} #> #> $`12-for-loops.md` #> {xml_nodeset (1)} #> [1] #> $`14-looping-data-sets.md` #> {xml_nodeset (8)} #> [1] [2] [3] [4] [5] [6] \\ ... #> [7] [8] #> $`17-scope.md` #> {xml_nodeset (0)} #> ## ------------------------------------------------ ## Method `Lesson$summary` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$summary() # episode summary (default) #> ! Summary not guaranteed for styles-based lessons #> # A tibble: 4 × 12 #> page sections headings callouts challenges solutions code output warning #> #> 1 10-lunch… 0 0 0 0 0 0 0 0 #> 2 12-for-l… 24 24 7 7 10 32 4 0 #> 3 14-loopi… 9 10 3 3 3 11 4 0 #> 4 17-scope… 3 3 2 2 0 6 1 0 #> # ℹ 3 more variables: error , images , links ## ------------------------------------------------ ## Method `Lesson$thin` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$thin() #> Removing 1 episode: 10-lunch.md ## ------------------------------------------------ ## Method `Lesson$reset` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$episodes[[1]]$body #> {xml_document} #> #> [1] \\n [2] \\n {xml_document} #> frg$reset()$episodes[[1]]$body # reset #> {xml_document} #> #> [1] \\n [2] \\n NULL ## ------------------------------------------------ ## Method `Lesson$handout` ## ------------------------------------------------ lsn <- Lesson$new(lesson_fragment(\"sandpaper-fragment\"), jekyll = FALSE) cat(lsn$handout()) #> ## Using RMarkdown #> #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` cat(lsn$handout(solution = TRUE)) #> ## Using RMarkdown #> #> ## Challenge 1: Can you do it? #> #> What is the output of this command? #> #> ```{r, eval=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::: solution #> #> ## Output #> #> ```{r, echo=FALSE} #> paste(\"This\", \"new\", \"template\", \"looks\", \"good\") #> ``` #> #> :::::::::::::::::::::::::::::::::: #> #> ## Challenge 2: how do you nest solutions within challenge blocks? #> #> :::::::::::::::::::::::: solution #> #> You can add a line with at least three colons and a `solution` tag. ## ------------------------------------------------ ## Method `Lesson$validate_headings` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_headings() #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “For Loops” #> ├─## A for loop executes commands once for each value in a collection. #> ├─## A for loop is made up of a collection, a loop variable, and a body. #> ├─## The first line of the for loop must end with a colon, and the body must be #> ├─## Loop variables can be called anything. #> ├─## The body of a loop can contain many statements. #> ├─## Use range to iterate over a sequence of numbers. #> ├─## The Accumulator pattern turns many values into one. #> ├─## Classifying Errors #> ├─## Solution (duplicated) #> ├─## Tracing Execution #> ├─## Solution (duplicated) #> ├─## Reversing a String #> ├─## Solution (duplicated) #> ├─## Practice Accumulating #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Solution (duplicated) #> ├─## Cumulative Sum #> ├─## Solution (duplicated) #> ├─## Identifying Variable Name Errors #> ├─## Solution (duplicated) #> ├─## Identifying Item Errors #> └─## Solution (duplicated) #> ──────────────────────────────────────────────────────────────────────────────── #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ──────────────────────────────────────────────────────────────────────────────── #> ! There were errors in 13/37 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/12-for-loops.md,line=183:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=200:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=227:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=252:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=270:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=289:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=305:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=336:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=371:: (duplicated) #> ::warning file=_episodes/12-for-loops.md,line=400:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) ## ------------------------------------------------ ## Method `Lesson$validate_divs` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_divs() ## ------------------------------------------------ ## Method `Lesson$validate_links` ## ------------------------------------------------ frg <- Lesson$new(lesson_fragment()) frg$validate_links() #> ! There were errors in 4/14 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg ## ------------------------------------------------ ## Method `Lesson$trace_lineage` ## ------------------------------------------------ frag <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(frag, jekyll = FALSE) lsn$has_children # TRUE #> [1] TRUE lsn$episodes[[1]]$children # first episode shows 1 immediate child #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd lsn$trace_lineage(lsn$files[[1]]) # find recursive children of 1st episode #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":null,"dir":"Reference","previous_headings":"","what":"Add a pegboard node before or after a node — add_pegboard_nodes","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"nodes namespace \"http://carpentries.org/pegboard/\"","code":""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"","code":"add_pegboard_nodes(node, df)"},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"node single node df data frame generated make_div_pairs()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/add_pegboard_nodes.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add a pegboard node before or after a node — add_pegboard_nodes","text":"NULL, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if a node is after another node — after_thing","title":"Check if a node is after another node — after_thing","text":"Check node another node","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if a node is after another node — after_thing","text":"","code":"after_thing(body, thing = \"code_block\")"},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if a node is after another node — after_thing","text":"body XML node thing name XML node node , defaults \"code_block\"","code":""},{"path":"https://carpentries.github.io/pegboard/reference/after_thing.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if a node is after another node — after_thing","text":"single boolean value indicating node single sibling code block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":null,"dir":"Reference","previous_headings":"","what":"test if the children of a given nodeset are kramdown blocks — are_blocks","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"test children given nodeset kramdown blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"","code":"are_blocks(krams)"},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"krams nodeset","code":""},{"path":"https://carpentries.github.io/pegboard/reference/are_blocks.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"test if the children of a given nodeset are kramdown blocks — are_blocks","text":"boolean vector equal length nodeset","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":null,"dir":"Reference","previous_headings":"","what":"Clean the div tags from an xml document — clean_div_tags","title":"Clean the div tags from an xml document — clean_div_tags","text":"Clean div tags xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Clean the div tags from an xml document — clean_div_tags","text":"","code":"clean_div_tags(body)"},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Clean the div tags from an xml document — clean_div_tags","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Clean the div tags from an xml document — clean_div_tags","text":"TRUE divs detected cleaned, FALSE divs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Clean the div tags from an xml document — clean_div_tags","text":"Commonmark knows raw HTML looks like read HTML block, escaping tag. every HTML tag preceded blank line, :
\\n\\n<\/div> becomes two html_block elements However, element preceded non-html element, becomes part html element.
\\n<\/div> becomes single html_block element: Sometimes, process can gobble text markdown instead HTML, function find multiple tags HTML blocks separates different blocks.","code":" <div class='hello'>\\n <\/html_block> </div>\\n <\/html_block> <div class='hello'>\\n</div>\\n <\/html_block>"},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/clean_div_tags.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Clean the div tags from an xml document — clean_div_tags","text":"","code":"txt <- \"
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ```
```{r} It's not that challenging ``` <\/div>
We just have to try harder and use `
` tags ```{r} cat('better faster stronger with
') ``` <\/div> <\/div>
## Good divs <\/div> \" library(purrr) library(xml2) f <- tempfile() writeLines(txt, f) ex <- tinkr::to_xml(f) xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (5)} #> [1] <div class='challenge'>\\n## Challe ... #> [2] <div class='solution'>\\n```{r}\\nIt ... #> [3] </div>\\n</div>\\n<\/html_block> #> [4] <div class='good'>\\n<\/html_block> #> [5] </div>\\n<\/html_block> pegboard:::clean_div_tags(ex$body) #> [1] TRUE xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (8)} #> [1] &l ... #> [2] &l ... #> [3] &l ... #> [4] &l ... #> [5] &l ... #> [6] &l ... #> [7] <div class='good'>\\n<\/html_block> #> [8] </div>\\n<\/html_block> pegboard:::label_div_tags(ex$body) xml2::xml_find_all(ex$body, \".//d1:html_block[contains(text(), 'div')]\") #> {xml_nodeset (8)} #> [1] &l ... #> [2] &l ... #> [3] &l ... #> [4] &l ... #> [5] &l ... #> [6] &l ... #> [7] <div class='good'>\\n<\/html_block> #> [8] </div>\\n<\/html_block>"},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":null,"dir":"Reference","previous_headings":"","what":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"Sometimes pandoc fenced divs bunched together, makes difficult track pairs. separates different paragraph elements can track ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"","code":"clean_fenced_divs(body)"},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"DEPRECATED.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/clean_fenced_divs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Clean pandoc fenced divs and place them in their own paragraph elements — clean_fenced_divs","text":"","code":"txt <- \"::::::: challenge ## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` ::::: solution :::: ```{r} It's not that challenging ``` :::: ::: solution :::::::: We just have to try harder and use `
` tags ```{r} cat('better faster stronger with
') ``` What if we include some `:::` code in here or ::: like this ::::: ::::: ::: good ## Good divs :::\" f <- tempfile() writeLines(txt, f) ex <- tinkr::to_xml(f, sourcepos = TRUE) ex$body #> {xml_document} #> #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] [7] \\n [8] [9] <img src='htt ... #> [10] \\n [11] \\n [12] \\n [13] \\n [14] \\n [1] \"::::::: challenge\" \"::::: solution ::::\" \"::::\" #> [4] \"::: solution ::::::::\" \":::::\" \":::::\" #> [7] \"::: good\" \":::\" pegboard:::clean_fenced_divs(ex$body) xml2::xml_text(xml2::xml_find_all(ex$body, predicate)) #> [1] \"::::::: challenge\" \"::::: solution ::::\" \"::::\" #> [4] \"::: solution ::::::::\" \":::::\" \":::::\" #> [7] \"::: good\" \":::\""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":null,"dir":"Reference","previous_headings":"","what":"Issue a warning via CLI if it exists or send a message — issue_warning","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"allows us control messages emitted continue keep CLI suggested package.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"","code":"issue_warning( msg = NULL, cli = has_cli(), what = NULL, url = NULL, n = NULL, N = NULL, infos = list(), reports = list(), ... ) pb_message(..., domain = NULL, appendLF = TRUE) line_report(msg = \"\", path, pos, sep = \"\\t\", type = \"warning\") append_labels(l, i = TRUE, e = \"\", cli = FALSE, f = \"style_inverse\") message_muffler(expr, keep = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"msg message glue CLI string. Defaults NULL cli TRUE, stylizes e f name specific element report error url url extra information help. n number elements errored N number total elements infos information errors shown user reports reported errors. ... named arguments evaluated message via glue CLI domain see gettext. NA, messages translated, see also note stop. appendLF logical: messages given character string newline appended? path path file report pos position error sep character use separate human message line number type (used context CI ) type warning thrown (defaults warning) l vector/list characters index elements append e new element append element f function cli transform e expr R expression. keep TRUE, messages kept list. Defautls FALSE cli message discarded.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"nothing, invisibly; used side-effect , l, appended keep = FALSE, output expr, keep = TRUE, list elements val = expr msg = s","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"vast majority code function copied directly message() function.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/cli_helpers.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Issue a warning via CLI if it exists or send a message — issue_warning","text":"","code":"pegboard:::pb_message(\"hello\") #> hello x <- letters[1:5] x2 <- pegboard:::append_labels(x, c(1, 3), \"appended\", cli = requireNamespace(\"cli\", quietly = TRUE), f = \"col_cyan\" ) writeLines(glue::glue(\"[{x}]->[{x2}]\")) #> [a]->[a appended] #> [b]->[b] #> [c]->[c appended] #> [d]->[d] #> [e]->[e] pegboard:::message_muffler({ cli::cli_text(\"hello there! I'm staying in!\") pegboard:::pb_message(\"normal looking message that's not getting through\") message(\"this message makes it out!\") runif(1) }) #> this message makes it out! #> [1] 0.08075014 pegboard:::message_muffler({ cli::cli_text(\"hello there! I'm staying in!\") pegboard:::pb_message(\"normal looking message that's not getting through\") message(\"this message makes it out!\") runif(1) }, keep = TRUE) #> this message makes it out! #> $val #> [1] 0.834333 #> #> $msg #> $msg[[1]] #> > #> #> $msg[[2]] #> > #> #>"},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":null,"dir":"Reference","previous_headings":"","what":"Collect and append validation messages — collect_labels","title":"Collect and append validation messages — collect_labels","text":"Given data frame containing results validation tests, append column labels describes failure.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Collect and append validation messages — collect_labels","text":"","code":"collect_labels(VAL, cli = FALSE, msg = heading_tests)"},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Collect and append validation messages — collect_labels","text":"VAL data frame containing results tests cli indicator use cli package format warnings msg named vector template messages provide test formatted glue package.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/collect_labels.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Collect and append validation messages — collect_labels","text":"","code":"# As an example, consider a data frame where you have observations in rows # and the results of individual tests in columns: set.seed(2023-11-16) dat <- data.frame( name = letters[1:10], rank = sample(1:3, 10, replace = TRUE), A = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)), B = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)), C = sample(c(TRUE, FALSE), 10, replace = TRUE, prob = c(7, 3)) ) dat #> name rank A B C #> 1 a 1 TRUE FALSE TRUE #> 2 b 1 FALSE FALSE TRUE #> 3 c 3 FALSE TRUE TRUE #> 4 d 1 TRUE TRUE TRUE #> 5 e 2 TRUE TRUE TRUE #> 6 f 2 FALSE TRUE TRUE #> 7 g 3 TRUE FALSE TRUE #> 8 h 2 TRUE TRUE FALSE #> 9 i 2 TRUE FALSE TRUE #> 10 j 3 FALSE TRUE TRUE # you can see what the results of the tests were, but it would be a good # idea to have a lookup table describing what these results mean dat_tests <- c( A = \"[missing widget]: {name}\", B = \"[incorrect rank]: {rank}\", C = \"[something else]\" ) # collect_labels will create the output you need: pb <- asNamespace(\"pegboard\") res <- pb$collect_labels(dat, msg = dat_tests) res #> name rank A B C labels #> 1 a 1 TRUE FALSE TRUE [incorrect rank]: 1 #> 2 b 1 FALSE FALSE TRUE [missing widget]: b [incorrect rank]: 1 #> 3 c 3 FALSE TRUE TRUE [missing widget]: c #> 4 d 1 TRUE TRUE TRUE #> 5 e 2 TRUE TRUE TRUE #> 6 f 2 FALSE TRUE TRUE [missing widget]: f #> 7 g 3 TRUE FALSE TRUE [incorrect rank]: 3 #> 8 h 2 TRUE TRUE FALSE [something else] #> 9 i 2 TRUE FALSE TRUE [incorrect rank]: 2 #> 10 j 3 FALSE TRUE TRUE [missing widget]: j writeLines(res$labels) #> [incorrect rank]: 1 #> [missing widget]: b [incorrect rank]: 1 #> [missing widget]: c #> #> #> [missing widget]: f #> [incorrect rank]: 3 #> [something else] #> [incorrect rank]: 2 #> [missing widget]: j if (requireNamespace(\"cli\", quietly = TRUE)) { # you can also specify cli to TRUE to format with CLI res <- pb$collect_labels(dat, cli = TRUE, msg = dat_tests) writeLines(res$labels) } #> [incorrect rank]: 1 #> [missing widget]: b [incorrect rank]: 1 #> [missing widget]: c #> #> #> [missing widget]: f #> [incorrect rank]: 3 #> [something else] #> [incorrect rank]: 2 #> [missing widget]: j"},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":null,"dir":"Reference","previous_headings":"","what":"Add labels to div tags in the form of a ","title":"Add labels to div tags in the form of a ","text":"Add labels div tags form \"dtag\" node paired \"label\" attribute.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add labels to div tags in the form of a ","text":"","code":"label_div_tags(body) find_div_tags(body) clear_div_labels(body)"},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add labels to div tags in the form of a ","text":"body xml document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add labels to div tags in the form of a ","text":"label_div_tags(): document, modified clear_div_labels(): document, modified find_div_tags(): node list","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/div_labels.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Add labels to div tags in the form of a ","text":"","code":"txt <- \"# Example with a mix of div tags > PLEASE NEVER DO THE LESSONS THIS WAY > > I AM LITERALLY JUST TESTING A TERRIBLE EXAMPLE. --------------------------------------------------------------------------------
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` :::: solution ```{r} It's not that challenging ``` :::
We just have to try harder and use `
` tags :::::: callout ```{r} cat('better faster stronger with
') ``` :::: :::::: discussion ::::: <\/div> <\/div>
## Good divs <\/div> \" tmp <- tempfile() writeLines(txt, tmp) ex <- tinkr::to_xml(tmp) ex$body #> {xml_document} #> #> [1] \\n Example with a mix of ... #> [2] \\n \\n PLEASE NEVE ... #> [3] #> [4] <div class='challenge'>\\n## Chall ... #> [5] \\n do that challenging thing.<\/te ... #> [6] cat('it might be c ... #> [7] \\n :::: solution<\/text>\\n<\/paragr ... #> [8] It's not that chal ... #> [9] \\n :::<\/text>\\n<\/paragraph> #> [10] <div class='solution'>\\nWe just h ... #> [11] \\n :::::: callout<\/text>\\n<\/parag ... #> [12] cat('better faster ... #> [13] \\n ::::<\/text>\\n \\n ... #> [14] </div>\\n</div>\\n<\/html_block> #> [15] <div class='good'>\\n<\/html_block> #> [16] \\n Good divs<\/text>\\n<\/he ... #> [17] </div>\\n<\/html_block> pegboard:::label_div_tags(ex$body) ex$body #> {xml_document} #> #> [1] \\n Example with a mix of ... #> [2] \\n \\n PLEASE NEVE ... #> [3] #> [4] #> [5] & ... #> [6] \\n [7] \\n do that challenging thing.<\/te ... #> [8] cat('it might be c ... #> [9] #> [10] \\n :::: solution<\/text>\\n<\/paragr ... #> [11] It's not that chal ... #> [12] \\n :::<\/text>\\n<\/paragraph> #> [13] #> [14] #> [15] & ... #> [16] \\n [17] #> [18] \\n :::::: callout<\/text>\\n<\/parag ... #> [19] cat('better faster ... #> [20] #> ... pegboard:::clear_div_labels(ex$body)"},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":null,"dir":"Reference","previous_headings":"","what":"elevate all children of a node — elevate_children","title":"elevate all children of a node — elevate_children","text":"elevate children node","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"elevate all children of a node — elevate_children","text":"","code":"elevate_children(parent, remove = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"elevate all children of a node — elevate_children","text":"parent xml node (notably block quote) remove logical value. TRUE (default), parent node removed document.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"elevate all children of a node — elevate_children","text":"elevated nodes, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/elevate_children.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"elevate all children of a node — elevate_children","text":"","code":"if (FALSE) { # \\dontrun{ scope <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) # get all the challenges (2 blocks) scope$get_blocks(\".challenge\") b1 <- scope$get_blocks(\".challenge\")[[1]] elevate_children(b1) # now there is only one block: scope$get_blocks(\".challenge\") } # }"},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":null,"dir":"Reference","previous_headings":"","what":"Find nodes between two nodes with a given dtag — find_between_tags","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"Find nodes two nodes given dtag","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"","code":"find_between_tags( tag, body, ns = \"pb\", find = \"dtag[@label='{tag}']\", include = FALSE )"},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"tag integer representing unique dtag attribute body xml document ns namespace body find xpath element search (without namespace tag) include TRUE, tags included output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"nodeset tags dtag attribute matching tag","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/find_between_tags.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Find nodes between two nodes with a given dtag — find_between_tags","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$unblock() # removing blockquotes and replacing with div tags # find all the div tags ns <- pegboard:::get_ns(loop$body) tags <- xml2::xml_find_all(loop$body, \".//pb:dtag\", ns) tags <- xml2::xml_attr(tags, \"label\") tags #> [1] \"div-1-challenge\" \"div-2-solution\" \"div-2-solution\" \"div-1-challenge\" #> [5] \"div-3-challenge\" \"div-4-solution\" \"div-4-solution\" \"div-3-challenge\" #> [9] \"div-5-challenge\" \"div-6-solution\" \"div-6-solution\" \"div-5-challenge\" # grab the contents of the first div tag pegboard:::find_between_tags(tags[[1]], loop$body) #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n --- #> title: \"Using RMarkdown\" #> teaching: 10 #> exercises: 2 #> --- #> #> :::::::::::::::::::::::::::::::::::::: questions #> #> - How do you write a lesson using RMarkdown and `{sandpaper}`? #> #> :::::::::::::::::::::::::::::::::::::::::::::::: #> #> ::::::::::::::::::::::::::::::::::::: objectives #> #> - Explain how to use markdown with the new lesson template #> - Demonstrate how to include pieces of code, figures, and nested challenge blocks #> #> :::::::::::::::::::::::::::::::::::::::::::::::: #> #> ```{r cat-child, child=\"files/cat.Rmd\"} #> ``` pb$find_children(intro) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd # this is identical to the `$children` element of an Episode object ep <- Episode$new(fs::path(ex, \"episodes\", \"intro.Rmd\")) ep$children #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd # Loading the child document reveals another child child <- Episode$new(ep$children[[1]]) child$children #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/files/session.Rmd child$show() #> Here is a picture of a kitten: #> #> ![I hope you have a good day](https://placekitten.com/300/300){alt='a random cute kitten'} #> #> ```{r sessionInfo(), child=\"files/session.Rmd\"} #> ``` #> # `trace_children()` ------------------------------------------------------- # In the context of the lesson, we can find all the descendants lsn <- Lesson$new(ex, jekyll = FALSE) pb$trace_children(ep, lsn) #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\" # This is the same as using the method of the same name in the Lesson object # using the path to the episode lsn$trace_lineage(ep$path) #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> [2] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> [3] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd\" # show the children purrr::walk(lsn$children, function(ep) { message(\"----\", ep$path, \"----\") ep$show() } ) #> ----/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd---- #> Here is a picture of a kitten: #> #> ![I hope you have a good day](https://placekitten.com/300/300){alt='a random cute kitten'} #> #> ```{r sessionInfo(), child=\"files/session.Rmd\"} #> ``` #> #> ----/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd---- #>
#> Here is the sesion information for this build<\/summary> #> #> ```{r session-info} #> sessioninfo::session_info() #> ``` #> #> <\/details> #>"},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":null,"dir":"Reference","previous_headings":"","what":"Make paired labels for opening and closing div tags — find_div_pairs","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"Make paired labels opening closing div tags","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"","code":"find_div_pairs(divs, close = div_close_regex())"},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"close regex valid closing tag nodes character vector div open close tags","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"integer vector pairs labels opening closing tag. Note labels produced cumulative sum node depths.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/find_div_pairs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Make paired labels for opening and closing div tags — find_div_pairs","text":"","code":"nodes <- c( \"
\", \"
\" , \"<\/div>\", \"
\", \"
\", \"<\/div>\", \"<\/div>\", \"<\/div>\") pegboard:::find_div_pairs(nodes) #> [1] 1 2 2 3 4 4 3 1"},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":null,"dir":"Reference","previous_headings":"","what":"Find the level of the current node releative to the document — find_node_level","title":"Find the level of the current node releative to the document — find_node_level","text":"Find level current node releative document","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find the level of the current node releative to the document — find_node_level","text":"","code":"find_node_level(node)"},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find the level of the current node releative to the document — find_node_level","text":"node XML node object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/find_node_level.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find the level of the current node releative to the document — find_node_level","text":"number indicating nested current node . 0 represents document , 1 represents child elements document, etc.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Find and fix unresolved template links within an Episode XML body — fix_links","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"Links like [link text]({{ page.root }}/destination.html) parsed correctly commonmark parser output text. Use find missing links transform link image elements.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"","code":"fix_links(body) find_broken_links(body) fix_broken_links(fragments) make_link_patterns(ns = \"md:\") get_link_fragment_nodes(node) fix_broken_link(nodes) links_within_text_regex() text_to_links(txt, ns = NULL, type, sourcepos = NULL) make_link(txt, pattern, type = \"rel_link\") find_between_nodes(a, b, include = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"body XML document. ns namespace object node node determined text representation link destination txt text derived xml2::xml_text() type either \"image\" \"link\". sourcepos defaults NULL. NULL, sourcepos attribute text node(s) applied new nodes. pattern regular expression used splitting link surrounding text.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"fix_links(): modified body find_broken_link(): list element represents fragmented link. Inside element two elements: parent: parent paragraph node link nodes: series four five nodes make link text get_link_fragments(): preceding three four nodes, text link alt text image. text_to_links(): ns NULL: character vector XML text nodes, otherwise, new XML text nodes. get_link_fragments(): preceding three four nodes, text link alt text image.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"find_broken_links() uses pattern generated make_link_patterns() search potential links. fix_broken_links() uses output find_broken_links() replace node fragments links. make_link_patterns() generator create XPath query search liquid markup following closing bracket. get_link_fragment_nodes(): Get source link node fragments fix_broken_link() takes set nodes comprises single link recomposes link image node. links_within_text_regex(): finding different types links within markdown text can challenging involves characters used regex grouping character classes. general, want two things text get back document: split links text identify parts resulting vector links. way, can convert links links text text. text_to_links(): Splits links away text returns nodeset insert make_link(): makes link depending link type","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"motivation","dir":"Reference","previous_headings":"","what":"Motivation","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"Jekyll implements liquid template language, can break syntax expected commonmark. syntax appears link context, link rendred text. Carpentries Lessons created 2023 use Jekyll templating embedded many links. order convert pre-workbench lesson use Workbench, need make sure links accurately represented avoid invalid syntax broken links sneaking lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"implementation-details","dir":"Reference","previous_headings":"","what":"Implementation Details","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"example, valid line link looks like [Home](index.html) text appear XML : However, link uses liquid templating variable : [Home]({{ page.root }}/index.html) text, appear XML Note: nodes asis elements tinkr protecting square brackets. run fix_links(), nodes collapsed link: can transform link replace liquid templating something makes sense sandpaper.","code":"... Home<\/link> and other text<\/text> ... ... [<\/text> Home<\/text> ]<\/text> ({{ page.root }}/index.html) and other text<\/text> ... ... Home<\/link> and other text<\/text> ..."},{"path":"https://carpentries.github.io/pegboard/reference/fix_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Find and fix unresolved template links within an Episode XML body — fix_links","text":"","code":"loop <- fs::path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") e <- Episode$new(loop, fix_links = FALSE) e$links # five links #> {xml_nodeset (5)} #> [1] [2] [3] [4] [5] {xml_nodeset (4)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... # fix_links() --------------------------------------------------------------- e$body <- asNamespace(\"pegboard\")$fix_links(e$body) e$links # eight links #> {xml_nodeset (8)} #> [1] [2] [3] [4] [5] [6] \\ ... #> [7] [8] {xml_nodeset (5)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... #> [3] [4] \\ ... #> [5] .//md:text[@asis][text()=']']/following-sibling::md:text[(contains(text(), '({{') and contains(text(), '}}'))] # links_within_text_regex() ------------------------------------------------- helpers <- pegboard:::links_within_text_regex() helpers #> to_split #> \"(? find_links #> \"(? res #> 1 text ![image text](a.png #> 2 with #> 3 a link](b.org #> 4 and text grepl(helpers[\"find_links\"], res, perl = TRUE) #> [1] TRUE FALSE TRUE FALSE # text_to_links() ----------------------------------------------------------- txt <- \"Some text [and _a link_]({{ page.root }}/link.to#thing), some other text.\" pegboard:::text_to_links(txt, type = \"link\") #> [1] \"Some text <\/text>\" #> [2] \"and _a link_<\/text><\/link>\" #> [3] \", \\nsome other text.<\/text>\" md <- c(md = \"http://commonmark.org/xml/1.0\") class(md) <- \"xml_namespace\" pegboard:::text_to_links(txt, md, \"link\") #> {xml_nodeset (3)} #> [1] Some text <\/text> #> [2] \\n and _a link_< ... #> [3] , \\nsome other text.<\/text>"},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":null,"dir":"Reference","previous_headings":"","what":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"Liquid syntax wraps variables double moustache braces may may spaces within moustaches. example, get link page root, use page.root make readable. However, violates expectation commonmark parser makes think “oh, just ordinary text”.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"","code":"fix_liquid_relative_link(path, encoding = \"UTF-8\")"},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"path path MD file encoding encoding text, defaults UTF-8","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_liquid_relative_link.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Remove spaces in relative links with liquid variables — fix_liquid_relative_link","text":"function fixes issue removing spaces within braces.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"function perform transformation three node types:","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"","code":"fix_sandpaper_links(body, yml = list(), path = NULL, known = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"body XML document yml list key/value pairs derived _config.yml file path path current episode known character vector known episodes lesson, relative lesson root.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"body, invisibly","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"image link html_node transformation remove relative paths (\"../\") replace Jekyll templating (e.g. \" page.root \" \" site.swc_pages \" either nothing link software carpentry, respectively.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"absolutely comprehensive links fail converted. happens, please report issue: https://github.com/carpentries/pegboard/issues/new/","code":""},{"path":"https://carpentries.github.io/pegboard/reference/fix_sandpaper_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Fix relative and jekyll links to be compatible with sandpaper — fix_sandpaper_links","text":"","code":"loop <- fs::path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") e <- Episode$new(loop) pegboard:::make_link_table(e)$orig #> [1] \"https://docs.python.org/3/library/glob.html#glob.glob\" #> [2] \"https://docs.python.org/3/library/glob.html\" #> [3] \"https://docs.python.org/3/library/glob.html\" #> [4] \"https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html\" #> [5] \"https://docs.python.org/3/library/stdtypes.html#str.split\" #> [6] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [7] \"../no-workie.svg\" #> [8] \"{{ page.root }}/index.html\" #> [9] \"{{ site.swc_pages }}/shell-novice\" #> [10] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [11] \"../no-workie.svg\" #> [12] \"{{ page.root }}/no-workie.svg\" #> [13] \"{{ page.root }}{% link index.md %}\" e$use_sandpaper() pegboard:::make_link_table(e)$orig #> [1] \"https://docs.python.org/3/library/glob.html#glob.glob\" #> [2] \"https://docs.python.org/3/library/glob.html\" #> [3] \"https://docs.python.org/3/library/glob.html\" #> [4] \"https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html\" #> [5] \"https://docs.python.org/3/library/stdtypes.html#str.split\" #> [6] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [7] \"no-workie.svg\" #> [8] \"index.html\" #> [9] \"https://swcarpentry.github.io/shell-novice\" #> [10] \"https://carpentries.org/assets/img/TheCarpentries.svg\" #> [11] \"no-workie.svg\" #> [12] \"no-workie.svg\" #> [13] \"index.md\""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":null,"dir":"Reference","previous_headings":"","what":"Gather blocks from the XML body of a carpentries lesson — get_blocks","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"search XML document block_quotes specified type level extract nodeset.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"","code":"get_blocks(body, type = NULL, level = 0)"},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"body XML body carpentries lesson (xml2 object) type type block quote Jekyll syntax like \".challenge\", \".discussion\", \".solution\" level level block within document. Defaults 1, represents block_quotes nested within block quotes. Increase nubmer increase level nesting.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"xml nodeset object element representing blockquote matched input criteria.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"moment, blocks returned specified level. select type = \".solution\", level = 1, receive blocks contain solution blocks even though blocks almost always nested within blocks.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_blocks.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Gather blocks from the XML body of a carpentries lesson — get_blocks","text":"","code":"frg <- Lesson$new(lesson_fragment()) # Find all the blocks in the get_blocks(frg$episodes[[\"17-scope.md\"]]$body) #> {xml_nodeset (2)} #> [1] \\n [2] \\n {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n loop$reset() get_challenges(loop$use_dovetail()$unblock()$body, \"chunk\") #> {xml_nodeset (3)} #> [1] [2] [3] \".","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get code blocks from xml document — get_code","text":"xml nodeset object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get code blocks from xml document — get_code","text":"uses XPath function fn:starts-() search code block automatically includes opening brace, regular expressions allowed. used $code, $output, $error elements Episode class.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_code.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get code blocks from xml document — get_code","text":"","code":"e <- Episode$new(fs::path(lesson_fragment(), \"_episodes\", \"17-scope.md\")) get_code(e$body) #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (1)} #> [1] {xml_nodeset (2)} #> [1] [2] elements containing div tags grab first tag pair filter div tag class (type) grab elements tags","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/get_divs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get paired div blocks — get_divs","text":"","code":"loop <- Episode$new(file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\")) loop$body # a full document with block quotes and code blocks, etc #> {xml_document} #> #> [1] \\n [2] \\n [3] [4] [5] \\n [6] \\n [7] [8] [9] [10] [11] \\n [12] \\n [13] [14] [15] \\n [16] \\n [17] \\n [18] \\n [19] \\n [20] <img src=\"h ... #> ... loop$unblock() # removing blockquotes and replacing with div tags pegboard:::get_divs(loop$body, 'challenge') # all challenge blocks #> $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n pegboard:::get_divs(loop$body, 'solution') # all solution blocks #> $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n "},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":null,"dir":"Reference","previous_headings":"","what":"Get images from an Episode/yarn object — get_images","title":"Get images from an Episode/yarn object — get_images","text":"Get images Episode/yarn object","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get images from an Episode/yarn object — get_images","text":"","code":"get_images(yrn, process = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get images from an Episode/yarn object — get_images","text":"yrn Episode/yarn object process TRUE (default), images processed via process_images() add alt attribute extract images HTML blocks. FALSE present nodes found XPath search.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get images from an Episode/yarn object — get_images","text":"xml_nodelist","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get images from an Episode/yarn object — get_images","text":"Markdown users can write images either markdown HTML. write images HTML, commonmark XML parser recognises generic \"HTML blocks\" found just searching .//md:image. function searches md:html_block md:html_inline image content can extract downstream analysis.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/get_images.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get images from an Episode/yarn object — get_images","text":"","code":"tmp <- tempfile() on.exit(unlink(tmp)) txt <- ' ![a kitten](https://placekitten.com/200/200){alt=\"a pretty kitten\"} an inline html image of a kitten ' writeLines(txt, tmp) ep <- Episode$new(tmp) ep$show() #> ![a kitten](https://placekitten.com/200/200){alt=\"a pretty kitten\"} #> #> #> #> #> #> an inline html image of a kitten #> # without process = TRUE, images in HTML elements are not converted ep$get_images() #> {xml_nodeset (3)} #> [1] [2] <img src=\"https: ... #> [3] <img src=\"http ... # setting process = TRUE will extract the HTML elements for analysis # (e.g to detect alt text) ep$get_images(process = TRUE) #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n loop$reset() get_solutions(loop$use_dovetail()$unblock()$body, \"chunk\") #> {xml_nodeset (3)} #> [1] [2] [3] [1] 1 2 2 1 x <- c(\"(\", \"(\", \")\", \"(\", \"(\", \")\", \")\", \")\") pegboard:::label_pairs(x, 4) #> [1] 1 2 2 3 4 4 3 1"},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":null,"dir":"Reference","previous_headings":"","what":"Example Lesson Fragments — lesson_fragment","title":"Example Lesson Fragments — lesson_fragment","text":"Partial lessons mainly used testing demonstration purposes","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Example Lesson Fragments — lesson_fragment","text":"","code":"lesson_fragment(name = \"lesson-fragment\")"},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Example Lesson Fragments — lesson_fragment","text":"name name lesson fragment. Can one : lesson-fragment rmd-lesson sandpaper-fragment sandpaper-fragment child","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Example Lesson Fragments — lesson_fragment","text":"path lesson fragment whose contents : lesson-fragment contains one _episodes directory three files: \"10-lunch.md\", \"14-looping-data-sets.md\", \"17-scope.md\" rmd-fragment contains one episode _episodes_rmd called 01-test.Rmd. sandpaper-fragment contains trimmed-Workbench lesson R Markdown content pre-built sandpaper-fragment--child contains much content sandpaper-fragment, episodes/index.Rmd file references child documents.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Example Lesson Fragments — lesson_fragment","text":"lesson-fragment example taken python novice gapminder lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/lesson_fragment.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Example Lesson Fragments — lesson_fragment","text":"","code":"lesson_fragment() #> [1] \"/home/runner/work/_temp/Library/pegboard/lesson-fragment\" lesson_fragment(\"rmd-lesson\") #> [1] \"/home/runner/work/_temp/Library/pegboard/rmd-lesson\" lesson_fragment(\"sandpaper-fragment\") #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment\" lesson_fragment(\"sandpaper-fragment-with-child\") #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child\""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"Liquid code blocks generally codified ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"","code":"liquid_to_commonmark(block, make_rmd = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"block code block make_rmd TRUE, language wrapped curly braces evaluated RMarkdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"node, invisibly.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":": .language-python However, simpler syntax can use: take code block convert longer use liquid tag (added \"ktag\" attribute \"kramdown\" tag)","code":"print(\"code goes \" + \"here\") print(\"code goes \" + \"here\")"},{"path":"https://carpentries.github.io/pegboard/reference/liquid_to_commonmark.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert liquid code blocks to commonmark code blocks — liquid_to_commonmark","text":"","code":"frg1 <- Lesson$new(lesson_fragment()) frg2 <- frg1$clone(deep = TRUE) py1 <- get_code(frg1$episodes[[\"17-scope.md\"]]$body, \".language\") py2 <- get_code(frg2$episodes[[\"17-scope.md\"]]$body, \".language\") py1 #> {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] [2] [3] {xml_nodeset (3)} #> [1] [2] [3] [1] TRUE purrr::map2(children, lsn$children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] FALSE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] FALSE #> # read children takes in a list of children episodes and appends that list # with the descendants # given a full list of children, it will return the same list these_children <- pb$read_children(lsn$episodes[[1]], children) purrr::map2(these_children, children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] TRUE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] TRUE #> # given a partial list, it will append to it new_children <- pb$read_children(lsn$episodes[[1]], children[1]) purrr::map2(new_children, children, identical) #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd` #> [1] TRUE #> #> $`/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/session.Rmd` #> [1] FALSE #>"},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":null,"dir":"Reference","previous_headings":"","what":"Create an xml document that contains two html_block elements that contain div tags. — make_div","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"Create xml document contains two html_block elements contain div tags.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"","code":"make_div(what, fenced = TRUE)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"class block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"xml document commonmark namespace","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/make_div.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create an xml document that contains two html_block elements that contain div tags. — make_div","text":"","code":"cha <- pegboard:::make_div(\"challenge\") cha #> {xml_document} #> #> [1] \\n ::::::::::::::::::::::::::::::: ... #> [2] \\n ::::::::::::::::::::::::::::::: ... cat(pegboard:::xml_to_md(cha)) #> :::::::::::::::::::::::::::::::::::::::: challenge #> #> ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a data frame describing the divs associated with nodes. — make_div_pairs","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"Native fenced divs may several tags grouped single element. order mark pairs, need account tags exist nodes. function creates ","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"","code":"make_div_pairs(nodes, path = NULL, yaml = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"nodes nodelist containing native div fenced div tags html_block paragraphs.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"list data frames node following columns: node: numeric index node div: text individual div element, stripped context label: label div pair (div-label-class) pos: position label relative associated node","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/make_div_pairs.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a data frame describing the divs associated with nodes. — make_div_pairs","text":"","code":"txt <- \"# Example with a mix of div tags > PLEASE NEVER DO THE LESSONS THIS WAY > > I AM LITERALLY JUST TESTING A TERRIBLE EXAMPLE. --------------------------------------------------------------------------------
## Challenge do that challenging thing. ```{r} cat('it might be challenging to do this') ``` :::: solution ```{r} It's not that challenging ``` :::
We just have to try harder and use `
` tags :::::: callout ```{r} cat('better faster stronger with
') ``` :::: :::::: discussion ::::: <\/div> <\/div>
## Good divs <\/div> \" tmp <- tempfile() writeLines(txt, tmp) ex <- tinkr::to_xml(tmp) pegboard:::clean_div_tags(ex$body) #> [1] TRUE nodes <- pegboard:::find_div_tags(ex$body) divs <- pegboard:::make_div_pairs(nodes) do.call(\"rbind\", divs) #> node div line label pos #> 1 1
NA div-1-challenge before #> 2 2 :::: solution NA div-2-solution before #> 3 3 ::: NA div-2-solution after #> 4 4
NA div-3-solution before #> 5 5 :::::: callout NA div-4-callout before #> 6.6 6 :::: NA div-4-callout after #> 6.7 6 :::::: discussion NA div-5-discussion before #> 6.8 6 ::::: NA div-5-discussion after #> 7 7 <\/div> NA div-3-solution after #> 8 8 <\/div> NA div-1-challenge after #> 9 9
NA div-6-good before #> 10 10 <\/div> NA div-6-good after"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a table of divs in an episode — make_div_table","title":"Create a table of divs in an episode — make_div_table","text":"Create table divs episode","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a table of divs in an episode — make_div_table","text":"","code":"make_div_table(yrn)"},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a table of divs in an episode — make_div_table","text":"yrn tinkr::yarn Episode object.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_div_table.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a table of divs in an episode — make_div_table","text":"data frame following columns: path: path file, relative lesson div: type div pb_label: label div line: line number div label","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a table for headings — make_heading_table","title":"Create a table for headings — make_heading_table","text":"Create table headings","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a table for headings — make_heading_table","text":"","code":"make_heading_table(headings, offset = 5L)"},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a table for headings — make_heading_table","text":"headings xml_nodeset object text \"level\" attributes offest offset yaml header (artifact tinkr), defaults 5L, two fences plus title, teaching, exercises.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a table for headings — make_heading_table","text":"data frame three columns: heading text heading level heading level pos position heading document node node containing heading","code":""},{"path":"https://carpentries.github.io/pegboard/reference/make_heading_table.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a table for headings — make_heading_table","text":"","code":"path <- file.path(lesson_fragment(), \"_episodes\", \"14-looping-data-sets.md\") loop <- Episode$new(path) pegboard:::make_heading_table(loop$headings, offset = length(loop$yaml)) #> heading level pos #> 1 Use a for loop to process files given a list of their names. 2 17 #> 2 Use glob.glob to find sets of files whose names match a pattern. 2 51 #> 3 Use glob and for to process batches of files. 2 84 #> 4 Determining Matches 2 110 #> 5 Solution 2 119 #> 6 Minimum File Size 2 125 #> 7 Solution 2 143 #> 8 Comparing Data 2 157 #> 9 Solution 2 162 #> 10 ZNK test links and images 3 187 #> node #> 1 2 3 4 5 6 7 8 9 10 scheme server port user #> 1 https docs.python.org NA #> 2 https docs.python.org NA #> 3 https docs.python.org NA #> 4 https pandas.pydata.org NA #> 5 https docs.python.org NA #> 9 https carpentries.org NA #> 10 NA #> 6 22010 #> 7 2122065360 #> 11 https carpentries.org NA #> 12 NA #> 13 -2132804248 #> 8 22010 #> path query #> 1 /3/library/glob.html #> 2 /3/library/glob.html #> 3 /3/library/glob.html #> 4 /pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 /3/library/stdtypes.html #> 9 /assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 #> 7 #> 11 /assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 #> 8 #> fragment #> 1 glob.glob #> 2 #> 3 #> 4 #> 5 str.split #> 9 #> 10 #> 6 #> 7 #> 11 #> 12 #> 13 #> 8 #> orig #> 1 https://docs.python.org/3/library/glob.html#glob.glob #> 2 https://docs.python.org/3/library/glob.html #> 3 https://docs.python.org/3/library/glob.html #> 4 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 https://docs.python.org/3/library/stdtypes.html#str.split #> 9 https://carpentries.org/assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 {{ page.root }}/index.html #> 7 {{ site.swc_pages }}/shell-novice #> 11 https://carpentries.org/assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 {{ page.root }}/no-workie.svg #> 8 {{ page.root }}{% link index.md %} #> text alt title type #> 1 glob.glob link #> 2 glob link #> 3 glob link #> 4 shape method link #> 5 split link #> 9 books as clubs img #> 10 books as clubs img #> 6 Home link #> 7 shell link #> 11 Carpentries logo image #> 12 Non-working image image #> 13 Non-working image with jekyll syntax image #> 8 link that isn't parsed correctly by commonmark link #> rel anchor sourcepos filepath parents node #> 1 FALSE 51 _episodes/14-looping-data-sets.md 2 FALSE 57 _episodes/14-looping-data-sets.md 3 FALSE 58 _episodes/14-looping-data-sets.md 4 FALSE 140 _episodes/14-looping-data-sets.md 5 FALSE 163 _episodes/14-looping-data-sets.md 9 FALSE 189 _episodes/14-looping-data-sets.md 10 FALSE 191 _episodes/14-looping-data-sets.md 6 FALSE 193 _episodes/14-looping-data-sets.md 7 FALSE 193 _episodes/14-looping-data-sets.md 11 FALSE 195 _episodes/14-looping-data-sets.md 12 FALSE 197 _episodes/14-looping-data-sets.md 13 FALSE 199 _episodes/14-looping-data-sets.md 8 FALSE 201 _episodes/14-looping-data-sets.md {xml_nodeset (2)} #> [1] <img src=\"ht ... #> [2] <img src=\".. ... lop$get_blocks(level = 1) #> {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (3)} #> [1] \\n [2] \\n [3] \\n {xml_nodeset (0)} # add tags pegboard:::label_div_tags(lop$body) lop$get_divs() #> $`div-1-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] \\n [9] \\n #> $`div-2-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] \\n [4] \\n #> $`div-3-challenge` #> {xml_nodeset (10)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n [6] \\n [7] \\n [8] [9] \\n [10] \\n #> $`div-4-solution` #> {xml_nodeset (4)} #> [1] \\n [2] \\n [3] [4] \\n #> $`div-5-challenge` #> {xml_nodeset (9)} #> [1] \\n [2] \\n [3] \\n [4] \\n [5] \\n [6] \\n [7] [8] \\n [9] \\n #> $`div-6-solution` #> {xml_nodeset (5)} #> [1] \\n [2] \\n [3] \\n [4] [5] \\n xml2::xml_text(lop$get_divs()[[1]]) #> [1] \"::::::::::::::::::::::::::::::::::::::: challenge\" #> [2] \"Determining Matches\" #> [3] \"Which of these files is not matched by the expression glob.glob('data/*as*.csv')?\" #> [4] \"data/gapminder_gdp_africa.csvdata/gapminder_gdp_americas.csvdata/gapminder_gdp_asia.csv1 and 2 are not matched.\" #> [5] \"::::::::::::::: solution\" #> [6] \"Solution\" #> [7] \"1 is not matched by the glob.\" #> [8] \":::::::::::::::::::::::::\" #> [9] \"::::::::::::::::::::::::::::::::::::::::::::::::::\""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":null,"dir":"Reference","previous_headings":"","what":"Set the alt text for a nodeset of images — set_alt_attr","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"finds attribute curly braces image declaration, extracts alt text, adds attribute image, useful parsing XML, affect rendering.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"","code":"set_alt_attr(images, xpath, ns)"},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"images nodeset images xpath XPath expression finds first curly brace immediately node. ns namespace XML","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"nodeset, invisibly.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_alt_attr.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Set the alt text for a nodeset of images — set_alt_attr","text":"function assumes images entering curly brace following.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":null,"dir":"Reference","previous_headings":"","what":"add the kramdown tags as attributes of special blocks — set_ktag_block","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"add kramdown tags attributes special blocks","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"","code":"set_ktag_block(tags)"},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"tags tags function kramdown_tags()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/set_ktag_block.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"add the kramdown tags as attributes of special blocks — set_ktag_block","text":"Kramdown bit weird uses tags trail elements like code blocks block quotes. follow block quotes, commonmark parse part block quote. problematic per-se run common situation Carpentries' curriculum: nested block quotes parsed commonmark, three tags end parsed part 2nd-level block quote: function take block quote elements add \"ktag\" attribute represents value tag. parsed xslt style sheet tags properly appended.","code":"> # Challenge 1 > > Some text here > > > # Solution 1 > > > > ~~~ > > print(\"hello world!\") > > ~~~ > > {: .language-pyton} > {: .solution} {: .challenge} ... > > ~~~ > > {: .language-pyton} > > {: .solution} > > {: .challenge}"},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":null,"dir":"Reference","previous_headings":"","what":"Test for the existence of a file — test_file_existence","title":"Test for the existence of a file — test_file_existence","text":"Test existence file","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Test for the existence of a file — test_file_existence","text":"","code":"test_file_existence(paths, home)"},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Test for the existence of a file — test_file_existence","text":"paths relative paths tested home root directory paths","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Test for the existence of a file — test_file_existence","text":"logical vector length paths indicating file exists _anywhere lesson infrastructure","code":""},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Test for the existence of a file — test_file_existence","text":"function detects existence files relative current folder taking account references built site. understand needed consider Workbench Jekyll takes contents source folders pools flat file structure website. , possible write links like [link](resource.html) [link](../learners/resource.md) continue valid.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/test_file_existence.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Test for the existence of a file — test_file_existence","text":"","code":"pb <- asNamespace(\"pegboard\") # Example: validation of links in a sandpaper context ----------------------- fs::dir_tree(lesson_fragment(\"sandpaper-fragment\")) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment #> ├── config.yaml #> ├── episodes #> │ ├── intro.Rmd #> │ └── nope.md #> ├── index.md #> ├── instructors #> │ └── a.md #> ├── learners #> │ └── setup.md #> ├── profiles #> │ └── b.md #> └── site #> ├── DESCRIPTION #> ├── README.md #> ├── _pkgdown.yaml #> └── built #> ├── a.md #> ├── b.md #> ├── config.yaml #> ├── fig #> │ └── intro-rendered-pyramid-1.png #> ├── index.md #> ├── intro.md #> ├── md5sum.txt #> └── setup.md links <- c( \"../episodes/fig/missing.png\", # does not exist \"../index.md\", # exists \"../instructors/a.md\", # exists \"../episodes/intro.Rmd\", # exists \"setup.md\", # exists \"intro.html\" # exists ) home <- fs::path(lesson_fragment(\"sandpaper-fragment\"), \"learners\") # show the resulting vector with our paths relative to the \"learners\" folder setNames(pb$test_file_existence(links, home), links) #> ../episodes/fig/missing.png ../index.md #> FALSE TRUE #> ../instructors/a.md ../episodes/intro.Rmd #> TRUE TRUE #> setup.md intro.html #> TRUE TRUE # Example: validation of links in a sandpaper context with children --------- # in this context, the references must be relative to the _parent_ file # for this example, the home folder is the parent of the child, which is # obtained from the `$build_parent` element in the child file. To demonstrate # this, I will first load the lesson context <- lesson_fragment(\"sandpaper-fragment-with-child\") lsn <- Lesson$new(context, jekyll = FALSE) fs::dir_tree(context) #> /home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child #> ├── config.yaml #> ├── episodes #> │ ├── files #> │ │ ├── cat.Rmd #> │ │ └── session.Rmd #> │ ├── intro.Rmd #> │ └── nope.md #> ├── index.md #> ├── instructors #> │ └── a.md #> ├── learners #> │ └── setup.md #> ├── profiles #> │ └── b.md #> └── site #> ├── DESCRIPTION #> ├── README.md #> ├── _pkgdown.yaml #> └── built #> ├── a.md #> ├── b.md #> ├── config.yaml #> ├── fig #> │ └── intro-rendered-pyramid-1.png #> ├── index.md #> ├── intro.md #> ├── md5sum.txt #> └── setup.md links <- c( \"../episodes/fig/missing.png\", # does not exist \"../index.md\", # exists \"../instructors/a.md\", # exists \"intro.Rmd\", # exists \"../learners/setup.md\", # does not exist \"intro.html\" # exists ) # in practice, we check that the episode has parents: lsn$episodes[[1]]$has_parents # episodes do not have parents #> [1] FALSE lsn$children[[2]]$has_parents # but children do! #> [1] TRUE # The \"home\" path in the context of a child document is the _build parent_, # which is the parent that will eventually contain the output of the child. # in the case of this lesson, both child files are used in the intro.Rmd, # even though `cat.Rmd` is the parent of `session.Rmd` setNames(lsn$get(\"parents\", \"children\"), fs::path_file(names(lsn$children))) #> $cat.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> #> $session.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/files/cat.Rmd\" #> # They both show that `intro.Rmd` is the build parent setNames(lsn$get(\"build_parents\", \"children\"), fs::path_file(names(lsn$children))) #> $cat.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> #> $session.Rmd #> [1] \"/home/runner/work/_temp/Library/pegboard/sandpaper-fragment-with-child/episodes/intro.Rmd\" #> # show the links as if they existed in the `session.Rmd` file home <- lsn$children[[2]]$build_parents setNames(pb$test_file_existence(links, home), links) #> ../episodes/fig/missing.png ../index.md #> FALSE TRUE #> ../instructors/a.md intro.Rmd #> TRUE TRUE #> ../learners/setup.md intro.html #> TRUE TRUE # Example: validation of links in a Jekyll context -------------------------- fs::dir_tree(lesson_fragment()) #> /home/runner/work/_temp/Library/pegboard/lesson-fragment #> ├── _config.yml #> └── _episodes #> ├── 10-lunch.md #> ├── 12-for-loops.md #> ├── 14-looping-data-sets.md #> └── 17-scope.md links <- c( \"../non-existent.md\", # does not exist \"../_config.yml\", # exists \"../_episodes/10-lunch.md\", # exists \"10-lunch.html\" # exists in built site ) # set the home folder to be the \"_extras\" folder home <- fs::path(lesson_fragment(), \"_extras\") # show the resulting vector with our paths setNames(pb$test_file_existence(links, home), links) #> ../non-existent.md ../_config.yml ../_episodes/10-lunch.md #> FALSE TRUE TRUE #> 10-lunch.html #> TRUE"},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":null,"dir":"Reference","previous_headings":"","what":"Throw a validation report as a single message — throw_heading_warnings","title":"Throw a validation report as a single message — throw_heading_warnings","text":"Collapse variable number validation reports single message can formatted CLI GitHub.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Throw a validation report as a single message — throw_heading_warnings","text":"","code":"throw_heading_warnings(VAL) throw_div_warnings(VAL) throw_link_warnings(VAL)"},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Throw a validation report as a single message — throw_heading_warnings","text":"VAL [data.frame] validation report derived one validate functions.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Throw a validation report as a single message — throw_heading_warnings","text":"NULL, invisibly. used side-effect formatting issuing messages via issue_warning().","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Throw a validation report as a single message — throw_heading_warnings","text":"One key features pegboard ability parse validate markdown elements. functions provide standard way creating reports user based whether CLI GitHub. prerequisites functions input data frame (generated actual validation function) internal set known templating vectors contain templates test show actual error along general information can help correct error (see ).","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"input-data-frame","dir":"Reference","previous_headings":"","what":"Input Data Frame","title":"Throw a validation report as a single message — throw_heading_warnings","text":"validations initially reported data frame following properties: one row per element columns indicate parsed attributes element, source file, source position, actual element XML node object. boolean columns indicate tests element, used collect_labels() add \"labels\" column data.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"templating-vectors","dir":"Reference","previous_headings":"","what":"Templating vectors","title":"Throw a validation report as a single message — throw_heading_warnings","text":"vectors come two forms [thing]_tests [thing]_info (e.g. validate_links(), link_tests link_info). named vectors match boolean columns data frame produced validation function. [thing]_tests vector contains templates describes error shows text caused error. [thing]_info contains general information address particular error. example, one common link error link descriptive (e.g. link text says \"click \"). column VAL data frame contains result test called \"descriptive\", look values link info tests vectors: throw_*_warnings() functions detect errors, use info tests vectors construct composite message.","code":"link_info[\"descriptive\"] #> descriptive #> \"Avoid uninformative link phrases \" link_tests[\"descriptive\"] #> descriptive #> \"[uninformative link text]: [{text}]({orig})\""},{"path":"https://carpentries.github.io/pegboard/reference/throw_warnings.html","id":"process","dir":"Reference","previous_headings":"","what":"Process","title":"Throw a validation report as a single message — throw_heading_warnings","text":"throw_*_warnings() functions basic procedure (indeed consolidated single function future) pass data collect_labels(), parse [thing]_tests templating vector label failing element VAL appropriate failure message gather source information failure pass failures [thing]_info elements matched unique failures issue_warning()","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert a given block quote to dovetail template — to_dovetail","title":"Convert a given block quote to dovetail template — to_dovetail","text":"dovetail package allows people write block quotes code blocks formatted roxygen2 syntax. internal function takes block quote element, elevates child elements, converts block quote code block uses custom xslt stylesheet render children block roxygen-formatted text code.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert a given block quote to dovetail template — to_dovetail","text":"","code":"to_dovetail(block, token = \"#'\")"},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert a given block quote to dovetail template — to_dovetail","text":"block block quote element token token use indicate markdown text code","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert a given block quote to dovetail template — to_dovetail","text":"block, converted code block","code":""},{"path":"https://carpentries.github.io/pegboard/reference/to_dovetail.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert a given block quote to dovetail template — to_dovetail","text":"","code":"if (FALSE) { # \\dontrun{ frg <- Lesson$new(lesson_fragment()) blo <- frg$episodes$`14-looping-data-sets.md`$get_blocks()[[2]] to_dovetail(blo) cat(xml2::xml_text(blo)) } # }"},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":null,"dir":"Reference","previous_headings":"","what":"Trim div fences from output — trim_fence","title":"Trim div fences from output — trim_fence","text":"Trim div fences output","code":""},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Trim div fences from output — trim_fence","text":"","code":"trim_fence(nodes)"},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Trim div fences from output — trim_fence","text":"nodes xml_nodeset whose first last node div fences","code":""},{"path":"https://carpentries.github.io/pegboard/reference/trim_fence.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Trim div fences from output — trim_fence","text":"nodeset without div fences","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"Convert Jekyll-based lesson sandpaper-based lesson","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"","code":"use_sandpaper(body, rmd = TRUE, yml = list(), path = NULL, known_paths = NULL)"},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"body xml body episode rmd TRUE, chunks converted RMarkdown chunks yml list derived _config.yml file defines site variables. path path source body. Defaults NULL. used conjunction known_paths known_paths character vector known paths lesson. used determine correct path files lesson.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"body","code":""},{"path":"https://carpentries.github.io/pegboard/reference/use_sandpaper.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Convert a Jekyll-based lesson to a sandpaper-based lesson — use_sandpaper","text":"Jekyll episode littered kramdown inline attribute tags liquid-formatted links. Converting sandpaper means following: links using liquid formatting (e.g. [text]({{ site.path }}/01-episode/) replaced relative counterparts ([text](01-episode.md). include statements links.md base_path.md removed image attributes kramdown : removed code blocks kramdown inline attribute tag converted commonmark via internal liquid_to_commonmark(). Lesson template-specific code removed setup chunk R Markdown files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate Callout Blocks for sandpaper episodes — validate_divs","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"Carpentries Workbench uses pandoc fenced divs create special blocks within lesson learners instructors provide breaks narrative flow focus specific tasks caveats. fenced divs look something like :","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"","code":"validate_divs(yrn) div_is_known(div_table) KNOWN_DIVS div_tests div_info"},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"object class character length 16. object class character length 1. object class character length 1.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"yrn tinkr::yarn Episode object. div_table data frame derived make_div_table()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"data frame following columns: div: type div label: label div line: line number div label is_known: logical value div known type (TRUE) (FALSE)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_divs.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Validate Callout Blocks for sandpaper episodes — validate_divs","text":"Lessons created Carpentries Workbench expected following fenced divs: objectives (top) questions (top) keypoints (bottom) following fenced divs can occur lesson, required: prereq callout caution challenge solution (nested inside challenge) hint (nested inside challenge) discussion checklist testimonial tab (can contain text, images, code blocks) group-tab (can contain text, images, code blocks) div names produce structure resulting DOM, special visual styling.","code":"::: callout ### Hello! This is a callout block :::"},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate headings — validate_headings","title":"Validate headings — validate_headings","text":"validate following aspects headings:","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate headings — validate_headings","text":"","code":"validate_headings(headings, title = NULL, offset = 5L) heading_tests heading_info headings_first_heading_is_second_level(VAL) headings_greater_than_first_level(VAL) headings_are_sequential(VAL) headings_have_names(VAL) headings_are_unique(VAL)"},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate headings — validate_headings","text":"object class character length 5. object class character length 5.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate headings — validate_headings","text":"headings object xml_nodelist. title title document offset number lines offset position (equal size yaml header). VAL data frame contains results make_heading_table() logical columns match name test.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate headings — validate_headings","text":"list two elements: data frame contains results make_heading_table() logical columns test FALSE indicates failed test given heading. data frame can printed tree show_heading_tree()","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Validate headings — validate_headings","text":"first heading starts level 2 (first_heading_is_second_level) greater level 1 (all_are_greater_than_first_level) increse sequentially (e.g. jumps 2 4) (all_are_sequential) names (all_have_names) unique hierarchy (all_are_unique)","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Validate headings — validate_headings","text":"internal function implemented Episode Lesson classes.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_headings.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Validate headings — validate_headings","text":"","code":"l <- Lesson$new(lesson_fragment()) e <- l$episodes[[3]] # Our headings validators run a series of tests on headings and return a data # frame with information about the headings along with the results of the # tests v <- pegboard:::validate_headings(e$headings, e$get_yaml()$title, length(e$yaml)) names(v) #> [1] \"results\" \"tree\" v$results #> heading level pos #> 1 Use a for loop to process files given a list of their names. 2 17 #> 2 Use glob.glob to find sets of files whose names match a pattern. 2 51 #> 3 Use glob and for to process batches of files. 2 84 #> 4 Determining Matches 2 110 #> 5 Solution 2 119 #> 6 Minimum File Size 2 125 #> 7 Solution 2 143 #> 8 Comparing Data 2 157 #> 9 Solution 2 162 #> 10 ZNK test links and images 3 187 #> node first_heading_is_second_level greater_than_first_level #> 1 2 3 4 5 6 7 8 9 10 are_sequential have_names are_unique #> 1 TRUE TRUE TRUE #> 2 TRUE TRUE TRUE #> 3 TRUE TRUE TRUE #> 4 TRUE TRUE TRUE #> 5 TRUE TRUE FALSE #> 6 TRUE TRUE TRUE #> 7 TRUE TRUE FALSE #> 8 TRUE TRUE TRUE #> 9 TRUE TRUE FALSE #> 10 TRUE TRUE TRUE v$results$path <- fs::path_rel(e$path, e$lesson) # The validator does not produce any warnings or messages, but this data # frame can be passed on to other functions that will throw them for us. We # have a function that will throw a warning/message for each heading that # fails the tests. These messages are controlled by `heading_tests` and # `heading_info`. pegboard:::heading_tests #> first_heading_is_second_level greater_than_first_level #> \"(must be level 2)\" \"(first level heading)\" #> are_sequential have_names #> \"(non-sequential heading jump)\" \"(no name)\" #> are_unique #> \"(duplicated)\" pegboard:::heading_info #> first_heading_is_second_level greater_than_first_level #> \"First heading must be level 2\" \"Level 1 headings are not allowed\" #> are_sequential have_names #> \"Headings must be sequential\" \"Headings must be named\" #> are_unique #> \"Headings must be unique\" pegboard:::throw_heading_warnings(v$results) #> ! There were errors in 3/10 headings #> ◌ Headings must be unique #> #> #> ::warning file=_episodes/14-looping-data-sets.md,line=119:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=143:: (duplicated) #> ::warning file=_episodes/14-looping-data-sets.md,line=162:: (duplicated) # Because the headings are best understood in tree form we have a utility # that will print the heading tree with the associated errors: pegboard:::show_heading_tree(v$tree) #> ── Heading structure ─────────────────────────────────────────────────────────── #> # Episode: “Looping Over Data Sets” #> ├─## Use a for loop to process files given a list of their names. #> ├─## Use glob.glob to find sets of files whose names match a pattern. #> ├─## Use glob and for to process batches of files. #> ├─## Determining Matches #> ├─## Solution (duplicated) #> ├─## Minimum File Size #> ├─## Solution (duplicated) #> ├─## Comparing Data #> └─## Solution (duplicated) #> └─### ZNK test links and images #> ────────────────────────────────────────────────────────────────────────────────"},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate Links in a markdown document — validate_links","title":"Validate Links in a markdown document — validate_links","text":"function validate links throw error markdown documents. include links images respect robots.txt websites.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate Links in a markdown document — validate_links","text":"","code":"validate_links(yrn) allowed_uri_protocols link_known_protocol(VAL) link_enforce_https(VAL) link_all_reachable(VAL) link_img_alt_text(VAL) link_length(VAL) link_descriptive(VAL) link_source_list(lt) link_internal_anchor(VAL, source_list, headings, body) link_internal_file(VAL, source_list, root) link_internal_well_formed(VAL, source_list) link_tests link_info"},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Validate Links in a markdown document — validate_links","text":"allowed_uri_protocols character string length 23 link_tests character string length 9 containing templates use output validate_links() formatting. link_info character string length 9 gives information informative links additional context failures.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate Links in a markdown document — validate_links","text":"yrn tinkr::yarn Episode object. lt output make_link_table() source_list output link_source_list headings xml_nodeset headings body xml_document root root path folder containing file containing paths ultimate parent files.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate Links in a markdown document — validate_links","text":"data frame parsed information xml2::url_parse() columns logical values indicating tests passed.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"link-validity","dir":"Reference","previous_headings":"","what":"Link Validity","title":"Validate Links in a markdown document — validate_links","text":"links must resolve specific location. exist, link invalid. moment, can local links.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"external-links","dir":"Reference","previous_headings":"","what":"External links","title":"Validate Links in a markdown document — validate_links","text":"links must start valid secure protocol. Allowed protocols taken allowed protocols Wordpress: http, https, ftp, ftps, mailto, news, irc, irc6, ircs, gopher, nntp, feed, telnet, mms, rtsp, sms, svn, tel, fax, xmpp, webcal, urn Misspellings unsupported protocols (e.g. javascript: bitcoin: flagged). addition, enforce use HTTPS HTTP.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"cross-lesson-links","dir":"Reference","previous_headings":"","what":"Cross-lesson links","title":"Validate Links in a markdown document — validate_links","text":"links protocol, resolve HTML version page correct capitalisation.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"anchors-aka-fragments-","dir":"Reference","previous_headings":"","what":"Anchors (aka fragments)","title":"Validate Links in a markdown document — validate_links","text":"Anchors located end URLs start # sign. used indicate section documenation span id.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"accessibility-a-y-","dir":"Reference","previous_headings":"","what":"Accessibility (a11y)","title":"Validate Links in a markdown document — validate_links","text":"Accessibillity ensures links accurate descriptive people slow connections use screen reader technology.","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"alt-text-for-images-","dir":"Reference","previous_headings":"","what":"Alt-text (for images)","title":"Validate Links in a markdown document — validate_links","text":"images must associated alt-text. pandoc, acheived writing alt attribute curly braces image: ![image caption](link){alt='alt text'}: https://webaim.org/techniques/alttext/","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"descriptive-text","dir":"Reference","previous_headings":"","what":"Descriptive text","title":"Validate Links in a markdown document — validate_links","text":"links must descriptive text associated , beneficial screen readers scanning links page list full \"link\", \"link\", \"link\": https://webaim.org/techniques/hypertext/link_text#uninformative","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"text-length","dir":"Reference","previous_headings":"","what":"Text length","title":"Validate Links in a markdown document — validate_links","text":"Link text length must greater 1: https://webaim.org/techniques/hypertext/link_text#link_length","code":""},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"note","dir":"Reference","previous_headings":"","what":"Note","title":"Validate Links in a markdown document — validate_links","text":"moment, currently test links reachable. feature planned future. function internal. Please use methods Episode Lesson classes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/reference/validate_links.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Validate Links in a markdown document — validate_links","text":"","code":"l <- Lesson$new(lesson_fragment()) e <- l$episodes[[3]] # Our link validators run a series of tests on links and images and return a # data frame with information about the links (via xml2::url_parse), along # with the results of the tests v <- asNamespace('pegboard')$validate_links(e) names(v) #> [1] \"scheme\" \"server\" \"port\" #> [4] \"user\" \"path\" \"query\" #> [7] \"fragment\" \"orig\" \"text\" #> [10] \"alt\" \"title\" \"type\" #> [13] \"rel\" \"anchor\" \"sourcepos\" #> [16] \"filepath\" \"parents\" \"node\" #> [19] \"known_protocol\" \"enforce_https\" \"internal_anchor\" #> [22] \"internal_file\" \"internal_well_formed\" \"all_reachable\" #> [25] \"img_alt_text\" \"descriptive\" \"link_length\" v #> scheme server port user #> 1 https docs.python.org NA #> 2 https docs.python.org NA #> 3 https docs.python.org NA #> 4 https pandas.pydata.org NA #> 5 https docs.python.org NA #> 9 https carpentries.org NA #> 10 NA #> 6 22010 #> 7 -2082140592 #> 11 https carpentries.org NA #> 12 NA #> 13 2122065360 #> 8 22010 #> path query #> 1 /3/library/glob.html #> 2 /3/library/glob.html #> 3 /3/library/glob.html #> 4 /pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 /3/library/stdtypes.html #> 9 /assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 #> 7 #> 11 /assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 #> 8 #> fragment #> 1 glob.glob #> 2 #> 3 #> 4 #> 5 str.split #> 9 #> 10 #> 6 #> 7 #> 11 #> 12 #> 13 #> 8 #> orig #> 1 https://docs.python.org/3/library/glob.html#glob.glob #> 2 https://docs.python.org/3/library/glob.html #> 3 https://docs.python.org/3/library/glob.html #> 4 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html #> 5 https://docs.python.org/3/library/stdtypes.html#str.split #> 9 https://carpentries.org/assets/img/TheCarpentries.svg #> 10 ../no-workie.svg #> 6 {{ page.root }}/index.html #> 7 {{ site.swc_pages }}/shell-novice #> 11 https://carpentries.org/assets/img/TheCarpentries.svg #> 12 ../no-workie.svg #> 13 {{ page.root }}/no-workie.svg #> 8 {{ page.root }}{% link index.md %} #> text alt title type #> 1 glob.glob link #> 2 glob link #> 3 glob link #> 4 shape method link #> 5 split link #> 9 books as clubs img #> 10 books as clubs img #> 6 Home link #> 7 shell link #> 11 Carpentries logo image #> 12 Non-working image image #> 13 Non-working image with jekyll syntax image #> 8 link that isn't parsed correctly by commonmark link #> rel anchor sourcepos filepath parents node #> 1 FALSE 51 _episodes/14-looping-data-sets.md 2 FALSE 57 _episodes/14-looping-data-sets.md 3 FALSE 58 _episodes/14-looping-data-sets.md 4 FALSE 140 _episodes/14-looping-data-sets.md 5 FALSE 163 _episodes/14-looping-data-sets.md 9 FALSE 189 _episodes/14-looping-data-sets.md 10 FALSE 191 _episodes/14-looping-data-sets.md 6 FALSE 193 _episodes/14-looping-data-sets.md 7 FALSE 193 _episodes/14-looping-data-sets.md 11 FALSE 195 _episodes/14-looping-data-sets.md 12 FALSE 197 _episodes/14-looping-data-sets.md 13 FALSE 199 _episodes/14-looping-data-sets.md 8 FALSE 201 _episodes/14-looping-data-sets.md known_protocol enforce_https internal_anchor internal_file #> 1 TRUE TRUE TRUE TRUE #> 2 TRUE TRUE TRUE TRUE #> 3 TRUE TRUE TRUE TRUE #> 4 TRUE TRUE TRUE TRUE #> 5 TRUE TRUE TRUE TRUE #> 9 TRUE TRUE TRUE TRUE #> 10 TRUE TRUE TRUE FALSE #> 6 TRUE TRUE TRUE TRUE #> 7 TRUE TRUE TRUE TRUE #> 11 TRUE TRUE TRUE TRUE #> 12 TRUE TRUE TRUE FALSE #> 13 TRUE TRUE TRUE TRUE #> 8 TRUE TRUE TRUE TRUE #> internal_well_formed all_reachable img_alt_text descriptive link_length #> 1 TRUE TRUE TRUE TRUE TRUE #> 2 TRUE TRUE TRUE TRUE TRUE #> 3 TRUE TRUE TRUE TRUE TRUE #> 4 TRUE TRUE TRUE TRUE TRUE #> 5 TRUE TRUE TRUE TRUE TRUE #> 9 TRUE TRUE TRUE TRUE TRUE #> 10 TRUE TRUE TRUE TRUE TRUE #> 6 TRUE TRUE TRUE TRUE TRUE #> 7 TRUE TRUE TRUE TRUE TRUE #> 11 TRUE TRUE FALSE TRUE TRUE #> 12 TRUE TRUE FALSE TRUE TRUE #> 13 TRUE TRUE FALSE TRUE TRUE #> 8 TRUE TRUE TRUE TRUE TRUE # URL protocols ----------------------------------------------------------- # To avoid potentially malicious situations, we have an explicit list of # allwed URI protocols, which can be found in the `allowed_uri_protocols` # character vector: asNamespace('pegboard')$allowed_uri_protocols #> [1] \"\" \"http\" \"https\" \"ftp\" \"ftps\" \"mailto\" \"news\" \"irc\" #> [9] \"irc6\" \"ircs\" \"gopher\" \"nntp\" \"feed\" \"telnet\" \"mms\" \"rtsp\" #> [17] \"sms\" \"svn\" \"tel\" \"fax\" \"xmpp\" \"webcal\" \"urn\" # note that we make an additional check for the http protocol. # Creating Warnings from the table ---------------------------------------- # The validator does not produce any warnings or messages, but this data # frame can be passed on to other functions that will throw them for us. We # have a function that will throw a warning/message for each link that # fails the tests. These messages are controlled by `link_tests` and # `link_info`. asNamespace('pegboard')$link_tests #> known_protocol #> \"[invalid protocol]: {scheme}\" #> enforce_https #> \"[needs HTTPS]: [{text}]({orig})\" #> internal_anchor #> \"[missing anchor]: [{text}]({orig})\" #> internal_file #> \"[missing file{format_parents(parents)}]: [{text}]({orig})\" #> internal_well_formed #> \"[incorrect formatting]: [{text}][{orig}] -> [{text}]({orig})\" #> all_reachable #> \"\" #> img_alt_text #> \"[image missing alt-text]: {orig}\" #> descriptive #> \"[uninformative link text]: [{text}]({orig})\" #> link_length #> \"[link text too short]: [{text}]({orig})\" asNamespace('pegboard')$link_info #> known_protocol #> \"Links must have a known URL protocol (e.g. https, ftp, mailto). See for a list of acceptable protocols.\" #> enforce_https #> \"Links must use HTTPS \" #> internal_anchor #> \"Some link anchors for relative links (e.g. [anchor]: link) are missing\" #> internal_file #> \"Some linked internal files do not exist \" #> internal_well_formed #> \"Some links were incorrectly formatted\" #> all_reachable #> \"\" #> img_alt_text #> \"Images need alt-text \" #> descriptive #> \"Avoid uninformative link phrases \" #> link_length #> \"Avoid single-letter or missing link text \" asNamespace('pegboard')$throw_link_warnings(v) #> ! There were errors in 4/13 images #> ◌ Some linked internal files do not exist #> ◌ Images need alt-text #> #> ::warning file=_episodes/14-looping-data-sets.md,line=191:: [missing file]: [](../no-workie.svg) #> ::warning file=_episodes/14-looping-data-sets.md,line=195:: [image missing alt-text]: https://carpentries.org/assets/img/TheCarpentries.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=197:: [missing file]: [Non-working image](../no-workie.svg) [image missing alt-text]: ../no-workie.svg #> ::warning file=_episodes/14-looping-data-sets.md,line=199:: [image missing alt-text]: { page.root }/no-workie.svg"},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":null,"dir":"Reference","previous_headings":"","what":"Convert xml to markdown — xml_to_md","title":"Convert xml to markdown — xml_to_md","text":"Convert xml markdown","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Convert xml to markdown — xml_to_md","text":"","code":"xml_to_md(body, stylesheet = \"xml2md_gfm_kramdown.xsl\", newlines = FALSE)"},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Convert xml to markdown — xml_to_md","text":"body xml document stylesheet name stylesheet passed get_stylesheet newlines logical indicating newlines (aka softbreaks) inserted elements (defaults FALSE, meaning separator added elements).","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Convert xml to markdown — xml_to_md","text":"character vector length 1","code":""},{"path":"https://carpentries.github.io/pegboard/reference/xml_to_md.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Convert xml to markdown — xml_to_md","text":"","code":"cha <- pegboard:::make_div(\"challenge\") sol <- pegboard:::make_div(\"solution\") xml2::xml_add_child(cha, xml2::xml_child(sol, 1), .where = 1) xml2::xml_add_child(cha, xml2::xml_child(sol, 2), .where = 2) cat(pegboard:::xml_to_md(cha)) #> :::::::::::::::::::::::::::::::::::::::: challenge #> #> :::::::::::::::: solution #> #> ::::::::::::::::::::::::: #> #> ::::::::::::::::::::::::::::::::::::::::::::::::::"},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-7","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.7 (2024-11-11)","text":"Add support validation caution fenced divs introduced https://github.com/carpentries/varnish/pull/149 (@froggleston #160)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-6","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.6 (2024-06-25)","text":"Hotfix {tinkr} upcoming bump 0.3.0 changes yarn$show() arguments: https://github.com/ropensci/tinkr/pull/108. (reported @froggleston https://github.com/carpentries/pegboard/issues/156, fixed: @froggleston, #157) Remove support checks Windows R 3.6","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-5","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.5 (2024-04-10)","text":"Add support tabbed content lessons (reported: @astroDimitrios, implemented: @astroDimitrios, @froggleston, https://github.com/carpentries/pegboard/pull/148https://github.com/carpentries/sandpaper/pull/571, https://github.com/carpentries/varnish/pull/121, ).","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-4","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.4 (2024-03-06)","text":"Hotfix R 4.3.3 bump results trailing commas glue function causing argument errors: https://github.com/tidyverse/glue/issues/320 (reported: @ns-rse, #149; fixed: @Bisaloo, #150). Required sandpaper CSS fix","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-7-3","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.7.3 (2023-11-22)","text":"New vignette(\"intro-lesson\", package = \"pegboard\") provides information working pegboard::Lesson objects. Documentation Episode Lesson objects updated bit descriptive point vignettes.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-3","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.3 (2023-11-22)","text":"Episode$unblock() method gains force argument allow method run even previously run.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-7-2","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.7.2 (2023-11-17)","text":"Snapshot update testthat 3.2.0","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bugfix-0-7-2","dir":"Changelog","previous_headings":"","what":"BUGFIX","title":"pegboard 0.7.2 (2023-11-17)","text":"validate_links() now differentiates links images reporting (reported: @joelnitta, #143; fixed: @zkamvar, #144)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-7-2","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.7.2 (2023-11-17)","text":"Two vignettes added XML Episode class Documentation validation reporting added","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-071-2023-10-03","dir":"Changelog","previous_headings":"","what":"pegboard 0.7.1 (2023-10-03)","title":"pegboard 0.7.1 (2023-10-03)","text":"child chunk options fail context longer cause failure. (reported: @trhallam, https://github.com/carpentries/workbench/issues/74, #139; fixed: @zkamvar, #140)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-070-2023-10-02","dir":"Changelog","previous_headings":"","what":"pegboard 0.7.0 (2023-10-02)","title":"pegboard 0.7.0 (2023-10-02)","text":"release introduces automated processing {knitr} child files, enables automatically available validation processing.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-7-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.7.0 (2023-10-02)","text":"Episode class objects gain children, parents, build_parents fields contain known relationships files. children parents represent immediate relationships build_parents represent distant ancestor object trigger build. Note parents fields populated Episode context Lesson object. Lesson class objects gain children field list stores Episode objects derived child files. Episode objects gain $has_parents active binding reporting object parent object. used context Lesson. Episode Lesson objects gain $has_children active binding, reporting child episodes lesson episode. Lesson objects gain $trace_lineage() method return absolute paths child files source path given episode exist. make_link_table() now new column called parents contains list column parents () files checked $validate_links(), $validate_divs(), $validate_headings() now process child files default. Note $validate_links() report missing files relative build parents.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-7-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.7.0 (2023-10-02)","text":"$load_built() method now load built markdown content, just episodes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-6-1","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.6.1 (2023-09-06)","text":"$validate_divs() method now recognises spoiler class fenced divs allow optional/expandable items automatically shown learner (implemented: @tobyhodges, #134)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-6-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.6.0 (2023-08-29)","text":"Workshop overview pages now able processed Lesson objects. Jekyll- based lessons, directory name must end -workshop (standard workshop overview lessons without episodes), sandpaper- based lessons, config.yaml file must contain overview: true tag (reported: @zkamvar, #118; fixed: @zkamvar, #132, reviewed @klbarnes20). pages indicated $overview field Lesson object. lessons workshop overview lessons, nothing change.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-6-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.6.0 (2023-08-29)","text":"Lessons underwent incomplete conversion Jekyll sandpaper now appropriate error message provided.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.3 (2023-07-08)","text":"$validate_links() longer throws error HTML images embedded comments (reported: @beastyblacksmith, #130; fixed: @zkamvar, #131, reviewed @ErinBecker) (transition) $move_objectives() $move_questions() methods longer place blocks second element markdown. originally implemented thought {dovetail} solution lesson infrastructure (thus needed setup chunk blocks). (transition) liquid-formatted links markdown inside now parsed correctly. leads lessons accurately transitioned use {sandpaper} (reported: @uschille, https://github.com/carpentries/lesson-transition/issues/46; fixed: @zkamvar, #121) (transition) images kramdown attributes new line now accurately transitioned use {sandpaper} (reported: @uschille, https://github.com/carpentries/lesson-transition/issues/46; fixed: @zkamvar, #121)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-5-3","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.5.3 (2023-07-08)","text":"failing test due workbench transition fixed (reported: @zkamvar, #125; fixed: @zkamvar, #127)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-2","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.2 (2023-04-05)","text":"README file longer run validation generally part website often , creates distractions.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-5-1","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.5.1 (2023-03-31)","text":"Fenced divs attributes now properly parsed (@zkamvar, #115).","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-5-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.5.0 (2023-03-31)","text":"Lesson object validators now validate non-episode files (reported: @zkamvar #110; fixed: @zkamvar #113). $validate_links() now respect links anchors spans. validators longer truncate GitHub actions (reported: @zkamvar #111, fixed: @zkamvar: #114). validators provide full context invalid links (just link text, link text).","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-5-0","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.5.0 (2023-03-31)","text":"tinkr’s minimum version set 0.2.0 recognise release CRAN bring new bugfixes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-4-3","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.4.3 (2023-01-26)","text":"$validate_links() now checks URL protocol external link matches known list protocols. match (e.g. javascript: bitcoin:) flagged. (@zkamvar #109)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-4-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.4.3 (2023-01-26)","text":"bug attributes following image cause missing alt text reported fixed. (discovered: @dpshelio @karenword; reported: @zkamvar #106; fixed: @zkamvar #108). fix also makes alt text parsing validation robust bug unknown protocol recognised invalid fixed. (discovered: @ndporter; reported: @zkamvar, #107; fixed: @zkamvar, #109)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"internals-0-4-3","dir":"Changelog","previous_headings":"","what":"INTERNALS","title":"pegboard 0.4.3 (2023-01-26)","text":"New internal function find_between_nodes() get nodes two sibling nodes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-4-2","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.4.2 (2023-01-10)","text":"test depended upstream resource fixed. Tests modified account new case image fixing.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-4-2","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.4.2 (2023-01-10)","text":"Internal fix_links() function improved documentation.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"tests-0-4-1","dir":"Changelog","previous_headings":"","what":"TESTS","title":"pegboard 0.4.1 (2023-01-06)","text":"test dependend upstream resource fixed.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-4-0","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.4.0 (2023-01-06)","text":"{tinkr} minimum version upgraded 0.1.0.9000 address square bracket protection implemented version.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-4-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.4.0 (2023-01-06)","text":"Jekyll links spaces processed correctly. broken update {tinkr} (reported: @zkamvar, #100; fixed: @zkamvar, #102)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-4-0","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.4.0 (2023-01-06)","text":"GitHub workflows updated run weekly.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-3-2","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.3.2 (2022-09-14)","text":"Soft dependencty {cli} recommended 0.3.4 prevent reporting issues (see #97) Soft dependencies ggraph, ggplot2, tidygraph removed. dependencies needed producing now---date survey document","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-3-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.3.1 (2022-08-16)","text":"preparation {tinkr} 0.1.0, changes path default stylesheet, using tinkr::stylesheet() convenience function access .","code":""},{"path":[]},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"episode-class-objects-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Episode class objects","title":"pegboard 0.3.0 (2022-05-25)","text":"$summary() method can summarise counts elements episode. fixes $error $output active bindings new $warning active binding show code blocks warning class.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"lesson-class-objects-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Lesson class objects","title":"pegboard 0.3.0 (2022-05-25)","text":"new public field “built” contain XML representations markdown files built RMarkdown files sandpaper lessons. new public field “sandpaper” boolean indicates lesson can built sandpaper. new $load_built() method load built files exist sandpaper lesson. new $get() method get element Episode class object contained within. new $summary() method call $summary() method Episode class object.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"messages-0-3-0","dir":"Changelog","previous_headings":"NEW FEATURES","what":"Messages","title":"pegboard 0.3.0 (2022-05-25)","text":"muffle_messages() internal function muffle messages originate {cli} {pegboard} packages. {cli} package available, messages class pbMessage, allow end users/package authors catch manipulate messages originate {pegboard}","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"transformation-0-2-7","dir":"Changelog","previous_headings":"","what":"TRANSFORMATION","title":"pegboard 0.2.7 (unreleased, no user-visible changes)","text":"make_pandoc_alt() (internal converter function) longer create alt text caption contains URL. messes downstream validation image links. fix_sandpaper_links() now also fixes links use {{ site.baseurl }}.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-6","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.6 (2022-05-11)","text":"internal function text_to_links() now processes unescaped ampersands internal function find_lesson_links() longer expects links strictly paragraph elements.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-2-5","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.2.5 (2022-05-10)","text":"validate_links() longer flag alt=\"\" errors. indicate decorative images. said, rare lessons, just case ’s needed. Source: https://webaim.org/techniques/alttext/#decorative","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"dependencies-0-2-4","dir":"Changelog","previous_headings":"","what":"DEPENDENCIES","title":"pegboard 0.2.4 (2022-02-25)","text":"{fs} package needs >= 1.5.0 (#83, @sstevens2)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-3","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.3 (2022-02-23)","text":"footnotes trailing newline longer accidentally appended relative link anchors getOption('sandpaper.links') NULL.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-2-2","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.2.2 (2022-02-23)","text":"getOption(\"sandpaper.links\") NULL (context {sandpaper} lesson) valid file, appended file read via Episode$new()","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-2-2","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.2.2 (2022-02-23)","text":"$validate_links() longer throws warnings short uninformative text link anchors (@zkamvar, #81)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-2-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.2.1 (2022-02-18)","text":"inline messages link validation errors verbose (@tobyhodges, #79)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-2-0","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.2.0 (2022-02-17)","text":"validate_divs() validate divs Episode ones expect.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-1-1","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.1.1 (2022-02-02)","text":"Correct mis-attribution LICENSE","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-010-2022-02-01","dir":"Changelog","previous_headings":"","what":"pegboard 0.1.0 (2022-02-01)","title":"pegboard 0.1.0 (2022-02-01)","text":"soft release {pegboard} coincide first announcement Carpentries Workbench.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"imports-0-1-0","dir":"Changelog","previous_headings":"","what":"IMPORTS","title":"pegboard 0.1.0 (2022-02-01)","text":"{lifecycle} longer imported package. using , makes sense leave production.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-1-0","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.1.0 (2022-02-01)","text":"get_list_block() now select last block multiple “keypoints” blocks (@zkamvar, #75) get_list_block() now throw warning block contain list elements (@zkamvar, #74)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9034","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9034","text":"get_stylesheet() now escapes spaces normalizes windows path tinkr stylesheet embedding (@zkamvar, #72)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9033","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9033","text":"$move_*() methods longer create redundant heading fenced div (@zkamvar, #26)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"documentation-0-0-0-9033","dir":"Changelog","previous_headings":"","what":"DOCUMENTATION","title":"pegboard 0.0.0.9033","text":"pkgdown site updated complete. div family functions uses roxygen family tag complete.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9032","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9032","text":"$use_sandpaper() method Episode objects now remove “root” “layout” yaml directives (@zkamvar, #68)","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9031","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9031","text":"Images attributes added now post-processed use_sandpaper() retain original attributes.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9030","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9030","text":"replace relative_root_path nothing instead ., fixes bug introduced 0.0.0.9028.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9029","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9029","text":"fix jekyll-based lessons using base_path.html define relative_root_path now corrected longer include directives links.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9028","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9028","text":"fix jekyll-based lesson auto-detection RMD lessons error pure Rmd lessons","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9027","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9027","text":"Jekyll-based lessons now auto-detect read R Markdown content exists. rmd flag Lesson initializer now nothing.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9026","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9026","text":"now use _config.yml file parse site-specific liquid template links fix #60","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fix-0-0-0-9025","dir":"Changelog","previous_headings":"","what":"BUG FIX","title":"pegboard 0.0.0.9025","text":"RMarkdown episodes setup chunk without specifying includes now considered valid setup chunks can chunks converted.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9024","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9024","text":"Episode$handout() create trimmed-R Markdown document challenge blocks code chunks purl = TRUE, can passed knitr::purl() processing R code handout. Lesson$handout() create concatenated version Episode$handout().","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-0-0-9023","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.0.0.9023","text":"validation messages revamped consistent across messages. validation methods Episode Lesson now return data frames contain detailed information element tests passed failed downstream analysis. Importantly, contain column called “node”, points exact XML node containing link/image/heading inspection/manipulation. validation reporting longer grouped error link validation information switched show error message problematic aspect/fix heading validation now works continuous integration functions longer rely dplyr installed","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9022","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9022","text":"Episode class now gains $confirm_sandpaper() method bypass assumption Episodes start kramdown-formatted documents attempt label divs episode (warning success). Lesson class now run $confirm_sandpaper() method markdown files jekyll = FALSE. Lesson$new() now default current working directory.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"misc-0-0-0-9022","dir":"Changelog","previous_headings":"","what":"MISC","title":"pegboard 0.0.0.9022","text":"internal get_list_block() longer auto-label divs.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9021","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9021","text":"Link validation now checks general uninformative link text empty links (@zkamvar, #49) make_link_table() treat linebreaks link text space character.","code":""},{"path":[]},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9020","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9020","text":"Lesson class now $validate_links() $validate_headings() methods. (@zkamvar, #48)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009019","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9019","title":"pegboard 0.0.0.9019","text":"NOTE: (@zkamvar, #44)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-features-0-0-0-9019","dir":"Changelog","previous_headings":"","what":"NEW FEATURES","title":"pegboard 0.0.0.9019","text":"Episode class now $links $images active bindings extracts links images (markdown HTML) document. make_link_table() creates table links parsed via xml2::url_parse() additional information caption alternative text (images). Episode class now $validate_links() method, validate links images common errors using https unresolved relative links. Episode$use_sandpaper() now converts images use alt text captions. Images ![alt](link) converted ![](link){alt='alt'} pandoc uses everything square brackets caption text. NOTE: now makes copy XML document.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"bug-fixes-0-0-0-9019","dir":"Changelog","previous_headings":"","what":"BUG FIXES","title":"pegboard 0.0.0.9019","text":"Episode$new() gains argument fix_liquid, fixes liquid variables relative links passed {tinkr} (https://github.com/carpentries/pegboard/issues/46) Post-processed links via fix_links() retains sourcepos attribute (fixed e5508cc9c9a3821381293bdac12647edfbc0608e). Episode$lesson longer assumes episode inside sub-folder (fixed 63432ef83ecc41a6aab53fe768e8eaec107278d5).","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009018","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9018","title":"pegboard 0.0.0.9018","text":"Episode$validate_headings() now properly displays duplicated headings. (@zkamvar, #45)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009017","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9017","title":"pegboard 0.0.0.9017","text":"Lesson class now respects order contents config.yaml (#42 via #43)","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009016","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9016","title":"pegboard 0.0.0.9016","text":"Episode class now $headings active binding $validate_headings() method validate headings (#23 via #41) now use {testthat} 3e tests Cloning Episode object now reliable","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009015","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9015","title":"pegboard 0.0.0.9015","text":"Episode class now sub-class tinkr::yarn class gains show(), head(), tail(), protect_math() methods.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009014","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9014","title":"pegboard 0.0.0.9014","text":"Innocent block quotes sullied ruthless kramdown postfix operators kept block quotes instead failing $unblock() conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009013","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9013","title":"pegboard 0.0.0.9013","text":"omnipresent {% include links.md %} now removed sandpaper conversion.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009012","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9012","title":"pegboard 0.0.0.9012","text":"Lesson class now work {sandpaper} (#24) new parameter jekyll Episode class gains new slot called extras handle sandpaper non-episodic things better error message thrown Episode$label_divs().","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009011","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9011","title":"pegboard 0.0.0.9011","text":"Swap {git2r} dependency {gert}, smoother interface matches dependencies {sandpaper}.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009010","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9010","title":"pegboard 0.0.0.9010","text":"Missing questions, objectives, keypoints longer fail cryptic error. informative warning thrown empty character vector returned. addresses issue {sandpaper}: https://github.com/carpentries/sandpaper/issues/79 URI pegboard tags now “http://carpentries.org/pegboard/”, fixes https://github.com/carpentries/pegboard/issues/18","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009009","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9009","title":"pegboard 0.0.0.9009","text":"Several Bug fixes, see https://github.com/carpentries/pegboard/pull/21 details. Travis hopefully banished","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009008","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9008","title":"pegboard 0.0.0.9008","text":"$label_divs() longer modifies fenced divs. @dtag labels attached html_block paragraph elements now replaced elements live within custom namespace called “pegboard”. allows us avoid manipulating document paragraph structure case fenced divs. $get_divs() now includes div tags/fences output. Internally, namespace handling gotten marginally better default namespace prefix modified md:. fenced divs longer manipulated labelling. new test expectation, expect_moved_yaml() tests yaml element successfully moved body document.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009007","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9007","title":"pegboard 0.0.0.9007","text":"$keypoints $objectives now available act like $questions $move_*() methods now add h2 header block $move_*() methods use pandoc syntax instead html div blocks. Internal changes creation elements longer relies complex namespace juggling","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009006","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9006","title":"pegboard 0.0.0.9006","text":"$label_divs() method now label div tags episode $move_* methods now auto-label div tags $questions field now returns questions block yaml header character vector.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009005","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9005","title":"pegboard 0.0.0.9005","text":"pandoc-style fenced divs now processed native div tags @dtag labels now format div-{n}-{class} {n} sequential number document {class} type div. labelling @dtags straightforward label tags sequentially.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009004","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9004","title":"pegboard 0.0.0.9004","text":"changes version largely enhancements handling div tags conversion. See #9 details $unblock() defaults converting div tags unless $use_sandpaper() called. $unblock() auto-name divs {class}-div-{number} $move_* functions now name html_blocks $get_divs() returns div tags named list $challenges now find either blocks, divs code, depending mutations $soltuions challenges (see ) $use_dovetail() warn user body empty $use_sandpaper() ","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009003","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9003","title":"pegboard 0.0.0.9003","text":"Jekyll-specific relative links now converted part use_sandpaper().","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-function-0-0-0-9003","dir":"Changelog","previous_headings":"","what":"NEW FUNCTION","title":"pegboard 0.0.0.9003","text":"fix_sandpaper_links() fix relative paths jekyll-specific links inside lessons yet otherwise converted.","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009002","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9002","title":"pegboard 0.0.0.9002","text":"version introduces conversions work together can chained convert episode old Jekyll style new {sandpaper} style. Things still much development though. conversions sandpaper dovetail clearly separated Episode class understands conversions performed private logical vector tracks changes. pkgdown site now built automatically github actions","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"new-episode-methods-0-0-0-9002","dir":"Changelog","previous_headings":"","what":"NEW EPISODE METHODS","title":"pegboard 0.0.0.9002","text":"use_dovetail() inserts setup chunk top file use_sandpaper() converts chunks liquid/kramdown syntax commonmark RMD syntax move_*() generate dovetail block just plain div block depending whether use_dovetail() called. remove_output() says tin remove_error() removes error code blocks $output $error can now grab output error chunks converted via use_sandpaper()","code":""},{"path":"https://carpentries.github.io/pegboard/news/index.html","id":"pegboard-0009001","dir":"Changelog","previous_headings":"","what":"pegboard 0.0.0.9001","title":"pegboard 0.0.0.9001","text":"Added NEWS.md file track changes package. Dependencies {yaml} {commonmark} now explicit Added methods Episode class move questions, objectives, keypoints YAML lesson body.","code":""}]