r package development

improvemnt as a programmer
Author
Published

Monday, February 24, 2025

Doi

what are packages?

R packages are collections of code, data, and documentation that extend R’s functionality beyond its core features. If you have an idea or notice a gap in the existing ecosystem, you can develop a package, test it, document it, and share it with the broader R community. You can distribute your package through the Comprehensive R Archive Network (CRAN)1 (CRAN) or GitHub.

1 CRAN reviews all submitted packages and distributes them as precompiled binaries

how to create a package

All you need (assuming you already know some R) is a solid idea or concept that interests you. Take the time to clarify your idea—what problem does your package solve? How will it be useful? Even if it’s just for you, that’s a great start.

Next, break the problem into steps and outline the primary functions you’ll need. Begin by creating a project folder to serve as the foundation of your package. Your functions will likely evolve as you refine them, but starting with a basic structure will help keep your development process organized.

an intermesso on r projects

Always use RStudio projects! This is just my opinion, but a well-founded one. RStudio projects, combined with the here and renv packages, will save you countless headaches. Together, they help keep your code reproducible and shareable in a structured environment.

Also, consider disabling the option to save your workspace on exit. It often leads to unnecessary clutter and can slow things down, especially when working with large datasets. 2

2 How large is “large”? That depends on your RAM.

back to creating packages

Your functions will likely evolve, merge, or be rewritten entirely as your package matures. That’s okay. Most ideas need refinement through trial and error in an isolated environment—your R session—before they’re ready for the world. Stay flexible and be willing to adjust your approach as you develop your package.

To deepen your understanding of package development, you don’t need a Coursera® certificate. Instead, focus on mastering the fundamentals of R programming and, most importantly, read R packages by Hadley Wickham and Jennifer Bryan. It’s short, informative, and packed with insights that will save you time and frustration.

documenting your functions

As you build and modify your functions, document them! Make notes on what each function does, its arguments, and any important details. This will form the basis of your formal documentation later.

One of my favorite shortcuts is using ChatGPT® to generate roxygen2 documentation. I provide a brief explanation of what my function does, a summary of its arguments, and the function code, then ask ChatGPT® to generate the roxygen2 documentation. This saves time—but be warned: ChatGPT® has a habit of “hallucinating,” so always review its output carefully.

write formal tests

While it’s natural to test functions informally in the console, you should also create automated tests to verify their correctness in various scenarios. While I’m not entirely sure if CRAN requires formal tests for all user-facing functions, I totally recommend using the testthat package to create these automated tests.

regularly check your progress

If it hurts, do more of it. — Joko Willink

Run devtools::check() regularly throughout the development process. It’s much easier to fix a few small issues as they arise than to deal with a mountain of errors all at once. Frequent checks will make your package better, reduce frustration for the CRAN reviewers, and improve the experience for your future users.

Even if you’re only sharing it on GitHub, always check your package. Your goal should be to provide users with a solid, well-tested, and reliable tool free of logical or implementation errors.

release it to the world

Once you’ve triple-checked (and quadruple-checked) your package and resolved all warnings and notes3, you’re ready to submit to CRAN.

3 Some notes are unavoidable—new packages, for example, always receive a maintainer-related note that can’t be resolved.

Be prepared to communicate with CRAN reviewers and check your email regularly. The submission process can involve some back-and-forth, so try to be patient as you work to get your package on CRAN.

personal experience

What I have described here is based on my personal experience developing R packages. I’ve released three packages to CRAN, despair,matriz, and logos.

The despair package was a purely fun and silly desire to create (de)motivational quotes and codenames called bard.bits that could be used as code names.

The matriz Born out of necessity, this package automates the creation, editing, deletion, and updating of literature matrices and BibTeX references. I built it because my research methods class required us to create literature matrices by hand in Excel®, which was painfully tedious.

The logos package introduces the writings of the Old and New testament in English, Greek and Hebrew to the R community after realizing they were not available on CRAN or GitHub. 4 I only realized this gap because, in an attempt to do textual analysis on the gospel of John in its original language, I discovered publicly available biblical data was scarce within the R community.

4 the Mormon scriptures have been bundled into a package by Andrew Heiss

I’ve also worked on other packages available on my GitHub profile. Some are still works in progress, but if you’re interested in any of them, you can install devtools and download them directly from GitHub.

devtools::instal_github("jpmonteagudo28/matriz", "jpmonteagudo28/despair","jpmonteagudo28/logos")

Here’s how to install the three packages from CRAN:


install.packages(c("logos","matriz","despair"))
# Downloading packages -------------------------------------------------------
# - Downloading logos from CRAN ...               OK [3.2 Mb in 0.77s]
# - Downloading matriz from CRAN ...              OK [378.5 Kb in 0.65s]
# - Downloading writexl from CRAN ...             OK [198.4 Kb in 0.54s]
# - Downloading despair from CRAN ...             OK [113.6 Kb in 0.53s]
# Successfully downloaded 4 packages in 5.7 seconds.
# 
# The following package(s) will be installed:
# - despair [0.1.1]
# - logos   [0.1.0]
# - matriz  [1.0.1]
# - writexl [1.5.1]
# These packages will be installed into "C:/Users/yourname/folder/".
# 
# Do you want to proceed? [Y/n]: y
# 
# # Installing packages --------------------------------------------------------
# - Installing logos ...                          OK [installed binary and cached in 0.92s]
# - Installing writexl ...                        OK [installed binary and cached in 0.57s]
# - Installing matriz ...                         OK [installed binary and cached in 0.57s]
# - Installing despair ...                        OK [installed binary and cached in 0.55s]
# Successfully installed 4 packages in 2.8 seconds.

A taste of despair:

library(despair)

# set a reproducible character seed
sad_seed <- set.char.seed("an ugly horse parade")

# let the demotivation rain
demotivate(cat = "work", seed = sad_seed)
#> [1] "Monday is an awful way to spend 1/7th of your life."

# Let's now boost your ego…perhaps
motivate(cat = "stoic",seed = sad_seed)
#> [1] "Difficulties strengthen the mind, as labor does the body. - Seneca"

# Now come up with a funny Shakesperean code name for a project
bard.bits(cat = "dsm_5", seed = sad_seed)
#> [1] "critical starling"

Here’s the logos package in action:


library(logos)

select_passage("Jhn",chapter = 1,verse = 1:6, language = "English",testament = "new")
#> [1] "In the beginning was the Word, and the Word was with God, and the Word was God."              "The same was in the beginning with God."                                                      "All things were made through him; and without him was not anything made that hath been made."
#> [4] "In him was life; and the life was the light of men."                                          "And the light shineth in the darkness; and the darkness apprehended it not."                  "There came a man, sent from God, whose name was John."

# now in Greek
select_passage("Jhn",chapter = 1,verse = 1:6, language = "Greek",testament = "new")
#> [1] "Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος. " "οὗτος ἦν ἐν ἀρχῇ πρὸς τὸν θεόν. "                                        "πάντα διʼ αὐτοῦ ἐγένετο, καὶ χωρὶς αὐτοῦ ἐγένετο οὐδὲ ἕν. ὃ γέγονεν "    "ἐν αὐτῷ ζωὴ ἦν, καὶ ἡ ζωὴ ἦν τὸ φῶς τῶν ἀνθρώπων· "                     
#> [5] "καὶ τὸ φῶς ἐν τῇ σκοτίᾳ φαίνει, καὶ ἡ σκοτία αὐτὸ οὐ κατέλαβεν. "        "Ἐγένετο ἄνθρωπος ἀπεσταλμένος παρὰ θεοῦ, ὄνομα αὐτῷ Ἰωάννης· "

Now the matriz package:


library(matriz)
lit_matrix <- init_matrix()

# Get matriz structure to guide in creating records
matriz_names()
#>                        class
#> year                 numeric
#> citation           character
#> keywords           character
#> profession         character
#> electronic           logical
#> purpose            character
#> study_design       character
#> outcome_var        character
#> predictor_var      character
#> sample               numeric
#> dropout_rate         numeric
#> setting            character
#> inclusion_criteria character
#> ethnicity          character
#> age                  numeric
#> sex                   factor
#> income                factor
#> education          character
#> measures           character
#> analysis           character
#> results            character
#> limitations        character
#> implications       character
#> ethical_concerns   character
#> biases             character
#> notes              character

# Start filling out individual record with article info
article <- data.frame(year = 2025,
                citation = " ",
                keywords = " ",
                profession = "underwater basket weaver",
                electronic = "YES",
                purpose = "To investigate the depth of the oceans and retireve weaving materials",
                study_design = "ethnography", 
                outcome_var = "perceived attitudes towards basket weaving",
                predictor_var = NA, 
                sample = "a small school of clown fish", 
                setting = "Italy",
                drop_rate = 0.13, 
                inclusion_criteria = "clow fish in Adriatic Sea", 
                ehtnicity = "oceanic", 
                age = "0 - 1 year",
                sex = "both",
                income = " ",
                education = "none",
                measures = "perceived attitudes",
                analysis = "qualitative", 
                results = "no significant differences",
                limitations = "small sample size", 
                implications = "clow fish don't like humans taking their homes for their own basket weaving endeavors",
                ethical_concerns = "no informed consent given to school of clown fish",
                biases = "clownfish always try to be funny. Lack of seriounness",
                notes = "more research needed")

# Add the record to the literature matrix
lit_matrix <- add_record(lit_matrix, article, .before = 1)

# Update record if mistake was made
lit_matrix <- update_record(lit_matrix, notes, where = year == 2025, set_to = "actually, the clow fish don't want us to come back.")

Citation

For attribution, please cite this work as:
Monteagudo, JP. 2025. “R Package Development.” February 24, 2025. https://doi.org/10.59350/x86y2-rfa38.