diff --git a/R/find_exports.R b/R/find_exports.R index c7afa20b..52a67684 100644 --- a/R/find_exports.R +++ b/R/find_exports.R @@ -20,7 +20,7 @@ find_extendr_attrs_ids <- function(lns) { } # Gets function/module metadata from a subset of lines. -# Finds first occurence of `fn` or `impl`. +# Finds first occurrence of `fn` or `impl`. extract_meta <- function(lns) { # Matches fn|impl<'a> item_name result <- stringi::stri_match_first_regex( diff --git a/R/import-standalone-obj-type.R b/R/import-standalone-obj-type.R index 20a88bda..422b4f79 100644 --- a/R/import-standalone-obj-type.R +++ b/R/import-standalone-obj-type.R @@ -58,7 +58,6 @@ #' @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 @@ -83,92 +82,109 @@ obj_type_friendly <- function(x, value = TRUE) { n_dim <- length(dim(x)) if (!n_dim) { - if (!rlang::is_list(x) && length(x) == 1) { - if (rlang::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) - )) + return(vec_or_scalar_type_friendly(x, value)) + } + vec_type_friendly(x) +} + +vec_or_scalar_type_friendly <- function(x, value) { + if (!rlang::is_list(x) && length(x) == 1) { + if (rlang::is_na(x)) { + return(.match_na_scalar(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) - )) + if (value) { + return(.make_description(x)) } + + return(.match_default_scalar(x)) } + if (length(x) == 0) { + return(.match_empty_object(x)) + } vec_type_friendly(x) } +.show_infinities <- 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, ...) +} + +.make_description <- function(x) { + if (is.numeric(x) && is.infinite(x)) { + return(.show_infinities(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)) + } + + 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) + ) +} + +.match_default_scalar <- function(x) { + switch(typeof(x), + logical = "a logical value", + integer = "an integer", + double = if (is.infinite(x)) .show_infinities(x) else "a number", + complex = "a complex number", + character = if (nzchar(x)) "a string" else "\"\"", + raw = "a raw value", + .rlang_stop_unexpected_typeof(x) + ) +} + +.match_na_scalar <- function(x) { + 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) + ) +} + +.match_empty_object <- function(x) { + 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 <- function(x, length = FALSE) { if (!rlang::is_vector(x)) { rlang::abort("`x` must be a vector.") @@ -176,37 +192,11 @@ vec_type_friendly <- function(x, length = FALSE) { 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 < 2) { - return(add_length("a list")) - } else if (is.data.frame(x)) { - return("a data frame") - } else if (n_dim == 2) { - return("a list matrix") - } else { - return("a list array") - } + return(.list_type_friendly(x, type, length, 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") - ) + type <- .get_message_pattern(type) if (n_dim < 2) { kind <- "vector" @@ -220,39 +210,65 @@ vec_type_friendly <- function(x, length = FALSE) { if (n_dim >= 2) { out } else { - add_length(out) + .with_length(x, out, length, n_dim) } } -.rlang_as_friendly_type <- function(type) { - switch( - type, +.list_type_friendly <- function(x, type, length, n_dim) { + if (n_dim < 2) { + return(.with_length(x, "a list", length, n_dim)) + } else if (is.data.frame(x)) { + return("a data frame") + } else if (n_dim == 2) { + return("a list matrix") + } else { + return("a list array") + } +} - list = "a list", +.with_length <- function(x, type, length, n_dim) { + if (length && !n_dim) { + paste0(type, sprintf(" of length %s", length(x))) + } else { + type + } +} +.get_message_pattern <- function(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") + ) +} + +.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 ) } @@ -296,16 +312,14 @@ obj_type_oo <- function(x) { #' @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 = rlang::caller_arg(x), - call = rlang::caller_env() -) { +stop_input_type <- function(x, + what, + ..., + allow_na = FALSE, + allow_null = FALSE, + show_value = TRUE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { # From standalone-cli.R cli <- rlang::env_get_list( nms = c("format_arg", "format_code"), diff --git a/R/import-standalone-types-check.R b/R/import-standalone-types-check.R index 6099af20..1d6ef280 100644 --- a/R/import-standalone-types-check.R +++ b/R/import-standalone-types-check.R @@ -59,7 +59,7 @@ # Scalars ----------------------------------------------------------------- -.standalone_types_check_dot_call <- .Call +.standalone_types_check_dot_call <- .Call # nolint: object_length_linter. check_bool <- function(x, ..., @@ -67,6 +67,7 @@ check_bool <- function(x, allow_null = FALSE, arg = rlang::caller_arg(x), call = rlang::caller_env()) { + if (!missing(x) && .standalone_types_check_dot_call(rlang::ffi_standalone_is_bool_1.0.7, x, allow_na, allow_null)) { return(invisible(NULL)) } @@ -126,12 +127,7 @@ check_string <- function(x, return(TRUE) } - if (allow_na && (identical(x, NA) || identical(x, rlang::na_chr)) - ) { - return(TRUE) - } - - FALSE + allow_na && (identical(x, NA) || identical(x, rlang::na_chr)) } check_name <- function(x, @@ -166,17 +162,15 @@ 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 = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_number_decimal <- function(x, + ..., + min = NULL, + max = NULL, + allow_infinite = TRUE, + allow_na = FALSE, + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (missing(x)) { exit_code <- IS_NUMBER_false } else if (0 == (exit_code <- .standalone_types_check_dot_call( @@ -311,13 +305,11 @@ check_symbol <- function(x, ) } -check_arg <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_arg <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (rlang::is_symbol(x)) { return(invisible(NULL)) @@ -338,13 +330,11 @@ check_arg <- function( ) } -check_call <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_call <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (rlang::is_call(x)) { return(invisible(NULL)) @@ -365,13 +355,11 @@ check_call <- function( ) } -check_environment <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_environment <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (rlang::is_environment(x)) { return(invisible(NULL)) @@ -392,13 +380,11 @@ check_environment <- function( ) } -check_function <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_function <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (rlang::is_function(x)) { return(invisible(NULL)) @@ -444,13 +430,11 @@ check_closure <- function(x, ) } -check_formula <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_formula <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (rlang::is_formula(x)) { return(invisible(NULL)) @@ -524,13 +508,11 @@ check_logical <- function(x, ) } -check_data_frame <- function( - x, - ..., - allow_null = FALSE, - arg = rlang::caller_arg(x), - call = rlang::caller_env() -) { +check_data_frame <- function(x, + ..., + allow_null = FALSE, + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { if (!missing(x)) { if (is.data.frame(x)) { return(invisible(NULL)) diff --git a/R/sanitize_code.R b/R/sanitize_code.R index 1fd8de82..368e1d87 100644 --- a/R/sanitize_code.R +++ b/R/sanitize_code.R @@ -14,10 +14,10 @@ remove_line_comments <- function(lns) { stringi::stri_replace_first_regex(lns, "//.*$", "") } -# Because R does not allow strightforward iteration over +# Because R does not allow straightforward iteration over # scalar strings, determining `/*` and `*/` positions can be challenging. # E.g., regex matches 3 `/*` and 3 `*/` in `/*/**/*/`. -# 1. We find all occurence of `/*` and `*/`. +# 1. We find all occurrence of `/*` and `*/`. # 2. We find non-overlapping `/*` and `*/`. # 3. We build pairs of open-close comment delimiters by collapsing nested # comments. @@ -66,7 +66,7 @@ fill_block_comments <- function(lns, fill_with = " ") { # nolint: object_usage_l while (i <= n) { if (comment_syms[["start"]][i] == comment_syms[["end"]][i - 1L]) { # If current overlaps with previous, exclude current and - # jump over the next one, which is inclded automatically. + # jump over the next one, which is included automatically. selects[i] <- FALSE i <- i + 1L } @@ -86,8 +86,8 @@ fill_block_comments <- function(lns, fill_with = " ") { # nolint: object_usage_l "Malformed comments.", "x" = "Number of start {.code /*} and end {.code */} \\ delimiters are not equal.", - "i" = "Found {n_open} occurence{?s} of {.code /*}.", - "i" = "Found {n_close} occurence{?s} of {.code */}." + "i" = "Found {n_open} occurrence{?s} of {.code /*}.", + "i" = "Found {n_close} occurrence{?s} of {.code */}." ), class = "rextendr_error" ) diff --git a/R/source.R b/R/source.R index 263b5fac..8ec5adb5 100644 --- a/R/source.R +++ b/R/source.R @@ -39,7 +39,7 @@ #' calls to [rust_source()]. #' @param quiet Logical indicating whether compile output should be generated or not. #' @param use_rtools Logical indicating whether to append the path to Rtools -#' to the `PATH` variable on Windows using the `RTOOLS40_HOME` environment +#' to the `PATH` variable on Windows using the `RTOOLS4X_HOME` environment #' variable (if it is set). The appended path depends on the process #' architecture. Does nothing on other platforms. #' @param use_dev_extendr Logical indicating whether to use development version of diff --git a/R/try_save_all.R b/R/try_save_all.R index 0041728a..220f653a 100644 --- a/R/try_save_all.R +++ b/R/try_save_all.R @@ -1,6 +1,6 @@ #' Try to save open files if \pkg{rextendr} is called from an IDE. #' -#' Uses rstudio API (if available) to save modfied files. +#' Uses rstudio API (if available) to save modified files. #' Improves package development experience within RStudio. #' @param quiet Logical scalar indicating whether the output should be quiet (`TRUE`) #' or verbose (`FALSE`). diff --git a/R/use_crate.R b/R/use_crate.R index 520fdb7b..cea33920 100644 --- a/R/use_crate.R +++ b/R/use_crate.R @@ -7,12 +7,12 @@ #' crate #' @param git character scalar, the full URL of the remote Git repository #' @param version character scalar, the version of the crate to add -#' @param optional boolean scalar, whether to mark the dependency as optional +#' @param optional boolean scalar, whether to mark the dependency as optional #' (FALSE by default) #' @param path character scalar, the package directory #' #' @details -#' For more details regarding these and other options, see the +#' For more details regarding these and other options, see the #' \href{https://doc.rust-lang.org/cargo/commands/cargo-add.html}{Cargo docs} #' for `cargo-add`. #' @@ -33,7 +33,7 @@ #' #' # add to [dependencies] with specific version #' use_crate("serde", version = "1.0.1") -#' +#' #' # add to [dependencies] with optional compilation #' use_crate("serde", optional = TRUE) #' } @@ -43,9 +43,7 @@ use_crate <- function( git = NULL, version = NULL, optional = FALSE, - path = "." -){ - + path = ".") { # check args check_string(crate) check_character(features, allow_null = TRUE) @@ -54,7 +52,9 @@ use_crate <- function( check_bool(optional) check_string(path) - if (!is.null(version)){ crate <- paste0(crate, "@", version) } + if (!is.null(version)) { + crate <- paste0(crate, "@", version) + } # combine main options cargo_add_opts <- list( @@ -69,7 +69,9 @@ use_crate <- function( # combine option names and values into single strings adtl_args <- unname(purrr::imap_chr( cargo_add_opts, - function(x, i){ paste(i, paste0(x, collapse = " ")) } + function(x, i) { + paste(i, paste0(x, collapse = " ")) + } )) # get rust directory in project folder @@ -90,5 +92,4 @@ use_crate <- function( ) invisible() - } diff --git a/tests/testthat/test-make-module-macro.R b/tests/testthat/test-make-module-macro.R index 240b16ae..e5aead68 100644 --- a/tests/testthat/test-make-module-macro.R +++ b/tests/testthat/test-make-module-macro.R @@ -84,11 +84,11 @@ test_that("Macro generation fails on invalid comments in code", { ) expect_rextendr_error( make_module_macro("/*/*/**/"), - "Found 3 occurences" + "Found 3 occurrences" ) expect_rextendr_error( make_module_macro("/*/*/**/"), - "Found 1 occurence" + "Found 1 occurrence" ) expect_rextendr_error(