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{
}}
-\preformatted{ContentBlock <- getFromNamespace("ContentBlock", "teal.reporter")
-ContentBlock$new()
-
-}
-\if{html}{\out{
}}
-
-}
-
}
\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", {