Skip to content

Commit 6adac52

Browse files
authored
Merge pull request #726 from DavisVaughan/tbl-new-data-frame
- `new_tibble()` uses `vctrs::new_data_frame()` internally (#726, @DavisVaughan).
2 parents 0f7901e + 6c179fb commit 6adac52

File tree

7 files changed

+67
-29
lines changed

7 files changed

+67
-29
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ importFrom(pillar,type_sum)
8686
importFrom(pkgconfig,set_config)
8787
importFrom(utils,head)
8888
importFrom(utils,tail)
89+
importFrom(vctrs,new_data_frame)
8990
importFrom(vctrs,new_rcrd)
9091
importFrom(vctrs,num_as_location)
9192
importFrom(vctrs,unspecified)

R/new.R

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ new_tibble <- function(x, ..., nrow, class = NULL, subclass = NULL) {
4444
cnd_signal(error_new_tibble_must_be_list())
4545
}
4646

47-
#' The `...` argument allows adding more attributes to the subclass.
48-
x <- update_tibble_attrs(x, ...)
49-
5047
#' An `nrow` argument is required.
5148
if (missing(nrow)) {
5249
cnd <- error_new_tibble_needs_nrow()
@@ -63,22 +60,54 @@ new_tibble <- function(x, ..., nrow, class = NULL, subclass = NULL) {
6360
#' equal to this value.
6461
#' (But this is not checked by the constructor).
6562
#' This takes the place of the "row.names" attribute in a data frame.
66-
if (!is_integerish(nrow, 1)) {
63+
if (is_integerish(nrow, 1)) {
64+
nrow <- as.integer(nrow)
65+
} else {
6766
cnd_signal(error_new_tibble_needs_nrow())
6867
}
6968

69+
args <- attributes(x)
70+
71+
if (is.null(args)) {
72+
args <- list()
73+
}
74+
75+
new_attrs <- pairlist2(...)
76+
nms <- names(new_attrs)
77+
78+
for (i in seq_along(nms)) {
79+
nm <- nms[[i]]
80+
81+
if (nm == "") {
82+
next
83+
}
84+
85+
args[[nm]] <- new_attrs[[i]]
86+
}
87+
7088
#' `x` must have names (or be empty),
7189
#' but the names are not checked for correctness.
7290
if (length(x) == 0) {
7391
# Leaving this because creating a named list of length zero seems difficult
74-
names(x) <- character()
75-
} else if (is.null(names(x))) {
92+
args[["names"]] <- character()
93+
} else if (is.null(args[["names"]])) {
7694
cnd_signal(error_names_must_be_non_null())
7795
}
7896

79-
attr(x, "row.names") <- .set_row_names(nrow)
80-
class(x) <- c(class[!class %in% tibble_class], tibble_class)
81-
x
97+
if (is.null(class)) {
98+
class <- tibble_class_no_data_frame
99+
} else {
100+
class <- c(class[!class %in% tibble_class], tibble_class_no_data_frame)
101+
}
102+
103+
slots <- c("x", "n", "class")
104+
args[slots] <- list(x, nrow, class)
105+
106+
# `new_data_frame()` restores compact row names
107+
args[["row.names"]] <- NULL
108+
109+
# do.call() is faster than exec() in this case
110+
do.call(new_data_frame, args)
82111
}
83112

84113
#' @description
@@ -131,11 +160,8 @@ validate_nrow <- function(names, lengths, nrow) {
131160
}
132161
}
133162

134-
update_tibble_attrs <- function(x, ...) {
135-
.Call(`tibble_update_attrs`, x, pairlist2(...))
136-
}
137-
138163
tibble_class <- c("tbl_df", "tbl", "data.frame")
164+
tibble_class_no_data_frame <- c("tbl_df", "tbl")
139165

140166
# Errors ------------------------------------------------------------------
141167

R/tibble-package.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#' @importFrom vctrs unspecified vec_as_subscript2 num_as_location vec_ptype_abbr
1010
#' @importFrom vctrs vec_names vec_names2 vec_set_names
1111
#' @importFrom vctrs new_rcrd
12+
#' @importFrom vctrs new_data_frame
1213
#' @aliases NULL tibble-package
1314
#' @details
1415
#' `r lifecycle::badge("stable")`

man/new_tibble.Rd

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/attributes.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
#include "tibble.h"
22

3-
SEXP tibble_update_attrs(SEXP x, SEXP dots) {
4-
x = PROTECT(Rf_shallow_duplicate(x));
5-
6-
while(dots != R_NilValue) {
7-
SEXP tag = TAG(dots);
8-
if (tag != R_NilValue) {
9-
Rf_setAttrib(x, tag, CAR(dots));
10-
}
11-
dots = CDR(dots);
12-
}
13-
UNPROTECT(1);
14-
return x;
15-
}
16-
173
SEXP tibble_restore_impl(SEXP xo, SEXP x) {
184
xo = PROTECT(Rf_shallow_duplicate(xo));
195

src/init.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
static const R_CallMethodDef CallEntries[] = {
88
{"tibble_matrixToDataFrame", (DL_FUNC) &tibble_matrixToDataFrame, 1},
99
{"tibble_string_to_indices", (DL_FUNC) &tibble_string_to_indices, 1},
10-
{"tibble_update_attrs", (DL_FUNC) &tibble_update_attrs, 2},
1110
{"tibble_restore_impl", (DL_FUNC) &tibble_restore_impl, 2},
1211
{"tibble_need_coerce", (DL_FUNC) &tibble_need_coerce, 1},
1312

tests/testthat/test-new.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,32 @@ test_that("new_tibble() with additional attributes", {
5858
expect_identical(tbl_df, tbl_foo)
5959
})
6060

61+
test_that("new_tibble() can add attributes on zero column tibbles with no attributes", {
62+
expect_identical(
63+
attr(new_tibble(list(), nrow = 0L, foo = 10), "foo"),
64+
10
65+
)
66+
})
67+
68+
test_that("new_tibble() ignores unnamed additional attributes", {
69+
expect_identical(
70+
new_tibble(list(x = 1), "foo", nrow = 1),
71+
new_tibble(list(x = 1), nrow = 1)
72+
)
73+
74+
expect_identical(
75+
new_tibble(list(x = 1), "foo", bar = "bar", nrow = 1),
76+
new_tibble(list(x = 1), bar = "bar", nrow = 1)
77+
)
78+
})
79+
80+
test_that("new_tibble() allows setting names through `...`", {
81+
expect_identical(
82+
new_tibble(list(1), names = "x", nrow = 1),
83+
new_tibble(list(x = 1), nrow = 1)
84+
)
85+
})
86+
6187
test_that("new_tibble checks", {
6288
scoped_lifecycle_errors()
6389

0 commit comments

Comments
 (0)