From 2ab8a67c86aa17f189d4cfcaac8310cfe0ee2802 Mon Sep 17 00:00:00 2001 From: Blake Vernon Date: Wed, 30 Apr 2025 10:22:19 -0600 Subject: [PATCH] remove glue --- DESCRIPTION | 5 ++-- NAMESPACE | 2 -- R/clean.R | 4 ++-- R/eval.R | 20 ++++++++-------- R/find_exports.R | 4 ++-- R/helpers.r | 2 +- R/knitr_engine.R | 6 ++--- R/make_module_macro.R | 13 ++++++---- R/register_extendr.R | 7 +++++- R/rextendr.R | 1 - R/rextendr_document.R | 10 +++++--- R/rust_sitrep.R | 4 ++-- R/sanitize_code.R | 2 +- R/source.R | 31 +++++++++++++----------- R/toml_serialization.R | 23 +++++++++--------- R/track_rust_source.R | 2 +- R/use_extendr.R | 49 +++++++++++++++++++++----------------- tests/testthat/test-eval.R | 2 +- tests/testthat/test-toml.R | 2 +- 19 files changed, 101 insertions(+), 88 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9f21c1d4..4e309dbb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,8 +43,7 @@ Imports: callr, cli, desc, - dplyr, - glue (>= 1.7.0), + dplyr, jsonlite, pkgbuild (>= 1.4.0), processx, @@ -67,6 +66,6 @@ Config/testthat/edition: 3 Config/testthat/parallel: true Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.2.9000 SystemRequirements: Rust 'cargo'; the crate 'libR-sys' must compile without error diff --git a/NAMESPACE b/NAMESPACE index 06644682..10368162 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -27,8 +27,6 @@ export(use_msrv) export(vendor_pkgs) export(write_license_note) importFrom(dplyr,mutate) -importFrom(glue,glue) -importFrom(glue,glue_collapse) importFrom(rlang,"%||%") importFrom(rlang,.data) importFrom(rlang,.env) diff --git a/R/clean.R b/R/clean.R index 0a57070f..cc085ae9 100644 --- a/R/clean.R +++ b/R/clean.R @@ -42,8 +42,8 @@ clean <- function(path = ".", echo = TRUE) { args <- c( "clean", - glue::glue("--manifest-path={manifest_path}"), - glue::glue("--target-dir={target_dir}"), + paste0("--manifest-path=", manifest_path), + paste0("--target-dir=", target_dir), if (tty_has_colors()) { "--color=always" } else { diff --git a/R/eval.R b/R/eval.R index 4638a833..66acd017 100644 --- a/R/eval.R +++ b/R/eval.R @@ -29,6 +29,9 @@ #' } #' @export rust_eval <- function(code, env = parent.frame(), ...) { + check_character(code, call = rlang::caller_call(), class = "rextendr_error") + check_environment(env, call = rlang::caller_call(), class = "rextendr_error") + rust_eval_deferred(code = code, env = env, ...)() } @@ -45,7 +48,7 @@ rust_eval <- function(code, env = parent.frame(), ...) { #' @noRd rust_eval_deferred <- function(code, env = parent.frame(), ...) { # make sure code is given as a single character string - code <- glue_collapse(code, sep = "\n") + code <- paste0(code, collapse = "\n") # Snippet hash is constructed from the Rust source code and # a unique identifier of the compiled dll. @@ -57,17 +60,14 @@ rust_eval_deferred <- function(code, env = parent.frame(), ...) { snippet_hash <- rlang::hash(list(the$count, code)) # nolint: object_usage_linter # The unique hash is then used to generate unique function names - fn_name <- glue("rextendr_rust_eval_fun_{snippet_hash}") + fn_name <- paste0("rextendr_rust_eval_fun_", snippet_hash) # wrap code into Rust function - code_wrapped <- glue(r"( -fn {fn_name}() -> Result {{ - let x = {{ - {code} - }}; - Ok(x.into()) -}} -)") + code_wrapped <- sprintf( + "fn %s() -> Result {\n let x = {\n %s\n };\n Ok(x.into())\n}", + fn_name, + code + ) # Attempt to figure out whether the Rust code returns a result or not, # and make the result invisible or not accordingly. This regex approach diff --git a/R/find_exports.R b/R/find_exports.R index cf1b690d..3756a0c2 100644 --- a/R/find_exports.R +++ b/R/find_exports.R @@ -25,7 +25,7 @@ find_extendr_attrs_ids <- function(lns) { extract_meta <- function(lns) { # Matches fn|impl<'a> item_name result <- stringi::stri_match_first_regex( - glue_collapse(lns, sep = "\n"), + paste0(lns, collapse = "\n"), "(?:(?struct)|(?enum)|(?fn)|(?impl)(?:\\s*<(?.+?)>)?)\\s+(?(?:r#)?(?:_\\w+|[A-z]\\w*))" # nolint: line_length_linter ) |> as.data.frame() |> @@ -37,7 +37,7 @@ extract_meta <- function(lns) { # This unfortunately does not provide # meaningful output or source line numbers. code_sample <- stringi::stri_sub( - glue_collapse(lns, sep = "\n "), + paste0(lns, collapse = "\n "), 1, 80 ) diff --git a/R/helpers.r b/R/helpers.r index bbcee7cc..f35846dd 100644 --- a/R/helpers.r +++ b/R/helpers.r @@ -29,7 +29,7 @@ get_cargo_envvars <- function() { path_envvar <- Sys.getenv("PATH", unset = "") # nolint: object_usage_linter cargo_path <- path.expand("~/.cargo/bin") # nolint: object_usage_linter # "current" means appending or overwriting the envvars in addition to the current ones. - cargo_envvars <- c("current", PATH = glue("{path_envvar}:{cargo_path}")) + cargo_envvars <- c("current", PATH = paste(path_envvar, cargo_path, sep = ":")) } cargo_envvars } diff --git a/R/knitr_engine.R b/R/knitr_engine.R index ee5c4a8b..7e9d3262 100644 --- a/R/knitr_engine.R +++ b/R/knitr_engine.R @@ -16,8 +16,6 @@ eng_extendrsrc <- function(options) { eng_impl(options, rust_source) } - - eng_impl <- function(options, extendr_engine) { if (!requireNamespace("knitr", quietly = TRUE)) { cli::cli_abort( @@ -36,8 +34,8 @@ eng_impl <- function(options, extendr_engine) { code <- options$code } - code <- glue_collapse(code, sep = "\n") # code to compile - code_out <- glue_collapse(options$code, sep = "\n") # code to output to html + code <- paste0(code, collapse = "\n") # code to compile + code_out <- paste0(options$code, collapse = "\n") # code to output to html # engine.opts is a list of arguments to be passed to rust_eval, e.g. # engine.opts = list(dependencies = list(`pulldown-cmark` = "0.8")) diff --git a/R/make_module_macro.R b/R/make_module_macro.R index 1063a43d..f4202c6d 100644 --- a/R/make_module_macro.R +++ b/R/make_module_macro.R @@ -15,13 +15,16 @@ make_module_macro <- function(code, module_name = "rextendr") { # make sure we have cleanly separated lines lines <- stringi::stri_split_lines( - glue_collapse(code, sep = "\n"), + paste0(code, collapse = "\n"), omit_empty = TRUE )[[1]] idents <- find_exports(sanitize_rust_code(lines)) - outlines <- c("extendr_module! {", glue("mod {module_name};")) - outlines <- c(outlines, glue::glue_data(idents, "{type} {name};")) - outlines <- c(outlines, "}") - outlines + + c( + "extendr_module! {", + paste0("mod ", module_name, ";"), + paste0(idents[["type"]], " ", idents[["name"]], ";"), + "}" + ) } diff --git a/R/register_extendr.R b/R/register_extendr.R index c954d3c1..92813de8 100644 --- a/R/register_extendr.R +++ b/R/register_extendr.R @@ -28,6 +28,11 @@ #' @seealso [rextendr::document()] #' @export register_extendr <- function(path = ".", quiet = FALSE, force = FALSE, compile = NA) { + check_string(path, call = rlang::caller_call(), class = "rextendr_error") + check_bool(quiet, call = rlang::caller_call(), class = "rextendr_error") + check_bool(force, call = rlang::caller_call(), class = "rextendr_error") + check_bool(compile, allow_na = TRUE, call = rlang::caller_call(), class = "rextendr_error") + local_quiet_cli(quiet) rextendr_setup(path = path) @@ -130,7 +135,7 @@ register_extendr <- function(path = ".", quiet = FALSE, force = FALSE, compile = #' @noRd make_wrappers <- function(module_name, package_name, outfile, path = ".", use_symbols = FALSE, quiet = FALSE) { - wrapper_function <- glue("wrap__make_{module_name}_wrappers") + wrapper_function <- paste0("wrap__make_", module_name, "_wrappers") x <- .Call( wrapper_function, use_symbols = use_symbols, diff --git a/R/rextendr.R b/R/rextendr.R index bf16b783..b3f973f9 100644 --- a/R/rextendr.R +++ b/R/rextendr.R @@ -7,7 +7,6 @@ "_PACKAGE" #' @importFrom dplyr mutate -#' @importFrom glue glue glue_collapse #' @importFrom rlang dots_list names2 as_function is_missing is_atomic is_null #' @importFrom rlang is_na .data .env caller_env as_name as_label enquo %||% #' @importFrom stringi stri_replace_all_regex diff --git a/R/rextendr_document.R b/R/rextendr_document.R index 9883945d..6144725f 100644 --- a/R/rextendr_document.R +++ b/R/rextendr_document.R @@ -10,13 +10,17 @@ #' @return No return value, called for side effects. #' @export document <- function(pkg = ".", quiet = FALSE, roclets = NULL) { + check_string(pkg, call = rlang::caller_call(), class = "rextendr_error") + check_bool(quiet, call = rlang::caller_call(), class = "rextendr_error") + check_character(roclets, allow_null = TRUE, call = rlang::caller_call(), class = "rextendr_error") + withr::local_envvar(devtools::r_env_vars()) register_extendr(path = pkg, quiet = quiet) rlang::check_installed("devtools") devtools::document(pkg = pkg, roclets = roclets, quiet = quiet) - if (!isTRUE(quiet)) { + if (!quiet) { check_namespace_file(pkg) } } @@ -26,7 +30,7 @@ check_if_roxygen_used <- function(namespace_content) { } check_if_dyn_lib_used <- function(namespace_content, pkg_name) { - expected_pattern <- glue::glue("useDynLib\\({pkg_name},\\s*\\.registration = TRUE\\)") + expected_pattern <- paste0("useDynLib\\(", pkg_name, ",\\s*\\.registration = TRUE\\)") any(stringi::stri_detect_regex(namespace_content, expected_pattern)) } @@ -50,7 +54,7 @@ check_namespace_file <- function(path = ".") { ) ) - use_dyn_lib_ref <- glue::glue("useDynLib({package_name}, .registration = TRUE)") # nolint: object_usage_linter. + use_dyn_lib_ref <- paste0("useDynLib(", package_name, ", .registration = TRUE)") # nolint: object_usage_linter. cli::cli_warn( c( diff --git a/R/rust_sitrep.R b/R/rust_sitrep.R index bbd39c8e..e1bd61b1 100644 --- a/R/rust_sitrep.R +++ b/R/rust_sitrep.R @@ -172,7 +172,7 @@ rustup_toolchain_target <- function() { #' @noRd verify_toolchains <- function(toolchains, host) { if (rlang::is_empty(toolchains)) { - return(list(toolchains = toolchains, missing_toolchain = glue("stable-{host}"))) + return(list(toolchains = toolchains, missing_toolchain = paste0("stable-", host))) } default_toolchain_index <- stringi::stri_detect_fixed(toolchains, "(default)") @@ -187,7 +187,7 @@ verify_toolchains <- function(toolchains, host) { candidate_toolchains <- toolchains[candidates] toolchains[candidates] <- cli::col_yellow(toolchains[candidates]) } else { - missing_toolchain <- glue("stable-{host}") + missing_toolchain <- paste0("stable-", host) } } list(toolchains = toolchains, missing_toolchain = missing_toolchain, candidate_toolchains = candidate_toolchains) diff --git a/R/sanitize_code.R b/R/sanitize_code.R index bf968f10..0015729c 100644 --- a/R/sanitize_code.R +++ b/R/sanitize_code.R @@ -23,7 +23,7 @@ remove_line_comments <- function(lns) { # comments. # 4. We fill in space between remaining delimiters with spaces (simplest way). fill_block_comments <- function(lns, fill_with = " ") { # nolint: object_usage_linter - lns <- glue_collapse(lns, sep = "\n") + lns <- paste0(lns, collapse = "\n") # Fast path if character input is empty if (length(lns) == 0L || !nzchar(lns)) { diff --git a/R/source.R b/R/source.R index 0a518aeb..1ce90b1c 100644 --- a/R/source.R +++ b/R/source.R @@ -239,14 +239,17 @@ rust_function <- function(code, if (vctrs::vec_is_empty(options)) { attr_arg <- "" } else { - attr_arg <- options |> - glue::glue_data("{Name} = {RustValue}") |> - glue::glue_collapse(sep = ", ") - attr_arg <- glue::glue("({attr_arg})") + attr_arg <- paste( + options[["Name"]], + options[["RustValue"]], + sep = " = ", + collapse = ", " + ) + attr_arg <- paste0("(", attr_arg, ")") } code <- c( - glue::glue("#[extendr{attr_arg}]"), + paste0("#[extendr", attr_arg, "]"), stringi::stri_trim(code) ) @@ -328,8 +331,8 @@ invoke_cargo <- function(toolchain, specific_target, dir, profile, rtools_home <- normalizePath( Sys.getenv( - glue("RTOOLS{rtools_version}_HOME"), - glue("C:\\rtools{rtools_version}") + paste0("RTOOLS", rtools_version, "_HOME"), + paste0("C:\\rtools", rtools_version) ), mustWork = TRUE ) @@ -362,13 +365,13 @@ invoke_cargo <- function(toolchain, specific_target, dir, profile, compilation_result <- processx::run( command = "cargo", args = c( - glue("+{toolchain}"), + paste0("+", toolchain), "build", "--lib", - glue("--target={specific_target}"), - glue("--manifest-path={file.path(dir, 'Cargo.toml')}"), - glue("--target-dir={file.path(dir, 'target')}"), - glue("--profile={profile}"), + paste0("--target=", specific_target), + paste0("--manifest-path=", file.path(dir, "Cargo.toml")), + paste0("--target-dir=", file.path(dir, "target")), + paste0("--profile=", profile), "--message-format=json-diagnostic-rendered-ansi", if (tty_has_colors()) { "--color=always" @@ -394,14 +397,14 @@ invoke_cargo <- function(toolchain, specific_target, dir, profile, #' #' Checks the output of cargo and filters messages according to `level`. #' Retrieves rendered ANSI strings and prepares them -#' for `cli` and `glue` formatting. +#' for `cli` formatting. #' @param json_output \[ JSON(n) \] JSON messages produced by cargo. #' @param level \[ string \] Log level. #' Commonly used values are `"error"` and `"warning"`. #' @param tty_has_colors \[ logical(1) \] Indicates if output #' supports ANSI sequences. If `FALSE`, ANSI sequences are stripped off. #' @return \[ character(n) \] Vector of strings -#' that can be passed to `cli` or `glue` functions. +#' that can be passed to `cli` functions. #' @noRd gather_cargo_output <- function(json_output, level, tty_has_colors) { rendered_output <- diff --git a/R/toml_serialization.R b/R/toml_serialization.R index e3523b32..b31488b3 100644 --- a/R/toml_serialization.R +++ b/R/toml_serialization.R @@ -65,7 +65,7 @@ to_toml <- function(..., .format_int = .format_int, .format_dbl = .format_dbl ) - body <- glue_collapse(body, "\n") + body <- paste0(body, collapse = "\n") if (!nzchar(body)) { body <- NULL } @@ -73,17 +73,17 @@ to_toml <- function(..., # The values can be (1) header and body, (2) header only, or (3) body only. # In the case of (2) and (3) the other element is of length 0, so we need to # remove them by `c()` first, and then concatenate by "\n" if both exists - glue_collapse(c(header, body), "\n") + paste0(c(header, body), collapse = "\n") }) - glue_collapse(tables, "\n\n") + paste0(tables, collapse = "\n\n") } make_header <- function(nm, arg) { # For future support of array-of-table # https://toml.io/en/v1.0.0-rc.3#array-of-tables if (nzchar(nm) && !is.data.frame(arg)) { - as.character(glue("[{nm}]")) + paste0("[", nm, "]") } else { character(0) } @@ -123,7 +123,7 @@ format_toml.data.frame <- function(x, .tbl_name, .top_level = FALSE) { rows <- nrow(x) - header <- glue("[[{.tbl_name}]]") + header <- paste0("[[", .tbl_name, "]]") if (rows == 0L) { return(as.character(header)) } @@ -135,7 +135,6 @@ format_toml.data.frame <- function(x, if (length(item) == 0L) { result <- character(0) } else { - result <- format_toml( as.list(item), ..., @@ -203,9 +202,9 @@ format_toml_atomic <- function(x, "[ ]" } else { formatter <- rlang::as_function(.formatter) - items <- glue_collapse(formatter(x), ", ") + items <- paste0(formatter(x), collapse = ", ") if (len > 1L || !is.null(dims)) { - items <- glue("[ {items} ]") + items <- paste0("[ ", items, " ]") } # Ensure type-stability as.character(items) @@ -223,9 +222,9 @@ format_toml.character <- function(x, .str_as_literal = TRUE, .top_level = FALSE) { if (isTRUE(.str_as_literal)) { - .formatter <- \(.x) glue("'{.x}'") + .formatter <- \(.x) paste0("'", .x, "'") } else { - .formatter <- \(.x) glue("\"{escape_dbl_quotes(.x)}\"") + .formatter <- \(.x) paste0("\"", escape_dbl_quotes(.x), "\"") } format_toml_atomic( x, @@ -291,11 +290,11 @@ format_toml.list <- function(x, ..., .top_level = FALSE) { ) } result <- map2(names, x, function(nm, val) { - glue("{nm} = {format_toml(val, ..., .top_level = FALSE)}") + paste0(nm, " = ", format_toml(val, ..., .top_level = FALSE)) }) if (!.top_level) { - result <- glue("{{ {paste0(result, collapse = \", \")} }}") + result <- paste("{", paste0(result, collapse = ", "), "}") } if (!is_atomic(result)) { result <- list_c(result) diff --git a/R/track_rust_source.R b/R/track_rust_source.R index dca7e967..ae7533d1 100644 --- a/R/track_rust_source.R +++ b/R/track_rust_source.R @@ -94,6 +94,6 @@ get_library_path <- function(path = ".") { # Constructs path to the library file (e.g., package_name.dll) file.path( rprojroot::find_package_root_file("src", path = path), - glue::glue("{pkg_name(path)}{.Platform$dynlib.ext}") + paste0(pkg_name(path), .Platform$dynlib.ext) ) } diff --git a/R/use_extendr.R b/R/use_extendr.R index 46a5588e..edb57ef0 100644 --- a/R/use_extendr.R +++ b/R/use_extendr.R @@ -22,15 +22,21 @@ #' generated or not. #' @export use_extendr <- function( - path = ".", - crate_name = NULL, - lib_name = NULL, - quiet = FALSE, - overwrite = NULL, - edition = c("2021", "2018") -) { + path = ".", + crate_name = NULL, + lib_name = NULL, + quiet = FALSE, + overwrite = NULL, + edition = c("2021", "2018")) { # https://github.com/r-lib/cli/issues/434 + check_string(path, call = rlang::caller_call(), class = "rextendr_error") + check_string(crate_name, allow_null = TRUE, call = rlang::caller_call(), class = "rextendr_error") + check_string(lib_name, allow_null = TRUE, call = rlang::caller_call(), class = "rextendr_error") + check_bool(quiet, call = rlang::caller_call(), class = "rextendr_error") + check_bool(overwrite, allow_null = TRUE, call = rlang::caller_call(), class = "rextendr_error") + # check_string(edition, call = rlang::caller_call(), class = "rextendr_error") + local_quiet_cli(quiet) if (!interactive()) { @@ -305,7 +311,7 @@ as_valid_rust_name <- function(name) { #' @param call \[ env \] Environment of the caller, passed to `cli::cli_abort()`. #' @noRd throw_if_invalid_rust_name <- function(name, call = caller_env()) { - quo <- enquo(name) # nolint: object_usage_linter + quo <- rlang::enquo(name) # nolint: object_usage_linter if (!rlang::is_scalar_character(name) || !is_valid_rust_name(name)) { cli::cli_abort( c( @@ -331,12 +337,11 @@ throw_if_invalid_rust_name <- function(name, call = caller_env()) { #' Otherwise, the file will be overwritten. #' @noRd use_rextendr_template <- function( - template, - save_as = template, - data = list(), - quiet = FALSE, - overwrite = NULL -) { + template, + save_as = template, + data = list(), + quiet = FALSE, + overwrite = NULL) { local_quiet_cli(quiet) if (isFALSE(overwrite) && file.exists(save_as)) { @@ -346,7 +351,7 @@ use_rextendr_template <- function( return(invisible(NULL)) } - if (is_installed("usethis") && is.null(overwrite)) { + if (rlang::is_installed("usethis") && is.null(overwrite)) { created <- usethis::use_template( template, save_as = save_as, @@ -367,13 +372,13 @@ use_rextendr_template <- function( template_content <- brio::read_file(template_path) - template_content <- glue::glue_data( - template_content, - .x = data, - .open = "{{{", - .close = "}}}", - .trim = FALSE - ) + if (!rlang::is_empty(data)) { + template_content <- gsub( + pattern = paste0("\\{\\{\\{", names(data), "\\}\\}\\}"), + replacement = unlist(data, use.names = FALSE), + x = template_content + ) + } write_file( stringi::stri_trim(template_content), diff --git a/tests/testthat/test-eval.R b/tests/testthat/test-eval.R index 4d007dc9..57a4bca8 100644 --- a/tests/testthat/test-eval.R +++ b/tests/testthat/test-eval.R @@ -22,7 +22,7 @@ test_that("multiple `rust_eval_deferred()` work correctly", { provided_values <- seq_len(5) deferred_handles <- map( provided_values, - \(.x) rust_eval_deferred(glue::glue("{.x}i32")) + \(.x) rust_eval_deferred(paste0(.x, "i32")) ) obtained_values <- map_int(deferred_handles, rlang::exec) diff --git a/tests/testthat/test-toml.R b/tests/testthat/test-toml.R index a1bcb639..1f53311d 100644 --- a/tests/testthat/test-toml.R +++ b/tests/testthat/test-toml.R @@ -93,7 +93,7 @@ test_that("`toml` is generated correctly", { "ndarray = [ ]" ) - reference <- glue_collapse(reference, "\n") + reference <- paste0(reference, collapse = "\n") expect_equal(toml, reference) })