Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix aggregate functions to not fail with special episode names #512

Merged
merged 7 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: sandpaper
Title: Create and Curate Carpentries Lessons
Version: 0.13.0
Version: 0.13.1
Authors@R: c(
person(given = "Zhian N.",
family = "Kamvar",
Expand Down
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# sandpaper 0.13.1 (unreleased)

* Aggregate pages will no longer fail if an episode has a prefix that is the
same as that aggregate page (e.g. `images.html` will no longer fail if there
is an episode that starts with `images-`) (reported: @mwhamgenomics, #511;
fixed: @zkamvar, #512)

# sandpaper 0.13.0 (2023-09-06)

## NEW FEATURES
Expand Down
36 changes: 22 additions & 14 deletions R/build_aio.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#' @rdname build_agg
build_aio <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(pkg = pkg, pages = pages, title = "All in One View",
slug = "aio", aggregate = "*", prefix = TRUE, quiet = quiet)
build_agg_page(
pkg = pkg,
pages = pages,
title = "All in One View",
slug = "aio",
aggregate = "*",
prefix = TRUE,
quiet = quiet
)
}


Expand All @@ -12,24 +19,26 @@ build_aio <- function(pkg, pages = NULL, quiet = FALSE) {
#'
#' @param name the name of the section, prefixed with `episode-`
#' @param contents the episode contents from [get_content()]
#' @param parent the parent div of the AiO page.
#' @param parent the parent div of the AiO page.
#' @return the section that was added to the parent
#'
#' @keywords internal
#' @seealso [build_aio()], [get_content()]
#' @examples
#' if (FALSE) {
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#'
#' # read in the All in One page and extract its content
#' aio <- get_content("aio", content = "self::*", pkg = pkg)
#' episode_content <- get_content("01-introduction", pkg = pkg)
#' make_aio_section("aio-01-introduction",
#' contents = episode_content, parent = aio)
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#'
#' # read in the All in One page and extract its content
#' aio <- get_content("aio", content = "self::*", pkg = pkg)
#' episode_content <- get_content("01-introduction", pkg = pkg)
#' make_aio_section("aio-01-introduction",
#' contents = episode_content, parent = aio
#' )
#' }
make_aio_section <- function(name, contents, parent) {
uri <- sub("aio-", "", name)
# trim off the aio because we know it's a prefix
uri <- sub("^aio-", "", name)
title <- escape_ampersand(xml2::xml_text(contents[[1]]))
new_section <- "<section id='{name}'><p>Content from <a href='{uri}.html'>{title}</a></p><hr/></section>"
section <- xml2::read_xml(glue::glue(new_section))
Expand All @@ -56,7 +65,7 @@ section_contents <- function(section) {

update_section <- function(section, new) {
to_clean <- section_contents(section)
info <- xml2::xml_find_first(section, "./hr")
info <- xml2::xml_find_first(section, "./hr")
xml2::xml_remove(to_clean)
for (node in rev(new)) {
xml2::xml_add_sibling(info, node, .where = "after")
Expand All @@ -70,4 +79,3 @@ get_title <- function(doc) {

# nocov end


28 changes: 16 additions & 12 deletions R/build_images.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#' @rdname build_agg
build_images <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(pkg = pkg,
build_agg_page(
pkg = pkg,
pages = pages,
title = "All Images",
slug = "images",
aggregate = "/img/..",
prefix = FALSE,
quiet = quiet)
quiet = quiet
)
}

#' Make a section of aggregated images
Expand All @@ -23,17 +25,17 @@ build_images <- function(pkg, pages = NULL, quiet = FALSE) {
#' @seealso [build_images()], [get_content()]
#' @examples
#' if (FALSE) {
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#'
#' # read in the All in One page and extract its content
#' img <- get_content("images", content = "self::*", pkg = pkg)
#' fig_content <- get_content("01-introduction", content = "/figure", pkg = pkg)
#' make_images_section("01-introduction", contents = fig_content, parent = img)
#' # read in the All in One page and extract its content
#' img <- get_content("images", content = "self::*", pkg = pkg)
#' fig_content <- get_content("01-introduction", content = "/figure", pkg = pkg)
#' make_images_section("01-introduction", contents = fig_content, parent = img)
#' }
make_images_section <- function(name, contents, parent) {
title <- escape_ampersand(names(name))
uri <- sub("^images-", "", name)
uri <- name
new_section <- "<section id='{name}'>
<h2 class='section-heading'><a href='{uri}.html'>{title}</a></h2>
<hr class='half-width'/>
Expand All @@ -42,10 +44,11 @@ make_images_section <- function(name, contents, parent) {

for (element in seq_along(contents)) {
content <- contents[[element]]
alt <- xml2::xml_text(xml2::xml_find_all(content, "./img/@alt"))
alt <- xml2::xml_text(xml2::xml_find_all(content, "./img/@alt"))
n <- length(alt)
xml2::xml_add_child(section, "h3", glue::glue("Figure {element}"),
id = glue::glue("{name}-figure-{element}"))
id = glue::glue("{name}-figure-{element}")
)
for (i in seq_along(alt)) {
txt <- alt[[i]]
if (length(txt) == 0) {
Expand All @@ -55,10 +58,11 @@ make_images_section <- function(name, contents, parent) {
txt <- "[decorative]"
}
desc <- glue::glue("Image {i} of {n}: {sQuote(txt)}")
xml2::xml_add_child(section, "p", 'aria-hidden'="true", desc)
xml2::xml_add_child(section, "p", "aria-hidden" = "true", desc)
}
xml2::xml_add_child(section, contents[[element]])
xml2::xml_add_child(section, "hr")
}
xml2::xml_add_child(parent, section)
}

58 changes: 34 additions & 24 deletions R/build_instructor_notes.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {
inote <- .resources$get()[["instructors"]]
inote <- inote[get_slug(inote) == "instructor-notes"]
html <- render_html(inote)
if (html != '') {
html <- xml2::read_html(html)
if (html != "") {
html <- xml2::read_html(html)
fix_nodes(html)
} else {
html <- xml2::read_html("<p></p>")
Expand All @@ -29,28 +29,32 @@ build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {

page_globals$instructor$update(this_dat)

this_dat$body = use_learner(html)
this_dat$body <- use_learner(html)
page_globals$learner$update(this_dat)

page_globals$meta$update(this_dat)

build_html(template = "extra", pkg = pkg, nodes = html,
global_data = page_globals, path_md = "instructor-notes.html", quiet = TRUE)
build_html(
template = "extra", pkg = pkg, nodes = html,
global_data = page_globals, path_md = "instructor-notes.html", quiet = TRUE
)
}
# shortcut if we don't have any episodes
is_overview <- lsn$overview && length(lsn$episodes) == 0
if (is_overview) {
return(invisible(NULL))
}
agg <- "/div[contains(@class, 'instructor-note')]//*[@class='accordion-body' or @class='accordion-header']"
build_agg_page(pkg = pkg,
build_agg_page(
pkg = pkg,
pages = pages,
title = this_dat$pagetitle,
slug = "instructor-notes",
aggregate = agg,
append = "section[@id='aggregate-instructor-notes']",
prefix = FALSE,
quiet = quiet)
quiet = quiet
)
}

#' Make a section of aggregated instructor notes
Expand All @@ -68,23 +72,28 @@ build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {
#' @seealso [build_instructor_notes()], [get_content()]
#' @examples
#' if (FALSE) {
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#'
#' # read in the All in One page and extract its content
#' notes <- get_content("instructor-notes", content =
#' "section[@id='aggregate-instructor-notes']", pkg = pkg, instructor = TRUE)
#' agg <- "/div[contains(@class, 'instructor-note')]//div[@class='accordion-body']"
#' note_content <- get_content("01-introduction", content = agg, pkg = pkg)
#' make_instructornotes_section("01-introduction", contents = note_content,
#' parent = notes)
#' lsn <- "/path/to/lesson"
#' pkg <- pkgdown::as_pkgdown(fs::path(lsn, "site"))
#'
#' # NOTE: if the object for "contents" ends with "_learn", no content will be
#' # appended
#' note_learn <- note_content
#' make_instructornotes_section("01-introduction", contents = note_learn,
#' parent = notes)
#' # read in the All in One page and extract its content
#' notes <- get_content("instructor-notes",
#' content =
#' "section[@id='aggregate-instructor-notes']", pkg = pkg, instructor = TRUE
#' )
#' agg <- "/div[contains(@class, 'instructor-note')]//div[@class='accordion-body']"
#' note_content <- get_content("01-introduction", content = agg, pkg = pkg)
#' make_instructornotes_section("01-introduction",
#' contents = note_content,
#' parent = notes
#' )
#'
#' # NOTE: if the object for "contents" ends with "_learn", no content will be
#' # appended
#' note_learn <- note_content
#' make_instructornotes_section("01-introduction",
#' contents = note_learn,
#' parent = notes
#' )
#' }
make_instructornotes_section <- function(name, contents, parent) {
# Since we have hidden the instructor notes from the learner sections,
Expand All @@ -95,14 +104,14 @@ make_instructornotes_section <- function(name, contents, parent) {
return(invisible(NULL))
}
title <- names(name)
uri <- sub("^instructor-notes-", "", name)
uri <- name
new_section <- "<section id='{name}'>
<h2 class='section-heading'><a href='{uri}.html'>{title}</a></h2>
<hr class='half-width'/>
</section>"
section <- xml2::read_xml(glue::glue(new_section))
for (element in contents) {
is_heading <- xml2::xml_name(element) == "h3" &
is_heading <- xml2::xml_name(element) == "h3" &
xml2::xml_attr(element, "class") == "accordion-header"
if (is_heading) {
# when we have an instructor note heading, we need to just add it and
Expand Down Expand Up @@ -132,3 +141,4 @@ make_instructor_note_linkback <- function(node, name) {
xml2::xml_set_attr(node, "id", newid)
node
}

19 changes: 11 additions & 8 deletions R/build_keypoints.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#' @rdname build_agg
build_keypoints <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(pkg = pkg,
pages = pages,
title = "Key Points",
slug = "key-points",
aggregate = "/div[starts-with(@id, 'keypoints')]/div[@class='callout-inner']/div[@class='callout-content']/*",
prefix = FALSE,
quiet = quiet)
build_agg_page(
pkg = pkg,
pages = pages,
title = "Key Points",
slug = "key-points",
aggregate = "/div[starts-with(@id, 'keypoints')]/div[@class='callout-inner']/div[@class='callout-content']/*",
prefix = FALSE,
quiet = quiet
)
}

make_keypoints_section <- function(name, contents, parent) {
title <- escape_ampersand(names(name))
uri <- sub("^keypoints-", "", name)
uri <- name
new_section <- "<section id='{name}'>
<h2 class='section-heading'><a href='{uri}.html'>{title}</a></h2>
<hr class='half-width'/>
Expand All @@ -22,3 +24,4 @@ make_keypoints_section <- function(name, contents, parent) {
}
xml2::xml_add_child(parent, section)
}

43 changes: 23 additions & 20 deletions R/serve.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,24 @@
#' @seealso [build_lesson()], render the lesson once, locally.
#' @examples
#' if (FALSE) {
#' # create an example lesson
#' tmp <- tempfile()
#' create_lesson(tmp, open = FALSE)
#' # create an example lesson
#' tmp <- tempfile()
#' create_lesson(tmp, open = FALSE)
#'
#' # open the episode for editing
#' file.edit(fs::path(tmp, "episodes", "01-introduction.Rmd"))
#' # open the episode for editing
#' file.edit(fs::path(tmp, "episodes", "01-introduction.Rmd"))
#'
#' # serve the lesson and begin editing the file. Watch how the file will
#' # auto-update whenever you save it.
#' sandpaper::serve()
#' #
#' # to stop the server, run
#' servr::daemon_stop()
#' #
#' # If you want to use a different port, you can specify it directly
#' sandpaper::serve(host = "127.0.0.1", port = "3435")
#' # serve the lesson and begin editing the file. Watch how the file will
#' # auto-update whenever you save it.
#' sandpaper::serve()
#' #
#' # to stop the server, run
#' servr::daemon_stop()
#' #
#' # If you want to use a different port, you can specify it directly
#' sandpaper::serve(host = "127.0.0.1", port = "3435")
#' }
#nocov start
# nocov start
# Note: we can not test this in covr because I'm not entirely sure of how to get
# it going
serve <- function(path = ".", quiet = !interactive(), ...) {
Expand All @@ -76,7 +76,7 @@ serve <- function(path = ".", quiet = !interactive(), ...) {
}
for (f in file_list) {
if (!quiet) {
cli::cli_alert_info("Rebuilding {.path f}")
cli::cli_alert_info("Rebuilding {.path {f}}")
}
build_lesson(f, preview = FALSE, quiet = quiet)
}
Expand All @@ -92,7 +92,7 @@ serve <- function(path = ".", quiet = !interactive(), ...) {
# @param base the base path
make_filter <- function(base = this_path) {
no_site <- file.path(base, "site")
no_git <- file.path(base, ".git")
no_git <- file.path(base, ".git")
# return a filter function for the files
function(x) {
return(x[(!startsWith(x, no_site) | !startsWith(x, no_git))])
Expand All @@ -101,7 +101,10 @@ serve <- function(path = ".", quiet = !interactive(), ...) {
this_filter <- make_filter(this_path)
# to start, build the site and then watch things:
rend(this_path)
servr::httw(prod, watch = this_path, filter = this_filter, handler = rend,
...)
servr::httw(prod,
watch = this_path, filter = this_filter, handler = rend,
...
)
}
#nocov end
# nocov end

Loading
Loading