Skip to content

Commit

Permalink
Merge commit '887fb750e05ced7c745b30bbca0480e9d510810a'
Browse files Browse the repository at this point in the history
#Conflicts:
#	NEWS.md
  • Loading branch information
hadley committed Nov 22, 2023
2 parents 90aac8b + 887fb75 commit 4abcc2a
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 48 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Suggests:
rlang,
rmarkdown,
RSQLite,
testthat (>= 3.0.0),
testthat (>= 3.2.0),
vctrs (>= 0.3.0),
waldo (>= 0.3.0),
withr
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
* If rlang is installed, glue will generate more informative errors if an
interpolated expression either can't be parsed or fails to evaluate (#229).

* `+` now works in more situations, and gives errors when one side isn't a
character vector. It no longer automatically applies glue interpolation to
a non-glue input, if there is one. You'll need to do that yourself (#286).

* `glue_collapse(character())` (and hence `glue_sql_collapse(character())`) now
return `""`, so that they always return a single string (#88).

Expand Down
18 changes: 14 additions & 4 deletions R/glue.R
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ glue_data <- function(.x, ..., .sep = "", .envir = parent.frame(),
.open = "{", .close = "}", .na = "NA", .null = character(),
.comment = "#", .literal = FALSE, .transformer = identity_transformer, .trim = TRUE) {

if (is.null(.envir)) {
.envir <- emptyenv()
}
.envir <- .envir %||% emptyenv()
stopifnot(is.environment(.envir))

# Perform all evaluations in a temporary environment
if (is.null(.x)) {
Expand Down Expand Up @@ -355,7 +354,18 @@ as.character.glue <- function(x, ...) {

#' @export
`+.glue` <- function(e1, e2) {
glue(e1, e2, .envir = parent.frame())
if (!is.null(e1) && !is.character(e1)) {
stop("LHS must be a character vector.")
}
if (!is.null(e2) && !is.character(e2)) {
stop("RHS must be a character vector.")
}

glue_data(
"{e1}{e2}",
.x = list(e1 = e1, e2 = e2),
.envir = parent.frame()
)
}

#' @importFrom methods setOldClass
Expand Down
2 changes: 1 addition & 1 deletion README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ glue('My name is {name},',
head(mtcars) %>% glue_data("{rownames(.)} has {hp} hp")
```

##### Or within dplyr pipelines
##### `glue()` is useful within dplyr pipelines
```{r, message = FALSE}
library(dplyr)
head(iris) %>%
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<!-- badges: start -->

[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/glue)](https://cran.r-project.org/package=glue)
[![R-CMD-check](https://github.com/tidyverse/glue/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/glue/actions/workflows/R-CMD-check.yaml)
[![R-CMD-check](https://github.com/tidyverse/glue/actions/workflows/.github/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/glue/actions/workflows/.github/workflows/R-CMD-check.yaml)
[![test-coverage](https://github.com/tidyverse/glue/actions/workflows/test-coverage.yaml/badge.svg)](https://github.com/tidyverse/glue/actions/workflows/test-coverage.yaml)
<!-- badges: end -->

Expand Down Expand Up @@ -100,7 +100,7 @@ head(mtcars) %>% glue_data("{rownames(.)} has {hp} hp")
#> Valiant has 105 hp
```

##### Or within dplyr pipelines
##### `glue()` is useful within dplyr pipelines

``` r
library(dplyr)
Expand Down Expand Up @@ -284,17 +284,17 @@ glue("x + y") + " = {x + y}"
Some other implementations of string interpolation in R (although not
using identical syntax).

- [stringr::str_interp](https://stringr.tidyverse.org/reference/str_interp.html)
- [R.utils::gstring](https://cran.r-project.org/package=R.utils)
- [rprintf](https://cran.r-project.org/package=rprintf)
- [stringr::str_interp](https://stringr.tidyverse.org/reference/str_interp.html)
- [R.utils::gstring](https://cran.r-project.org/package=R.utils)
- [rprintf](https://cran.r-project.org/package=rprintf)

String templating is closely related to string interpolation, although
not exactly the same concept. Some packages implementing string
templating in R include.

- [whisker](https://cran.r-project.org/package=whisker)
- [brew](https://cran.r-project.org/package=brew)
- [jinjar](https://cran.r-project.org/package=jinjar)
- [whisker](https://cran.r-project.org/package=whisker)
- [brew](https://cran.r-project.org/package=brew)
- [jinjar](https://cran.r-project.org/package=jinjar)

## Code of Conduct

Expand Down
35 changes: 21 additions & 14 deletions tests/testthat/_snaps/color.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,57 @@

Code
glue_col("{%}")
Error <simpleError>
<text>:1:1: unexpected input
Condition
Error in `parse()`:
! <text>:1:1: unexpected input
1: %
^

---

Code
glue_col("{foo %}")
Error <simpleError>
object 'foo' of mode 'function' was not found
Condition
Error in `get()`:
! object 'foo' of mode 'function' was not found

---

Code
glue_col("{foo %}")
Error <simpleError>
object 'foo' of mode 'function' was not found
Condition
Error in `get()`:
! object 'foo' of mode 'function' was not found

# glue_col() can exploit the `.literal` argument

Code
glue_col("Colorless {green idea's} sleep furiously")
Error <simpleError>
Unterminated quote (')
Condition
Error in `glue_data()`:
! Unterminated quote (')

---

Code
glue_col("Colorless {green idea\"s} sleep furiously")
Error <simpleError>
Unterminated quote (")
Condition
Error in `glue_data()`:
! Unterminated quote (")

---

Code
glue_col("Colorless {green idea`s} sleep furiously")
Error <simpleError>
Unterminated quote (`)
Condition
Error in `glue_data()`:
! Unterminated quote (`)

---

Code
glue_col("Hey a URL: {blue https://example.com/#section}")
Error <simpleError>
A '#' comment in a glue expression must terminate with a newline.
Condition
Error in `glue_data()`:
! A '#' comment in a glue expression must terminate with a newline.

36 changes: 30 additions & 6 deletions tests/testthat/_snaps/glue.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
# `+` method requires character vectors

Code
as_glue("a") + 1
Condition
Error in `+.glue`:
! RHS must be a character vector.
Code
1 + as_glue("a")
Condition
Error in `+.glue`:
! LHS must be a character vector.

# `+` method errors for inputs of incompatible size

Code
as_glue(letters[1:2]) + letters[1:3]
Condition
Error:
! Variables must be length 1 or 3

# unterminated comment

Code
glue("pre {1 + 5 # comment} post")
Error <simpleError>
A '#' comment in a glue expression must terminate with a newline.
Condition
Error in `glue_data()`:
! A '#' comment in a glue expression must terminate with a newline.

---

Code
glue("pre {1 + 5 # comment")
Error <simpleError>
A '#' comment in a glue expression must terminate with a newline.
Condition
Error in `glue_data()`:
! A '#' comment in a glue expression must terminate with a newline.

# `.literal` treats quotes and `#` as regular characters

Code
glue("{'fo`o\"#}", .transformer = function(x, ...) x)
Error <simpleError>
Unterminated quote (')
Condition
Error in `glue_data()`:
! Unterminated quote (')

10 changes: 6 additions & 4 deletions tests/testthat/_snaps/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

Code
glue_sql("{x + }")
Error <rlang_error>
Failed to parse glue component
Condition
Error:
! Failed to parse glue component
Caused by error in `parse()`:
! <text>:2:0: unexpected end of input
1: x +
^
Code
glue_sql("{NOTFOUND}")
Error <rlang_error>
Failed to evaluate glue component {NOTFOUND}
Condition
Error:
! Failed to evaluate glue component {NOTFOUND}
Caused by error:
! object 'NOTFOUND' not found

12 changes: 7 additions & 5 deletions tests/testthat/_snaps/transformer.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

Code
identity_transformer("x + ")
Error <rlang_error>
Failed to parse glue component
Condition
Error:
! Failed to parse glue component
Caused by error in `parse()`:
! <text>:2:0: unexpected end of input
1: x +
^
Code
identity_transformer("NOTFOUND")
Error <rlang_error>
Failed to evaluate glue component {NOTFOUND}
Caused by error:
Condition
Error:
! Failed to evaluate glue component {NOTFOUND}
Caused by error in `identity_transformer()`:
! argument "envir" is missing, with no default

40 changes: 35 additions & 5 deletions tests/testthat/test-glue.R
Original file line number Diff line number Diff line change
Expand Up @@ -502,16 +502,46 @@ test_that("throws informative error if interpolating a function", {
expect_error(glue("{cat}"), "is a function")

# some crayon functions are OK, make sure this still works
if (require("crayon")) {
if (require("crayon", quietly = TRUE)) {
expect_s3_class(glue("{red}red{reset}"), "glue")
}
})

test_that("+ method for glue works", {
expect_identical(glue("foo") + "bar", as_glue("foobar"))
test_that("`+` method for glue works", {
expect_identical(glue("foo") + "bar", "foobar")
expect_identical("foo" + glue("bar"), "foobar")
})

x <- 1
expect_identical(glue("x = ") + "{x}", glue("x = {x}"))
test_that("`+` method requires character vectors", {
expect_snapshot(error = TRUE, {
as_glue("a") + 1
1 + as_glue("a")
})
})

test_that("`+` method does not interpolate twice", {
expect_identical(glue("{x}", x = "{wut}") + "y", "{wut}y")
})

test_that("`+` method returns length-0 if there is a length-0 input", {
expect_identical(as_glue("hello") + character(), character())
})

test_that("`+` method returns length-0 if there is a `NULL` input", {
expect_identical(as_glue("hello") + NULL, character())
})

test_that("`+` recycles", {
x <- c("a", "b", "c")
expect_identical("(" + as_glue(x) + ")", paste0("(", x, ")"))
y <- as.character(1:3)
expect_identical(as_glue(x) + y, c("a1", "b2", "c3"))
})

test_that("`+` method errors for inputs of incompatible size", {
expect_snapshot(error = TRUE, {
as_glue(letters[1:2]) + letters[1:3]
})
})

test_that("unterminated quotes are error", {
Expand Down

0 comments on commit 4abcc2a

Please sign in to comment.