From 056b972b4aa6544e7d2fea9f3119b6f079400ad8 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:59:15 +1100 Subject: [PATCH 01/17] Add purrr standalones for pmap --- R/map.R | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/R/map.R b/R/map.R index 0c23a76..c2b466f 100644 --- a/R/map.R +++ b/R/map.R @@ -12,6 +12,11 @@ map_chr <- function(.x, .f, ...) { .rlang_purrr_map_mold(.x, .f, character(1L), ...) } +#' no@Rd +map_int <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, integer(1), ...) +} + #' @noRd .rlang_purrr_map_mold <- function(.x, .f, .mold, ...) { .f <- as_function(.f, env = global_env()) @@ -20,6 +25,28 @@ map_chr <- function(.x, .f, ...) { out } +#' @noRd +pmap <- function(.l, .f, ...) { + .f <- as.function(.f) + args <- .rlang_purrr_args_recycle(.l) + do.call("mapply", c( + FUN = list(quote(.f)), + args, MoreArgs = quote(list(...)), + SIMPLIFY = FALSE, USE.NAMES = FALSE + )) +} + +.rlang_purrr_args_recycle <- function(args) { + lengths <- map_int(args, length) + n <- max(lengths) + + stopifnot(all(lengths == 1L | lengths == n)) + to_recycle <- lengths == 1L + args[to_recycle] <- map(args[to_recycle], function(x) rep.int(x, n)) + + args +} + #' Apply a function to each element of a vector and return Quarto block vector #' #' [map_qto()] loops a list over a package function defined by .type or a custom @@ -79,3 +106,4 @@ map_qto <- function(.x, } ) } + From ec712ba0c291123b5ee00757ee104b5dccb0eca9 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:02:25 +1100 Subject: [PATCH 02/17] call -> .call --- R/block.R | 8 ++++---- R/callout.R | 4 ++-- R/map.R | 6 +++--- R/with.R | 20 ++++++++++---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/R/block.R b/R/block.R index c695245..d9aa169 100644 --- a/R/block.R +++ b/R/block.R @@ -18,8 +18,8 @@ #' - [knitr::asis_output()] #' #' @export -qto_block <- function(..., sep = "", collapse = "", call = caller_env()) { - check_dots_unnamed(call = call) +qto_block <- function(..., sep = "", collapse = "", .call = caller_env()) { + check_dots_unnamed(call = .call) structure( paste(..., sep = sep, collapse = collapse), class = c("knit_asis", "quarto_block") @@ -65,7 +65,7 @@ qto_div <- function(..., collapse = "", drop_empty = TRUE, drop_na = TRUE, - call = caller_env()) { + .call = caller_env()) { check_dots_unnamed() .content <- .content %||% dots_list(...) @@ -89,7 +89,7 @@ qto_div <- function(..., qto_fence(.attributes = .attributes), paste0(.content, collapse = collapse), qto_fence(), - call = call + .call = .call ) } diff --git a/R/callout.R b/R/callout.R index 2f04757..5c3a585 100644 --- a/R/callout.R +++ b/R/callout.R @@ -37,7 +37,7 @@ qto_callout <- function(..., id = NULL, class = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { type <- arg_match(type) class <- paste0("callout-", type) @@ -67,6 +67,6 @@ qto_callout <- function(..., class = class, id = id, .attributes = .attributes, - call = call + .call = .call ) } diff --git a/R/map.R b/R/map.R index c2b466f..166330f 100644 --- a/R/map.R +++ b/R/map.R @@ -80,11 +80,11 @@ map_qto <- function(.x, .sep = "", .collapse = "", .call = caller_env()) { - .type <- arg_match(.type, error_call = call) + .type <- arg_match(.type, error_call = .call) map( .x, - \(x) { + function(x) { .f <- .f %||% switch(.type, block = qto_block, div = qto_div, @@ -93,7 +93,7 @@ map_qto <- function(.x, ) if (!rlang::is_function(.f)) { - .f <- rlang::as_function(.f, call = call) + .f <- rlang::as_function(.f, call = .call) } x <- .f(x, ...) diff --git a/R/with.R b/R/with.R index 8fd8f78..2d2cea3 100644 --- a/R/with.R +++ b/R/with.R @@ -28,7 +28,7 @@ with_body_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) outset_string <- ifelse(isTRUE(outset), "-outset", "") cls <- sprintf(".column-body%s%s", outset_string, extension_string) @@ -38,7 +38,7 @@ with_body_column <- function(..., ..., id = id, .attributes = .attributes, - call = call + .call = .call ) } @@ -49,7 +49,7 @@ with_page_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) cls <- sprintf(".column-page%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -58,7 +58,7 @@ with_page_column <- function(..., ..., id = id, .attributes = .attributes, - call = call + .call = .call ) } @@ -69,7 +69,7 @@ with_screen_inset_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right", "shaded")) cls <- sprintf(".column-screen-inset%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -78,7 +78,7 @@ with_screen_inset_column <- function(..., ..., id = id, .attributes = .attributes, - call = call + .call = .call ) } @@ -89,7 +89,7 @@ with_screen_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) cls <- sprintf(".column-screen%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -98,7 +98,7 @@ with_screen_column <- function(..., ..., id = id, .attributes = .attributes, - call = call + .call = .call ) } @@ -107,13 +107,13 @@ with_screen_column <- function(..., with_margin_column <- function(..., id = NULL, .attributes = NULL, - call = caller_env()) { + .call = caller_env()) { .attributes <- c(".column-margin", as.list(.attributes)) .attributes <- list_drop_empty(.attributes) qto_div( ..., id = id, .attributes = .attributes, - call = call + .call = .call ) } From 3efc12c48442b1a018af2e1ffef6b678923662c2 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:46:06 +1100 Subject: [PATCH 03/17] Implement pmap_qto --- NAMESPACE | 1 + R/map.R | 38 +++++++++++++++++++++++++++++++++++--- man/page-layout.Rd | 12 ++++++------ man/qto_block.Rd | 4 ++-- man/qto_callout.Rd | 4 ++-- man/qto_div.Rd | 4 ++-- 6 files changed, 48 insertions(+), 15 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 18c32e5..09ac028 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,7 @@ S3method(print,quarto_block) export(map_qto) +export(pmap_qto) export(qto_attributes) export(qto_block) export(qto_callout) diff --git a/R/map.R b/R/map.R index 166330f..0b51f1f 100644 --- a/R/map.R +++ b/R/map.R @@ -12,7 +12,7 @@ map_chr <- function(.x, .f, ...) { .rlang_purrr_map_mold(.x, .f, character(1L), ...) } -#' no@Rd +#' @noRd map_int <- function(.x, .f, ...) { .rlang_purrr_map_mold(.x, .f, integer(1), ...) } @@ -81,7 +81,6 @@ map_qto <- function(.x, .collapse = "", .call = caller_env()) { .type <- arg_match(.type, error_call = .call) - map( .x, function(x) { @@ -102,8 +101,41 @@ map_qto <- function(.x, return(x) } - qto_block(x, sep = .sep, collapse = .collapse, call = .call) + qto_block(x, sep = .sep, collapse = .collapse, .call = .call) } ) } +#' @export +pmap_qto <- function(.l, + .f = NULL, + ..., + .type = c("block", "div", "callout", "heading"), + .sep = "", + .collapse = "", + .call = caller_env()) { + .type <- arg_match(.type, error_call = .call) + pmap( + .l, + function(...) { + .f <- .f %||% switch(.type, + block = qto_block, + div = qto_div, + callout = qto_callout, + heading = qto_heading + ) + + if (!rlang::is_function(.f)) { + .f <- rlang::as_function(.f, call = .call) + } + + x <- .f(...) + + if (inherits(x, "quarto_block")) { + return(x) + } + + qto_block(x, sep = .sep, collapse = .collapse, .call = .call) + } + ) +} diff --git a/man/page-layout.Rd b/man/page-layout.Rd index e883b49..61045a8 100644 --- a/man/page-layout.Rd +++ b/man/page-layout.Rd @@ -15,7 +15,7 @@ with_body_column( class = NULL, extension = NULL, .attributes = NULL, - call = caller_env() + .call = caller_env() ) with_page_column( @@ -24,7 +24,7 @@ with_page_column( class = NULL, extension = NULL, .attributes = NULL, - call = caller_env() + .call = caller_env() ) with_screen_inset_column( @@ -33,7 +33,7 @@ with_screen_inset_column( class = NULL, extension = NULL, .attributes = NULL, - call = caller_env() + .call = caller_env() ) with_screen_column( @@ -42,10 +42,10 @@ with_screen_column( class = NULL, extension = NULL, .attributes = NULL, - call = caller_env() + .call = caller_env() ) -with_margin_column(..., id = NULL, .attributes = NULL, call = caller_env()) +with_margin_column(..., id = NULL, .attributes = NULL, .call = caller_env()) } \arguments{ \item{...}{ @@ -73,7 +73,7 @@ period character is applied as a prefix.} \item{.attributes}{Optional list of attributes. If supplied, any attributes passed to \code{...} are ignored.} -\item{call}{The execution environment of a currently +\item{.call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/qto_block.Rd b/man/qto_block.Rd index b04734f..609f7aa 100644 --- a/man/qto_block.Rd +++ b/man/qto_block.Rd @@ -4,7 +4,7 @@ \alias{qto_block} \title{Create a block of text to render as Markdown text in Quarto} \usage{ -qto_block(..., sep = "", collapse = "", call = caller_env()) +qto_block(..., sep = "", collapse = "", .call = caller_env()) } \arguments{ \item{...}{dots to convert to character vector} @@ -16,7 +16,7 @@ qto_block(..., sep = "", collapse = "", call = caller_env()) \code{\link[base]{NA_character_}}. When \code{collapse} is a string, the result is always a string (\code{\link[base]{character}} of length 1).} -\item{call}{The execution environment of a currently +\item{.call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/qto_callout.Rd b/man/qto_callout.Rd index 5b73002..e6b3559 100644 --- a/man/qto_callout.Rd +++ b/man/qto_callout.Rd @@ -14,7 +14,7 @@ qto_callout( id = NULL, class = NULL, .attributes = NULL, - call = caller_env() + .call = caller_env() ) } \arguments{ @@ -51,7 +51,7 @@ period character is applied as a prefix.} \item{.attributes}{Optional list of attributes. If supplied, any attributes passed to \code{...} are ignored.} -\item{call}{The execution environment of a currently +\item{.call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/qto_div.Rd b/man/qto_div.Rd index 6beba61..e7b81e6 100644 --- a/man/qto_div.Rd +++ b/man/qto_div.Rd @@ -14,7 +14,7 @@ qto_div( collapse = "", drop_empty = TRUE, drop_na = TRUE, - call = caller_env() + .call = caller_env() ) } \arguments{ @@ -41,7 +41,7 @@ ignored. If \code{.content} is \code{NULL}, it is set as all values passed to \c \item{drop_na}{If \code{TRUE}, drop \code{NA} values from \code{.content} or \code{...}} -\item{call}{The execution environment of a currently +\item{.call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} From 77d3f7c324a5ffa548ff5c38e2126b7f029fb62c Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:49:05 +1100 Subject: [PATCH 04/17] Move standalones to separate file --- R/import-standalone-purrr.R | 49 +++++++++++++++++++++++++++++++++++++ R/map.R | 49 ------------------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) create mode 100644 R/import-standalone-purrr.R diff --git a/R/import-standalone-purrr.R b/R/import-standalone-purrr.R new file mode 100644 index 0000000..ec9bae5 --- /dev/null +++ b/R/import-standalone-purrr.R @@ -0,0 +1,49 @@ +#' all functions here are copied from the +#' `standalone-purrr.R` script in rlang: +#' https://github.com/r-lib/rlang/blob/main/R/standalone-purrr.R +#' @noRd +map <- function(.x, .f, ...) { + .f <- as_function(.f, env = global_env()) + lapply(.x, .f, ...) +} + +#' @noRd +map_chr <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, character(1L), ...) +} + +#' @noRd +map_int <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, integer(1), ...) +} + +#' @noRd +.rlang_purrr_map_mold <- function(.x, .f, .mold, ...) { + .f <- as_function(.f, env = global_env()) + out <- vapply(.x, .f, .mold, ..., USE.NAMES = FALSE) + names(out) <- names(.x) + out +} + +#' @noRd +pmap <- function(.l, .f, ...) { + .f <- as.function(.f) + args <- .rlang_purrr_args_recycle(.l) + do.call("mapply", c( + FUN = list(quote(.f)), + args, MoreArgs = quote(list(...)), + SIMPLIFY = FALSE, USE.NAMES = FALSE + )) +} + +#' @noRd +.rlang_purrr_args_recycle <- function(args) { + lengths <- map_int(args, length) + n <- max(lengths) + + stopifnot(all(lengths == 1L | lengths == n)) + to_recycle <- lengths == 1L + args[to_recycle] <- map(args[to_recycle], function(x) rep.int(x, n)) + + args +} diff --git a/R/map.R b/R/map.R index 0b51f1f..0109ed1 100644 --- a/R/map.R +++ b/R/map.R @@ -1,52 +1,3 @@ -#' map, map_chr, and .rlang_purrr_map_mold are copied from the -#' `standalone-purrr.R` script in rlang: -#' https://github.com/r-lib/rlang/blob/main/R/standalone-purrr.R -#' @noRd -map <- function(.x, .f, ...) { - .f <- as_function(.f, env = global_env()) - lapply(.x, .f, ...) -} - -#' @noRd -map_chr <- function(.x, .f, ...) { - .rlang_purrr_map_mold(.x, .f, character(1L), ...) -} - -#' @noRd -map_int <- function(.x, .f, ...) { - .rlang_purrr_map_mold(.x, .f, integer(1), ...) -} - -#' @noRd -.rlang_purrr_map_mold <- function(.x, .f, .mold, ...) { - .f <- as_function(.f, env = global_env()) - out <- vapply(.x, .f, .mold, ..., USE.NAMES = FALSE) - names(out) <- names(.x) - out -} - -#' @noRd -pmap <- function(.l, .f, ...) { - .f <- as.function(.f) - args <- .rlang_purrr_args_recycle(.l) - do.call("mapply", c( - FUN = list(quote(.f)), - args, MoreArgs = quote(list(...)), - SIMPLIFY = FALSE, USE.NAMES = FALSE - )) -} - -.rlang_purrr_args_recycle <- function(args) { - lengths <- map_int(args, length) - n <- max(lengths) - - stopifnot(all(lengths == 1L | lengths == n)) - to_recycle <- lengths == 1L - args[to_recycle] <- map(args[to_recycle], function(x) rep.int(x, n)) - - args -} - #' Apply a function to each element of a vector and return Quarto block vector #' #' [map_qto()] loops a list over a package function defined by .type or a custom From 8ecf8431600716fb432a99847f1804ffa0c1aaf2 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Wed, 20 Dec 2023 21:14:34 +1100 Subject: [PATCH 05/17] docs --- R/map.R | 19 +++++++++++++++++++ man/map_qto.Rd | 3 +++ man/pmap_qto.Rd | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 man/pmap_qto.Rd diff --git a/R/map.R b/R/map.R index 0109ed1..b03eb43 100644 --- a/R/map.R +++ b/R/map.R @@ -23,6 +23,7 @@ #' #' qto_block(qto_list) #' +#' @seealso [quartools::pmap_qto], [purrr::map] #' @export map_qto <- function(.x, .f = NULL, @@ -57,6 +58,24 @@ map_qto <- function(.x, ) } +#' Map over multiple inputs simultaenously and return Quarto block vector +#' +#' [pmap_qto()] loops a list of vectors over a package function defined by .type or a custom +#' function that returns a quarto block output. This function always returns a +#' list of quarto block objects. +#' +#' @param .l An input vector. +#' @param .f Optional function to apply to each element. If function does not +#' return a "quarto_block" class object, the output is passed to [qto_block()] +#' @param ... Additional parameters passed to function defined by `.f`. +#' @param .type If .f is `NULL`, type is used to define the function applied to +#' each element of the vector. Options include "block", "div", "callout", or +#' "heading". +#' @param .sep,.collapse Additional parameters passed to [qto_block()] if .f +#' does not return a quarto block class object. Ignored if .f does return a +#' quarto block class object. +#' @inheritParams rlang::args_error_context +#' @seealso [quartools::map_qto], [purrr::pmap] #' @export pmap_qto <- function(.l, .f = NULL, diff --git a/man/map_qto.Rd b/man/map_qto.Rd index b6f5e28..69c42ca 100644 --- a/man/map_qto.Rd +++ b/man/map_qto.Rd @@ -49,3 +49,6 @@ qto_list <- map_qto( qto_block(qto_list) } +\seealso{ +\link{pmap_qto}, \link[purrr:map]{purrr::map} +} diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd new file mode 100644 index 0000000..e1e724c --- /dev/null +++ b/man/pmap_qto.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/map.R +\name{pmap_qto} +\alias{pmap_qto} +\title{Map over multiple inputs simultaenously and return Quarto block vector} +\usage{ +pmap_qto( + .l, + .f = NULL, + ..., + .type = c("block", "div", "callout", "heading"), + .sep = "", + .collapse = "", + .call = caller_env() +) +} +\arguments{ +\item{.l}{An input vector.} + +\item{.f}{Optional function to apply to each element. If function does not +return a "quarto_block" class object, the output is passed to \code{\link[=qto_block]{qto_block()}}} + +\item{...}{Additional parameters passed to function defined by \code{.f}.} + +\item{.type}{If .f is \code{NULL}, type is used to define the function applied to +each element of the vector. Options include "block", "div", "callout", or +"heading".} + +\item{.sep, .collapse}{Additional parameters passed to \code{\link[=qto_block]{qto_block()}} if .f +does not return a quarto block class object. Ignored if .f does return a +quarto block class object.} + +\item{.call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} +} +\description{ +\code{\link[=pmap_qto]{pmap_qto()}} loops a list of vectors over a package function defined by .type or a custom +function that returns a quarto block output. This function always returns a +list of quarto block objects. +} +\seealso{ +\link{map_qto}, \link[purrr:pmap]{purrr::pmap} +} From 6b1627b61ea21b1d4f7dda48ac6c96c7d7dd8d71 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:34:33 +1100 Subject: [PATCH 06/17] Add tests - Add pmap and map tests --- R/import-standalone-purrr.R | 4 +++ tests/testthat/_snaps/map.md | 57 ++++++++++++++++++++++++++++++++++++ tests/testthat/test_map.R | 38 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 tests/testthat/_snaps/map.md create mode 100644 tests/testthat/test_map.R diff --git a/R/import-standalone-purrr.R b/R/import-standalone-purrr.R index ec9bae5..a4627b0 100644 --- a/R/import-standalone-purrr.R +++ b/R/import-standalone-purrr.R @@ -1,3 +1,5 @@ +# nocov start + #' all functions here are copied from the #' `standalone-purrr.R` script in rlang: #' https://github.com/r-lib/rlang/blob/main/R/standalone-purrr.R @@ -47,3 +49,5 @@ pmap <- function(.l, .f, ...) { args } + +# nocov end \ No newline at end of file diff --git a/tests/testthat/_snaps/map.md b/tests/testthat/_snaps/map.md new file mode 100644 index 0000000..cf5b8b5 --- /dev/null +++ b/tests/testthat/_snaps/map.md @@ -0,0 +1,57 @@ +# map_qto works + + Code + qto_list + Output + [[1]] + + ::: {.callout-note} + This is a note. + ::: + + + [[2]] + + ::: {.callout-note} + And this is a note. + ::: + + + [[3]] + + ::: {.callout-note} + And this is a note + ::: + + + +--- + + Code + qto_list + Output + [[1]] + foo + + [[2]] + bar + + [[3]] + baz + + +# pmap_qto works + + Code + qto_list + Output + [[1]] + Answer: Yes + + [[2]] + Answer: No + + [[3]] + Answer: Yes + + diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R new file mode 100644 index 0000000..52d0dea --- /dev/null +++ b/tests/testthat/test_map.R @@ -0,0 +1,38 @@ +check_types <- function(lst) { + res <- vapply(lst, function(x) { + "quarto_block" %in% class(x) + }, logical(1L)) + all(res) +} + +test_that("map_qto works", { + qto_list <- map_qto( + list("This is a note.", "And this is a note.", "And this is a note"), + .type = "callout" + ) + expect_length(qto_list, 3L) + expect_true(check_types(qto_list)) + expect_snapshot(qto_list) + + + qto_list <- map_qto( + list("foo", "bar", "baz"), + .f = function(x) x + ) + expect_length(qto_list, 3L) + expect_true(check_types(qto_list)) + expect_snapshot(qto_list) +}) + +test_that("pmap_qto works", { + qto_list <- pmap_qto( + list( + list("Answer: ", "Answer: ", "Answer: "), + list("Yes", "No", "Yes") + ) + ) + expect_length(qto_list, 3L) + expect_true(check_types(qto_list)) + expect_snapshot(qto_list) +}) + From 76ef8ca14d172fcb8ce73a078e43f10ce3aa72e9 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:45:04 +1100 Subject: [PATCH 07/17] Update docs --- R/map.R | 23 ++++++++++++----------- man/map_qto.Rd | 2 +- man/pmap_qto.Rd | 12 +++++++++++- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/R/map.R b/R/map.R index b03eb43..f37ea0d 100644 --- a/R/map.R +++ b/R/map.R @@ -23,7 +23,7 @@ #' #' qto_block(qto_list) #' -#' @seealso [quartools::pmap_qto], [purrr::map] +#' @seealso [quartools::pmap_qto()], [purrr::map()] #' @export map_qto <- function(.x, .f = NULL, @@ -65,17 +65,18 @@ map_qto <- function(.x, #' list of quarto block objects. #' #' @param .l An input vector. -#' @param .f Optional function to apply to each element. If function does not -#' return a "quarto_block" class object, the output is passed to [qto_block()] -#' @param ... Additional parameters passed to function defined by `.f`. -#' @param .type If .f is `NULL`, type is used to define the function applied to -#' each element of the vector. Options include "block", "div", "callout", or -#' "heading". -#' @param .sep,.collapse Additional parameters passed to [qto_block()] if .f -#' does not return a quarto block class object. Ignored if .f does return a -#' quarto block class object. #' @inheritParams rlang::args_error_context -#' @seealso [quartools::map_qto], [purrr::pmap] +#' @inheritParams map_qto +#' @examples +#' qto_list <- pmap_qto( +#' list( +#' list("Answer:", "Answer:", "Answer:"), +#' list("Yes", "No", "Yes") +#' ) +#' ) +#' qto_block(qto_list) +#' +#' @seealso [quartools::map_qto()], [purrr::pmap()] #' @export pmap_qto <- function(.l, .f = NULL, diff --git a/man/map_qto.Rd b/man/map_qto.Rd index 69c42ca..c296a45 100644 --- a/man/map_qto.Rd +++ b/man/map_qto.Rd @@ -50,5 +50,5 @@ qto_block(qto_list) } \seealso{ -\link{pmap_qto}, \link[purrr:map]{purrr::map} +\code{\link[=pmap_qto]{pmap_qto()}}, \code{\link[purrr:map]{purrr::map()}} } diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd index e1e724c..6038b42 100644 --- a/man/pmap_qto.Rd +++ b/man/pmap_qto.Rd @@ -39,7 +39,17 @@ mentioned in error messages as the source of the error. See the \code{\link[=pmap_qto]{pmap_qto()}} loops a list of vectors over a package function defined by .type or a custom function that returns a quarto block output. This function always returns a list of quarto block objects. +} +\examples{ +qto_list <- pmap_qto( + list( + list("Answer:", "Answer:", "Answer:"), + list("Yes", "No", "Yes") + ) +) +qto_block(qto_list) + } \seealso{ -\link{map_qto}, \link[purrr:pmap]{purrr::pmap} +\code{\link[=map_qto]{map_qto()}}, \code{\link[purrr:pmap]{purrr::pmap()}} } From a3af78884a40761ce772db19de0076e0cd1c0ede Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:49:23 +1100 Subject: [PATCH 08/17] Examples --- R/map.R | 12 ++++++++++++ man/pmap_qto.Rd | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/R/map.R b/R/map.R index f37ea0d..d0d63cf 100644 --- a/R/map.R +++ b/R/map.R @@ -76,6 +76,18 @@ map_qto <- function(.x, #' ) #' qto_block(qto_list) #' +#' qto_list <- pmap_qto( +#' list( +#' "Hello", +#' "World", +#' "!" +#' ), +#' .f = function(x, y, z) { +#' sprintf("%s %s%s", x, y, z) +#' } +#' ) +#' qto_block(qto_list) +#' #' @seealso [quartools::map_qto()], [purrr::pmap()] #' @export pmap_qto <- function(.l, diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd index 6038b42..fcc15c4 100644 --- a/man/pmap_qto.Rd +++ b/man/pmap_qto.Rd @@ -49,6 +49,18 @@ qto_list <- pmap_qto( ) qto_block(qto_list) +qto_list <- pmap_qto( + list( + "Hello", + "World", + "!" + ), + .f = function(x, y, z) { + sprintf("\%s \%s\%s", x, y, z) + } +) +qto_block(qto_list) + } \seealso{ \code{\link[=map_qto]{map_qto()}}, \code{\link[purrr:pmap]{purrr::pmap()}} From dca452fd2208e41c94e6492b03375af5b34e5d5f Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:09:22 +1100 Subject: [PATCH 09/17] Refactor mapping functions - pmap/map shouldn't be resolving the mapper every iteration - pmap should now be using the outer dots of the pmap function --- R/map.R | 49 +++++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/R/map.R b/R/map.R index d0d63cf..f868e9a 100644 --- a/R/map.R +++ b/R/map.R @@ -1,3 +1,16 @@ +resolve_mapping_function <- function(.f, .type, .call) { + .f <- .f %||% switch(.type, + block = qto_block, + div = qto_div, + callout = qto_callout, + heading = qto_heading + ) + if (!is_function(.f)) { + .f <- as_function(.f, call = .call) + } + .f +} + #' Apply a function to each element of a vector and return Quarto block vector #' #' [map_qto()] loops a list over a package function defined by .type or a custom @@ -33,20 +46,10 @@ map_qto <- function(.x, .collapse = "", .call = caller_env()) { .type <- arg_match(.type, error_call = .call) + .f <- resolve_mapping_function(.f, .type, .call) map( .x, function(x) { - .f <- .f %||% switch(.type, - block = qto_block, - div = qto_div, - callout = qto_callout, - heading = qto_heading - ) - - if (!rlang::is_function(.f)) { - .f <- rlang::as_function(.f, call = .call) - } - x <- .f(x, ...) if (inherits(x, "quarto_block")) { @@ -58,6 +61,9 @@ map_qto <- function(.x, ) } + + + #' Map over multiple inputs simultaenously and return Quarto block vector #' #' [pmap_qto()] loops a list of vectors over a package function defined by .type or a custom @@ -98,27 +104,14 @@ pmap_qto <- function(.l, .collapse = "", .call = caller_env()) { .type <- arg_match(.type, error_call = .call) + .f <- resolve_mapping_function(.f, .type, .call) pmap( .l, function(...) { - .f <- .f %||% switch(.type, - block = qto_block, - div = qto_div, - callout = qto_callout, - heading = qto_heading - ) - - if (!rlang::is_function(.f)) { - .f <- rlang::as_function(.f, call = .call) - } - x <- .f(...) - - if (inherits(x, "quarto_block")) { - return(x) - } - + if (inherits(x, "quarto_block")) return(x) qto_block(x, sep = .sep, collapse = .collapse, .call = .call) - } + }, + ... ) } From 1f848f98f505919b266cacb083e783bc2f43e594 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:28:20 +1100 Subject: [PATCH 10/17] Add test for mapping fn resolve --- R/map.R | 8 ++------ tests/testthat/test_map.R | 8 ++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/R/map.R b/R/map.R index f868e9a..6da1d35 100644 --- a/R/map.R +++ b/R/map.R @@ -1,4 +1,4 @@ -resolve_mapping_function <- function(.f, .type, .call) { +resolve_mapping_function <- function(.f = NULL, .type = NULL, .call = NULL) { .f <- .f %||% switch(.type, block = qto_block, div = qto_div, @@ -51,11 +51,7 @@ map_qto <- function(.x, .x, function(x) { x <- .f(x, ...) - - if (inherits(x, "quarto_block")) { - return(x) - } - + if (inherits(x, "quarto_block")) return(x) qto_block(x, sep = .sep, collapse = .collapse, .call = .call) } ) diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index 52d0dea..7257bbf 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -5,6 +5,14 @@ check_types <- function(lst) { all(res) } +test_that("mapping function is resolved correctly", { + expect_identical( + resolve_mapping_function(.type = "block"), + qto_block + ) + expect_type(resolve_mapping_function(.f = ~.x + 1L), "closure") +}) + test_that("map_qto works", { qto_list <- map_qto( list("This is a note.", "And this is a note.", "And this is a note"), From 2d11d2ed242bfc1d928e686899636f5fa79a1d12 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 18:52:15 +1100 Subject: [PATCH 11/17] create partial funcs for map/pmap - collapse and sep weren't being passed to qto_* functions if they were being used via the .type parameter. we now prefill this using an anonymous func --- R/map.R | 47 +++++++++++++++++++++++++++------------ tests/testthat/test_map.R | 6 +---- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/R/map.R b/R/map.R index 6da1d35..9c0d952 100644 --- a/R/map.R +++ b/R/map.R @@ -1,14 +1,24 @@ -resolve_mapping_function <- function(.f = NULL, .type = NULL, .call = NULL) { - .f <- .f %||% switch(.type, - block = qto_block, - div = qto_div, - callout = qto_callout, - heading = qto_heading +partial_qto_func <- function(f, collapse, sep) { + function(...) { + f(..., collapse = collapse, sep = sep) + } +} + +resolve_mapping_function <- function(f = NULL, + type = NULL, + collapse = NULL, + sep = NULL, + call = NULL) { + f <- f %||% switch(type, + block = partial_qto_func(qto_block, collapse, sep), + div = partial_qto_func(qto_div, collapse, sep), + callout = partial_qto_func(qto_callout, collapse, sep), + heading = partial_qto_func(qto_heading, collapse, sep), ) - if (!is_function(.f)) { - .f <- as_function(.f, call = .call) + if (!is_function(f)) { + f <- as_function(f, call = call) } - .f + f } #' Apply a function to each element of a vector and return Quarto block vector @@ -46,7 +56,13 @@ map_qto <- function(.x, .collapse = "", .call = caller_env()) { .type <- arg_match(.type, error_call = .call) - .f <- resolve_mapping_function(.f, .type, .call) + .f <- resolve_mapping_function( + f = .f, + type = .type, + collapse = .collapse, + sep = .sep, + call = .call + ) map( .x, function(x) { @@ -57,9 +73,6 @@ map_qto <- function(.x, ) } - - - #' Map over multiple inputs simultaenously and return Quarto block vector #' #' [pmap_qto()] loops a list of vectors over a package function defined by .type or a custom @@ -100,7 +113,13 @@ pmap_qto <- function(.l, .collapse = "", .call = caller_env()) { .type <- arg_match(.type, error_call = .call) - .f <- resolve_mapping_function(.f, .type, .call) + .f <- resolve_mapping_function( + f = .f, + type = .type, + collapse = .collapse, + sep = .sep, + call = .call + ) pmap( .l, function(...) { diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index 7257bbf..c5aee2d 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -6,11 +6,7 @@ check_types <- function(lst) { } test_that("mapping function is resolved correctly", { - expect_identical( - resolve_mapping_function(.type = "block"), - qto_block - ) - expect_type(resolve_mapping_function(.f = ~.x + 1L), "closure") + expect_type(resolve_mapping_function(f = ~.x + 1L), "closure") }) test_that("map_qto works", { From ce5ef818d849ac255109aca6d11e546737db4a28 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:04:44 +1100 Subject: [PATCH 12/17] dont pass to qto_div or qto_callout collapse and sep aren't passed to div or callout --- R/map.R | 6 ++++-- tests/testthat/test_map.R | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/map.R b/R/map.R index 9c0d952..33c4b67 100644 --- a/R/map.R +++ b/R/map.R @@ -1,6 +1,8 @@ partial_qto_func <- function(f, collapse, sep) { - function(...) { - f(..., collapse = collapse, sep = sep) + if (identical(f, qto_callout) || identical(f, qto_div)) { + function(...) f(...) + } else { + function(...) f(..., collapse = collapse, sep = sep) } } diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index c5aee2d..7650c76 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -39,4 +39,3 @@ test_that("pmap_qto works", { expect_true(check_types(qto_list)) expect_snapshot(qto_list) }) - From cff9d14da89cd434aed5b5118a7fd822609a3ad1 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:02:30 +1100 Subject: [PATCH 13/17] Update test_map.R --- tests/testthat/test_map.R | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index 7650c76..a4059ab 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -5,10 +5,17 @@ check_types <- function(lst) { all(res) } -test_that("mapping function is resolved correctly", { - expect_type(resolve_mapping_function(f = ~.x + 1L), "closure") +test_that("mapping function works", { + expect_type(resolve_mapping_function(f = ~ .x + 1L), "closure") + + fn <- resolve_mapping_function(type = "block", sep = " ", collapse = " ") + expect_identical( + fn("Hello", c("world", "!")), + qto_block("Hello", c("world", "!"), sep = " ", collapse = " ") + ) }) + test_that("map_qto works", { qto_list <- map_qto( list("This is a note.", "And this is a note.", "And this is a note"), @@ -39,3 +46,4 @@ test_that("pmap_qto works", { expect_true(check_types(qto_list)) expect_snapshot(qto_list) }) + From 9cea38049414a2120faf18a3f6c6c6ee7a97b013 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:16:08 +1100 Subject: [PATCH 14/17] tests --- tests/testthat/_snaps/map.md | 24 ++++++++++++++++++++++++ tests/testthat/test_map.R | 21 +++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/testthat/_snaps/map.md b/tests/testthat/_snaps/map.md index cf5b8b5..8d7f967 100644 --- a/tests/testthat/_snaps/map.md +++ b/tests/testthat/_snaps/map.md @@ -55,3 +55,27 @@ Answer: Yes +--- + + Code + qto_list + Output + [[1]] + + * mpg is: 21 + * cyl is: 6 + * disp is: 160 + + [[2]] + + * mpg is: 21 + * cyl is: 6 + * disp is: 160 + + [[3]] + + * mpg is: 22.8 + * cyl is: 4 + * disp is: 108 + + diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index a4059ab..7bc7812 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -5,7 +5,7 @@ check_types <- function(lst) { all(res) } -test_that("mapping function works", { +test_that("resolve_mapping_function works", { expect_type(resolve_mapping_function(f = ~ .x + 1L), "closure") fn <- resolve_mapping_function(type = "block", sep = " ", collapse = " ") @@ -45,5 +45,22 @@ test_that("pmap_qto works", { expect_length(qto_list, 3L) expect_true(check_types(qto_list)) expect_snapshot(qto_list) -}) + + qto_list <- pmap_qto( + mtcars[seq(3L), seq(3L)], + function(mpg, cyl, disp) { + qto_li( + .list = list( + sprintf("mpg is: %s", mpg), + sprintf("cyl is: %s", cyl), + sprintf("disp is: %s", disp) + ) + ) + } + ) + expect_length(qto_list, 3L) + expect_true(check_types(qto_list)) + expect_snapshot(qto_list) + +}) From f362692d9baab31b8bee2bec0ba5acc1beb2dabd Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Sun, 24 Dec 2023 08:46:19 +1100 Subject: [PATCH 15/17] Revert .call -> call --- R/block.R | 8 ++++---- R/callout.R | 4 ++-- R/map.R | 32 +++++++++++++++++--------------- R/with.R | 20 ++++++++++---------- man/map_qto.Rd | 4 ++-- man/page-layout.Rd | 12 ++++++------ man/pmap_qto.Rd | 20 +++++++++++--------- man/qto_block.Rd | 4 ++-- man/qto_callout.Rd | 4 ++-- man/qto_div.Rd | 4 ++-- 10 files changed, 58 insertions(+), 54 deletions(-) diff --git a/R/block.R b/R/block.R index d9aa169..c695245 100644 --- a/R/block.R +++ b/R/block.R @@ -18,8 +18,8 @@ #' - [knitr::asis_output()] #' #' @export -qto_block <- function(..., sep = "", collapse = "", .call = caller_env()) { - check_dots_unnamed(call = .call) +qto_block <- function(..., sep = "", collapse = "", call = caller_env()) { + check_dots_unnamed(call = call) structure( paste(..., sep = sep, collapse = collapse), class = c("knit_asis", "quarto_block") @@ -65,7 +65,7 @@ qto_div <- function(..., collapse = "", drop_empty = TRUE, drop_na = TRUE, - .call = caller_env()) { + call = caller_env()) { check_dots_unnamed() .content <- .content %||% dots_list(...) @@ -89,7 +89,7 @@ qto_div <- function(..., qto_fence(.attributes = .attributes), paste0(.content, collapse = collapse), qto_fence(), - .call = .call + call = call ) } diff --git a/R/callout.R b/R/callout.R index 5c3a585..2f04757 100644 --- a/R/callout.R +++ b/R/callout.R @@ -37,7 +37,7 @@ qto_callout <- function(..., id = NULL, class = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { type <- arg_match(type) class <- paste0("callout-", type) @@ -67,6 +67,6 @@ qto_callout <- function(..., class = class, id = id, .attributes = .attributes, - .call = .call + call = call ) } diff --git a/R/map.R b/R/map.R index 33c4b67..0e77da4 100644 --- a/R/map.R +++ b/R/map.R @@ -56,21 +56,21 @@ map_qto <- function(.x, .type = c("block", "div", "callout", "heading"), .sep = "", .collapse = "", - .call = caller_env()) { - .type <- arg_match(.type, error_call = .call) + call = caller_env()) { + .type <- arg_match(.type, error_call = call) .f <- resolve_mapping_function( f = .f, type = .type, collapse = .collapse, sep = .sep, - call = .call + call = call ) map( .x, function(x) { x <- .f(x, ...) if (inherits(x, "quarto_block")) return(x) - qto_block(x, sep = .sep, collapse = .collapse, .call = .call) + qto_block(x, sep = .sep, collapse = .collapse, call = call) } ) } @@ -94,13 +94,15 @@ map_qto <- function(.x, #' qto_block(qto_list) #' #' qto_list <- pmap_qto( -#' list( -#' "Hello", -#' "World", -#' "!" -#' ), -#' .f = function(x, y, z) { -#' sprintf("%s %s%s", x, y, z) +#' mtcars[seq(3L), seq(3L)], +#' function(mpg, cyl, disp) { +#' qto_li( +#' .list = list( +#' sprintf("mpg is: %s", mpg), +#' sprintf("cyl is: %s", cyl), +#' sprintf("disp is: %s", disp) +#' ) +#' ) #' } #' ) #' qto_block(qto_list) @@ -113,21 +115,21 @@ pmap_qto <- function(.l, .type = c("block", "div", "callout", "heading"), .sep = "", .collapse = "", - .call = caller_env()) { - .type <- arg_match(.type, error_call = .call) + call = caller_env()) { + .type <- arg_match(.type, error_call = call) .f <- resolve_mapping_function( f = .f, type = .type, collapse = .collapse, sep = .sep, - call = .call + call = call ) pmap( .l, function(...) { x <- .f(...) if (inherits(x, "quarto_block")) return(x) - qto_block(x, sep = .sep, collapse = .collapse, .call = .call) + qto_block(x, sep = .sep, collapse = .collapse, call = call) }, ... ) diff --git a/R/with.R b/R/with.R index 2d2cea3..8fd8f78 100644 --- a/R/with.R +++ b/R/with.R @@ -28,7 +28,7 @@ with_body_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) outset_string <- ifelse(isTRUE(outset), "-outset", "") cls <- sprintf(".column-body%s%s", outset_string, extension_string) @@ -38,7 +38,7 @@ with_body_column <- function(..., ..., id = id, .attributes = .attributes, - .call = .call + call = call ) } @@ -49,7 +49,7 @@ with_page_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) cls <- sprintf(".column-page%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -58,7 +58,7 @@ with_page_column <- function(..., ..., id = id, .attributes = .attributes, - .call = .call + call = call ) } @@ -69,7 +69,7 @@ with_screen_inset_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right", "shaded")) cls <- sprintf(".column-screen-inset%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -78,7 +78,7 @@ with_screen_inset_column <- function(..., ..., id = id, .attributes = .attributes, - .call = .call + call = call ) } @@ -89,7 +89,7 @@ with_screen_column <- function(..., class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { extension_string <- handle_extensions(extension, c("left", "right")) cls <- sprintf(".column-screen%s", extension_string) .attributes <- c(cls, as.list(.attributes)) @@ -98,7 +98,7 @@ with_screen_column <- function(..., ..., id = id, .attributes = .attributes, - .call = .call + call = call ) } @@ -107,13 +107,13 @@ with_screen_column <- function(..., with_margin_column <- function(..., id = NULL, .attributes = NULL, - .call = caller_env()) { + call = caller_env()) { .attributes <- c(".column-margin", as.list(.attributes)) .attributes <- list_drop_empty(.attributes) qto_div( ..., id = id, .attributes = .attributes, - .call = .call + call = call ) } diff --git a/man/map_qto.Rd b/man/map_qto.Rd index c296a45..ad23f80 100644 --- a/man/map_qto.Rd +++ b/man/map_qto.Rd @@ -11,7 +11,7 @@ map_qto( .type = c("block", "div", "callout", "heading"), .sep = "", .collapse = "", - .call = caller_env() + call = caller_env() ) } \arguments{ @@ -30,7 +30,7 @@ each element of the vector. Options include "block", "div", "callout", or does not return a quarto block class object. Ignored if .f does return a quarto block class object.} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/page-layout.Rd b/man/page-layout.Rd index 61045a8..e883b49 100644 --- a/man/page-layout.Rd +++ b/man/page-layout.Rd @@ -15,7 +15,7 @@ with_body_column( class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env() + call = caller_env() ) with_page_column( @@ -24,7 +24,7 @@ with_page_column( class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env() + call = caller_env() ) with_screen_inset_column( @@ -33,7 +33,7 @@ with_screen_inset_column( class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env() + call = caller_env() ) with_screen_column( @@ -42,10 +42,10 @@ with_screen_column( class = NULL, extension = NULL, .attributes = NULL, - .call = caller_env() + call = caller_env() ) -with_margin_column(..., id = NULL, .attributes = NULL, .call = caller_env()) +with_margin_column(..., id = NULL, .attributes = NULL, call = caller_env()) } \arguments{ \item{...}{ @@ -73,7 +73,7 @@ period character is applied as a prefix.} \item{.attributes}{Optional list of attributes. If supplied, any attributes passed to \code{...} are ignored.} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd index fcc15c4..af2abaf 100644 --- a/man/pmap_qto.Rd +++ b/man/pmap_qto.Rd @@ -11,7 +11,7 @@ pmap_qto( .type = c("block", "div", "callout", "heading"), .sep = "", .collapse = "", - .call = caller_env() + call = caller_env() ) } \arguments{ @@ -30,7 +30,7 @@ each element of the vector. Options include "block", "div", "callout", or does not return a quarto block class object. Ignored if .f does return a quarto block class object.} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} @@ -50,13 +50,15 @@ qto_list <- pmap_qto( qto_block(qto_list) qto_list <- pmap_qto( - list( - "Hello", - "World", - "!" - ), - .f = function(x, y, z) { - sprintf("\%s \%s\%s", x, y, z) + mtcars[seq(3L), seq(3L)], + function(mpg, cyl, disp) { + qto_li( + .list = list( + sprintf("mpg is: \%s", mpg), + sprintf("cyl is: \%s", cyl), + sprintf("disp is: \%s", disp) + ) + ) } ) qto_block(qto_list) diff --git a/man/qto_block.Rd b/man/qto_block.Rd index 609f7aa..b04734f 100644 --- a/man/qto_block.Rd +++ b/man/qto_block.Rd @@ -4,7 +4,7 @@ \alias{qto_block} \title{Create a block of text to render as Markdown text in Quarto} \usage{ -qto_block(..., sep = "", collapse = "", .call = caller_env()) +qto_block(..., sep = "", collapse = "", call = caller_env()) } \arguments{ \item{...}{dots to convert to character vector} @@ -16,7 +16,7 @@ qto_block(..., sep = "", collapse = "", .call = caller_env()) \code{\link[base]{NA_character_}}. When \code{collapse} is a string, the result is always a string (\code{\link[base]{character}} of length 1).} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/qto_callout.Rd b/man/qto_callout.Rd index e6b3559..5b73002 100644 --- a/man/qto_callout.Rd +++ b/man/qto_callout.Rd @@ -14,7 +14,7 @@ qto_callout( id = NULL, class = NULL, .attributes = NULL, - .call = caller_env() + call = caller_env() ) } \arguments{ @@ -51,7 +51,7 @@ period character is applied as a prefix.} \item{.attributes}{Optional list of attributes. If supplied, any attributes passed to \code{...} are ignored.} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} diff --git a/man/qto_div.Rd b/man/qto_div.Rd index e7b81e6..6beba61 100644 --- a/man/qto_div.Rd +++ b/man/qto_div.Rd @@ -14,7 +14,7 @@ qto_div( collapse = "", drop_empty = TRUE, drop_na = TRUE, - .call = caller_env() + call = caller_env() ) } \arguments{ @@ -41,7 +41,7 @@ ignored. If \code{.content} is \code{NULL}, it is set as all values passed to \c \item{drop_na}{If \code{TRUE}, drop \code{NA} values from \code{.content} or \code{...}} -\item{.call}{The execution environment of a currently +\item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} From 0b7c59cc1edab8974bd98f325d1fbc7a1cf1dc71 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Sun, 24 Dec 2023 11:24:46 +1100 Subject: [PATCH 16/17] Fix docs --- R/map.R | 3 ++- man/map_qto.Rd | 3 ++- man/pmap_qto.Rd | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/R/map.R b/R/map.R index 0e77da4..28f8d8c 100644 --- a/R/map.R +++ b/R/map.R @@ -38,7 +38,8 @@ resolve_mapping_function <- function(f = NULL, #' "heading". #' @param .sep,.collapse Additional parameters passed to [qto_block()] if .f #' does not return a quarto block class object. Ignored if .f does return a -#' quarto block class object. +#' quarto block class object. Also passed to the .type function if it is +#' a "heading" or "block". #' @inheritParams rlang::args_error_context #' @examples #' qto_list <- map_qto( diff --git a/man/map_qto.Rd b/man/map_qto.Rd index ad23f80..b0e51ca 100644 --- a/man/map_qto.Rd +++ b/man/map_qto.Rd @@ -28,7 +28,8 @@ each element of the vector. Options include "block", "div", "callout", or \item{.sep, .collapse}{Additional parameters passed to \code{\link[=qto_block]{qto_block()}} if .f does not return a quarto block class object. Ignored if .f does return a -quarto block class object.} +quarto block class object. Also passed to the .type function if it is +a "heading" or "block".} \item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd index af2abaf..8600590 100644 --- a/man/pmap_qto.Rd +++ b/man/pmap_qto.Rd @@ -28,7 +28,8 @@ each element of the vector. Options include "block", "div", "callout", or \item{.sep, .collapse}{Additional parameters passed to \code{\link[=qto_block]{qto_block()}} if .f does not return a quarto block class object. Ignored if .f does return a -quarto block class object.} +quarto block class object. Also passed to the .type function if it is +a "heading" or "block".} \item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be From f93059ee9bf76b3c800f12e0fed096fc9bf26584 Mon Sep 17 00:00:00 2001 From: "Elian H. Thiele-Evans" <60372411+ElianHugh@users.noreply.github.com> Date: Sun, 24 Dec 2023 11:40:04 +1100 Subject: [PATCH 17/17] Tests, docs --- R/map.R | 8 +++++--- man/map_qto.Rd | 4 ++-- man/pmap_qto.Rd | 4 ++-- tests/testthat/test_map.R | 40 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/R/map.R b/R/map.R index 28f8d8c..c959e40 100644 --- a/R/map.R +++ b/R/map.R @@ -1,6 +1,8 @@ partial_qto_func <- function(f, collapse, sep) { - if (identical(f, qto_callout) || identical(f, qto_div)) { + if (identical(f, qto_callout)) { function(...) f(...) + } else if ((identical(f, qto_div))) { + function(...) f(..., collapse = collapse) } else { function(...) f(..., collapse = collapse, sep = sep) } @@ -38,8 +40,8 @@ resolve_mapping_function <- function(f = NULL, #' "heading". #' @param .sep,.collapse Additional parameters passed to [qto_block()] if .f #' does not return a quarto block class object. Ignored if .f does return a -#' quarto block class object. Also passed to the .type function if it is -#' a "heading" or "block". +#' quarto block class object. Also passed to the relevant .type function if it supports +#' the collapse and/or sep parameters. #' @inheritParams rlang::args_error_context #' @examples #' qto_list <- map_qto( diff --git a/man/map_qto.Rd b/man/map_qto.Rd index b0e51ca..d73bd5a 100644 --- a/man/map_qto.Rd +++ b/man/map_qto.Rd @@ -28,8 +28,8 @@ each element of the vector. Options include "block", "div", "callout", or \item{.sep, .collapse}{Additional parameters passed to \code{\link[=qto_block]{qto_block()}} if .f does not return a quarto block class object. Ignored if .f does return a -quarto block class object. Also passed to the .type function if it is -a "heading" or "block".} +quarto block class object. Also passed to the relevant .type function if it supports +the collapse and/or sep parameters.} \item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be diff --git a/man/pmap_qto.Rd b/man/pmap_qto.Rd index 8600590..237b516 100644 --- a/man/pmap_qto.Rd +++ b/man/pmap_qto.Rd @@ -28,8 +28,8 @@ each element of the vector. Options include "block", "div", "callout", or \item{.sep, .collapse}{Additional parameters passed to \code{\link[=qto_block]{qto_block()}} if .f does not return a quarto block class object. Ignored if .f does return a -quarto block class object. Also passed to the .type function if it is -a "heading" or "block".} +quarto block class object. Also passed to the relevant .type function if it supports +the collapse and/or sep parameters.} \item{call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be diff --git a/tests/testthat/test_map.R b/tests/testthat/test_map.R index 7bc7812..bc7dd33 100644 --- a/tests/testthat/test_map.R +++ b/tests/testthat/test_map.R @@ -8,11 +8,46 @@ check_types <- function(lst) { test_that("resolve_mapping_function works", { expect_type(resolve_mapping_function(f = ~ .x + 1L), "closure") - fn <- resolve_mapping_function(type = "block", sep = " ", collapse = " ") + block_fn <- resolve_mapping_function( + type = "block", + sep = " ", + collapse = " " + ) expect_identical( - fn("Hello", c("world", "!")), + block_fn("Hello", c("world", "!")), qto_block("Hello", c("world", "!"), sep = " ", collapse = " ") ) + + div_fn <- resolve_mapping_function( + type = "div", + sep = " ", + collapse = "bar" + ) + expect_identical( + div_fn("foo", "baz"), + qto_div("foo", "bar", "baz") + ) + + callout_fn <- resolve_mapping_function( + type = "callout", + sep = " ", + collapse = "bar" + ) + expect_identical( + callout_fn("foo", "baz"), + qto_callout("foo", "baz") + ) + + heading_fn <- resolve_mapping_function( + type = "heading", + sep = " ", + collapse = " " + ) + expect_identical( + heading_fn("foo", "baz"), + qto_heading("foo", "baz", collapse = " ", sep = " ") + ) + }) @@ -62,5 +97,4 @@ test_that("pmap_qto works", { expect_length(qto_list, 3L) expect_true(check_types(qto_list)) expect_snapshot(qto_list) - })