diff --git a/NAMESPACE b/NAMESPACE index 4d5c97daa..0b5c4c21f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -49,6 +49,7 @@ S3method("length<-",vctrs_rcrd) S3method("length<-",vctrs_vctr) S3method("levels<-",vctrs_sclr) S3method("levels<-",vctrs_vctr) +S3method("names<-",vctrs_rcrd) S3method("names<-",vctrs_sclr) S3method("names<-",vctrs_vctr) S3method("|",vctrs_vctr) diff --git a/NEWS.md b/NEWS.md index b1874b741..50ea14ba7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # vctrs (development version) +* `vec_set_names()` no longer corrupts `vctrs_rcrd` types (#1419). + * `vec_detect_complete()` now computes completeness for `vctrs_rcrd` types in the same way as data frames, which means that if any field is missing, the entire record is considered incomplete (#1386). diff --git a/R/type-rcrd.R b/R/type-rcrd.R index fd161415e..ffcb334d5 100644 --- a/R/type-rcrd.R +++ b/R/type-rcrd.R @@ -50,6 +50,15 @@ names.vctrs_rcrd <- function(x) { NULL } +#' @export +`names<-.vctrs_rcrd` <- function(x, value) { + if (is_null(value)) { + x + } else { + abort("Can't assign names to a .") + } +} + #' @export format.vctrs_rcrd <- function(x, ...) { if (inherits(x, "vctrs_foobar")) { diff --git a/tests/testthat/test-type-rcrd.R b/tests/testthat/test-type-rcrd.R index 5e57df741..47ebc8d42 100644 --- a/tests/testthat/test-type-rcrd.R +++ b/tests/testthat/test-type-rcrd.R @@ -26,6 +26,28 @@ test_that("vec_proxy() transforms records to data frames", { ) }) +# base methods ------------------------------------------------------------ + +test_that("has no names", { + x <- new_rcrd(list(a = 1, b = 2L)) + + expect_null(names(x)) + expect_null(vec_names(x)) +}) + +test_that("removing names with `NULL` is a no-op (#1419)", { + x <- new_rcrd(list(a = 1, b = 2L)) + + expect_identical(`names<-`(x, NULL), x) + expect_identical(vec_set_names(x, NULL), x) +}) + +test_that("setting character names is an error (#1419)", { + x <- new_rcrd(list(a = 1, b = 2L)) + + expect_error(`names<-`(x, "x"), "Can't assign names") + expect_error(vec_set_names(x, "x"), "Can't assign names") +}) # coercion ----------------------------------------------------------------