28  chores

Published

2025-04-18

WARNING

This chapter is being developed. Thank you for your patience.

The chores package was developed by Simon Couch1 to “help you complete repetitive, hard-to-automate tasks quickly”. We previously covered the ellmer package (see Chapter 27), which we’ll use to configure our chosen LLM.

install.packages(c('ellmer', 'chores'))
# or the dev versions
pak::pak('tidyverse/ellmer')
pak::pak("simonpcouch/chores")

28.1 Navbar App

In this branch we’ll use chores to add roxygen2 documentation to an updated version of the movie review application. The application still contains the original scatter plot with inputs for variables, aesthetics, and a plot title. However, the UI has been built around the page_navbar layout from bslib, with nav_panel()s containing graphs and tables for Counts, Distributions, and Awards.

28.1.1 Modules

The modules in the application have the following naming convention:

mod_ <tab> _ <type> _ ui/server

  • <tab> is the name of the tab (Compare, Counts, Distributions, Awards)
  • <type>
    • vars: ‘variable’ collection modules to return inputs
    • tbl: table display modules
    • type of display in module (i.e., point, bar, vbox, etc.)

The modules for each tab are organized into abstract syntax trees2 in the sections below.

28.1.1.1 Compare

The Compare tab uses two modules:

  1. mod_compare_vars collects the variable and aesthetic inputs.
  2. mod_compare_point takes the inputs and builds the plotly point plot.
█─ ─nav_ui  
│ ├─█─mod_compare_vars_ui 
│ └─█─mod_compare_point_ui 
└─█─nav_server 
  ├─█─mod_compare_vars_server 
  └─█─mod_compare_point_server

28.1.1.2 Counts

The Counts tab includes five modules:

  1. mod_counts_vars collects a grouping variable and start and end dates for the theater release year
  2. mod_counts_vbox displays the value box
  3. mod_counts_waffle displays the waffle plot
  4. mod_counts_bar displays the horizontal bar plot

Counts graphs

Counts graphs
█─ ─nav_ui  
│ ├─█─mod_counts_vars_ui 
│ ├─█─mod_counts_vbox_ui 
│ ├─█─mod_counts_bar_ui 
│ └─█─mod_counts_waffle_ui 
└─█─nav_server 
  ├─█─mod_counts_vars_sever 
  ├─█─mod_counts_vbox_server 
  ├─█─mod_counts_bar_server 
  └─█─mod_counts_waffle_server 
  1. mod_counts_tbl will display the counts table, but it’s still being developed (we’ll cover this in the gander chapter).

Counts table

Counts table
█─ ─nav_ui  
│ ├─█─mod_counts_vars_ui 
│ └─█─mod_counts_tbl_ui 
└─█─nav_server 
  ├─█─mod_compare_vars_server
  └─█─mod_counts_tbl_server 

28.1.1.3 Distributions

The Distributions tab uses four modules:

  1. mod_dist_vars collects a grouping y variable, a numeric x variable, and the alpha and size aesthetics.
  2. mod_dist_box displays the horizontal box plot.
  3. mod_dist_raincloud displays the rain cloud plot.

Distributions graphs

Distributions graphs
█─ ─nav_ui  
│ ├─█─mod_dist_vars_ui 
│ ├─█─mod_dist_box_ui 
│ └─█─mod_dist_raincloud_ui 
└─█─nav_server 
  ├─█─mod_dist_vars_server 
  ├─█─mod_dist_box_server 
  └─█─mod_dist_raincloud_server 
  1. mod_dist_tbl displays a table of summary statistics for the numeric variable across the levels of the grouping variable.

Distributions table

Distributions table
█─ ─nav_ui  
│ ├─█─mod_dist_vars_ui 
│ └─█─mod_dist_tbl_ui 
└─█─nav_server 
  ├─█─mod_dist_vars_server 
  └─█─mod_dist_tbl_server 

28.1.1.4 Awards

Awards has three modules:

  1. mod_awards_vars returns the award type and start and end values for the theater release year.
  2. mod_awards_point displays the point plot with labels for the movies or stars (actors).

Awards graphs

Awards graphs
█─ ─nav_ui  
│ ├─█─mod_awards_vars_ui 
│ └─█─mod_awards_point_ui 
└─█─nav_server 
  ├─█─mod_awards_vars_server 
  └─█─mod_awards_point_server 
  1. mod_awards_tbl displays the data used in the point plot.

Awards table

Awards table
█─ ─nav_ui  
│ ├─█─mod_awards_vars_ui 
│ └─█─mod_awards_tbl_ui 
└─█─nav_server 
  ├─█─mod_awards_vars_server 
  └─█─mod_awards_tbl_server

28.1.2 Utility functions

Three new utility functions have been added to the application. The display_type() (Section 8.3.2) and test_logger() (Section 16.3) functions from previous sections are also included.

28.1.2.1 Name case

The name_case() function converts the column names to title case (and it’s used in most of the module functions):

name_case(x = "critics_rating", case = "title")
## [1] "Critics Rating"
name_case(x = "Critics Rating", case = "lower")
## [1] "critics rating"

28.1.2.2 Variable summary

The dist_var_summary() function creates the summary statistics table in the Distributions tab using the group and numerical variables.

█─ ─nav_ui  
│ └─█─mod_dist_tbl_ui 
└─█─nav_server 
  └─█─mod_dist_tbl_server 
    └─█─dist_var_summary
dist_var_summary(
  data = movies, 
  grp_var = 'critics_rating', 
  num_var = 'audience_score')
## # A tibble: 3 × 7
##   Group            N  Mean    SD   Min   Max   IQR
##   <fct>        <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Rotten         307  49.7  17.9    11    95  28  
## 2 Certified F…   135  79.4  11.2    35    97  16.5
## 3 Fresh          209  70.0  15.6    29    94  25

28.1.2.3 Movie awards

When provided an award type (Films or Stars) and start and end theater release dates, the create_movie_awards converts the movies data into the movie awards data for the graph and table the Awards tab:

█─ ─nav_ui   
│ ├─█─mod_awards_point_ui 
└─█─nav_server 
  └─█─mod_awards_point_server 
    └─█─create_movie_awards 
create_movie_awards(
  df = movies,
  award = "Films", 
  start_year = 1990, 
  end_year = 1995)
## # A tibble: 8 × 3
##   title                        award          year
##   <chr>                        <chr>         <dbl>
## 1 The Age of Innocence         Best Director  1993
## 2 The Doors                    Best Director  1991
## 3 The Man Without a Face       Best Director  1993
## 4 Heaven & Earth               Best Director  1994
## 5 The Wedding Banquet (Xi yan) Best Director  1993
## 6 Jade                         Best Director  1995
## 7 Point Break                  Best Director  1991
## 8 Mighty Aphrodite             Best Director  1995

28.2 Setting up chores

We’ll use the Anthropic’s Claude model for the chores add-in. This can be configured following the instructions on the package website.

Open .Renviron and add ANTHROPIC_API_KEY:

# open .Rprofile
usethis::edit_r_environ()

Use the .chores_chat option to set the model:

options(.chores_chat = ellmer::chat_claude())

You should see:3

Using model = "claude-3-7-sonnet-latest".

28.2.1 Configure add-in

chores comes with an add-in (an interface to write prompts) which I’ll be demonstrating in Positron 4

After adding the JSON to keybindings.json, the chores add-in will pop-up in the Viewer:

Positron chores add-in

Positron chores add-in

28.3 Addin

chores comes with three helpers: cli, roxygen, testthat. Below is an example of the roxygen helper in Positron with our name_case() function:

Click to enlarge

Click to enlarge

chores doesn’t write comprehensive documentation, but it will

generate a subset of a complete documentation entry, to be then completed by a developer:

Specifically, it will write the @title, @description, any arguments (i.e., @param), and what the function @returns. The chores helper will also export the function by default.

The chores helper returned the following roxygen2 documentation:

#' Change the case of text
#'
#' @param x A character vector.
#' @param case One of `"title"` or `"lower"`. Optional.
#'
#' @returns
#' A character vector with the case changed according to the specified format.
#' Will error if input is not a character vector or if an unsupported case is specified.
#'
#' @export

The mod_compare_vars_ui() function is also demonstrated below:

TIP: Padding

I recommend placing about 10 lines of extra padding above the function you’re using chores to document. I’ve found this ensures the first few lines of the function aren’t overwritten by the helper response.

Click to enlarge

Click to enlarge

The roxygen2 documentation for the mod_compare_vars_ui() function is below:

#' UI module for comparing movie variables
#'
#' @param id A string. The module ID.
#'
#' @returns A UI element containing inputs for selecting variables to compare 
#' in a scatter plot, including X and Y variables, color variable, and
#' customization controls for alpha, size, and plot title.
#'
#' @export

So far, all of the documentation I’ve generated using chores has been correct, and it puts me in a better starting place that the standard roxygen2 skeleton produced by RStudio. You can read more about the helper prompts in the chores package documentation.

Below we’ll cover how to add custom helper prompts that can be used with the chores addin.

28.4 Custom helpers

chores gives users the ability to add custom helpers (prompts). These prompts can be written in markdown and must be named either replace, prefix, or suffix.

replace: will remove the highlighted code and replace it with a response.

prefix: will place the response above the highlighted text.

suffix: will place the response below the highlighted text.

Below is a shinymod-prefix helper prompt that has some specific instructions for documenting Shiny modules (see Section 5.2).

inst/prompts/shinymod-prefix.md

You are an expert Shiny developer who loves providing detailed explanations of complex topics to non-technical audiences.

Follow the tidyverse style guide:

  • Limit code to 80 characters per line
  • Place a space before and after =
  • Only use a single empty line when needed to separate sections
  • Always use double quotes for strings
  • Always use backticks for inline code
  • Use double quotes, not single quotes, for quoting text
  • Use base pipe |> (not %>%)
  • Reference UI/server functions using brackets

Use the following documentation for the aes() function from ggplot2 as an example:

#' Construct aesthetic mappings
#'
#' Aesthetic mappings describe how variables in the data are mapped to visual
#' properties (aesthetics) of geoms. Aesthetic mappings can be set in
#' [ggplot()] and in individual layers.
#'
#' This function also standardises aesthetic names by converting `color` to 
#' `colour` (also in substrings, e.g., `point_color` to `point_colour`) and
#' translating old style R names to ggplot names (e.g., `pch` to `shape` 
#' and `cex` to `size`).
  • When documenting a UI function, reference the corresponding server function (and vice versa).
    • For example, mod_vars_ui() should reference mod_vars_server().
mod_vars_ui <- function(id) {
  ns <- NS(id)
    tagList(
        varSelectInput(
          inputId = ns('chr_var'),
          label = strong('Group variable'),
          data = chr_data,
          selected = 'Critics Rating'
        )
    )
}
mod_vars_server <- function(id) {
  moduleServer(id, function(input, output, session) {    
    return(
      reactive({
        list(
          'chr_var' = input$chr_var
        )
      })
    )
  })
}

Example documentation for mod_vars_ui():

#' UI for count variables module
#'
#' Creates inputs for selecting a grouping variable. This function is designed
#' to work together with [mod_vars_server()].
#'
#' @param id A character string used to identify the namespace for the module.
#'
#' @return A `tagList` containing UI elements:
#'  * A variable select input for the grouping variable
#'
#' @seealso [mod_vars_server()] for the server-side logic
#'
#' @examples
#' # UI implementation
#' ui <- fluidPage(
#'   mod_vars_ui('vars1')
#' )
#'
#' # Server implementation
#' server <- function(input, output, session) {
#'   vars <- mod_vars_server('vars1')
#' }
#'
  • Indicate if returned values are reactive.
  • Return responses in roxygen2 comments (no R code blocks)
  • Include 5 blank lines of ‘padding’ after all responses

To add a custom helper to the chores addin, you can provide the URL to a raw markdown file on GitHub using chores::prompt_new():

chores::prompt_new(
  "shinymod", 
  "prefix", 
  contents = "https://raw.githubusercontent.com/mjfrigaard/chorrrin/refs/heads/main/inst/prompts/shinymod-prefix.md"
)

28.4.1 Extension package

If you have a collection of repetitive tasks you’d like to include in the chores addin, you can create and install a small chores extension package. For example, I’ve created the chorrrin extension package.5

# install.packages("pak")
pak::pak("mjfrigaard/chorrrin")
library(chorrrin)

chorrrin contains a modlog-replace helper for re-writing Shiny modules using the logger package (we covered this in Section 13.3.3) and a modtest-replace for writing Shiny module tests using Shiny’s testServer() function (see Testing modules).

As you can see from the image below, I can highlight the module function I’d like to add log messages to, click Ctrl + Cmd + C, select the helper, and click Enter:

Example modlog helper in Positron

Example modlog helper in Positron

Recap

chores delivers on it’s intention to ’complete repetitive, hard-to-automate tasks quickly.” I used it to quickly generate documentation, log messages, and tests for the modules in this branch’s application. The generated responses still required revision/edits, but being able use use a keyboard shortcut and start with a first draft saves time (and neurons).


  1. Simon Couch also the author of the ensure and gander packages.↩︎

  2. Create abstract syntax trees with the lobstr::ast() function.↩︎

  3. At the time of this writing, this was the latest Claude model from Anthropic.↩︎

  4. You can see examples using RStudio on the package website.↩︎

  5. Follow the example chores extension package and instructions provided in the chores documentation.↩︎