Anyways. Lots to explore: new datasets, friendly/informative summary messages of scraped variables, tabling of latent correlations...
Next update will probably be less function-forward. @drmowinckels.io's #RPackageAdvent2025 thread has got me exited about website and documentation improvements.
A festive digital illustration features the blue R logo wearing a red Santa hat with white trim on the left. To its right stands a green Christmas tree made entirely of curly braces arranged in a triangular shape. White and light-blue %>% pipe symbols float across a dark blue, starry background like snowflakes. A speech bubble above the R logo says “Ho Ho Ho! 📦” in red text. At the bottom, white text reads: “R Package Development Advent Calendar 2025” and below it, “25 Days of Coding Magic • Dec 1–25.
My #RPackageAdvent2025 recap is live! 📦✨ Get the complete guide to modern R package development: setup, docs, testing, CI/CD, and CRAN submission. All 25 days of tips, tools, and best practices in one place! Dive in! #RStats #RPackageDevelopment
Link: https://drmo.site/8ny3eU
A festive digital illustration features the blue R logo wearing a red Santa hat with white trim on the left. To its right stands a green Christmas tree made entirely of curly braces arranged in a triangular shape. White and light-blue %>% pipe symbols float across a dark blue, starry background like snowflakes. A speech bubble above the R logo says “Ho Ho Ho! 📦” in red text. At the bottom, white text reads: “R Package Development Advent Calendar 2025” and below it, “25 Days of Coding Magic • Dec 1–25.
Excited to share my R Package Development Advent Calendar 2025 summary! 🎁 All 25 days of modern R pkg dev in one guide. Master `usethis`, GitHub Actions, `pkgdown`, `testthat`, & CRAN prep. Level up your R packages! 🚀 #RStats #RPackageAdvent2025 #Rpkg https://drmo.site/8ny3eU
Your Next Steps:
✨ Apply these tools to your packages
📚 Bookmark for reference
🤝 Share knowledge with community
🚀 Build amazing R packages
Thank you for following #RPackageAdvent2025! Now go make the R ecosystem better! 🎄📦
Keep Learning: r-pkgs.org | usethis.r-lib.org
We Made It! 🎉
25 days. Complete modern R package development workflow. From usethis automation to CRAN submission. You have everything you need!
#rstats #CRAN #RPackageAdvent2025 #ThatsAWrap
Day 25: CRAN Submission Checklist and cran-comments.md
Final steps for successful CRAN submission.
Pro Tip: Be proactive about communicating any unusual aspects of your package to CRAN reviewers.
#rstats #RPackageAdvent2025
my_summarise <- function(data, ...) { data |> dplyr::summarise(...) }
my_mutate <- function(data, col, value) { data |> dplyr::mutate({{ col }} := value) }
my_function <- function(...) { dots <- rlang::list2(...) # process dots }
Day 24: rlang - Tidy Evaluation in Packages
Handle user expressions safely in package functions.
Pro Tip: Use {{ }} (embrace) for single arguments, ... for multiple arguments.
Resources: rlang.r-lib.org
#rstats #RPackageAdvent2025
Oh wow, that's a neat/powerful idea. Do you have an exemplar of this in action (that's convenient for you to recall)?
I think for our next release I'm just going to be working my way through a bunch of the suggestions in your #RPackageAdvent2025 (pkgdown themes!!!), and this one sounds really cool
cli::cli_progress_bar("Processing files", total = length(files)) for (file in files) { # process file cli::cli_progress_update() }
cli::cli_alert_success("Package built successfully!") cli::cli_alert_warning("Missing documentation for {.fn my_function}") cli::cli_abort("Invalid input: {.val {invalid_value}}")
Day 23: cli - Beautiful Command Line Interfaces
Create user-friendly messages and progress indicators.
Pro Tip: Use semantic markup like {.fn function_name} and {.val value} for consistent formatting.
Resources: cli.r-lib.org
#RpackageAdvent2025 #rstats
Day 22: S3, S4, and S7 Object Systems
Create robust object-oriented interfaces with R's object systems.
Pro Tip: Use S3 for simple classes, S4 for complex validation, S7 for modern OOP.
Resources: rconsortium.github.io/S7
#rstats #RPackageAdvent2025
Day 21: rhub - Multi-Platform Testing (Thread)
Test your package on multiple platforms before CRAN submission.
Resources: r-hub.github.io/rhub/
#rstats #RPackageAdvent2025
bench::mark( my_function(big_data), filter_gc = FALSE )
results <- bench::mark( old_approach = old_function(data), new_approach = new_function(data), check = FALSE, # Skip result equality check iterations = 100 ) plot(results)
Day 20: Performance Testing with bench
Profile and benchmark your package functions.
Pro Tip: Include benchmarks in your test suite to catch performance regressions.
Resources: bench.r-lib.org
#rstats #RPackageAdvent2025
Day 19: goodpractice - Package Health Checks
Get comprehensive feedback on package quality
goodpractice::gp()
Checks include:
⬩ Function length and complexity
⬩ Namespace usage
⬩ DESCRIPTION completeness
⬩ Code coverage
Resources: github.com/mangothecat/goodpractice
#rstats #RPackageAdvent2025
lintr::lint_package() styler::style_pkg()
# .lintr file in project root linters: linters_with_defaults( line_length_linter(120), commented_code_linter = NULL )
Day 18: Use linters!
Maintain consistent, readable code style automatically.
Usage:
lintr::lint_package()
styler::style_pkg()
Pro Tip: Add both to pre-commit hooks for automatic code formatting.
Resources: lintr.r-lib.org
#rstats #RPackageAdvent2025
# In vignette setup vcr::use_cassette("demo_data", { demo_data <- fetch_api_data("example") })
test_that("API returns expected data", { use_cassette("github_api", { response <- httr::GET("https://api.github.com/users/octocat") expect_equal(httr::status_code(response), 200) }) })
Day 17: vcr - Recording API Calls for Tests
Record real API responses for reliable, fast tests without hitting live APIs.
Pro Tip: Commit cassette files to git for reproducible tests across environments.
Resources: docs.ropensci.org/vcr
#rstats #RPackageAdvent2025
Day 16: Testing with Mocks using testthat
Test functions that depend on external resources using testthat's built-in mocking.
Pro Tip: Use local_mocked_bindings() to mock functions within the test scope only.
Resources: testthat.r-lib.org
#rstats #RPackageAdvent2025
test_that("plots look right", { p <- ggplot(mtcars, aes(mpg, wt)) + geom_point() vdiffr::expect_doppelganger("mtcars-scatter", p) })
test_that("error messages are informative", { expect_snapshot(my_function(bad_input), error = TRUE) })
Day 15: Snapshot Testing with testthat
Test complex outputs that are hard to specify exactly.
Pro Tip: Review snapshot changes carefully - they capture everything, including whitespace and formatting.
#rstats #RPackageAdvent2025
test_that("plot output is stable", { p <- my_plot(data) vdiffr::expect_doppelganger("basic-plot", p) })
Day 14: testthat 3rd Edition Features
Modern testing with the latest testthat features.
Setup:
usethis::use_testthat(3)
Pro Tip: Use test_that() with descriptive names that explain what should happen.
Resources: testthat.r-lib.org
#rstats #RPackageAdvent2025
usethis::use_github_action("test-coverage") usethis::use_coverage() # Adds codecov badge
covr::package_coverage() covr::report() covr::package_coverage() |> covr::zero_coverage()
Day 13: covr - Test Coverage Reporting
Track how much of your code is tested.
use #nocov for code you don't want to cover (like basic R functions etc)
Pro Tip: Focus on testing critical functions thoroughly rather than chasing 100%.
Resources: covr.r-lib.org
#rstats #RPackageAdvent2025
- name: Render README run: Rscript -e 'rmarkdown::render("README.Rmd")'
Day 12: README.Rmd Automation
Create dynamic READMEs that stay up-to-date with your code.
Setup:
usethis::use_readme_rmd()
Include these sections:
• Installation instructions
• Basic usage example
• Lifecycle badges
• Build status badges
#rstats #RPackageAdvent2025
# mypackage 1.2.0 ## New features * Added `new_function()` for advanced analysis (#15) ## Bug fixes * Fixed issue with missing values in `existing_function()` (#12) ## Breaking changes * `old_param` renamed to `new_param` in `main_function()`
Day 11: NEWS.md and Semantic Versioning
Keep users informed about package changes.
Create NEWS.md:
usethis::use_news_md()
Pro Tip: Follow semantic versioning: MAJOR.MINOR.PATCH for breaking.feature.bugfix changes.
#rstats #RPackageAdvent2025
#' @lifecycle experimental new_function <- function() { # function body }
#' @lifecycle deprecated old_function <- function() { lifecycle::deprecate_warn("1.0.0", "old_function()", "new_function()") # function body }
Day 10: lifecycle - Managing Function Deprecation
Communicate changes to users gracefully with lifecycle badges.
Setup:
usethis::use_lifecycle()
Pro Tip: Use lifecycle stages: experimental → stable → superseded → deprecated.
Resources: lifecycle.r-lib.org
#rstats #RPackageAdvent2025
Day 9: Vignettes with knitr and rmarkdown
Create comprehensive tutorials and examples for your package.
usethis::use_vignette("getting-started")
● Start with a clear problem statement
● Show realistic examples
● Keep computational time under 5 minutes
#rstats #RPackageAdvent2025
I'm also a keen R package developer, and huge fan of the devtools/usethis/r-lib ecosystem which provides the tooling to make package development intuitive, (relatively) easy and joyous.
@drmowinckels.io is currently posting an amazing series on this: check out #RPackageAdvent2025
template: params: bootswatch: flatly reference: - title: "Data manipulation" contents: - starts_with("mutate") - ends_with("_join")
Day 8: pkgdown Customization and Deployment
Transform your package documentation into a polished website.
Advanced customization:
Auto-deployment:
usethis::use_github_action("pkgdown")
Pro Tip: Group functions logically in the reference section for better navigation.
#rstats #RPackageAdvent2025
Cross-references: 🔗 #' @seealso [other_function()], [pkg::function()] #' @family utility functions #' @inheritParams parent_function
Advanced tags: ⚡ #' @section Warning: #' This function modifies data in place. #' #' `r paste("Generated on", Sys.Date())` # Run R code
Day 7: roxygen2 Advanced Tags and Cross-References 📝
Master documentation with advanced roxygen2 features, with markdown-style writing! 🎯
💡 Pro Tip: Use @inheritDotParams to inherit ... parameter documentation.
📚 Resources: roxygen2.r-lib.org
#rstats #roxygen2 #Documentation #RPackageAdvent2025
Let the tool handle the details so you focus on code.
Tomorrow: Advanced roxygen2 for better documentation! 📝
Resources: usethis.r-lib.org
#rstats #usethis #Dependencies #RPackageAdvent2025
usethis::use_package("dplyr") usethis::use_package("data.table", min_version = "1.14.0") usethis::use_package("ggplot2", type = "Suggests")
Day 6/25: Adding dependencies to your #rstats package 🧵
#rstats #RPackageAdvent2025
The Manual DESCRIPTION Problem: You need to add dplyr to your package. Open DESCRIPTION, find Imports, type "dplyr," hope you didn't typo it, wonder if you need a version constraint, forget to sort alphabetically.
template: bootstrap: 5 navbar: structure: left: [intro, reference, articles, tutorials] right: [search, github]
Day 5: Package Structure with pkgdown Site Generation 🌐
Create beautiful documentation websites for your packages! ✨
usethis::use_pkgdown()
pkgdown::build_site()
💡 Pro Tip: Use usethis::use_pkgdown_github_pages() for deployment.
📚 Resources: pkgdown.r-lib.org
#rstats #RPackageAdvent2025
Essential .gitignore entries: 🔒 .Rproj.user .Rhistory .RData .Ruserdata docs/
Essential .Rbuildignore entries: 🚫 ^.*\.Rproj$ ^\.Rproj\.user$ ^README\.Rmd$ ^LICENSE\.md$ ^\.github$ ^_pkgdown\.yml$ ^docs$ ^pkgdown$
Day 4: .Rbuildignore and .gitignore Best Practices 📁
Control what gets included in your package build and git repository! 🎯
💡 Pro Tip: Use usethis::use_build_ignore() to add entries programmatically.
#rstats #BestPractices #Git #RPackageAdvent2025 🗃️