Package Creation and Metadata

Get Ready

Check required packages

all(
  c("devtools", "roxygen2", "testthat", "knitr", "pkgdown", "usethis") %in%
    installed.packages()
)

Lay the foundations

Load devtools and create your package infrastructure

library(devtools)
create_package("~/Desktop/fishr")

This will open a new RStudio project called fishr with the basic package infrastructure.

Use devtools and usethis

We can load devtools and usethis automatically via our .Rprofile file so that they are always loaded during development.

Note that this is not adding devtools nor usethis as a package dependency, it makes it available to help us during development.

use_devtools()

Note that devtools makes all of usethis available in your R session, so this is equivalent to also having library(usethis).

Paste the contents of your clipboard of both commands in .Rprofile, and restart R.

Confirm git is configured correctly (and update if necessary)

This should have been done in your setup, but it’s not a bad idea to double check.

git_sitrep()
dev_sitrep()

If git_sitrep warns missing a username and email, run the following command to configure git:

use_git_config(
  user.name = "Your Name",
  user.email = "Your Email"
)

If dev_sitrep suggests any package updates, please go ahead and do that.

Initialize this package as a git repo

use_git()

This sets up your project as a git repository, and with your permission makes the first commit.

Connect your repository to GitHub

use_github()

This creates a GitHub repo and sets it as your remote.

Push your committed code

At this step you may be required to authenticate with GitHub.

git push origin main

Write your first function

Open a new file in R/ to hold your code

use_r("cpue")

Write your function definition in this file

cpue calculates catch per unit effort by dividing total catch by fishing effort. The function optionally applies a gear-specific correction factor to standardize CPUE across different fishing gear types. The function returns the adjusted CPUE value.

cpue <- function(catch, effort, gear_factor = 1) {
  raw_cpue <- catch / effort

  raw_cpue * gear_factor
}

Load your package with load_all()

load_all()

And test out our new function:

cpue(10, 5)
TipMake a commit

Now that we have a basic working function, commit your changes.

Check your package

check()

Set a license

use_mit_license()

DESCRIPTION file:

Package: fishr
Title: Calculate standard catch metrics for fisheries
Version: 0.0.0.9000
Authors@R:
    person("Jane", "Doe",
           email = "jane.doe@something.com",
           role = c("aut", "cre"),
           comment = c(ORCID = "XXXX-XXXX-XXXX-XXXX"))
Description: Provides functions for calculating and analyzing fisheries
    catch data, such as Catch Per Unit Effort (CPUE), a fundamental metric in
    fisheries science.
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2

Check again

check()

Documentation Basics

Add a roxygen block just above your function definition

Insert template with Ctrl + Alt + Shift + R or Cmd + Option + Shift + R

#' Calculate Catch Per Unit Effort (CPUE)
#'
#' Calculates CPUE from catch and effort data, with optional gear standardization.
#'
#' @param catch Numeric vector of catch (e.g., kg)
#' @param effort Numeric vector of effort (e.g., hours)
#' @param gear_factor Numeric adjustment for gear standardization (default is 1)
#'
#' @return A numeric vector of CPUE values
#' @export
#'
#' @examples
#' cpue(100, 10)
#' cpue(100, 10, gear_factor = 0.5)
cpue <- function(catch, effort, gear_factor = 1) {
  ...
}

Build function documentation (man/cpue.Rd) from roxygen

document()

You can preview it with ?function_name

load_all()

?cpue

NAMESPACE file

# Generated by roxygen2: do not edit by hand

export(cpue)
TipMake a commit

Check package to ensure documentation conforms to standards

check()

Create package-level documentation

use_package_doc()

document()

See rendered documentation at man/fishr-package.Rd

Preview and check again

load_all()

?fishr

check()
TipMake a commit

README

use_readme_rmd()
---
output: github_document
---

<!-- README.md is generated from README.Rmd. Please edit that file -->



# fishr

<!-- badges: start -->

<!-- badges: end -->

The goal of fishr is to provide functions for calculating Catch Per Unit Effort (CPUE),
a fundamental metric in fisheries science.

## Installation

You can install the development version of fishr from [GitHub](https://github.com/) with:

```r
# install.packages("pak")
pak::pak("yourname/fishr")
```

## Example usage

```{r example}
library(fishr)
cpue(catch = 100, effort = 10)

# With gear standardization
cpue(catch = 100, effort = 10, gear_factor = 0.5)
```
build_readme()
check()
TipMake a commit

Set a default DESCRIPTION

This avoids having to manually edit DESCRIPTION every time you create a package

edit_r_profile()

Add this to your .Rprofile file:

# Set usethis options:
options(
  usethis.description = list(
    "Authors@R" = utils::person(
      "Jane",
      "Doe",
      email = "jane.doe@example.com",
      role = c("aut", "cre"),
      comment = c(ORCID = "0000-1111-2222-3333")
    )
  )
)

options(
  warnPartialMatchArgs = TRUE,
  warnPartialMatchDollar = TRUE,
  warnPartialMatchAttr = TRUE
)

Restart R for changes to take effect.

Common Pain Points

Some typical pain points when developing packages:

  • When to use load_all() vs install()?
    • load_all(): During active development (fast, doesn’t install). Working inside your package project.
    • install(): When you want to test as a “real” package, outside your package project.
  • Managing dependencies
    • Which functions need @importFrom?
    • When to use package::function() vs importing?
    • Dependencies in NAMESPACE vs DESCRIPTION
  • Documentation drift
    • Keeping roxygen comments in sync with code
    • Updating examples when function signatures change
  • Understanding check() errors and warnings
    • What’s critical vs nice-to-have?
    • Common CRAN check issues
  • Package state confusion
    • Why isn’t my change showing up?
    • Do I need to restart R?