diff --git a/NAMESPACE b/NAMESPACE index 46884560e..431656761 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -82,6 +82,7 @@ export(uses_testthat) export(wd) export(with_debug) import(fs) +import(rlang) importFrom(cli,cat_bullet) importFrom(cli,cat_rule) importFrom(ellipsis,check_dots_used) diff --git a/R/active.R b/R/active.R index 51e1e4b20..af5edb665 100644 --- a/R/active.R +++ b/R/active.R @@ -1,9 +1,6 @@ find_active_file <- function(arg = "file", call = parent.frame()) { if (!is_rstudio_running()) { - cli::cli_abort( - "Argument {.arg {arg}} is missing, with no default", - call = call - ) + cli::cli_abort("{.arg {arg}} is absent but must be supplied.", call = call) } normalizePath(rstudioapi::getSourceEditorContext()$path) } diff --git a/R/build-readme.R b/R/build-readme.R index ddd1da7d2..ac9e218e4 100644 --- a/R/build-readme.R +++ b/R/build-readme.R @@ -18,11 +18,11 @@ build_rmd <- function( ..., quiet = TRUE ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) pkg <- as.package(path) - rlang::check_installed("rmarkdown") + check_installed("rmarkdown") save_all() paths <- files diff --git a/R/build-site.R b/R/build-site.R index 9935963c3..8fb2d7067 100644 --- a/R/build-site.R +++ b/R/build-site.R @@ -10,13 +10,13 @@ #' @return NULL #' @export build_site <- function(path = ".", quiet = TRUE, ...) { - rlang::check_installed("pkgdown") + check_installed("pkgdown") save_all() pkg <- as.package(path) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) withr::with_temp_libpaths(action = "prefix", code = { install(pkg = pkg$path, upgrade = "never", reload = FALSE, quiet = quiet) diff --git a/R/check-mac.R b/R/check-mac.R index ebfd616ca..4b3ab098d 100644 --- a/R/check-mac.R +++ b/R/check-mac.R @@ -19,7 +19,7 @@ check_mac_release <- function( quiet = FALSE, ... ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) check_mac( pkg = pkg, @@ -42,7 +42,7 @@ check_mac_devel <- function( quiet = FALSE, ... ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) check_mac( pkg = pkg, @@ -100,7 +100,7 @@ check_mac <- function( url <- "https://mac.r-project.org/macbuilder/v1/submit" - rlang::check_installed("httr") + check_installed("httr") body <- list( pkgfile = httr::upload_file(built_path), rflavor = tolower(version) diff --git a/R/check-win.R b/R/check-win.R index 87e6b5853..d3a999950 100644 --- a/R/check-win.R +++ b/R/check-win.R @@ -28,7 +28,7 @@ check_win_devel <- function( quiet = FALSE, ... ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) check_win( pkg = pkg, @@ -51,7 +51,7 @@ check_win_release <- function( quiet = FALSE, ... ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) check_win( pkg = pkg, @@ -74,7 +74,7 @@ check_win_oldrelease <- function( quiet = FALSE, ... ) { - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) check_win( pkg = pkg, @@ -184,7 +184,7 @@ change_maintainer_email <- function(path, email, call = parent.frame()) { } upload_ftp <- function(file, url, verbose = FALSE) { - rlang::check_installed("curl") + check_installed("curl") stopifnot(file_exists(file)) stopifnot(is.character(url)) diff --git a/R/check.R b/R/check.R index e1617759e..bcab40bb0 100644 --- a/R/check.R +++ b/R/check.R @@ -98,7 +98,7 @@ check <- function( show_env_vars(pkgbuild::compiler_flags(FALSE)) } - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) if (identical(vignettes, FALSE)) { args <- union(args, "--ignore-vignettes") diff --git a/R/devtools-package.R b/R/devtools-package.R index 510dbf097..9cd484d81 100644 --- a/R/devtools-package.R +++ b/R/devtools-package.R @@ -11,6 +11,7 @@ ## usethis namespace: start #' @importFrom lifecycle deprecated +#' @import rlang ## usethis namespace: end NULL diff --git a/R/import-standalone-obj-type.R b/R/import-standalone-obj-type.R new file mode 100644 index 000000000..f83964194 --- /dev/null +++ b/R/import-standalone-obj-type.R @@ -0,0 +1,370 @@ +# Standalone file: do not edit by hand +# Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-obj-type.R +# Generated by: usethis::use_standalone("r-lib/rlang", "obj-type") +# ---------------------------------------------------------------------- +# +# --- +# repo: r-lib/rlang +# file: standalone-obj-type.R +# last-updated: 2025-10-02 +# license: https://unlicense.org +# imports: rlang (>= 1.1.0) +# --- +# +# ## Changelog +# +# 2025-10-02: +# - `obj_type_friendly()` now shows the dimensionality of arrays. +# +# 2024-02-14: +# - `obj_type_friendly()` now works for S7 objects. +# +# 2023-05-01: +# - `obj_type_friendly()` now only displays the first class of S3 objects. +# +# 2023-03-30: +# - `stop_input_type()` now handles `I()` input literally in `arg`. +# +# 2022-10-04: +# - `obj_type_friendly(value = TRUE)` now shows numeric scalars +# literally. +# - `stop_friendly_type()` now takes `show_value`, passed to +# `obj_type_friendly()` as the `value` argument. +# +# 2022-10-03: +# - Added `allow_na` and `allow_null` arguments. +# - `NULL` is now backticked. +# - Better friendly type for infinities and `NaN`. +# +# 2022-09-16: +# - Unprefixed usage of rlang functions with `rlang::` to +# avoid onLoad issues when called from rlang (#1482). +# +# 2022-08-11: +# - Prefixed usage of rlang functions with `rlang::`. +# +# 2022-06-22: +# - `friendly_type_of()` is now `obj_type_friendly()`. +# - Added `obj_type_oo()`. +# +# 2021-12-20: +# - Added support for scalar values and empty vectors. +# - Added `stop_input_type()` +# +# 2021-06-30: +# - Added support for missing arguments. +# +# 2021-04-19: +# - Added support for matrices and arrays (#141). +# - Added documentation. +# - Added changelog. +# +# nocov start + +#' Return English-friendly type +#' @param x Any R object. +#' @param value Whether to describe the value of `x`. Special values +#' like `NA` or `""` are always described. +#' @param length Whether to mention the length of vectors and lists. +#' @return A string describing the type. Starts with an indefinite +#' article, e.g. "an integer vector". +#' @noRd +obj_type_friendly <- function(x, value = TRUE) { + if (is_missing(x)) { + return("absent") + } + + if (is.object(x)) { + if (inherits(x, "quosure")) { + type <- "quosure" + } else { + type <- class(x)[[1L]] + } + return(sprintf("a <%s> object", type)) + } + + if (!is_vector(x)) { + return(.rlang_as_friendly_type(typeof(x))) + } + + n_dim <- length(dim(x)) + + if (!n_dim) { + if (!is_list(x) && length(x) == 1) { + if (is_na(x)) { + return(switch( + typeof(x), + logical = "`NA`", + integer = "an integer `NA`", + double = if (is.nan(x)) { + "`NaN`" + } else { + "a numeric `NA`" + }, + complex = "a complex `NA`", + character = "a character `NA`", + .rlang_stop_unexpected_typeof(x) + )) + } + + show_infinites <- function(x) { + if (x > 0) { + "`Inf`" + } else { + "`-Inf`" + } + } + str_encode <- function(x, width = 30, ...) { + if (nchar(x) > width) { + x <- substr(x, 1, width - 3) + x <- paste0(x, "...") + } + encodeString(x, ...) + } + + if (value) { + if (is.numeric(x) && is.infinite(x)) { + return(show_infinites(x)) + } + + if (is.numeric(x) || is.complex(x)) { + number <- as.character(round(x, 2)) + what <- if (is.complex(x)) "the complex number" else "the number" + return(paste(what, number)) + } + + return(switch( + typeof(x), + logical = if (x) "`TRUE`" else "`FALSE`", + character = { + what <- if (nzchar(x)) "the string" else "the empty string" + paste(what, str_encode(x, quote = "\"")) + }, + raw = paste("the raw value", as.character(x)), + .rlang_stop_unexpected_typeof(x) + )) + } + + return(switch( + typeof(x), + logical = "a logical value", + integer = "an integer", + double = if (is.infinite(x)) show_infinites(x) else "a number", + complex = "a complex number", + character = if (nzchar(x)) "a string" else "\"\"", + raw = "a raw value", + .rlang_stop_unexpected_typeof(x) + )) + } + + if (length(x) == 0) { + return(switch( + typeof(x), + logical = "an empty logical vector", + integer = "an empty integer vector", + double = "an empty numeric vector", + complex = "an empty complex vector", + character = "an empty character vector", + raw = "an empty raw vector", + list = "an empty list", + .rlang_stop_unexpected_typeof(x) + )) + } + } + + vec_type_friendly(x) +} + +vec_type_friendly <- function(x, length = FALSE) { + if (!is_vector(x)) { + abort("`x` must be a vector.") + } + type <- typeof(x) + n_dim <- length(dim(x)) + + add_length <- function(type) { + if (length && !n_dim) { + paste0(type, sprintf(" of length %s", length(x))) + } else { + type + } + } + + if (type == "list") { + if (n_dim == 0) { + return(add_length("a list")) + } else if (n_dim == 2) { + if (is.data.frame(x)) { + return("a data frame") + } else { + return("a list matrix") + } + } else { + return(sprintf("a list %sD array", n_dim)) + } + } + + type <- switch( + type, + logical = "a logical %s", + integer = "an integer %s", + numeric = , + double = "a double %s", + complex = "a complex %s", + character = "a character %s", + raw = "a raw %s", + type = paste0("a ", type, " %s") + ) + + if (n_dim == 0) { + kind <- "vector" + } else if (n_dim == 2) { + kind <- "matrix" + } else { + kind <- sprintf("%sD array", n_dim) + } + out <- sprintf(type, kind) + + if (n_dim >= 2) { + out + } else { + add_length(out) + } +} + +.rlang_as_friendly_type <- function(type) { + switch( + type, + + list = "a list", + + NULL = "`NULL`", + environment = "an environment", + externalptr = "a pointer", + weakref = "a weak reference", + S4 = "an S4 object", + + name = , + symbol = "a symbol", + language = "a call", + pairlist = "a pairlist node", + expression = "an expression vector", + + char = "an internal string", + promise = "an internal promise", + ... = "an internal dots object", + any = "an internal `any` object", + bytecode = "an internal bytecode object", + + primitive = , + builtin = , + special = "a primitive function", + closure = "a function", + + type + ) +} + +.rlang_stop_unexpected_typeof <- function(x, call = caller_env()) { + abort( + sprintf("Unexpected type <%s>.", typeof(x)), + call = call + ) +} + +#' Return OO type +#' @param x Any R object. +#' @return One of `"bare"` (for non-OO objects), `"S3"`, `"S4"`, +#' `"R6"`, or `"S7"`. +#' @noRd +obj_type_oo <- function(x) { + if (!is.object(x)) { + return("bare") + } + + class <- inherits(x, c("R6", "S7_object"), which = TRUE) + + if (class[[1]]) { + "R6" + } else if (class[[2]]) { + "S7" + } else if (isS4(x)) { + "S4" + } else { + "S3" + } +} + +#' @param x The object type which does not conform to `what`. Its +#' `obj_type_friendly()` is taken and mentioned in the error message. +#' @param what The friendly expected type as a string. Can be a +#' character vector of expected types, in which case the error +#' message mentions all of them in an "or" enumeration. +#' @param show_value Passed to `value` argument of `obj_type_friendly()`. +#' @param ... Arguments passed to [abort()]. +#' @inheritParams args_error_context +#' @noRd +stop_input_type <- function( + x, + what, + ..., + allow_na = FALSE, + allow_null = FALSE, + show_value = TRUE, + arg = caller_arg(x), + call = caller_env() +) { + # From standalone-cli.R + cli <- env_get_list( + nms = c("format_arg", "format_code"), + last = topenv(), + default = function(x) sprintf("`%s`", x), + inherit = TRUE + ) + + if (allow_na) { + what <- c(what, cli$format_code("NA")) + } + if (allow_null) { + what <- c(what, cli$format_code("NULL")) + } + if (length(what)) { + what <- oxford_comma(what) + } + if (inherits(arg, "AsIs")) { + format_arg <- identity + } else { + format_arg <- cli$format_arg + } + + message <- sprintf( + "%s must be %s, not %s.", + format_arg(arg), + what, + obj_type_friendly(x, value = show_value) + ) + + abort(message, ..., call = call, arg = arg) +} + +oxford_comma <- function(chr, sep = ", ", final = "or") { + n <- length(chr) + + if (n < 2) { + return(chr) + } + + head <- chr[seq_len(n - 1)] + last <- chr[n] + + head <- paste(head, collapse = sep) + + # Write a or b. But a, b, or c. + if (n > 2) { + paste0(head, sep, final, " ", last) + } else { + paste0(head, " ", final, " ", last) + } +} + +# nocov end diff --git a/R/import-standalone-types-check.R b/R/import-standalone-types-check.R new file mode 100644 index 000000000..82668e6cd --- /dev/null +++ b/R/import-standalone-types-check.R @@ -0,0 +1,607 @@ +# Standalone file: do not edit by hand +# Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-types-check.R +# Generated by: usethis::use_standalone("r-lib/rlang", "types-check") +# ---------------------------------------------------------------------- +# +# --- +# repo: r-lib/rlang +# file: standalone-types-check.R +# last-updated: 2023-03-13 +# license: https://unlicense.org +# dependencies: standalone-obj-type.R +# imports: rlang (>= 1.1.0) +# --- +# +# ## Changelog +# +# 2025-09-19: +# - `check_logical()` gains an `allow_na` argument (@jonthegeek, #1724) +# +# 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). +# - Added `check_data_frame()` (@mgirlich). +# +# 2023-03-07: +# - Added dependency on rlang (>= 1.1.0). +# +# 2023-02-15: +# - Added `check_logical()`. +# +# - `check_bool()`, `check_number_whole()`, and +# `check_number_decimal()` are now implemented in C. +# +# - For efficiency, `check_number_whole()` and +# `check_number_decimal()` now take a `NULL` default for `min` and +# `max`. This makes it possible to bypass unnecessary type-checking +# and comparisons in the default case of no bounds checks. +# +# 2022-10-07: +# - `check_number_whole()` and `_decimal()` no longer treat +# non-numeric types such as factors or dates as numbers. Numeric +# types are detected with `is.numeric()`. +# +# 2022-10-04: +# - Added `check_name()` that forbids the empty string. +# `check_string()` allows the empty string by default. +# +# 2022-09-28: +# - Removed `what` arguments. +# - Added `allow_na` and `allow_null` arguments. +# - Added `allow_decimal` and `allow_infinite` arguments. +# - Improved errors with absent arguments. +# +# +# 2022-09-16: +# - Unprefixed usage of rlang functions with `rlang::` to +# avoid onLoad issues when called from rlang (#1482). +# +# 2022-08-11: +# - Added changelog. +# +# nocov start + +# Scalars ----------------------------------------------------------------- + +.standalone_types_check_dot_call <- .Call + +check_bool <- function( + x, + ..., + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if ( + !missing(x) && + .standalone_types_check_dot_call( + ffi_standalone_is_bool_1.0.7, + x, + allow_na, + allow_null + ) + ) { + return(invisible(NULL)) + } + + stop_input_type( + x, + c("`TRUE`", "`FALSE`"), + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_string <- function( + x, + ..., + allow_empty = TRUE, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + is_string <- .rlang_check_is_string( + x, + allow_empty = allow_empty, + allow_na = allow_na, + allow_null = allow_null + ) + if (is_string) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a single string", + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +.rlang_check_is_string <- function(x, allow_empty, allow_na, allow_null) { + if (is_string(x)) { + if (allow_empty || !is_string(x, "")) { + return(TRUE) + } + } + + if (allow_null && is_null(x)) { + return(TRUE) + } + + if (allow_na && (identical(x, NA) || identical(x, na_chr))) { + return(TRUE) + } + + FALSE +} + +check_name <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + is_string <- .rlang_check_is_string( + x, + allow_empty = FALSE, + allow_na = FALSE, + allow_null = allow_null + ) + if (is_string) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a valid name", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +IS_NUMBER_true <- 0 +IS_NUMBER_false <- 1 +IS_NUMBER_oob <- 2 + +check_number_decimal <- function( + x, + ..., + min = NULL, + max = NULL, + allow_infinite = TRUE, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (missing(x)) { + exit_code <- IS_NUMBER_false + } else if ( + 0 == + (exit_code <- .standalone_types_check_dot_call( + ffi_standalone_check_number_1.0.7, + x, + allow_decimal = TRUE, + min, + max, + allow_infinite, + allow_na, + allow_null + )) + ) { + return(invisible(NULL)) + } + + .stop_not_number( + x, + ..., + exit_code = exit_code, + allow_decimal = TRUE, + min = min, + max = max, + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_number_whole <- function( + x, + ..., + min = NULL, + max = NULL, + allow_infinite = FALSE, + allow_na = FALSE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (missing(x)) { + exit_code <- IS_NUMBER_false + } else if ( + 0 == + (exit_code <- .standalone_types_check_dot_call( + ffi_standalone_check_number_1.0.7, + x, + allow_decimal = FALSE, + min, + max, + allow_infinite, + allow_na, + allow_null + )) + ) { + return(invisible(NULL)) + } + + .stop_not_number( + x, + ..., + exit_code = exit_code, + allow_decimal = FALSE, + min = min, + max = max, + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +.stop_not_number <- function( + x, + ..., + exit_code, + allow_decimal, + min, + max, + allow_na, + allow_null, + arg, + call +) { + if (allow_decimal) { + what <- "a number" + } else { + what <- "a whole number" + } + + if (exit_code == IS_NUMBER_oob) { + min <- min %||% -Inf + max <- max %||% Inf + + if (min > -Inf && max < Inf) { + what <- sprintf("%s between %s and %s", what, min, max) + } else if (x < min) { + what <- sprintf("%s larger than or equal to %s", what, min) + } else if (x > max) { + what <- sprintf("%s smaller than or equal to %s", what, max) + } else { + abort("Unexpected state in OOB check", .internal = TRUE) + } + } + + stop_input_type( + x, + what, + ..., + allow_na = allow_na, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_symbol <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_symbol(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a symbol", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_arg <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_symbol(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an argument name", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_call <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_call(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a defused call", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_environment <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_environment(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an environment", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_function <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_function(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a function", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_closure <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_closure(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "an R function", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_formula <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_formula(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a formula", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + + +# 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)) + } + } + + stop_input_type( + x, + "a character vector", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_logical <- function( + x, + ..., + allow_na = TRUE, + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is_logical(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)) + } + } + + stop_input_type( + x, + "a logical vector", + ..., + allow_na = FALSE, + allow_null = allow_null, + arg = arg, + call = call + ) +} + +check_data_frame <- function( + x, + ..., + allow_null = FALSE, + arg = caller_arg(x), + call = caller_env() +) { + if (!missing(x)) { + if (is.data.frame(x)) { + return(invisible(NULL)) + } + if (allow_null && is_null(x)) { + return(invisible(NULL)) + } + } + + stop_input_type( + x, + "a data frame", + ..., + allow_null = allow_null, + arg = arg, + call = call + ) +} + +# nocov end diff --git a/R/install.R b/R/install.R index b56402cbb..35d6faf9d 100644 --- a/R/install.R +++ b/R/install.R @@ -91,7 +91,7 @@ install <- } opts <- c(opts, args) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) remotes::install_deps( pkg$path, @@ -169,7 +169,7 @@ install_deps <- function( ) { pkg <- as.package(pkg) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) remotes::install_deps( pkg$path, @@ -201,7 +201,7 @@ install_dev_deps <- function( pkg <- as.package(pkg) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) remotes::install_deps( pkg$path, diff --git a/R/lint.R b/R/lint.R index 10f9b1ac5..4df26a9d0 100644 --- a/R/lint.R +++ b/R/lint.R @@ -12,12 +12,12 @@ #' @seealso [lintr::lint_package()], [lintr::lint()] #' @export lint <- function(pkg = ".", cache = TRUE, ...) { - rlang::check_installed("lintr") + check_installed("lintr") pkg <- as.package(pkg) cli::cli_inform(c(i = "Linting {.pkg {pkg$package}}")) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) lintr::lint_package(pkg$path, cache = cache, ...) } diff --git a/R/package.R b/R/package.R index c632b064a..be9a0f318 100644 --- a/R/package.R +++ b/R/package.R @@ -36,9 +36,7 @@ as.package <- function(x = NULL, create = deprecated()) { #' package_file("figures", "figure_1") #' } package_file <- function(..., path = ".") { - if (!is.character(path) || length(path) != 1) { - cli::cli_abort("{.arg path} must be a string.") - } + check_string(path) if (!dir_exists(path)) { cli::cli_abort("{.path {path}} is not a directory.") } diff --git a/R/pkgbuild.R b/R/pkgbuild.R index 7b9c75811..ff9b5b9d7 100644 --- a/R/pkgbuild.R +++ b/R/pkgbuild.R @@ -23,7 +23,7 @@ build <- function( cli::cli_abort("{.arg pkg} must exist") } - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) pkgbuild::build( path = pkg, diff --git a/R/pkgload.R b/R/pkgload.R index ac6b960e2..3688a1d03 100644 --- a/R/pkgload.R +++ b/R/pkgload.R @@ -23,7 +23,7 @@ load_all <- function( save_all() - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) pkgload::load_all( path = path, diff --git a/R/release.R b/R/release.R index 65c6c8c11..cb79c44d4 100644 --- a/R/release.R +++ b/R/release.R @@ -297,7 +297,7 @@ upload_cran <- function(pkg, built_path, call = parent.frame()) { # Initial upload --------- cli::cli_inform(c(i = "Uploading package & comments")) - rlang::check_installed("httr") + check_installed("httr") body <- list( pkg_id = "", name = maint$name, diff --git a/R/remotes.R b/R/remotes.R index 8d7cf7689..0e9093fc2 100644 --- a/R/remotes.R +++ b/R/remotes.R @@ -4,12 +4,12 @@ with_ellipsis <- function(fun) { f <- function(...) { ellipsis::check_dots_used( - action = getOption("devtools.ellipsis_action", rlang::warn) + action = getOption("devtools.ellipsis_action", warn) ) !!b } - f <- rlang::expr_interp(f) + f <- expr_interp(f) body(fun) <- body(f) fun diff --git a/R/run-source.R b/R/run-source.R index 262a79804..ffcc6e4d0 100644 --- a/R/run-source.R +++ b/R/run-source.R @@ -29,9 +29,9 @@ #' sha1 = "54f1db27e60") #' } source_url <- function(url, ..., sha1 = NULL) { - stopifnot(is.character(url), length(url) == 1) - rlang::check_installed("digest") - rlang::check_installed("httr") + check_string(url) + check_installed("digest") + check_installed("httr") temp_file <- file_temp() on.exit(file_delete(temp_file), add = TRUE) @@ -42,7 +42,7 @@ source_url <- function(url, ..., sha1 = NULL) { check_sha1(temp_file, sha1) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) source(temp_file, ...) } @@ -111,7 +111,7 @@ check_sha1 <- function(path, sha1) { #' source_gist(6872663, filename = "hi.r", sha1 = "54f1db27e60") #' } source_gist <- function(id, ..., filename = NULL, sha1 = NULL, quiet = FALSE) { - rlang::check_installed("gh") + check_installed("gh") stopifnot(length(id) == 1) url_match <- "((^https://)|^)gist.github.com/([^/]+/)?([0-9a-f]+)$" @@ -131,7 +131,7 @@ source_gist <- function(id, ..., filename = NULL, sha1 = NULL, quiet = FALSE) { cli::cli_inform(c(i = "Sourcing gist {.str {id}}")) } - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) source_url(url, ..., sha1 = sha1) } diff --git a/R/show-news.R b/R/show-news.R index 15cbc6411..8a488f009 100644 --- a/R/show-news.R +++ b/R/show-news.R @@ -23,7 +23,7 @@ show_news <- function(pkg = ".", latest = TRUE, ...) { } ) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) out <- utils::news(..., db = news_db) if (latest) { diff --git a/R/spell-check.R b/R/spell-check.R index 55cda5062..96a5b5025 100644 --- a/R/spell-check.R +++ b/R/spell-check.R @@ -10,7 +10,7 @@ #' @param vignettes also check all `rmd` and `rnw` files in the pkg `vignettes` folder #' @param use_wordlist ignore words in the package [WORDLIST][spelling::get_wordlist] file spell_check <- function(pkg = ".", vignettes = TRUE, use_wordlist = TRUE) { - rlang::check_installed("spelling") + check_installed("spelling") pkg <- as.package(pkg) spelling::spell_check_package( pkg = pkg, diff --git a/R/test.R b/R/test.R index 575a6ea40..95da249a4 100644 --- a/R/test.R +++ b/R/test.R @@ -97,13 +97,13 @@ load_package_for_testing <- function(pkg) { #' @export #' @rdname test test_coverage <- function(pkg = ".", show_report = interactive(), ...) { - rlang::check_installed(c("covr", "DT")) + check_installed(c("covr", "DT")) save_all() pkg <- as.package(pkg) cli::cli_inform(c(i = "Computing test coverage for {.pkg {pkg$package}}")) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) withr::local_envvar(r_env_vars()) coverage <- covr::package_coverage(pkg$path, ...) @@ -135,8 +135,8 @@ test_coverage_active_file <- function( export_all = TRUE, ... ) { - rlang::check_installed(c("covr", "DT")) - check_dots_used(action = getOption("devtools.ellipsis_action", rlang::warn)) + check_installed(c("covr", "DT")) + check_dots_used(action = getOption("devtools.ellipsis_action", warn)) test_file <- find_test_file(file) test_dir <- path_dir(test_file) diff --git a/R/vignettes.R b/R/vignettes.R index ec878eabb..4eea96a53 100644 --- a/R/vignettes.R +++ b/R/vignettes.R @@ -128,7 +128,7 @@ clean_vignettes <- function(pkg = ".") { } dir_delete_if_empty <- function(x) { - if (dir_exists(x) && rlang::is_empty(dir_ls(x))) { + if (dir_exists(x) && is_empty(dir_ls(x))) { dir_delete(x) cli::cli_inform(c(x = "Removing {.file {path_file(x)}}")) } diff --git a/R/zzz.R b/R/zzz.R index d0d2b9e92..98d3c6cdc 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -16,7 +16,7 @@ NULL devtools_default_options <- list( devtools.path = "~/R-dev", devtools.install.args = "", - devtools.ellipsis_action = rlang::warn + devtools.ellipsis_action = warn ) .onLoad <- function(libname, pkgname) { diff --git a/tests/testthat/_snaps/active.md b/tests/testthat/_snaps/active.md index 20afa4bbc..ec6b503e1 100644 --- a/tests/testthat/_snaps/active.md +++ b/tests/testthat/_snaps/active.md @@ -4,7 +4,7 @@ find_active_file() Condition Error: - ! Argument `file` is missing, with no default + ! `file` is absent but must be supplied. # fails if can't find tests diff --git a/tests/testthat/_snaps/package.md b/tests/testthat/_snaps/package.md index d38799b26..a1748b71a 100644 --- a/tests/testthat/_snaps/package.md +++ b/tests/testthat/_snaps/package.md @@ -4,7 +4,7 @@ package_file(path = 1) Condition Error in `package_file()`: - ! `path` must be a string. + ! `path` must be a single string, not the number 1. Code package_file(path = "doesntexist") Condition diff --git a/tests/testthat/test-build-manual.R b/tests/testthat/test-build-manual.R index 75b64e7ae..f9357d8e7 100644 --- a/tests/testthat/test-build-manual.R +++ b/tests/testthat/test-build-manual.R @@ -7,7 +7,7 @@ test_that("build_manual() shows stderr on failure", { # Too hard to replicate actual error, so we just simulate local_mocked_bindings(rd2pdf = function(...) { stderr <- "! LaTeX Error: File `inconsolata.sty' not found." - rlang::abort("System command 'R' failed", stderr = stderr) #nolint + abort("System command 'R' failed", stderr = stderr) #nolint }) expect_snapshot(build_manual(pkg), error = TRUE, transform = function(x) {