From 716f1c533dc7d007f654afd73c2733bcd50f561f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:27:25 +0000 Subject: [PATCH 1/9] Initial plan From c05cb4352a2ae19abb3fcc1ccb0755f1808e7b13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:32:09 +0000 Subject: [PATCH 2/9] Add foodwebr to DESCRIPTION and create package-structure article Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- DESCRIPTION | 1 + vignettes/articles/package-structure.qmd | 294 +++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 vignettes/articles/package-structure.qmd diff --git a/DESCRIPTION b/DESCRIPTION index 721e65a5..c4f27852 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,6 +18,7 @@ Imports: stats Suggests: altdoc, + foodwebr, knitr, rmarkdown, spelling, diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd new file mode 100644 index 00000000..7e32b1fa --- /dev/null +++ b/vignettes/articles/package-structure.qmd @@ -0,0 +1,294 @@ +--- +title: "Package Function Structure" +author: "UC Davis Seroepidemiology Research Group (UCD-SERG)" +date: "`r Sys.Date()`" +format: + revealjs: + output-file: package-structure-revealjs.html + html: default + docx: default +--- + +```{r} +#| include: false +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.width = 7, + fig.height = 5 +) +``` + +```{r setup} +#| message: false +library(rpt) +``` + +## Overview + +This article demonstrates how to visualize the structure and dependencies of package functions using the [`foodwebr`](https://lewinfox.com/foodwebr/) package. Understanding function dependencies helps developers: + +- Navigate and understand codebases more quickly +- Identify potential refactoring opportunities +- Document architecture and design decisions +- Onboard new contributors more effectively + +## What is foodwebr? + +The `foodwebr` package creates dependency graphs showing which functions call which other functions. These visualizations are particularly useful for: + +- Exploring unfamiliar codebases +- Understanding function relationships +- Identifying central or isolated functions +- Planning refactoring efforts + +## Installing foodwebr + +If you don't have `foodwebr` installed, you can install it from CRAN: + +```{r} +#| eval: false +install.packages("foodwebr") +``` + +Or from GitHub for the latest development version: + +```{r} +#| eval: false +devtools::install_github("lewinfox/foodwebr") +``` + +## Visualizing Package Structure + +### Basic Usage + +The `foodweb()` function analyzes function dependencies. When examining a package, you typically want to look at specific functions or the entire package namespace: + +```{r} +#| message: false +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +library(foodwebr) + +# Create a foodweb for the example_function +fw <- foodweb(FUN = example_function) +fw +``` + +### Plotting the Dependency Graph + +The `plot()` method creates an interactive visualization using DiagrammeR: + +```{r} +#| label: fig-basic-foodweb +#| fig-cap: "Basic function dependency graph for example_function" +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +plot(fw) +``` + +::: {.callout-note} +## Understanding the Graph + +- **Nodes** represent individual functions +- **Edges** (arrows) show function calls +- An arrow from A to B means "A calls B" +- Isolated nodes indicate functions with no dependencies or dependents +::: + +### Filtering Options + +By default, `foodwebr` filters to show only functions directly related to the specified function. You can control this behavior: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +# Show only connected functions (default) +fw_filtered <- foodweb(FUN = example_function, filter = TRUE) + +# Show all functions in the environment +fw_all <- foodweb(FUN = example_function, filter = FALSE) +``` + +### Examining the Entire Package + +To see all exported and internal functions in the package: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +# Get the package namespace environment +pkg_env <- asNamespace("rpt") + +# Create foodweb for entire package +fw_pkg <- foodweb(env = pkg_env) +fw_pkg +``` + +```{r} +#| label: fig-package-foodweb +#| fig-cap: "Complete dependency graph for all package functions" +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +plot(fw_pkg) +``` + +## Analyzing Dependencies + +### Understanding Function Roles + +From the dependency graph, you can identify different types of functions: + +- **Leaf functions**: Functions that don't call any other package functions (only base R or external packages) +- **Root functions**: Functions that are called by many others but don't call package functions themselves +- **Hub functions**: Functions that both call and are called by many functions +- **Isolated functions**: Functions with no connections to others + +### Example Analysis + +For our package: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +# Convert to text representation for inspection +cat(as.character(fw_pkg)) +``` + +::: {.callout-tip} +## Dependency Patterns + +In well-designed packages, you typically see: + +1. **Clear hierarchy**: Lower-level utility functions are called by higher-level API functions +2. **Limited cross-dependencies**: Functions in the same "layer" don't call each other excessively +3. **Focused functions**: Each function has a clear purpose with limited dependencies +::: + +## Advanced Usage + +### Using with tidygraph + +The `tidygraph` package provides powerful tools for graph analysis. You can convert a `foodweb` object to work with these tools: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) && requireNamespace("tidygraph", quietly = TRUE) +if (requireNamespace("tidygraph", quietly = TRUE)) { + tg <- tidygraph::as_tbl_graph(fw_pkg) + print(tg) +} +``` + +### Customizing Visualizations + +You can pass additional arguments to customize the graph appearance: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +#| eval: false +# These arguments are passed to DiagrammeR::grViz() +plot(fw_pkg, + width = 800, + height = 600) +``` + +### Exporting as Text + +Get the graphviz DOT representation: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +# As text +foodweb_text <- foodweb(env = asNamespace("rpt"), as.text = TRUE) +cat(foodweb_text) +``` + +## Practical Applications + +### Code Review + +Use dependency graphs during code review to: + +- Verify that new functions follow existing architectural patterns +- Identify unexpected dependencies +- Ensure proper separation of concerns +- Detect circular dependencies + +### Refactoring + +Before refactoring: + +1. Generate a dependency graph of the affected area +2. Identify all functions that will be impacted +3. Plan changes to minimize ripple effects +4. After refactoring, regenerate the graph to verify improvements + +### Documentation + +Include dependency graphs in: + +- Developer documentation +- Architecture decision records +- Package vignettes (like this one!) +- README files for complex packages + +::: {.callout-important} +## Keeping Documentation Updated + +When adding new functions or modifying dependencies, regenerate the foodweb graphs to keep documentation current. Consider adding automated checks in your CI/CD pipeline. +::: + +## Example: Growing Package + +As this package grows, the dependency graph will become more interesting. Here's a hypothetical example of what it might look like with additional functions: + +::: {.callout-note collapse="true"} +## Hypothetical Example + +Imagine we add these functions: + +- `validate_input()` - Input validation helper +- `calculate_statistic()` - Main calculation function +- `format_output()` - Output formatting function +- `example_function()` - High-level API function (existing) + +With `example_function()` calling `validate_input()`, `calculate_statistic()`, and `format_output()`, and `calculate_statistic()` calling `stats::median()`, the dependency graph would show: + +``` +example_function() -> { validate_input(), calculate_statistic(), format_output() } +calculate_statistic() -> { stats::median() } +validate_input() +format_output() +``` + +This would clearly show that `example_function()` is the main entry point, with well-separated concerns for validation, calculation, and formatting. +::: + +## Best Practices + +When designing package architecture: + +1. **Minimize dependencies**: Each function should have a clear, focused purpose +2. **Avoid circular dependencies**: A should not call B if B calls A +3. **Layer your functions**: Separate low-level utilities from high-level APIs +4. **Document dependencies**: Use `foodwebr` graphs in your documentation +5. **Review regularly**: Check dependency graphs during code review + +## Learn More + +- **foodwebr documentation**: +- **Package website**: +- **GitHub repository**: +- **DiagrammeR**: +- **tidygraph**: + +## Summary + +This article demonstrated how to use `foodwebr` to visualize and understand package function dependencies. Key takeaways: + +- `foodwebr` creates interactive dependency graphs +- Filtering options help focus on specific functions or show entire packages +- Dependency graphs aid in code review, refactoring, and documentation +- Integration with `tidygraph` enables advanced graph analysis +- Regular visualization helps maintain clean architecture + +As the `rpt` package grows, these visualization tools will become increasingly valuable for understanding and maintaining the codebase. + +## References + +::: {#refs} +::: From 884da647a9d4da3f94ec2b2a28a10bd820bae22c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:38:11 +0000 Subject: [PATCH 3/9] Add helper functions with dependencies for foodwebr demo and update tests Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- NAMESPACE | 1 + R/calculate_statistic.R | 13 ++++ R/calculate_summary.R | 21 ++++++ R/clean_data.R | 18 +++++ R/example_function.R | 7 +- R/format_result.R | 12 ++++ R/validate_input.R | 21 ++++++ man/calculate_summary.Rd | 21 ++++++ man/example_function.Rd | 4 +- tests/testthat/test-calculate_summary.R | 21 ++++++ tests/testthat/test-example_function.R | 8 +++ vignettes/articles/package-structure.qmd | 86 ++++++++++++++++++------ 12 files changed, 211 insertions(+), 22 deletions(-) create mode 100644 R/calculate_statistic.R create mode 100644 R/calculate_summary.R create mode 100644 R/clean_data.R create mode 100644 R/format_result.R create mode 100644 R/validate_input.R create mode 100644 man/calculate_summary.Rd create mode 100644 tests/testthat/test-calculate_summary.R diff --git a/NAMESPACE b/NAMESPACE index 79e14c4f..93b6af16 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,3 +1,4 @@ # Generated by roxygen2: do not edit by hand +export(calculate_summary) export(example_function) diff --git a/R/calculate_statistic.R b/R/calculate_statistic.R new file mode 100644 index 00000000..d882d062 --- /dev/null +++ b/R/calculate_statistic.R @@ -0,0 +1,13 @@ +#' Calculate Statistic +#' +#' Internal helper function to calculate a statistical measure on cleaned data. +#' +#' @param x A numeric vector +#' +#' @return The median value +#' @keywords internal +#' @noRd +calculate_statistic <- function(x) { + x_clean <- clean_data(x) + stats::median(x_clean) +} diff --git a/R/calculate_summary.R b/R/calculate_summary.R new file mode 100644 index 00000000..ab9357be --- /dev/null +++ b/R/calculate_summary.R @@ -0,0 +1,21 @@ +#' Calculate Summary Statistics +#' +#' Calculate multiple summary statistics for a numeric vector. +#' +#' @param x A numeric vector +#' +#' @return A named list with mean, median, and standard deviation +#' @export +#' +#' @examples +#' calculate_summary(c(1, 2, 3, 4, 5)) +#' calculate_summary(c(1, NA, 3, 4, 5)) +calculate_summary <- function(x) { + x_clean <- clean_data(x) + + list( + mean = format_result(mean(x_clean)), + median = example_function(x), + sd = format_result(stats::sd(x_clean)) + ) +} diff --git a/R/clean_data.R b/R/clean_data.R new file mode 100644 index 00000000..9b34e189 --- /dev/null +++ b/R/clean_data.R @@ -0,0 +1,18 @@ +#' Clean Data +#' +#' Internal helper function to clean data by removing NA values and preparing +#' for analysis. +#' +#' @param x A numeric vector +#' +#' @return A cleaned numeric vector with NA values removed +#' @keywords internal +#' @noRd +clean_data <- function(x) { + validate_input(x) + x_clean <- x[!is.na(x)] + if (length(x_clean) == 0) { + stop("No valid data remaining after removing NA values", call. = FALSE) + } + x_clean +} diff --git a/R/example_function.R b/R/example_function.R index 962aade8..5d95050f 100644 --- a/R/example_function.R +++ b/R/example_function.R @@ -1,14 +1,17 @@ #' Example Function #' #' This is an example function that demonstrates basic functionality. +#' It validates, cleans, calculates statistics, and formats the result. #' #' @param x A numeric vector #' -#' @return The median of the input vector +#' @return The median of the input vector, rounded to 2 decimal places #' @export #' #' @examples #' example_function(c(1, 2, 3, 4, 5)) +#' example_function(c(1, NA, 3, 4, 5)) example_function <- function(x) { - stats::median(x) + result <- calculate_statistic(x) + format_result(result) } diff --git a/R/format_result.R b/R/format_result.R new file mode 100644 index 00000000..95c246ec --- /dev/null +++ b/R/format_result.R @@ -0,0 +1,12 @@ +#' Format Result +#' +#' Internal helper function to format the result for output. +#' +#' @param result A numeric value +#' +#' @return A formatted numeric value (rounded to 2 decimal places) +#' @keywords internal +#' @noRd +format_result <- function(result) { + round(result, digits = 2) +} diff --git a/R/validate_input.R b/R/validate_input.R new file mode 100644 index 00000000..cb4cf91d --- /dev/null +++ b/R/validate_input.R @@ -0,0 +1,21 @@ +#' Validate Input Data +#' +#' Internal helper function to validate input data for statistical calculations. +#' +#' @param x A numeric vector +#' +#' @return TRUE if valid, throws error otherwise +#' @keywords internal +#' @noRd +validate_input <- function(x) { + if (!is.numeric(x)) { + stop("Input must be numeric", call. = FALSE) + } + if (length(x) == 0) { + stop("Input must have at least one element", call. = FALSE) + } + if (all(is.na(x))) { + stop("Input cannot be all NA values", call. = FALSE) + } + TRUE +} diff --git a/man/calculate_summary.Rd b/man/calculate_summary.Rd new file mode 100644 index 00000000..2dd13384 --- /dev/null +++ b/man/calculate_summary.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/calculate_summary.R +\name{calculate_summary} +\alias{calculate_summary} +\title{Calculate Summary Statistics} +\usage{ +calculate_summary(x) +} +\arguments{ +\item{x}{A numeric vector} +} +\value{ +A named list with mean, median, and standard deviation +} +\description{ +Calculate multiple summary statistics for a numeric vector. +} +\examples{ +calculate_summary(c(1, 2, 3, 4, 5)) +calculate_summary(c(1, NA, 3, 4, 5)) +} diff --git a/man/example_function.Rd b/man/example_function.Rd index 497dea06..74d7e12e 100644 --- a/man/example_function.Rd +++ b/man/example_function.Rd @@ -10,11 +10,13 @@ example_function(x) \item{x}{A numeric vector} } \value{ -The median of the input vector +The median of the input vector, rounded to 2 decimal places } \description{ This is an example function that demonstrates basic functionality. +It validates, cleans, calculates statistics, and formats the result. } \examples{ example_function(c(1, 2, 3, 4, 5)) +example_function(c(1, NA, 3, 4, 5)) } diff --git a/tests/testthat/test-calculate_summary.R b/tests/testthat/test-calculate_summary.R new file mode 100644 index 00000000..aa648da2 --- /dev/null +++ b/tests/testthat/test-calculate_summary.R @@ -0,0 +1,21 @@ +test_that("calculate_summary works", { + result <- calculate_summary(c(1, 2, 3, 4, 5)) + expect_type(result, "list") + expect_named(result, c("mean", "median", "sd")) + expect_equal(result$mean, 3) + expect_equal(result$median, 3) + expect_equal(result$sd, 1.58) +}) + +test_that("calculate_summary handles NA values", { + result <- calculate_summary(c(1, NA, 3, 4, 5)) + expect_type(result, "list") + expect_equal(result$median, 3.5) + expect_equal(result$mean, 3.25) +}) + +test_that("calculate_summary handles errors", { + expect_error(calculate_summary(character()), "Input must be numeric") + expect_error(calculate_summary(numeric()), "Input must have at least one element") + expect_error(calculate_summary(c(NA_real_, NA_real_, NA_real_)), "Input cannot be all NA values") +}) diff --git a/tests/testthat/test-example_function.R b/tests/testthat/test-example_function.R index f86a3be1..c77dbc7a 100644 --- a/tests/testthat/test-example_function.R +++ b/tests/testthat/test-example_function.R @@ -1,4 +1,12 @@ test_that("example_function works", { expect_equal(example_function(c(1, 2, 3)), 2) expect_equal(example_function(c(1, 2, 3, 4, 5)), 3) + expect_equal(example_function(c(1, NA, 3, 4, 5)), 3.5) + expect_equal(example_function(c(1.111, 2.222, 3.333)), 2.22) +}) + +test_that("example_function handles errors", { + expect_error(example_function(character()), "Input must be numeric") + expect_error(example_function(numeric()), "Input must have at least one element") + expect_error(example_function(c(NA_real_, NA_real_, NA_real_)), "Input cannot be all NA values") }) diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index 7e32b1fa..0f6d51c3 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -157,8 +157,47 @@ In well-designed packages, you typically see: 1. **Clear hierarchy**: Lower-level utility functions are called by higher-level API functions 2. **Limited cross-dependencies**: Functions in the same "layer" don't call each other excessively 3. **Focused functions**: Each function has a clear purpose with limited dependencies + +In the `rpt` package, we can see this pattern: + +- `validate_input()` is a low-level helper (no package dependencies) +- `clean_data()` calls `validate_input()` +- `calculate_statistic()` calls `clean_data()` +- `format_result()` is a low-level formatter (no package dependencies) +- `example_function()` is a high-level API that calls `calculate_statistic()` and `format_result()` +- `calculate_summary()` is another high-level API that calls `clean_data()` and `example_function()` + +This creates a clear layered architecture with well-separated concerns. ::: +## Package Architecture + +### Current Structure + +Let's examine the actual structure of the `rpt` package: + +```{r} +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +# List all functions in the package +pkg_functions <- ls(asNamespace("rpt")) +cat("Package functions:\n") +cat(paste("-", sort(pkg_functions), collapse = "\n")) +``` + +The dependency relationships are: + +- **Exported functions** (user-facing API): + - `example_function()`: Calls `calculate_statistic()` → `format_result()` + - `calculate_summary()`: Calls `clean_data()` → `example_function()` + +- **Internal functions** (implementation details): + - `validate_input()`: No package dependencies (leaf function) + - `clean_data()`: Calls `validate_input()` + - `calculate_statistic()`: Calls `clean_data()` + - `format_result()`: No package dependencies (leaf function) + +This architecture demonstrates good separation of concerns with clear data flow from validation through cleaning to calculation and formatting. + ## Advanced Usage ### Using with tidygraph @@ -232,31 +271,35 @@ Include dependency graphs in: When adding new functions or modifying dependencies, regenerate the foodweb graphs to keep documentation current. Consider adding automated checks in your CI/CD pipeline. ::: -## Example: Growing Package - -As this package grows, the dependency graph will become more interesting. Here's a hypothetical example of what it might look like with additional functions: +## Exploring Specific Functions -::: {.callout-note collapse="true"} -## Hypothetical Example +You can focus on specific functions to understand their dependencies: -Imagine we add these functions: +### Example Function Dependencies -- `validate_input()` - Input validation helper -- `calculate_statistic()` - Main calculation function -- `format_output()` - Output formatting function -- `example_function()` - High-level API function (existing) +```{r} +#| label: fig-example-function +#| fig-cap: "Dependency graph for example_function showing all related functions" +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +fw_example <- foodweb(FUN = example_function) +plot(fw_example) +``` -With `example_function()` calling `validate_input()`, `calculate_statistic()`, and `format_output()`, and `calculate_statistic()` calling `stats::median()`, the dependency graph would show: +### Summary Function Dependencies -``` -example_function() -> { validate_input(), calculate_statistic(), format_output() } -calculate_statistic() -> { stats::median() } -validate_input() -format_output() +```{r} +#| label: fig-summary-function +#| fig-cap: "Dependency graph for calculate_summary showing its relationships" +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +fw_summary <- foodweb(FUN = calculate_summary) +plot(fw_summary) ``` -This would clearly show that `example_function()` is the main entry point, with well-separated concerns for validation, calculation, and formatting. -::: +These focused views help understand: + +- What functions a specific function depends on (its dependencies) +- What functions depend on a specific function (its dependents) +- The complete call chain for a given function ## Best Practices @@ -286,7 +329,12 @@ This article demonstrated how to use `foodwebr` to visualize and understand pack - Integration with `tidygraph` enables advanced graph analysis - Regular visualization helps maintain clean architecture -As the `rpt` package grows, these visualization tools will become increasingly valuable for understanding and maintaining the codebase. +The `rpt` package demonstrates a clean layered architecture with: +- Low-level utility functions (`validate_input`, `format_result`) +- Mid-level processing functions (`clean_data`, `calculate_statistic`) +- High-level API functions (`example_function`, `calculate_summary`) + +This structure makes the code easier to understand, test, and maintain. ## References From c1c9d5c0e71240d9d50a5825be0e95c3d0b667d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:42:09 +0000 Subject: [PATCH 4/9] Fix YAML error and validate documentation build Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- tests/testthat/test-calculate_summary.R | 10 ++++++++-- tests/testthat/test-example_function.R | 10 ++++++++-- vignettes/articles/package-structure.qmd | 1 - 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test-calculate_summary.R b/tests/testthat/test-calculate_summary.R index aa648da2..325ba056 100644 --- a/tests/testthat/test-calculate_summary.R +++ b/tests/testthat/test-calculate_summary.R @@ -16,6 +16,12 @@ test_that("calculate_summary handles NA values", { test_that("calculate_summary handles errors", { expect_error(calculate_summary(character()), "Input must be numeric") - expect_error(calculate_summary(numeric()), "Input must have at least one element") - expect_error(calculate_summary(c(NA_real_, NA_real_, NA_real_)), "Input cannot be all NA values") + expect_error( + calculate_summary(numeric()), + "Input must have at least one element" + ) + expect_error( + calculate_summary(c(NA_real_, NA_real_, NA_real_)), + "Input cannot be all NA values" + ) }) diff --git a/tests/testthat/test-example_function.R b/tests/testthat/test-example_function.R index c77dbc7a..d7d98a3b 100644 --- a/tests/testthat/test-example_function.R +++ b/tests/testthat/test-example_function.R @@ -7,6 +7,12 @@ test_that("example_function works", { test_that("example_function handles errors", { expect_error(example_function(character()), "Input must be numeric") - expect_error(example_function(numeric()), "Input must have at least one element") - expect_error(example_function(c(NA_real_, NA_real_, NA_real_)), "Input cannot be all NA values") + expect_error( + example_function(numeric()), + "Input must have at least one element" + ) + expect_error( + example_function(c(NA_real_, NA_real_, NA_real_)), + "Input cannot be all NA values" + ) }) diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index 0f6d51c3..c9bb6079 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -217,7 +217,6 @@ if (requireNamespace("tidygraph", quietly = TRUE)) { You can pass additional arguments to customize the graph appearance: ```{r} -#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) #| eval: false # These arguments are passed to DiagrammeR::grViz() plot(fw_pkg, From 6fef1bd46a3485ef2d83ab6b188c0d9937baa7f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:45:36 +0000 Subject: [PATCH 5/9] Address code review feedback: fix formatting and remove redundant validation Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- R/clean_data.R | 6 +----- vignettes/articles/package-structure.qmd | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/R/clean_data.R b/R/clean_data.R index 9b34e189..7bd4d3fc 100644 --- a/R/clean_data.R +++ b/R/clean_data.R @@ -10,9 +10,5 @@ #' @noRd clean_data <- function(x) { validate_input(x) - x_clean <- x[!is.na(x)] - if (length(x_clean) == 0) { - stop("No valid data remaining after removing NA values", call. = FALSE) - } - x_clean + x[!is.na(x)] } diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index c9bb6079..16e2251d 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -329,9 +329,9 @@ This article demonstrated how to use `foodwebr` to visualize and understand pack - Regular visualization helps maintain clean architecture The `rpt` package demonstrates a clean layered architecture with: -- Low-level utility functions (`validate_input`, `format_result`) -- Mid-level processing functions (`clean_data`, `calculate_statistic`) -- High-level API functions (`example_function`, `calculate_summary`) +- Low-level utility functions (`validate_input()`, `format_result()`) +- Mid-level processing functions (`clean_data()`, `calculate_statistic()`) +- High-level API functions (`example_function()`, `calculate_summary()`) This structure makes the code easier to understand, test, and maintain. From b251d7029ff6aebbfee88ac458f15cbb3d9d6861 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:22:17 +0000 Subject: [PATCH 6/9] Fix workflow failures: increment version, add NEWS entry, fix lint and docs Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- DESCRIPTION | 3 ++- NEWS.md | 4 ++++ R/validate_input.R | 6 +++--- inst/WORDLIST | 8 ++++++++ vignettes/articles/package-structure.qmd | 1 + 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index c4f27852..863df5c3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rpt Title: What the Package Does (One Line, Title Case) -Version: 0.0.0.9010 +Version: 0.0.0.9011 Authors@R: c( person("First", "Last", , "first.last@example.com", role = c("aut", "cre")) ) @@ -15,6 +15,7 @@ Language: en-US Depends: R (>= 4.1.0) Imports: + cli, stats Suggests: altdoc, diff --git a/NEWS.md b/NEWS.md index db48a7fa..17a14a40 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # rpt (development version) +* Added package structure visualization article using foodwebr to demonstrate function dependencies and call graphs +* Created layered helper function architecture for realistic foodwebr demonstrations +* Added `calculate_summary()` function for computing summary statistics + * Switched from pkgdown to altdoc for documentation generation. Now using Quarto Website for documentation with native math equation support via MathJax. * Removed pkgdown-specific configurations and workflows. * Retained RevealJS multi-format support for Quarto vignettes and articles. diff --git a/R/validate_input.R b/R/validate_input.R index cb4cf91d..d02e2e6f 100644 --- a/R/validate_input.R +++ b/R/validate_input.R @@ -9,13 +9,13 @@ #' @noRd validate_input <- function(x) { if (!is.numeric(x)) { - stop("Input must be numeric", call. = FALSE) + cli::cli_abort("Input must be numeric", call = NULL) } if (length(x) == 0) { - stop("Input must have at least one element", call. = FALSE) + cli::cli_abort("Input must have at least one element", call = NULL) } if (all(is.na(x))) { - stop("Input cannot be all NA values", call. = FALSE) + cli::cli_abort("Input cannot be all NA values", call = NULL) } TRUE } diff --git a/inst/WORDLIST b/inst/WORDLIST index c870787c..0ec290e1 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -2,8 +2,10 @@ CMD Callouts CodeFactor Codecov +DiagrammeR Lifecycle MathJax +README RevealJS Tabsets ackage @@ -11,12 +13,18 @@ altdoc callout callouts cdot +codebases emplate foldable +foodweb +foodwebr +formatter frac +graphviz linter lintr mc pkgdown serodynamics tabset +tidygraph diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index 16e2251d..891b0dcf 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -2,6 +2,7 @@ title: "Package Function Structure" author: "UC Davis Seroepidemiology Research Group (UCD-SERG)" date: "`r Sys.Date()`" +prefer-html: true format: revealjs: output-file: package-structure-revealjs.html From 2e67d68dd04f16e6704dcbf2b700aed1b1773e00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:31:09 +0000 Subject: [PATCH 7/9] Remove DOCX format from vignettes to fix foodwebr HTML widget rendering Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- vignettes/_metadata.yml | 2 -- vignettes/articles/package-structure.qmd | 2 -- 2 files changed, 4 deletions(-) diff --git a/vignettes/_metadata.yml b/vignettes/_metadata.yml index 78eeb23c..0787245f 100644 --- a/vignettes/_metadata.yml +++ b/vignettes/_metadata.yml @@ -16,5 +16,3 @@ format: number-sections: true number-depth: 2 fig-cap-location: top - docx: - number-sections: true diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index 891b0dcf..c1a6a592 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -2,12 +2,10 @@ title: "Package Function Structure" author: "UC Davis Seroepidemiology Research Group (UCD-SERG)" date: "`r Sys.Date()`" -prefer-html: true format: revealjs: output-file: package-structure-revealjs.html html: default - docx: default --- ```{r} From 986f7424f20032dec4263efc8edd208eea239e36 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:01:23 +0000 Subject: [PATCH 8/9] Restore DOCX format and add package-structure to website navigation Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- altdoc/quarto_website.yml | 3 +++ vignettes/_metadata.yml | 2 ++ vignettes/articles/package-structure.qmd | 10 ++++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/altdoc/quarto_website.yml b/altdoc/quarto_website.yml index 3a4362cf..1ef327ee 100644 --- a/altdoc/quarto_website.yml +++ b/altdoc/quarto_website.yml @@ -34,6 +34,8 @@ website: file: vignettes/quarto_vignette.qmd - text: "Advanced" file: vignettes/articles/quarto_article.qmd + - text: "Package Structure" + file: vignettes/articles/package-structure.qmd sidebar: collapse-level: 1 contents: @@ -48,6 +50,7 @@ website: - section: Advanced contents: - vignettes/articles/quarto_article.qmd + - vignettes/articles/package-structure.qmd - section: $ALTDOC_MAN_BLOCK style: floating - text: News diff --git a/vignettes/_metadata.yml b/vignettes/_metadata.yml index 0787245f..78eeb23c 100644 --- a/vignettes/_metadata.yml +++ b/vignettes/_metadata.yml @@ -16,3 +16,5 @@ format: number-sections: true number-depth: 2 fig-cap-location: top + docx: + number-sections: true diff --git a/vignettes/articles/package-structure.qmd b/vignettes/articles/package-structure.qmd index c1a6a592..1e102155 100644 --- a/vignettes/articles/package-structure.qmd +++ b/vignettes/articles/package-structure.qmd @@ -16,6 +16,8 @@ knitr::opts_chunk$set( fig.width = 7, fig.height = 5 ) +# Check if we're rendering to a format that supports HTML widgets +is_html_output <- knitr::is_html_output() ``` ```{r setup} @@ -80,7 +82,7 @@ The `plot()` method creates an interactive visualization using DiagrammeR: ```{r} #| label: fig-basic-foodweb #| fig-cap: "Basic function dependency graph for example_function" -#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) && is_html_output plot(fw) ``` @@ -123,7 +125,7 @@ fw_pkg ```{r} #| label: fig-package-foodweb #| fig-cap: "Complete dependency graph for all package functions" -#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) && is_html_output plot(fw_pkg) ``` @@ -278,7 +280,7 @@ You can focus on specific functions to understand their dependencies: ```{r} #| label: fig-example-function #| fig-cap: "Dependency graph for example_function showing all related functions" -#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) && is_html_output fw_example <- foodweb(FUN = example_function) plot(fw_example) ``` @@ -288,7 +290,7 @@ plot(fw_example) ```{r} #| label: fig-summary-function #| fig-cap: "Dependency graph for calculate_summary showing its relationships" -#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) +#| eval: !expr requireNamespace("foodwebr", quietly = TRUE) && is_html_output fw_summary <- foodweb(FUN = calculate_summary) plot(fw_summary) ``` From 699e4501b0084c31dc7307e7d3e61e6bee90f5d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:19:18 +0000 Subject: [PATCH 9/9] Add _snaps directory to gitignore to fix macOS build Agent-Logs-Url: https://github.com/UCD-SERG/rpt/sessions/5481ca55-3b4b-4b97-ac1a-f32a17d5e289 Co-authored-by: d-morrison <2474437+d-morrison@users.noreply.github.com> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8eb30ad5..fd43895c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ _quarto/* !_quarto/_freeze/ *.docx *.knit.md +tests/testthat/_snaps/