From acac3f9052de116af911f088f5a7da277337a902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Wed, 24 Jul 2024 07:55:44 +0200 Subject: [PATCH] Improvements to standalone header (#1903) * Add ref and host to standalone header * Add code to generate the standalone * Make some more changes * Dogfood it * Add NEWS bullet * Use fs * Update a snapshot --------- Co-authored-by: Jenny Bryan --- NEWS.md | 3 + R/import-standalone-obj-type.R | 29 +++++++--- R/import-standalone-types-check.R | 3 +- R/use_standalone.R | 18 +++++- tests/testthat/_snaps/use_standalone.md | 76 +++++++++++++++++++++---- tests/testthat/test-use_standalone.R | 35 ++++++++++-- 6 files changed, 139 insertions(+), 25 deletions(-) diff --git a/NEWS.md b/NEWS.md index ac43cca6a..7b5a0b3a3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # usethis (development version) +* `use_standalone()` inserts an improved header that includes the code needed to + update the standalone file (@krlmlr, #1903). + * `use_release_issue()` and `use_upkeep()` behave better when the user has a fork. The user is asked just once to choose between `origin` and `upstream` as the target repo (#2023). diff --git a/R/import-standalone-obj-type.R b/R/import-standalone-obj-type.R index 72cfe37dc..47268d620 100644 --- a/R/import-standalone-obj-type.R +++ b/R/import-standalone-obj-type.R @@ -1,17 +1,27 @@ # Standalone file: do not edit by hand -# Source: +# 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: 2022-10-04 +# last-updated: 2024-02-14 # license: https://unlicense.org # imports: rlang (>= 1.1.0) # --- # # ## Changelog # +# 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. @@ -65,7 +75,7 @@ obj_type_friendly <- function(x, value = TRUE) { if (inherits(x, "quosure")) { type <- "quosure" } else { - type <- paste(class(x), collapse = "/") + type <- class(x)[[1L]] } return(sprintf("a <%s> object", type)) } @@ -261,19 +271,19 @@ vec_type_friendly <- function(x, length = FALSE) { #' Return OO type #' @param x Any R object. #' @return One of `"bare"` (for non-OO objects), `"S3"`, `"S4"`, -#' `"R6"`, or `"R7"`. +#' `"R6"`, or `"S7"`. #' @noRd obj_type_oo <- function(x) { if (!is.object(x)) { return("bare") } - class <- inherits(x, c("R6", "R7_object"), which = TRUE) + class <- inherits(x, c("R6", "S7_object"), which = TRUE) if (class[[1]]) { "R6" } else if (class[[2]]) { - "R7" + "S7" } else if (isS4(x)) { "S4" } else { @@ -315,10 +325,15 @@ stop_input_type <- function(x, 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.", - cli$format_arg(arg), + format_arg(arg), what, obj_type_friendly(x, value = show_value) ) diff --git a/R/import-standalone-types-check.R b/R/import-standalone-types-check.R index 6782d69b1..0943a8d58 100644 --- a/R/import-standalone-types-check.R +++ b/R/import-standalone-types-check.R @@ -1,5 +1,6 @@ # Standalone file: do not edit by hand -# Source: +# Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-types-check.R +# Generated by: usethis::use_standalone("r-lib/rlang", "types-check") # ---------------------------------------------------------------------- # # --- diff --git a/R/use_standalone.R b/R/use_standalone.R index cae24075b..e23d1cba7 100644 --- a/R/use_standalone.R +++ b/R/use_standalone.R @@ -74,7 +74,7 @@ use_standalone <- function(repo_spec, file = NULL, ref = NULL, host = NULL) { dest_path <- path("R", as_standalone_dest_file(file)) lines <- read_github_file(repo_spec, path = src_path, ref = ref, host = host) - lines <- c(standalone_header(repo_spec, src_path), lines) + lines <- c(standalone_header(repo_spec, src_path, ref, host), lines) write_over(proj_path(dest_path), lines, overwrite = TRUE) dependencies <- standalone_dependencies(lines, path) @@ -156,10 +156,22 @@ as_standalone_dest_file <- function(file) { gsub("standalone-", "import-standalone-", file) } -standalone_header <- function(repo_spec, path) { +standalone_header <- function(repo_spec, path, ref = NULL, host = NULL) { + ref_string <- ref %||% "HEAD" + host_string <- host %||% "https://github.com" + source_comment <- + glue("# Source: {host_string}/{repo_spec}/blob/{ref_string}/{path}") + + path_string <- path_ext_remove(sub("^standalone-", "", path_file(path))) + ref_string <- if (is.null(ref)) "" else glue(', ref = "{ref}"') + host_string <- if (is.null(host) || host == "https://github.com") "" else glue(', host = "{host}"') + code_hint <- glue('usethis::use_standalone("{repo_spec}", "{path_string}"{ref_string}{host_string})') + generated_comment <- glue('# Generated by: {code_hint}') + c( "# Standalone file: do not edit by hand", - glue("# Source: "), + source_comment, + generated_comment, paste0("# ", strrep("-", 72 - 2)), "#" ) diff --git a/tests/testthat/_snaps/use_standalone.md b/tests/testthat/_snaps/use_standalone.md index 9b1e3532e..1b1a447b6 100644 --- a/tests/testthat/_snaps/use_standalone.md +++ b/tests/testthat/_snaps/use_standalone.md @@ -1,3 +1,69 @@ +# standalone_header() works with various inputs + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.com/OWNER/REPO/blob/HEAD/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + +--- + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R", ref = "blah") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.com/OWNER/REPO/blob/blah/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\", ref = \"blah\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + +--- + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R", host = "https://github.com") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.com/OWNER/REPO/blob/HEAD/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + +--- + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R", host = "https://github.acme.com") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.acme.com/OWNER/REPO/blob/HEAD/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\", host = \"https://github.acme.com\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + +--- + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R", ref = "blah", host = "https://github.com") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.com/OWNER/REPO/blob/blah/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\", ref = \"blah\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + +--- + + Code + standalone_header("OWNER/REPO", "R/standalone-foo.R", ref = "blah", host = "https://github.acme.com") + Output + [1] "# Standalone file: do not edit by hand" + [2] "# Source: https://github.acme.com/OWNER/REPO/blob/blah/R/standalone-foo.R" + [3] "# Generated by: usethis::use_standalone(\"OWNER/REPO\", \"foo\", ref = \"blah\", host = \"https://github.acme.com\")" + [4] "# ----------------------------------------------------------------------" + [5] "#" + # can offer choices Code @@ -12,16 +78,6 @@ ! `file` is absent, but must be supplied. i Possible options are cli, downstream-deps, lazyeval, lifecycle, linked-version, obj-type, purrr, rlang, s3-register, sizes, types-check, vctrs, or zeallot. -# header provides useful summary - - Code - standalone_header("r-lib/usethis", "R/standalone-test.R") - Output - [1] "# Standalone file: do not edit by hand" - [2] "# Source: " - [3] "# ----------------------------------------------------------------------" - [4] "#" - # can extract imports Code diff --git a/tests/testthat/test-use_standalone.R b/tests/testthat/test-use_standalone.R index 638411c27..41d9337e7 100644 --- a/tests/testthat/test-use_standalone.R +++ b/tests/testthat/test-use_standalone.R @@ -1,3 +1,34 @@ +test_that("standalone_header() works with various inputs", { + expect_snapshot( + standalone_header("OWNER/REPO", "R/standalone-foo.R") + ) + expect_snapshot( + standalone_header("OWNER/REPO", "R/standalone-foo.R", ref = "blah") + ) + expect_snapshot( + standalone_header( + "OWNER/REPO", "R/standalone-foo.R", host = "https://github.com" + ) + ) + expect_snapshot( + standalone_header( + "OWNER/REPO", "R/standalone-foo.R", host = "https://github.acme.com" + ) + ) + expect_snapshot( + standalone_header( + "OWNER/REPO", "R/standalone-foo.R", + ref = "blah", host = "https://github.com" + ) + ) + expect_snapshot( + standalone_header( + "OWNER/REPO", "R/standalone-foo.R", + ref = "blah", host = "https://github.acme.com" + ) + ) +}) + test_that("can import standalone file with dependencies", { skip_if_offline("github.com") create_local_package() @@ -40,10 +71,6 @@ test_that("can offer choices", { }) }) -test_that("header provides useful summary", { - expect_snapshot(standalone_header("r-lib/usethis", "R/standalone-test.R")) -}) - test_that("can extract dependencies", { extract_deps <- function(deps) { out <- standalone_dependencies(c("# ---", deps, "# ---"), "test.R")