Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions R/pagination_utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#' Providing a value (e.g., `"|"`, `""`, or `"—"`) automatically enables filling and uses that
#' value for all cells in the empty rows. This helps maintain consistent vertical positioning
#' across all pages. The target row count is the maximum page size across all pages.
#' Use `NA` to fill with missing values while preserving original column types.
#' If you need consistent types across all pages, use `NA`.
#' Because `fill_empty` is a character placeholder, pages are coerced to character
#' columns when filling is applied (except when `fill_empty = NA`).
#'
#' @return A list of data frames, one for each page. When `split_by` is used, the list
#' is named with the group values. If a group spans multiple pages (when combined with
Expand Down Expand Up @@ -177,8 +181,13 @@ paginate_table <- function(
}
}

if (!is.null(fill_empty) && (!is.character(fill_empty) || length(fill_empty) != 1)) {
stop("`fill_empty` must be NULL or a single character string.")
if (!is.null(fill_empty)) {
fill_is_single_na <- length(fill_empty) == 1 && isTRUE(is.na(fill_empty))
fill_is_single_character <- is.character(fill_empty) && length(fill_empty) == 1

if (!(fill_is_single_na || fill_is_single_character)) {
stop("`fill_empty` must be NULL, NA, or a single character string.")
}
}

# Split data based on method
Expand Down Expand Up @@ -231,12 +240,28 @@ paginate_table <- function(
if (page_nrows < rows_per_page) {
rows_difference <- rows_per_page - page_nrows

# Create empty rows with specified fill value
empty_df <- data.frame(
matrix(fill_empty, nrow = rows_difference, ncol = ncol(data)),
stringsAsFactors = FALSE
)
colnames(empty_df) <- colnames(data)
if (isTRUE(is.na(fill_empty))) {
# Preserve original column classes when filling with missing values.
empty_df <- as.data.frame(
lapply(page, function(col) rep(col[NA_integer_], rows_difference)),
stringsAsFactors = FALSE,
check.names = FALSE
)
} else {
# Character placeholder fill uses character columns across all fields.
page <- as.data.frame(
lapply(page, as.character),
stringsAsFactors = FALSE,
check.names = FALSE
)

empty_df <- data.frame(
matrix(fill_empty, nrow = rows_difference, ncol = ncol(data)),
stringsAsFactors = FALSE,
check.names = FALSE
)
colnames(empty_df) <- colnames(data)
}

# Append to page
page <- rbind(page, empty_df)
Expand Down
6 changes: 5 additions & 1 deletion man/paginate_table.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 33 additions & 2 deletions tests/testthat/test_paginate_table.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ test_that("paginate_table validates inputs correctly", {

expect_error(
paginate_table(mtcars, 10, fill_empty = TRUE),
"`fill_empty` must be NULL or a single character string"
"`fill_empty` must be NULL, NA, or a single character string"
)

expect_error(
paginate_table(mtcars, 10, fill_empty = c("|", "-")),
"`fill_empty` must be NULL or a single character string"
"`fill_empty` must be NULL, NA, or a single character string"
)

expect_error(
Expand Down Expand Up @@ -198,3 +198,34 @@ test_that("paginate_table split_by handles single group", {
expect_equal(length(pages), 1)
expect_equal(nrow(pages[[1]]), nrow(df_single))
})

test_that("paginate_table fill_empty works with Date columns", {
df <- data.frame(
aval = runif(40, 10, 50),
dt = as.Date(rep(c("2025-01-02", "2025-02-03", "2025-03-04", "2025-04-05"), 10))
)

expect_no_error({
pages <- paginate_table(data = df, rows_per_page = 7, fill_empty = " ")
expect_true(length(pages) > 0)
expect_equal(nrow(pages[[length(pages)]]), 7)
expect_type(pages[[length(pages)]]$dt, "character")
expect_equal(pages[[length(pages)]][7, "dt"], " ")
})
})

test_that("paginate_table supports fill_empty = NA preserving column types", {
df <- data.frame(
aval = runif(40, 10, 50),
dt = as.Date(rep(c("2025-01-02", "2025-02-03", "2025-03-04", "2025-04-05"), 10))
)

pages <- paginate_table(data = df, rows_per_page = 7, fill_empty = NA)
last_page <- pages[[length(pages)]]

expect_equal(nrow(last_page), 7)
expect_type(last_page$aval, "double")
expect_s3_class(last_page$dt, "Date")
expect_true(anyNA(last_page[7, "aval"]))
expect_true(anyNA(last_page[7, "dt"]))
})
Loading