From 81b610316558d95789b66dc078be8d2549c9ba0b Mon Sep 17 00:00:00 2001 From: Vedha Viyash <49812166+vedhav@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:48:39 +0530 Subject: [PATCH] feat: allow html content to be added to a report (#294) --- R/ContentBlock.R | 20 +--- R/FileBlock.R | 3 + R/HTMLBlock.R | 62 ++++++++++++ R/Previewer.R | 2 + R/RcodeBlock.R | 16 ++++ R/Renderer.R | 13 ++- R/ReportCard.R | 11 +++ R/TextBlock.R | 15 +++ man/ContentBlock.Rd | 40 +------- man/FileBlock.Rd | 1 - man/HTMLBlock.Rd | 147 +++++++++++++++++++++++++++++ man/RcodeBlock.Rd | 42 ++++++++- man/ReportCard.Rd | 37 ++++++++ man/TextBlock.Rd | 42 ++++++++- tests/testthat/test-ContentBlock.R | 8 +- tests/testthat/test-HTMLBlock.R | 40 ++++++++ tests/testthat/test-RcodeBlock.R | 2 +- tests/testthat/test-Renderer.R | 5 +- tests/testthat/test-ReportCard.R | 9 +- tests/testthat/test-TextBlock.R | 2 +- 20 files changed, 446 insertions(+), 71 deletions(-) create mode 100644 R/HTMLBlock.R create mode 100644 man/HTMLBlock.Rd create mode 100644 tests/testthat/test-HTMLBlock.R diff --git a/R/ContentBlock.R b/R/ContentBlock.R index 04f9dbbc..9d325599 100644 --- a/R/ContentBlock.R +++ b/R/ContentBlock.R @@ -8,22 +8,9 @@ ContentBlock <- R6::R6Class( # nolint: object_name_linter. classname = "ContentBlock", public = list( - #' @description Initialize a `ContentBlock` object. - #' - #' @details Returns a `ContentBlock` object with no content and the default style. - #' - #' @return Object of class `ContentBlock`, invisibly. - #' @examples - #' ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") - #' ContentBlock$new() - #' - initialize = function() { - private$content <- character(0) - invisible(self) - }, #' @description Sets content of this `ContentBlock`. #' - #' @param content (`character(0)` or `character(1)`) string or file path assigned to this `ContentBlock` + #' @param content (`any`) R object #' #' @return `self`, invisibly. #' @examples @@ -32,13 +19,12 @@ ContentBlock <- R6::R6Class( # nolint: object_name_linter. #' block$set_content("Base64 encoded picture") #' set_content = function(content) { - checkmate::assert_character(content, min.len = 0, max.len = 1) private$content <- content invisible(self) }, #' @description Retrieves the content assigned to this block. #' - #' @return `character` string or file path assigned to this `ContentBlock`. + #' @return object stored in a `private$content` field #' @examples #' ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") #' block <- ContentBlock$new() @@ -64,7 +50,7 @@ ContentBlock <- R6::R6Class( # nolint: object_name_linter. } ), private = list( - content = character(0), + content = NULL, # this can be any R object # @description The copy constructor. # # @param name (`character(1)`) the name of the field diff --git a/R/FileBlock.R b/R/FileBlock.R index 9a33d195..bd2d1c48 100644 --- a/R/FileBlock.R +++ b/R/FileBlock.R @@ -56,6 +56,9 @@ FileBlock <- R6::R6Class( # nolint: object_name_linter. list(basename = base_name) } ), + private = list( + content = character(0) + ), lock_objects = TRUE, lock_class = TRUE ) diff --git a/R/HTMLBlock.R b/R/HTMLBlock.R new file mode 100644 index 00000000..70a90e33 --- /dev/null +++ b/R/HTMLBlock.R @@ -0,0 +1,62 @@ +#' @title `HTMLBlock` +#' @docType class +#' @description +#' Specialized `FileBlock` for managing HTML content in reports. +#' It's designed to handle various HTML content, and render the report as HTML, +#' however `htmlwidgets` objects can also be rendered to static document-ready format. +#' +#' @keywords internal +HTMLBlock <- R6::R6Class( # nolint: object_name_linter. + classname = "HTMLBlock", + inherit = ContentBlock, + public = list( + #' @description Initialize a `HTMLBlock` object. + #' + #' @param content An object that can be rendered as a HTML content assigned to + #' this `HTMLBlock` + #' + #' @return Object of class `HTMLBlock`, invisibly. + initialize = function(content) { + if (!missing(content)) { + checkmate::assert_multi_class(content, private$supported_types) + self$set_content(content) + } + invisible(self) + }, + + #' @description Create the `HTMLBlock` from a list. + #' + #' @param x (`named list`) with a single field `content` containing `shiny.tag`, + #' `shiny.tag.list` or `htmlwidget`. + #' + #' @return `self`, invisibly. + #' @examples + #' HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") + #' block <- HTMLBlock$new() + #' block$from_list(list(content = shiny::tags$div("test"))) + #' + from_list = function(x) { + checkmate::assert_list(x, types = private$supported_types) + checkmate::assert_names(names(x), must.include = "content") + self$set_content(x$content) + invisible(self) + }, + + #' @description Convert the `HTMLBlock` to a list. + #' + #' @return `named list` with a text and style. + #' @examples + #' HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") + #' block <- HTMLBlock$new(shiny::tags$div("test")) + #' block$to_list() + #' + to_list = function() { + list(content = self$get_content()) + } + ), + private = list( + supported_types = c("shiny.tag", "shiny.tag.list", "htmlwidget") + ), + lock_objects = TRUE, + lock_class = TRUE +) diff --git a/R/Previewer.R b/R/Previewer.R index 360f0e7d..fc37b626 100644 --- a/R/Previewer.R +++ b/R/Previewer.R @@ -319,6 +319,8 @@ block_to_html <- function(b) { ) } else if (inherits(b, "NewpageBlock")) { shiny::tags$br() + } else if (inherits(b, "HTMLBlock")) { + b_content } else { stop("Unknown block class") } diff --git a/R/RcodeBlock.R b/R/RcodeBlock.R index 9479e590..19f3b750 100644 --- a/R/RcodeBlock.R +++ b/R/RcodeBlock.R @@ -21,10 +21,25 @@ RcodeBlock <- R6::R6Class( # nolint: object_name_linter. #' block <- RcodeBlock$new() #' initialize = function(content = character(0), ...) { + checkmate::assert_class(content, "character") super$set_content(content) self$set_params(list(...)) invisible(self) }, + #' @description Sets content of this `RcodeBlock`. + #' + #' @param content (`any`) R object + #' + #' @return `self`, invisibly. + #' @examples + #' RcodeBlock <- getFromNamespace("RcodeBlock", "teal.reporter") + #' block <- RcodeBlock$new() + #' block$set_content("a <- 1") + #' + set_content = function(content) { + checkmate::assert_string(content) + super$set_content(content) + }, #' @description Sets the parameters of this `RcodeBlock`. #' #' @details Configures `rmarkdown` chunk parameters for the `R` code block, @@ -97,6 +112,7 @@ RcodeBlock <- R6::R6Class( # nolint: object_name_linter. } ), private = list( + content = character(0), params = list() ), lock_objects = TRUE, diff --git a/R/Renderer.R b/R/Renderer.R index 782a9935..8ff3996b 100644 --- a/R/Renderer.R +++ b/R/Renderer.R @@ -81,9 +81,11 @@ Renderer <- R6::R6Class( # nolint: object_name_linter. #' result_path <- Renderer$new()$renderRmd(reporter$get_blocks(), yaml_header) #' renderRmd = function(blocks, yaml_header, global_knitr = getOption("teal.reporter.global_knitr")) { - checkmate::assert_list(blocks, c("TextBlock", "PictureBlock", "NewpageBlock", "TableBlock", "RcodeBlock")) + checkmate::assert_list( + blocks, + c("TextBlock", "PictureBlock", "NewpageBlock", "TableBlock", "RcodeBlock", "HTMLBlock") + ) checkmate::assert_subset(names(global_knitr), names(knitr::opts_chunk$get())) - if (missing(yaml_header)) { yaml_header <- md_header(yaml::as.yaml(list(title = "Report"))) } @@ -220,6 +222,8 @@ Renderer <- R6::R6Class( # nolint: object_name_linter. private$tableBlock2md(block) } else if (inherits(block, "NewpageBlock")) { block$get_content() + } else if (inherits(block, "HTMLBlock")) { + private$htmlBlock2md(block) } else { stop("Unknown block class") } @@ -275,6 +279,11 @@ Renderer <- R6::R6Class( # nolint: object_name_linter. basename_table <- basename(block$get_content()) file.copy(block$get_content(), file.path(private$output_dir, basename_table)) sprintf("```{r echo = FALSE}\nreadRDS('%s')\n```", basename_table) + }, + htmlBlock2md = function(block) { + basename <- basename(tempfile(fileext = ".rds")) + suppressWarnings(saveRDS(block$get_content(), file = file.path(private$output_dir, basename))) + sprintf("```{r echo = FALSE}\nreadRDS('%s')\n```", basename) } ), lock_objects = TRUE, diff --git a/R/ReportCard.R b/R/ReportCard.R index 8ff1595e..c0221751 100644 --- a/R/ReportCard.R +++ b/R/ReportCard.R @@ -37,6 +37,17 @@ ReportCard <- R6::R6Class( # nolint: object_name_linter. self$append_content(TableBlock$new(table)) invisible(self) }, + #' @description Appends a html content to this `ReportCard`. + #' + #' @param content An object that can be rendered as a HTML content. + #' @return `self`, invisibly. + #' @examples + #' card <- ReportCard$new()$append_html(shiny::div("HTML Content")) + #' + append_html = function(content) { + self$append_content(HTMLBlock$new(content)) + invisible(self) + }, #' @description Appends a plot to this `ReportCard`. #' #' @param plot (`ggplot` or `grob` or `trellis`) plot object. diff --git a/R/TextBlock.R b/R/TextBlock.R index 32fd3669..a6d09078 100644 --- a/R/TextBlock.R +++ b/R/TextBlock.R @@ -27,6 +27,20 @@ TextBlock <- R6::R6Class( # nolint: object_name_linter. self$set_style(style) invisible(self) }, + #' @description Sets content of this `TextBlock`. + #' + #' @param content (`any`) R object + #' + #' @return `self`, invisibly. + #' @examples + #' ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") + #' block <- ContentBlock$new() + #' block$set_content("Base64 encoded picture") + #' + set_content = function(content) { + checkmate::assert_string(content) + super$set_content(content) + }, #' @description Sets the style of this `TextBlock`. #' #' @details The style has bearing on the rendering of this block. @@ -96,6 +110,7 @@ TextBlock <- R6::R6Class( # nolint: object_name_linter. } ), private = list( + content = character(0), style = character(0), styles = c("default", "header2", "header3", "verbatim") ), diff --git a/man/ContentBlock.Rd b/man/ContentBlock.Rd index fed18515..4a5ee94d 100644 --- a/man/ContentBlock.Rd +++ b/man/ContentBlock.Rd @@ -11,14 +11,6 @@ It serves as a foundation for constructing complex report structures. } \examples{ -## ------------------------------------------------ -## Method `ContentBlock$new` -## ------------------------------------------------ - -ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") -ContentBlock$new() - - ## ------------------------------------------------ ## Method `ContentBlock$set_content` ## ------------------------------------------------ @@ -41,40 +33,12 @@ block$get_content() \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-ContentBlock-new}{\code{ContentBlock$new()}} \item \href{#method-ContentBlock-set_content}{\code{ContentBlock$set_content()}} \item \href{#method-ContentBlock-get_content}{\code{ContentBlock$get_content()}} \item \href{#method-ContentBlock-from_list}{\code{ContentBlock$from_list()}} \item \href{#method-ContentBlock-to_list}{\code{ContentBlock$to_list()}} \item \href{#method-ContentBlock-clone}{\code{ContentBlock$clone()}} } -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ContentBlock-new}{}}} -\subsection{Method \code{new()}}{ -Initialize a \code{ContentBlock} object. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ContentBlock$new()}\if{html}{\out{
}} -} - -\subsection{Details}{ -Returns a \code{ContentBlock} object with no content and the default style. -} - -\subsection{Returns}{ -Object of class \code{ContentBlock}, invisibly. -} -\subsection{Examples}{ -\if{html}{\out{
}} -\preformatted{ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") -ContentBlock$new() - -} -\if{html}{\out{
}} - -} - } \if{html}{\out{
}} \if{html}{\out{}} @@ -88,7 +52,7 @@ Sets content of this \code{ContentBlock}. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{content}}{(\code{character(0)} or \code{character(1)}) string or file path assigned to this \code{ContentBlock}} +\item{\code{content}}{(\code{any}) R object} } \if{html}{\out{
}} } @@ -117,7 +81,7 @@ Retrieves the content assigned to this block. } \subsection{Returns}{ -\code{character} string or file path assigned to this \code{ContentBlock}. +object stored in a \code{private$content} field } \subsection{Examples}{ \if{html}{\out{
}} diff --git a/man/FileBlock.Rd b/man/FileBlock.Rd index a770cf4c..6c83ef45 100644 --- a/man/FileBlock.Rd +++ b/man/FileBlock.Rd @@ -47,7 +47,6 @@ block$to_list(tempdir())
Inherited methods
diff --git a/man/HTMLBlock.Rd b/man/HTMLBlock.Rd new file mode 100644 index 00000000..971bd698 --- /dev/null +++ b/man/HTMLBlock.Rd @@ -0,0 +1,147 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/HTMLBlock.R +\docType{class} +\name{HTMLBlock} +\alias{HTMLBlock} +\title{\code{HTMLBlock}} +\description{ +Specialized \code{FileBlock} for managing HTML content in reports. +It's designed to handle various HTML content, and render the report as HTML, +however \code{htmlwidgets} objects can also be rendered to static document-ready format. +} +\examples{ + +## ------------------------------------------------ +## Method `HTMLBlock$from_list` +## ------------------------------------------------ + +HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") +block <- HTMLBlock$new() +block$from_list(list(content = shiny::tags$div("test"))) + + +## ------------------------------------------------ +## Method `HTMLBlock$to_list` +## ------------------------------------------------ + +HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") +block <- HTMLBlock$new(shiny::tags$div("test")) +block$to_list() + +} +\keyword{internal} +\section{Super class}{ +\code{\link[teal.reporter:ContentBlock]{teal.reporter::ContentBlock}} -> \code{HTMLBlock} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-HTMLBlock-new}{\code{HTMLBlock$new()}} +\item \href{#method-HTMLBlock-from_list}{\code{HTMLBlock$from_list()}} +\item \href{#method-HTMLBlock-to_list}{\code{HTMLBlock$to_list()}} +\item \href{#method-HTMLBlock-clone}{\code{HTMLBlock$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTMLBlock-new}{}}} +\subsection{Method \code{new()}}{ +Initialize a \code{HTMLBlock} object. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{HTMLBlock$new(content)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{content}}{An object that can be rendered as a HTML content assigned to +this \code{HTMLBlock}} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +Object of class \code{HTMLBlock}, invisibly. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTMLBlock-from_list}{}}} +\subsection{Method \code{from_list()}}{ +Create the \code{HTMLBlock} from a list. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{HTMLBlock$from_list(x)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x}}{(\verb{named list}) with a single field \code{content} containing \code{shiny.tag}, +\code{shiny.tag.list} or \code{htmlwidget}.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +\code{self}, invisibly. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") +block <- HTMLBlock$new() +block$from_list(list(content = shiny::tags$div("test"))) + +} +\if{html}{\out{
}} + +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTMLBlock-to_list}{}}} +\subsection{Method \code{to_list()}}{ +Convert the \code{HTMLBlock} to a list. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{HTMLBlock$to_list()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +\verb{named list} with a text and style. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{HTMLBlock <- getFromNamespace("HTMLBlock", "teal.reporter") +block <- HTMLBlock$new(shiny::tags$div("test")) +block$to_list() + +} +\if{html}{\out{
}} + +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-HTMLBlock-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{HTMLBlock$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/RcodeBlock.Rd b/man/RcodeBlock.Rd index 3e5198de..8c106843 100644 --- a/man/RcodeBlock.Rd +++ b/man/RcodeBlock.Rd @@ -17,6 +17,15 @@ RcodeBlock <- getFromNamespace("RcodeBlock", "teal.reporter") block <- RcodeBlock$new() +## ------------------------------------------------ +## Method `RcodeBlock$set_content` +## ------------------------------------------------ + +RcodeBlock <- getFromNamespace("RcodeBlock", "teal.reporter") +block <- RcodeBlock$new() +block$set_content("a <- 1") + + ## ------------------------------------------------ ## Method `RcodeBlock$set_params` ## ------------------------------------------------ @@ -70,6 +79,7 @@ block$to_list() \subsection{Public methods}{ \itemize{ \item \href{#method-RcodeBlock-new}{\code{RcodeBlock$new()}} +\item \href{#method-RcodeBlock-set_content}{\code{RcodeBlock$set_content()}} \item \href{#method-RcodeBlock-set_params}{\code{RcodeBlock$set_params()}} \item \href{#method-RcodeBlock-get_params}{\code{RcodeBlock$get_params()}} \item \href{#method-RcodeBlock-get_available_params}{\code{RcodeBlock$get_available_params()}} @@ -82,7 +92,6 @@ block$to_list()
Inherited methods
}} @@ -121,6 +130,37 @@ block <- RcodeBlock$new() } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-RcodeBlock-set_content}{}}} +\subsection{Method \code{set_content()}}{ +Sets content of this \code{RcodeBlock}. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{RcodeBlock$set_content(content)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{content}}{(\code{any}) R object} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +\code{self}, invisibly. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{RcodeBlock <- getFromNamespace("RcodeBlock", "teal.reporter") +block <- RcodeBlock$new() +block$set_content("a <- 1") + +} +\if{html}{\out{
}} + +} + } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/man/ReportCard.Rd b/man/ReportCard.Rd index 9a910a28..2e3b41e0 100644 --- a/man/ReportCard.Rd +++ b/man/ReportCard.Rd @@ -68,6 +68,13 @@ card <- ReportCard$new() card <- ReportCard$new()$append_table(iris) +## ------------------------------------------------ +## Method `ReportCard$append_html` +## ------------------------------------------------ + +card <- ReportCard$new()$append_html(shiny::div("HTML Content")) + + ## ------------------------------------------------ ## Method `ReportCard$append_text` ## ------------------------------------------------ @@ -126,6 +133,7 @@ ReportCard$new()$set_name("NAME")$get_name() \itemize{ \item \href{#method-ReportCard-new}{\code{ReportCard$new()}} \item \href{#method-ReportCard-append_table}{\code{ReportCard$append_table()}} +\item \href{#method-ReportCard-append_html}{\code{ReportCard$append_html()}} \item \href{#method-ReportCard-append_plot}{\code{ReportCard$append_plot()}} \item \href{#method-ReportCard-append_text}{\code{ReportCard$append_text()}} \item \href{#method-ReportCard-append_rcode}{\code{ReportCard$append_rcode()}} @@ -192,6 +200,35 @@ that can be coerced into a table.} } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-ReportCard-append_html}{}}} +\subsection{Method \code{append_html()}}{ +Appends a html content to this \code{ReportCard}. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{ReportCard$append_html(content)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{content}}{An object that can be rendered as a HTML content.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +\code{self}, invisibly. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{card <- ReportCard$new()$append_html(shiny::div("HTML Content")) + +} +\if{html}{\out{
}} + +} + } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/man/TextBlock.Rd b/man/TextBlock.Rd index fd091681..b16b3ba5 100644 --- a/man/TextBlock.Rd +++ b/man/TextBlock.Rd @@ -19,6 +19,15 @@ TextBlock <- getFromNamespace("TextBlock", "teal.reporter") block <- TextBlock$new() +## ------------------------------------------------ +## Method `TextBlock$set_content` +## ------------------------------------------------ + +ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") +block <- ContentBlock$new() +block$set_content("Base64 encoded picture") + + ## ------------------------------------------------ ## Method `TextBlock$set_style` ## ------------------------------------------------ @@ -72,6 +81,7 @@ block$to_list() \subsection{Public methods}{ \itemize{ \item \href{#method-TextBlock-new}{\code{TextBlock$new()}} +\item \href{#method-TextBlock-set_content}{\code{TextBlock$set_content()}} \item \href{#method-TextBlock-set_style}{\code{TextBlock$set_style()}} \item \href{#method-TextBlock-get_style}{\code{TextBlock$get_style()}} \item \href{#method-TextBlock-get_available_styles}{\code{TextBlock$get_available_styles()}} @@ -84,7 +94,6 @@ block$to_list()
Inherited methods
}} @@ -123,6 +132,37 @@ block <- TextBlock$new() } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TextBlock-set_content}{}}} +\subsection{Method \code{set_content()}}{ +Sets content of this \code{TextBlock}. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TextBlock$set_content(content)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{content}}{(\code{any}) R object} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +\code{self}, invisibly. +} +\subsection{Examples}{ +\if{html}{\out{
}} +\preformatted{ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter") +block <- ContentBlock$new() +block$set_content("Base64 encoded picture") + +} +\if{html}{\out{
}} + +} + } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/tests/testthat/test-ContentBlock.R b/tests/testthat/test-ContentBlock.R index 141687e7..0db7e19f 100644 --- a/tests/testthat/test-ContentBlock.R +++ b/tests/testthat/test-ContentBlock.R @@ -11,9 +11,9 @@ testthat::test_that("set_content accepts a character object", { testthat::expect_no_error(block$set_content("test")) }) -testthat::test_that("set_content asserts the argument is character", { +testthat::test_that("set_content accepts a list object", { block <- ContentBlock$new() - testthat::expect_error(block$set_content(7), regexp = "Must be of type 'character'") + testthat::expect_no_error(block$set_content(list("a"))) }) testthat::test_that("set_content returns the ContentBlock object", { @@ -21,8 +21,8 @@ testthat::test_that("set_content returns the ContentBlock object", { testthat::expect_identical(block$set_content("test"), block) }) -testthat::test_that("get_content returns character(0) on a newly initialized ContentBlock", { - testthat::expect_equal(ContentBlock$new()$get_content(), character(0)) +testthat::test_that("get_content returns NULL on a newly initialized ContentBlock", { + testthat::expect_equal(ContentBlock$new()$get_content(), NULL) }) testthat::test_that("The deep copy constructor copies the content file to a new file", { diff --git a/tests/testthat/test-HTMLBlock.R b/tests/testthat/test-HTMLBlock.R new file mode 100644 index 00000000..8ec13044 --- /dev/null +++ b/tests/testthat/test-HTMLBlock.R @@ -0,0 +1,40 @@ +testthat::test_that("HTMLBlock object can be created", { + testthat::expect_no_error(HTMLBlock$new()) +}) + +testthat::test_that("new returns an object of type HTMLBlock", { + testthat::expect_true(inherits(HTMLBlock$new(), "HTMLBlock")) +}) + + +testthat::test_that("new accepts a shiny.tag", { + testthat::expect_no_error(HTMLBlock$new(shiny::tags$div())) +}) + +testthat::test_that("new accepts a shiny.tag.list", { + testthat::expect_no_error(HTMLBlock$new(shiny::tagList())) +}) + +testthat::test_that("new doesn't accept character", { + testthat::expect_error(HTMLBlock$new("test"), "'shiny.tag'/'shiny.tag.list'") +}) + +testthat::test_that("get_content returns a html content asis", { + content <- shiny::tags$div() + obj <- HTMLBlock$new(content) + testthat::expect_identical(obj$get_content(), content) +}) + +testthat::test_that("to_list returns a list containing a content (asis)", { + content <- shiny::tags$div() + obj <- HTMLBlock$new(content) + out <- obj$to_list() + testthat::expect_identical(out, list(content = content)) +}) + +testthat::test_that("from_list creates a HTMLBlock", { + list <- list(content = shiny::tags$div()) + obj <- HTMLBlock$new() + obj$from_list(list) + testthat::expect_identical(obj$get_content(), list$content) +}) diff --git a/tests/testthat/test-RcodeBlock.R b/tests/testthat/test-RcodeBlock.R index 6066d237..0b4a3503 100644 --- a/tests/testthat/test-RcodeBlock.R +++ b/tests/testthat/test-RcodeBlock.R @@ -13,7 +13,7 @@ testthat::test_that("set_content accepts a string", { testthat::test_that("set_content asserts the argument is a string", { block <- RcodeBlock$new() - testthat::expect_error(block$set_content(7), regexp = "Must be of type 'character'") + testthat::expect_error(block$set_content(7), regexp = "Must be of type 'string'") }) testthat::test_that("set_content returns the RcodeBlock object", { diff --git a/tests/testthat/test-Renderer.R b/tests/testthat/test-Renderer.R index cf3ece71..6df7141b 100644 --- a/tests/testthat/test-Renderer.R +++ b/tests/testthat/test-Renderer.R @@ -12,19 +12,20 @@ text_block1 <- TextBlock$new()$set_content("text")$set_style("header2") text_block2 <- TextBlock$new()$set_content("text") png_path <- system.file("img", "Rlogo.png", package = "png") picture_block <- PictureBlock$new()$set_content(ggplot2::ggplot(iris)) +html_block <- HTMLBlock$new(shiny::tags$div("test")) # https://github.com/davidgohel/flextable/issues/600 withr::with_options( opts_partial_match_old, table_block <- TableBlock$new()$set_content(iris) ) newpage_block <- NewpageBlock$new() -blocks <- list(text_block1, text_block2, picture_block, table_block, newpage_block) +blocks <- list(text_block1, text_block2, picture_block, table_block, newpage_block, html_block) testthat::test_that("renderRmd asserts the argument is a list of TextBlocks/PictureBlock/NewpageBlock/TableBlock", { renderer <- Renderer$new() testthat::expect_error( renderer$renderRmd(append(blocks, "STH")), - regexp = "May only contain the following types: \\{TextBlock,PictureBlock,NewpageBlock,TableBlock,RcodeBlock\\}" + regexp = "May only contain the following types: \\{TextBlock,PictureBlock,NewpageBlock,TableBlock,RcodeBlock,HTMLBlock\\}" # nolint line_length ) }) diff --git a/tests/testthat/test-ReportCard.R b/tests/testthat/test-ReportCard.R index afd5730c..8aa9b422 100644 --- a/tests/testthat/test-ReportCard.R +++ b/tests/testthat/test-ReportCard.R @@ -175,6 +175,7 @@ card$append_text("Header 2 text", "header2") card$append_text("A paragraph of default text", "header2") card$append_rcode(rcode) card$append_plot(eval(str2lang(rcode))) +card$append_html(shiny::tags$div("test")) picture_filename <- basename(card$get_content()[[4]]$get_content()) temp_dir <- file.path(tempdir(), "test") @@ -187,7 +188,8 @@ testthat::test_that("to_list internally triggers to_list on each Block", { TextBlock = list(text = "Header 2 text", style = "header2"), TextBlock = list(text = "A paragraph of default text", style = "header2"), RcodeBlock = list(text = rcode, params = list()), - PictureBlock = list(basename = picture_filename) + PictureBlock = list(basename = picture_filename), + HTMLBlock = list(content = shiny::tags$div("test")) ), metadata = list(), name = character(0)) ) testthat::expect_true(picture_filename %in% list.files(temp_dir)) @@ -199,12 +201,13 @@ testthat::test_that("from_list", { TextBlock = list(text = "Header 2 text", style = "header2"), TextBlock = list(text = "A paragraph of default text", style = "header2"), RcodeBlock = list(text = rcode, params = list()), - PictureBlock = list(basename = picture_filename) + PictureBlock = list(basename = picture_filename), + HTMLBlock = list(content = shiny::tags$div("test")) ), metadata = list()), temp_dir ) testthat::expect_true(inherits(cardf, "ReportCard")) - testthat::expect_length(cardf$get_content(), 4L) + testthat::expect_length(cardf$get_content(), 5L) }) unlink(temp_dir, recursive = TRUE) diff --git a/tests/testthat/test-TextBlock.R b/tests/testthat/test-TextBlock.R index faa30b04..a01fe0c0 100644 --- a/tests/testthat/test-TextBlock.R +++ b/tests/testthat/test-TextBlock.R @@ -13,7 +13,7 @@ testthat::test_that("set_content accepts a string", { testthat::test_that("set_content asserts the argument is a string", { block <- TextBlock$new() - testthat::expect_error(block$set_content(7), regexp = "Must be of type 'character'") + testthat::expect_error(block$set_content(7), regexp = "Must be of type 'string'") }) testthat::test_that("set_content returns the TextBlock object", {