From 7572078c1f4343dd153d75ceea5c6f70535e7f0e Mon Sep 17 00:00:00 2001
From: froggleston Validation will auto-check everything and return the results as data
frames. You can find more information abou the specific checks by
-reading Methods Summaries and Validation## # ℹ 3 more variables: error <int>, images <int>, links <int>
vignette("validation", package = "pegboard")
.vignette("validation", package = "pegboard")
.
Details of the individual functions can be found via
?validate_links()
, ?validate_divs()
, and
?validate_headings()
.
#> ## 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 @@ Link Validation#| $ 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 ...
+#| $ 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 "" "" "" "" ...
diff --git a/news/index.html b/news/index.html
index 7a3b6c7..0c0685b 100644
--- a/news/index.html
+++ b/news/index.html
@@ -42,7 +42,7 @@
pegboard 0.7.7 (2024-11-11)
NEW FEATURES
-- Add support and validation for
caution
fenced divs (fixed: @froggleston #160)
+- Add support and validation for
caution
fenced divs introduced in https://github.com/carpentries/varnish/pull/149 (@froggleston #160)
diff --git a/pkgdown.yml b/pkgdown.yml
index 98f1c90..937bbe1 100644
--- a/pkgdown.yml
+++ b/pkgdown.yml
@@ -6,7 +6,7 @@ articles:
intro-lesson: intro-lesson.html
intro-xml: intro-xml.html
articles/validation: validation.html
-last_built: 2024-11-08T15:50Z
+last_built: 2024-11-11T12:49Z
urls:
reference: https://carpentries.github.io/pegboard/reference
article: https://carpentries.github.io/pegboard/articles
diff --git a/reference/Episode.html b/reference/Episode.html
index d6dd88f..418b66d 100644
--- a/reference/Episode.html
+++ b/reference/Episode.html
@@ -1123,7 +1123,7 @@ Examples
scope <- Episode$new(file.path(lesson_fragment(), "_episodes", "17-scope.md"))
scope$write()
-#> Creating temporary directory '/tmp/Rtmp3tPmlj/dir16b131de6084'
+#> Creating temporary directory '/tmp/RtmpvjwUql/dir168757737362'
## ------------------------------------------------
## Method `Episode$handout`
diff --git a/reference/make_link_table.html b/reference/make_link_table.html
index 6845eaa..b17c4f9 100644
--- a/reference/make_link_table.html
+++ b/reference/make_link_table.html
@@ -81,20 +81,20 @@ Value
Examples
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 ## ## ## ## ## ## 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 ## ## ## ## ## ## 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>