From efe3cf57b49d0036333c34fe859dfc9cc455943f Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Tue, 6 Aug 2024 09:21:45 +0200 Subject: [PATCH 1/5] Ignore all clangd configuration folders --- .Rbuildignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.Rbuildignore b/.Rbuildignore index 3e00efe2b..151797da8 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -23,3 +23,4 @@ ^\.cache$ ^\.vscode$ ^compile_commands\.json$ +.*\.clangd$ From 16699b234f24445da79b6a9774fb5b0ed4dc9c32 Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Tue, 6 Aug 2024 09:31:24 +0200 Subject: [PATCH 2/5] Remove pkgload `::` hotpatch --- R/rlang-package.R | 3 --- 1 file changed, 3 deletions(-) diff --git a/R/rlang-package.R b/R/rlang-package.R index 3902dc95d..05f506847 100644 --- a/R/rlang-package.R +++ b/R/rlang-package.R @@ -18,6 +18,3 @@ compiled_by_gcc <- function() { #' @rawNamespace export(ffi_standalone_is_bool_1.0.7) #' @rawNamespace export(ffi_standalone_check_number_1.0.7) NULL - -# Enable pkgload to hotpatch `::` in detached namespaces -on_load(`::` <- base::`::`) From c8e06b929040278b92a387530d0b58e316411b53 Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Tue, 6 Aug 2024 09:32:51 +0200 Subject: [PATCH 3/5] Redocument --- man/cnd_inherits.Rd | 8 ++------ man/friendly_type.Rd | 3 ++- man/glue-operators.Rd | 10 ---------- man/missing_arg.Rd | 8 ++------ man/qq_show.Rd | 2 -- man/splice-operator.Rd | 4 ---- man/topic-data-mask-ambiguity.Rd | 2 -- man/topic-data-mask-programming.Rd | 8 -------- man/topic-data-mask.Rd | 6 ------ man/topic-defuse.Rd | 4 ---- man/topic-error-call.Rd | 4 ++-- man/topic-inject-out-of-context.Rd | 12 ------------ man/topic-inject.Rd | 2 -- man/topic-metaprogramming.Rd | 6 ------ man/topic-multiple-columns.Rd | 2 -- 15 files changed, 8 insertions(+), 73 deletions(-) diff --git a/man/cnd_inherits.Rd b/man/cnd_inherits.Rd index e01cecd19..83757452f 100644 --- a/man/cnd_inherits.Rd +++ b/man/cnd_inherits.Rd @@ -60,9 +60,7 @@ cnd <- callCC(function(throw) \{ class(cnd) #> [1] "rlang_error" "error" "condition" -}\if{html}{\out{}} - -\if{html}{\out{
}}\preformatted{class(cnd$parent) +class(cnd$parent) #> [1] "bar" "rlang_error" "error" "condition" }\if{html}{\out{
}} } @@ -81,9 +79,7 @@ away. Instead, it captures it only if the handler doesn't return a class(cnd) #> [1] "rlang_error" "error" "condition" -}\if{html}{\out{}} - -\if{html}{\out{
}}\preformatted{class(cnd$parent) +class(cnd$parent) #> [1] "bar" "rlang_error" "error" "condition" }\if{html}{\out{
}} diff --git a/man/friendly_type.Rd b/man/friendly_type.Rd index f053da8e5..4e726b837 100644 --- a/man/friendly_type.Rd +++ b/man/friendly_type.Rd @@ -17,6 +17,7 @@ indefinite article. \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} \code{friendly_type()} is deprecated. Please use the -\code{standalone-friendly-type.R} file instead. +\code{standalone-obj-type.R} file instead. You can import it +in your package with \code{usethis::use_standalone("r-lib/rlang", "obj-type")}. } \keyword{internal} diff --git a/man/glue-operators.Rd b/man/glue-operators.Rd index 6aaddeb68..1e9ed4831 100644 --- a/man/glue-operators.Rd +++ b/man/glue-operators.Rd @@ -11,9 +11,7 @@ #> foo #> #> 1 1 -}\if{html}{\out{}} -\if{html}{\out{
}}\preformatted{ foo <- "name" tibble::tibble("\{foo\}" := 1) #> # A tibble: 1 x 1 @@ -61,9 +59,7 @@ mtcars \%>\% my_mean(cyl) #> cyl #> #> 1 6.19 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_mean(cyl * am) #> # A tibble: 1 x 1 #> `cyl * am` @@ -82,9 +78,7 @@ mtcars \%>\% my_mean(cyl) #> mean #> #> 1 6.19 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_mean(cyl, name = "cyl") #> # A tibble: 1 x 1 #> cyl @@ -99,9 +93,7 @@ Using the wrong operator causes unexpected results: list2("\{\{ x \}\}" := 1) #> $`"name"` #> [1] 1 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ list2("\{x\}" := 1) #> $name #> [1] 1 @@ -128,9 +120,7 @@ Now the user may supply their own name if needed: #> `cyl * am` #> #> 1 2.06 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_mean(cyl * am, name = "mean_cyl_am") #> # A tibble: 1 x 1 #> mean_cyl_am diff --git a/man/missing_arg.Rd b/man/missing_arg.Rd index 47d0b2a75..64c6bdad7 100644 --- a/man/missing_arg.Rd +++ b/man/missing_arg.Rd @@ -54,9 +54,7 @@ missing argument: fn() #> [1] TRUE -}\if{html}{\out{
}} - -\if{html}{\out{
}}\preformatted{fn(1) +fn(1) #> [1] FALSE }\if{html}{\out{
}} @@ -75,9 +73,7 @@ default arguments as missing, even in internal contexts: fn() #> [1] FALSE -}\if{html}{\out{}} - -\if{html}{\out{
}}\preformatted{fn(1) +fn(1) #> [1] FALSE }\if{html}{\out{
}} diff --git a/man/qq_show.Rd b/man/qq_show.Rd index 913de347d..753b9edaf 100644 --- a/man/qq_show.Rd +++ b/man/qq_show.Rd @@ -26,9 +26,7 @@ evaluated by R: #> #> [[3]] #> [1] 3 -}\if{html}{\out{}} -\if{html}{\out{
}}\preformatted{ qq_show(list2(!!!1:3)) #> list2(1L, 2L, 3L) }\if{html}{\out{
}} diff --git a/man/splice-operator.Rd b/man/splice-operator.Rd index 4116a4949..a815a8a4b 100644 --- a/man/splice-operator.Rd +++ b/man/splice-operator.Rd @@ -85,9 +85,7 @@ explicitly enable \verb{!!!}. However, many functions implement \link[=list2]{dy #> 2 1 b #> 3 2 a #> 4 2 b -}\if{html}{\out{}} -\if{html}{\out{
}}\preformatted{ xs <- list(x = 1:2, y = c("a", "b")) tidyr::expand_grid(!!!xs) #> # A tibble: 4 x 2 @@ -177,9 +175,7 @@ box. \if{html}{\out{
}}\preformatted{n_args(1, 2) #> [1] 2 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ n_args(!!!mtcars) #> [1] 11 }\if{html}{\out{
}} diff --git a/man/topic-data-mask-ambiguity.Rd b/man/topic-data-mask-ambiguity.Rd index f9d8ec867..8b0350b94 100644 --- a/man/topic-data-mask-ambiguity.Rd +++ b/man/topic-data-mask-ambiguity.Rd @@ -72,9 +72,7 @@ This is especially useful in functions because the data frame is not known in ad data.frame(value = 1) \%>\% my_rescale(value) #> value #> 1 0.1 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ # Oh no! data.frame(factor = 0, value = 1) \%>\% my_rescale(value) #> factor value diff --git a/man/topic-data-mask-programming.Rd b/man/topic-data-mask-programming.Rd index c74b06994..12eb7c1a3 100644 --- a/man/topic-data-mask-programming.Rd +++ b/man/topic-data-mask-programming.Rd @@ -154,9 +154,7 @@ for (var in vars) print(dplyr::summarise(mtcars, mean = mean(.data[[var]]))) #> mean #> #> 1 0.406 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ purrr::map(vars, ~ dplyr::summarise(mtcars, mean = mean(.data[[.x]]))) #> [[1]] #> # A tibble: 1 x 1 @@ -193,9 +191,7 @@ my_mean(mtcars, am) #> mean #> #> 1 6.19 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ # Programmable my_mean(mtcars, tolower("CYL")) #> # A tibble: 1 x 1 @@ -331,17 +327,13 @@ mtcars \%>\% my_mean(cyl, carb) #> cyl carb #> #> 1 6.19 2.81 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_mean(foo = cyl, bar = carb) #> # A tibble: 1 x 2 #> foo bar #> #> 1 6.19 2.81 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_mean(starts_with("c"), mpg:disp) #> # A tibble: 1 x 4 #> cyl carb mpg disp diff --git a/man/topic-data-mask.Rd b/man/topic-data-mask.Rd index 7ce9bab44..2266224d1 100644 --- a/man/topic-data-mask.Rd +++ b/man/topic-data-mask.Rd @@ -9,16 +9,12 @@ Data-masking is a distinctive feature of R whereby programming is performed dire \if{html}{\out{
}}\preformatted{# Unmasked programming mean(mtcars$cyl + mtcars$am) #> [1] 6.59375 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ # Referring to columns is an error - Where is the data? mean(cyl + am) #> Error: #> ! object 'cyl' not found -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ # Data-masking with(mtcars, mean(cyl + am)) #> [1] 6.59375 @@ -118,9 +114,7 @@ Data-masking relies on three language features: \if{html}{\out{
}}\preformatted{expr(1 + 1) #> 1 + 1 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ eval(expr(1 + 1)) #> [1] 2 }\if{html}{\out{
}} diff --git a/man/topic-defuse.Rd b/man/topic-defuse.Rd index c71061bca..c84cf7c2c 100644 --- a/man/topic-defuse.Rd +++ b/man/topic-defuse.Rd @@ -13,9 +13,7 @@ Using \code{\link[=expr]{expr()}} we can observe the difference between computin \if{html}{\out{
}}\preformatted{# Return the result of `1 + 1` 1 + 1 #> [1] 2 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ # Return the expression `1 + 1` expr(1 + 1) #> 1 + 1 @@ -72,9 +70,7 @@ force <- function(arg) arg ignore(warning("boom")) #> NULL -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ force(warning("boom")) #> Warning in force(warning("boom")): boom }\if{html}{\out{
}} diff --git a/man/topic-error-call.Rd b/man/topic-error-call.Rd index 7d1b1ea8b..0d849357d 100644 --- a/man/topic-error-call.Rd +++ b/man/topic-error-call.Rd @@ -54,7 +54,7 @@ In both cases, the default error call is not very helpful to the end user becaus #> ! Unimplemented }\if{html}{\out{
}} -To fix this, let \code{abort()} knows about the function that it is throwing the error for by passing the corresponding function environment as \code{call} argument: +To fix this, let \code{abort()} know about the function that it is throwing the error for by passing the corresponding function environment as the \code{call} argument: \if{html}{\out{
}}\preformatted{stop_my_class <- function(message, call = caller_env()) \{ abort(message, class = "my_class", call = call) @@ -143,7 +143,7 @@ their_function() #> Run rlang::last_trace(drop = FALSE) to see 1 hidden frame. }\if{html}{\out{
}} -With the correct \code{call}, the backtrace is much simpler and let the user focus on the part of the stack that is relevant to them: +With the correct \code{call}, the backtrace is much simpler and lets the user focus on the part of the stack that is relevant to them: \if{html}{\out{
}}\preformatted{use_call <- TRUE their_function() diff --git a/man/topic-inject-out-of-context.Rd b/man/topic-inject-out-of-context.Rd index cff1625fe..a3bd83f1c 100644 --- a/man/topic-inject-out-of-context.Rd +++ b/man/topic-inject-out-of-context.Rd @@ -16,9 +16,7 @@ In the R language, \verb{\{} is like \code{(} but takes multiple expressions ins 2 \} #> [1] 2 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ list( \{ message("foo"); 2 \} ) @@ -31,9 +29,7 @@ Just like you can wrap an expression in as many parentheses as you'd like, you c \if{html}{\out{
}}\preformatted{((1)) #> [1] 1 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ \{\{ 2 \}\} #> [1] 2 }\if{html}{\out{
}} @@ -70,9 +66,7 @@ Double negation can be used in ordinary code to convert an input to logical: \if{html}{\out{
}}\preformatted{!!10 #> [1] TRUE -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ !!0 #> [1] FALSE }\if{html}{\out{
}} @@ -81,9 +75,7 @@ Triple negation is essentially the same as simple negation: \if{html}{\out{
}}\preformatted{!10 #> [1] FALSE -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ !!!10 #> [1] FALSE }\if{html}{\out{
}} @@ -93,15 +85,11 @@ This means that when injection operators are used in the wrong place, they will \if{html}{\out{
}}\preformatted{!"foo" #> Error in `!"foo"`: #> ! invalid argument type -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ !quote(foo) #> Error in `!quote(foo)`: #> ! invalid argument type -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ !quote(foo()) #> Error in `!quote(foo())`: #> ! invalid argument type diff --git a/man/topic-inject.Rd b/man/topic-inject.Rd index 11d23e766..40b790b99 100644 --- a/man/topic-inject.Rd +++ b/man/topic-inject.Rd @@ -70,9 +70,7 @@ rbind2("\{name\}" := 1:2, bar = 3:4) #> [,1] [,2] #> foo 1 2 #> bar 3 4 -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ rbind2("prefix_\{name\}" := 1:2, bar = 3:4) #> [,1] [,2] #> prefix_foo 1 2 diff --git a/man/topic-metaprogramming.Rd b/man/topic-metaprogramming.Rd index 74cea274d..a73a23934 100644 --- a/man/topic-metaprogramming.Rd +++ b/man/topic-metaprogramming.Rd @@ -47,9 +47,7 @@ For instance, here is how to create an automatic name for a defused argument usi f(cyl) #> [1] "cyl" -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ f(1 + 1) #> [1] "1 + 1" }\if{html}{\out{
}} @@ -96,9 +94,7 @@ Symbolise a single string with \code{\link[=sym]{sym()}} or \code{\link[=data_sy sym(var) #> cyl -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ data_sym(var) #> .data$cyl }\if{html}{\out{
}} @@ -113,9 +109,7 @@ syms(vars) #> #> [[2]] #> am -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ data_syms(vars) #> [[1]] #> .data$cyl diff --git a/man/topic-multiple-columns.Rd b/man/topic-multiple-columns.Rd index 62963c43a..f3c2cb6c6 100644 --- a/man/topic-multiple-columns.Rd +++ b/man/topic-multiple-columns.Rd @@ -117,9 +117,7 @@ This does work in simple cases: \if{html}{\out{
}}\preformatted{mtcars \%>\% my_group_by(cyl) \%>\% dplyr::group_vars() #> [1] "cyl" -}\if{html}{\out{
}} -\if{html}{\out{
}}\preformatted{ mtcars \%>\% my_group_by(list(cyl, am)) \%>\% dplyr::group_vars() #> [1] "cyl" "am" }\if{html}{\out{
}} From d2829e2f4db49f347945672da793021877598e42 Mon Sep 17 00:00:00 2001 From: Mike Du <58779940+ilovemane@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:51:06 +0100 Subject: [PATCH 4/5] `is_dictionaryish(NULL)` now returns true (#1741) --- NEWS.md | 2 ++ R/attr.R | 7 ++++++- tests/testthat/test-attr.R | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index d9e0aabae..af45d9517 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,8 @@ * `env_unlock()` is now defunct because recent versions of R no long make it possible to unlock an environment (#1705). Make sure to use an up-to-date version of pkgload (>= 1.4.0) following this change. + +* `is_dictionaryish()` now will return TRUE for NULL (@ilovemane, #1712). # rlang 1.1.4 diff --git a/R/attr.R b/R/attr.R index 04e3bf10d..f3b42290e 100644 --- a/R/attr.R +++ b/R/attr.R @@ -20,7 +20,7 @@ #' a logical vector as long as the input. #' #' @details -#' `is_named()` always returns `TRUE` for empty vectors because +#' `is_named()` always returns `TRUE` for empty vectors because #' #' @examples #' # is_named() is a scalar predicate about the whole vector of names: @@ -110,6 +110,10 @@ detect_void_name <- function(x) { is_dictionaryish <- function(x) { # 2022-01: Used in many packages. Don't deprecate without a # replacement. + if (is.null(x)) { + return(TRUE) + } + if (!length(x)) { return(!is.null(x)) } @@ -118,6 +122,7 @@ is_dictionaryish <- function(x) { } + #' Does an object have an element with this name? #' #' This function returns a logical value that indicates if a data diff --git a/tests/testthat/test-attr.R b/tests/testthat/test-attr.R index 79e00b755..cd5496e31 100644 --- a/tests/testthat/test-attr.R +++ b/tests/testthat/test-attr.R @@ -186,3 +186,8 @@ test_that("zap_srcref() works on calls", { expect_null(attributes(zap_srcref(call))) expect_true("srcref" %in% names(attributes(call))) }) + +test_that("is_dictionaryish return true if is NULL", { + + expect_true(is_dictionaryish(NULL)) +}) From 69659c49cc2b58bc68755693deaa2f271efadbc6 Mon Sep 17 00:00:00 2001 From: Marta Alcalde-Herraiz <91142894+martaalcalde@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:13:09 -0700 Subject: [PATCH 5/5] Add `allow_na` argument to `check_character()` (#1742) --- R/standalone-types-check.R | 17 ++++++++++++++++- tests/testthat/_snaps/standalone-types-check.md | 6 ++++++ tests/testthat/test-standalone-types-check.R | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/R/standalone-types-check.R b/R/standalone-types-check.R index 90a889f1b..22ea57ba8 100644 --- a/R/standalone-types-check.R +++ b/R/standalone-types-check.R @@ -9,6 +9,9 @@ # # ## Changelog # +# 2024-08-15: +# - `check_character()` gains an `allow_na` argument (@martaalcalde, #1724) +# # 2023-03-13: # - Improved error messages of number checkers (@teunbrand) # - Added `allow_infinite` argument to `check_number_whole()` (@mgirlich). @@ -457,15 +460,28 @@ check_formula <- function(x, # Vectors ----------------------------------------------------------------- +# TODO: Figure out what to do with logical `NA` and `allow_na = TRUE` + check_character <- function(x, ..., + allow_na = TRUE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { + if (!missing(x)) { if (is_character(x)) { + if (!allow_na && any(is.na(x))) { + abort( + sprintf("`%s` can't contain NA values.", arg), + arg = arg, + call = call + ) + } + return(invisible(NULL)) } + if (allow_null && is_null(x)) { return(invisible(NULL)) } @@ -475,7 +491,6 @@ check_character <- function(x, x, "a character vector", ..., - allow_na = FALSE, allow_null = allow_null, arg = arg, call = call diff --git a/tests/testthat/_snaps/standalone-types-check.md b/tests/testthat/_snaps/standalone-types-check.md index 16af3ed25..a54db03a6 100644 --- a/tests/testthat/_snaps/standalone-types-check.md +++ b/tests/testthat/_snaps/standalone-types-check.md @@ -450,6 +450,12 @@ Error in `checker()`: ! `foo` must be a character vector or `NULL`, not a list. + Code + err(checker(c("a", NA), check_character, allow_na = FALSE)) + Output + + Error in `checker()`: + ! `foo` can't contain NA values. # `check_logical()` checks diff --git a/tests/testthat/test-standalone-types-check.R b/tests/testthat/test-standalone-types-check.R index ce0a3dc0a..a8a6e177c 100644 --- a/tests/testthat/test-standalone-types-check.R +++ b/tests/testthat/test-standalone-types-check.R @@ -153,6 +153,7 @@ test_that("`check_environment()` checks", { test_that("`check_character()` checks", { expect_null(check_character("")) expect_null(check_character(na_chr)) + expect_null(check_character(c("a", NA))) expect_null(check_character(chr())) expect_null(check_character("foo")) expect_null(check_character(letters)) @@ -164,6 +165,7 @@ test_that("`check_character()` checks", { err(checker(NA, check_character)) err(checker(1, check_character)) err(checker(list("foo", "bar"), check_character, allow_null = TRUE)) + err(checker(c("a", NA), check_character, allow_na = FALSE)) }) })