16 {glue}

Note

This lecture used materials from the {glue} package vignette.

The glue package contains functions for string interpolation: gluing together character strings and R code.

Gluing and interpolating

  • glue() can be used to glue together pieces of text:
glue("glue", "some", "text", "together")
## gluesometexttogether
glue("glue", "some", "text", "together", .sep=" " )
## glue some text together
  • But glue’s real power comes with {}: anything inside of {} is evaluated and pasted into the string. This makes it easy to interpolate variables:
name <- "glue"
glue("We are learning how to use the {name} R package.")
## We are learning how to use the glue R package.
  • As well as more complex expressions:
release_date <- as.Date("2017-06-13")
glue("Release was on a {format(release_date, '%A')}.")
## Release was on a Tuesday.

What you see is awfully close to what you get

  • glue() lets you write code that makes it easy to predict what the final string will look like. There is considerably less syntactical noise and mystery compared to paste() and sprintf().
glue("
  A formatted string
  Can have multiple lines
    with additional indention preserved
  "
)
## A formatted string
## Can have multiple lines
##   with additional indention preserved
  • You can break the texts into individual pieces if you want (e.g. to limit the length of lines in your source code to, e.g., 80 characters), and the results do not change.
glue("The first version of the glue package was released on a {format(release_date, '%A')}.")
## The first version of the glue package was released on a Tuesday.
glue("The first version of the glue package was released on ",
     "a {format(release_date, '%A')}.")
## The first version of the glue package was released on a Tuesday.

Delimiters

  • By default, code to be evaluated goes inside {} in a glue string. If want a literal curly brace in your string, double it:
glue("The name of the package is {name}, not {{name}}.")
## The name of the package is glue, not {name}.
  • If you don’t want to use {}? No problem! You can customize the delimiters using .open and .close.
glue("The name of the package is [name], not {name}.",
     .open = "[", .close = "]")
## The name of the package is glue, not {name}.

Where glue looks for values

  • By default, glue() evaluates in the global environment.
x <- "the caller environment"
glue("By default, `glue()` evaluates code in {x}.")
## By default, `glue()` evaluates code in the caller environment.
  • But you can provide more narrowly scoped values by passing them in name = value form:
x <- "the local environment"
glue(
  "`glue()` can access values from {x} or from {y}. {z}",
  y = "named arguments",
  z = "Woo!"
)
## `glue()` can access values from the local environment or from named arguments. Woo!
  • If the relevant data lives in a data frame (or list or environment), use glue_data() instead:
mini_mtcars <- head(cbind(model = rownames(mtcars), mtcars))
rownames(mini_mtcars) <- NULL
glue_data(mini_mtcars, "{model} has {hp} hp.")
## Mazda RX4 has 110 hp.
## Mazda RX4 Wag has 110 hp.
## Datsun 710 has 93 hp.
## Hornet 4 Drive has 110 hp.
## Hornet Sportabout has 175 hp.
## Valiant has 105 hp.
mini_mtcars |>
  glue_data("{model} gets {mpg} miles per gallon.")
## Mazda RX4 gets 21 miles per gallon.
## Mazda RX4 Wag gets 21 miles per gallon.
## Datsun 710 gets 22.8 miles per gallon.
## Hornet 4 Drive gets 21.4 miles per gallon.
## Hornet Sportabout gets 18.7 miles per gallon.
## Valiant gets 18.1 miles per gallon.
  • Returning to glue(), recall that it defaults to evaluation in the caller environment. This has happy implications inside a dplyr::mutate() pipeline. The data-masking feature of mutate() means the columns of the target data frame are “in scope” for a glue() call:
library(dplyr)

mini_mtcars |>
  mutate(note = glue("{model} gets {mpg} miles per gallon.")) |>
  select(note, cyl, disp)
##                                            note cyl disp
## 1           Mazda RX4 gets 21 miles per gallon.   6  160
## 2       Mazda RX4 Wag gets 21 miles per gallon.   6  160
## 3        Datsun 710 gets 22.8 miles per gallon.   4  108
## 4    Hornet 4 Drive gets 21.4 miles per gallon.   6  258
## 5 Hornet Sportabout gets 18.7 miles per gallon.   8  360
## 6           Valiant gets 18.1 miles per gallon.   6  225

Why glue

paste("file_", 1:5, ".csv", sep = "")
## [1] "file_1.csv" "file_2.csv" "file_3.csv" "file_4.csv" "file_5.csv"
  • Or paste0(), where you don’t no need to write sep = "" all the time
paste0("file_", 1:5, ".csv")
## [1] "file_1.csv" "file_2.csv" "file_3.csv" "file_4.csv" "file_5.csv"
sprintf("file_%s.csv", 1:5)
## [1] "file_1.csv" "file_2.csv" "file_3.csv" "file_4.csv" "file_5.csv"
  • glue beats them all:
glue("file_{1:5}.csv")
## file_1.csv
## file_2.csv
## file_3.csv
## file_4.csv
## file_5.csv
glue("Pi is {round(pi, 1:4)}")
## Pi is 3.1
## Pi is 3.14
## Pi is 3.142
## Pi is 3.1416
glue("I got {41:45} in AST-{201:205}")
## I got 41 in AST-201
## I got 42 in AST-202
## I got 43 in AST-203
## I got 44 in AST-204
## I got 45 in AST-205

Summary:

Two main functions: glue() and glue_data() does almost all the jobs