Skip to content

Commit

Permalink
Merge branch 'main' into strict-addition
Browse files Browse the repository at this point in the history
  • Loading branch information
jennybc committed Sep 21, 2023
2 parents c478961 + e2b74ff commit 6d2cc1b
Show file tree
Hide file tree
Showing 26 changed files with 1,705 additions and 252 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
^MAINTENANCE\.md$
^internal$
^CRAN-SUBMISSION$
^vignettes/articles$
21 changes: 11 additions & 10 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,36 @@ Description: An implementation of interpreted string literals, inspired by
String Literals
<https://docs.julialang.org/en/v1.3/manual/strings/#Triple-Quoted-String-Literals-1>.
License: MIT + file LICENSE
URL: https://github.com/tidyverse/glue, https://glue.tidyverse.org/
URL: https://glue.tidyverse.org/, https://github.com/tidyverse/glue
BugReports: https://github.com/tidyverse/glue/issues
Depends:
R (>= 3.4)
Imports:
methods
Suggests:
covr,
crayon,
DBI,
DBI (>= 1.1.3),
dplyr,
forcats,
ggplot2,
knitr,
magrittr,
microbenchmark,
R.utils,
rmarkdown,
rprintf,
RSQLite,
stringr,
testthat (>= 3.0.0),
vctrs (>= 0.3.0),
waldo (>= 0.3.0),
withr
VignetteBuilder:
knitr
ByteCompile: true
Config/Needs/website: tidyverse/tidytemplate
Config/Needs/website:
bench,
forcats,
ggbeeswarm,
ggplot2,
R.utils,
rprintf,
tidyr,
tidyverse/tidytemplate
Config/testthat/edition: 3
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
Expand Down
10 changes: 10 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
character vector. It no longer automatically applies glue interpolation to
both sides; you'll need to do that yourself as needed (#286).

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

* `glue_sql()` now collapses an empty vector to `""` not `"NULL"` (#272).

* `glue_sql()` now uses `DBI::dbQuoteLiteral()` for all object types. This
should increase fidelity of escaping for different object types (#279).

* The "Speed of glue" vignette has been converted to an article, which allows several package to be removed from `Suggests` (and re-located to `Config/Needs/website`). The code got a light refresh, including a switch from microbenchmark to bench and more modern use of ggplot2.

* Add `$(C_VISIBILITY)` to compiler flags to hide internal symbols from the dll (#284 @lionel-).

# glue 1.6.2
Expand Down
1 change: 1 addition & 0 deletions R/color.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#' character, specify `.literal = TRUE`.
#'
#' @inheritParams glue
#' @inherit glue return
#' @export
#' @examplesIf require(crayon)
#' library(crayon)
Expand Down
27 changes: 22 additions & 5 deletions R/glue.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#' @param ... \[`expressions`]\cr Unnamed arguments are taken to be expression
#' string(s) to format. Multiple inputs are concatenated together before formatting.
#' Named arguments are taken to be temporary variables available for substitution.
#'
#' For `glue_data()`, elements in `...` override the values in `.x`.
#' @param .sep \[`character(1)`: \sQuote{""}]\cr Separator used to separate elements.
#' @param .envir \[`environment`: `parent.frame()`]\cr Environment to evaluate each expression in. Expressions are
#' evaluated from left to right. If `.x` is an environment, the expressions are
Expand Down Expand Up @@ -38,6 +40,7 @@
#' template with [trim()] or not.
#' @seealso <https://www.python.org/dev/peps/pep-0498/> and
#' <https://www.python.org/dev/peps/pep-0257/> upon which this is based.
#' @returns A glue object, as created by [as_glue()].
#' @examples
#' name <- "Fred"
#' age <- 50
Expand Down Expand Up @@ -87,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 @@ -216,18 +218,18 @@ glue <- function(..., .sep = "", .envir = parent.frame(), .open = "{", .close =
#' @param last String used to separate the last two items if `x` has at least
#' 2 items.
#' @inheritParams base::paste
#' @returns Always returns a length-1 glue object, as created by [as_glue()].
#' @examples
#' glue_collapse(glue("{1:10}"))
#'
#' # Wide values can be truncated
#' glue_collapse(glue("{1:10}"), width = 5)
#'
#' glue_collapse(1:4, ", ", last = " and ")
#' #> 1, 2, 3 and 4
#' @export
glue_collapse <- function(x, sep = "", width = Inf, last = "") {
if (length(x) == 0) {
return(as_glue(character()))
return(as_glue(""))
}
if (any(is.na(x))) {
return(as_glue(NA_character_))
Expand Down Expand Up @@ -258,6 +260,7 @@ glue_collapse <- function(x, sep = "", width = Inf, last = "") {
#' to the minimum indentation of all non-blank lines after the first.
#' - Lines can be continued across newlines by using `\\`.
#' @param x A character vector to trim.
#' @returns A character vector.
#' @export
#' @examples
#' glue("
Expand Down Expand Up @@ -297,9 +300,23 @@ print.glue <- function(x, ..., sep = "\n") {
}

#' Coerce object to glue
#'
#' A glue object is a character vector with S3 class `"glue"`. The `"glue"`
#' class implements a print method that shows the literal contents (rather than
#' the string implementation) and a `+` method, so that you can concatenate with
#' the addition operator.
#'
#' @param x object to be coerced.
#' @param ... further arguments passed to methods.
#' @returns A character vector with S3 class `"glue"`.
#' @export
#' @examples
#' x <- as_glue(c("abc", "\"\\\\", "\n"))
#' x
#'
#' x <- 1
#' y <- 3
#' glue("x + y") + " = {x + y}"
as_glue <- function(x, ...) {
UseMethod("as_glue")
}
Expand Down
4 changes: 3 additions & 1 deletion R/quoting.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#' Quoting operators
#'
#' These functions make it easy to quote each individual element and are useful
#' in conjunction with [glue_collapse()].
#' in conjunction with [glue_collapse()]. These are thin wrappers around
#' [base::encodeString()].
#' @param x A character to quote.
#' @name quoting
#' @inherit base::encodeString return
#' @export
#' @examples
#' x <- 1:5
Expand Down
1 change: 1 addition & 0 deletions R/safe.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#' with untrusted input, such as inputs in a Shiny application, where using the
#' normal functions would allow an attacker to execute arbitrary code.
#' @inheritParams glue
#' @inherit glue return
#' @export
#' @examples
#' "1 + 1" <- 5
Expand Down
89 changes: 65 additions & 24 deletions R/sql.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#' Interpolate strings with SQL escaping
#'
#' @description
#' SQL databases often have custom quotation syntax for identifiers and strings
#' which make writing SQL queries error prone and cumbersome to do. `glue_sql()` and
#' `glue_data_sql()` are analogs to [glue()] and [glue_data()] which handle the
Expand Down Expand Up @@ -134,14 +135,61 @@
#'
#' DBI::dbDisconnect(con)
#' @export
glue_sql <- function(..., .con, .envir = parent.frame(), .na = DBI::SQL("NULL")) {
DBI::SQL(glue(..., .envir = .envir, .na = .na, .transformer = sql_quote_transformer(.con, .na)))
glue_sql <- function(...,
.con,
.sep = "",
.envir = parent.frame(),
.open = "{",
.close = "}",
.na = DBI::SQL("NULL"),
.null = character(),
.comment = "#",
.literal = FALSE,
.trim = TRUE
) {
DBI::SQL(glue(
...,
.sep = .sep,
.envir = .envir,
.open = .open,
.close = .close,
.na = .na,
.null = .null,
.comment = .comment,
.literal = .literal,
.transformer = sql_quote_transformer(.con, .na),
.trim = .trim
))
}

#' @rdname glue_sql
#' @export
glue_data_sql <- function(.x, ..., .con, .envir = parent.frame(), .na = DBI::SQL("NULL")) {
DBI::SQL(glue_data(.x, ..., .envir = .envir, .na = .na, .transformer = sql_quote_transformer(.con, .na)))
glue_data_sql <- function(.x,
...,
.con,
.sep = "",
.envir = parent.frame(),
.open = "{",
.close = "}",
.na = DBI::SQL("NULL"),
.null = character(),
.comment = "#",
.literal = FALSE,
.trim = TRUE) {
DBI::SQL(glue_data(
.x,
...,
.sep = .sep,
.envir = .envir,
.open = .open,
.close = .close,
.na = .na,
.null = .null,
.comment = .comment,
.literal = .literal,
.transformer = sql_quote_transformer(.con, .na),
.trim = .trim
))
}

#' @rdname glue_collapse
Expand Down Expand Up @@ -175,37 +223,30 @@ sql_quote_transformer <- function(connection, .na) {
}
} else {
res <- eval(parse(text = text, keep.source = FALSE), envir)
if (length(res) == 0L) {
if (should_collapse) {
return("")
} else {
return(NULL)
}
}
if (inherits(res, "SQL")) {
if (should_collapse) {
res <- glue_collapse(res, ", ")
}
if (length(res) == 0L) {
res <- DBI::SQL("NULL")
}
return(res)
}
}

# convert objects to characters
is_object <- is.object(res)
if (is_object) {
res <- as.character(res)
}

is_na <- is.na(res)
if (any(is_na)) {
res[is_na] <- rep(list(.na), sum(is_na))
}

is_char <- vapply(res, function(x) !is.na(x) && is.character(x), logical(1))
res[is_char] <- lapply(res[is_char], function(x) DBI::dbQuoteLiteral(conn = connection, x))
res[!is_char] <- lapply(res[!is_char], function(x) DBI::SQL(conn = connection, x))
if (is.list(res)) {
res <- unlist(lapply(res, DBI::dbQuoteLiteral, conn = connection))
} else {
res <- DBI::dbQuoteLiteral(connection, res)
}

if (should_collapse) {
res <- glue_collapse(res, ", ")
}
if (length(res) == 0L) {
res <- DBI::SQL("NULL")
}
res
}
}
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
16 changes: 15 additions & 1 deletion man/as_glue.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion man/glue.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6d2cc1b

Please sign in to comment.