glue 1.2.0

  tidyverse, glue

  Jim Hester

glue 1.2.0 is now available on CRAN! glue is designed to make it easy to interpolate (“glue”) your data into strings. Compared to equivalents like paste() and sprintf() it is easier to write and less time consuming to maintain. It also has no non-base dependencies so is easy to include in packages.

Install the latest version with:

install.packages("glue")

glue has three primary functions, glue(), glue_data() and collapse(). glue() works in a similar way to double quotes " in a shell or python’s String Interpolation. You surround the code you want evaluated by {} and the value of the expression is inserted into the string.

name <- "Fred"
age <- 50
anniversary <- as.Date("1991-10-12")
glue('
  My name is {name}
  my age next year is {age + 1}
  my anniversary is {format(anniversary, "%A, %B %d, %Y")}
')
#>   My name is Fred
#>   my age next year is 51
#>   my anniversary is Saturday, October 12, 1991

glue is also vectorized over its inputs.

glue('
  {month.abb} is short for {month.name}
')
#>   Jan is short for January
#>   Feb is short for February
#>   Mar is short for March
#>   Apr is short for April
#>   May is short for May
#>   Jun is short for June
#>   Jul is short for July
#>   Aug is short for August
#>   Sep is short for September
#>   Oct is short for October
#>   Nov is short for November
#>   Dec is short for December

glue_data() works like glue(), but instead of looking up its variables from the calling environment it looks them up from the first argument (usually a data frame or tibble). This makes glue_data() very useful within pipe chains.

library(magrittr)
mtcars$model <- rownames(mtcars)
mtcars %>%
  head %>%
  glue_data("The {model} has {gear} gears, {cyl} cylinders, and {hp} horsepower.")
#> The Mazda RX4 has 4 gears, 6 cylinders, and 110 horsepower.
#> The Mazda RX4 Wag has 4 gears, 6 cylinders, and 110 horsepower.
#> The Datsun 710 has 4 gears, 4 cylinders, and 93 horsepower.
#> The Hornet 4 Drive has 3 gears, 6 cylinders, and 110 horsepower.
#> The Hornet Sportabout has 3 gears, 8 cylinders, and 175 horsepower.
#> The Valiant has 3 gears, 6 cylinders, and 105 horsepower.

collapse() is used to combine multiple values into one. The last argument is used to change the separator for the last value.

collapse(1:5, ", ", last = ", and ")
#> 1, 2, 3, 4, and 5

glue transformers

New to glue 1.2.0 are transformer functions, which allow you to define custom behavior for glue functions. For example a collapse_transformer() which automatically collapses any blocks which end with *.

collapse_transformer <- function(regex = "[*]$", ...) {
  function(code, envir) {
    if (grepl(regex, code)) {
        code <- sub(regex, "", code)
    }
    res <- evaluate(code, envir)
    collapse(res, ...)
  }
}

glue("
  {1:5*}
  {letters[1:5]*}",
  .transformer = collapse_transformer(sep = ", ", last = ", and "))
#> 1, 2, 3, 4, and 5
#> a, b, c, d, and e

Or an sprintf transformer which lets you use sprintf style numeric formatting with glue.

sprintf_transformer <- function(code, envir) {
  m <- regexpr("%.+$", code)
  if (m != -1) {
    format <- regmatches(code, m)
    regmatches(code, m) <- ""
    res <- evaluate(code, envir)
    do.call(sprintf, list(format, res))
  } else {
    evaluate(code, envir)
  }
}

glue_fmt <- function(..., .envir = parent.frame()) {
  glue(..., .transformer = sprintf_transformer, .envir = .envir)
}
glue_fmt("π = {pi%.5f}")
#> π = 3.14159

glue_sql()

Also new to glue 1.2.0 is glue_sql() and glue_sql_data(), which are helper functions defined with glue transformers to make it easy and safe to construct SQL statements.

Using glue_sql() values are automatically quoted appropriately and variables can be quoted with backticks.

con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
colnames(iris) <- gsub("[.]", "_", tolower(colnames(iris)))
DBI::dbWriteTable(con, "iris", iris)
var <- "sepal_width"
tbl <- "iris"
num <- 2
val <- "setosa"
glue_sql("
  SELECT {`var`}
  FROM {`tbl`}
  WHERE {`tbl`}.sepal_length > {num}
    AND {`tbl`}.species = {val}
  ", .con = con)
#> <SQL> SELECT `sepal_width`
#> FROM `iris`
#> WHERE `iris`.sepal_length > 2
#>   AND `iris`.species = 'setosa'

Other changes

There are many other bug fixes and other minor improvements. You can see a complete list in the release notes.

A big thanks goes to all the community members who contributed code and opened issues since the last release! (@artemklevtsov, @daroczig, @DarwinAwardWinner, @edarague, @hadley, @hughjonesd, @jennybc, @jimhester, @jjchern, @klmr, @krlmlr, @lionel-, @mgirlich, @mmuurr, @npjc, @pssguy, and @robinsones)