#' Vector type as a string
#'
#' `vec_ptype_full()` displays the full type of the vector. `vec_ptype_abbr()`
#' provides an abbreviated summary suitable for use in a column heading.
#'
#' @section S3 dispatch:
#' The default method for `vec_ptype_full()` uses the first element of the
#' class vector. Override this method if your class has parameters that should
#' be prominently displayed.
#'
#' The default method for `vec_ptype_abbr()` [abbreviate()]s `vec_ptype_full()`
#' to 8 characters. You should almost always override, aiming for 4-6
#' characters where possible.
#'
#' These arguments are handled by the generic and not passed to methods:
#' * `prefix_named`
#' * `suffix_shape`
#'
#' @param x A vector.
#' @param prefix_named If `TRUE`, add a prefix for named vectors.
#' @param suffix_shape If `TRUE` (the default), append the shape of
#' the vector.
#' @inheritParams rlang::args_dots_empty
#'
#' @keywords internal
#' @return A string.
#' @export
#' @examples
#' cat(vec_ptype_full(1:10))
#' cat(vec_ptype_full(iris))
#'
#' cat(vec_ptype_abbr(1:10))
vec_ptype_full <- function(x, ...) {
check_dots_empty0(...)
# Data frames and their subclasses have internal handling in the
# default method to get the inner types format
method <- s3_method_specific(x, "vec_ptype_full", ns = "vctrs")
return(method(x, ...))
UseMethod("vec_ptype_full")
}
#' @export
#' @rdname vec_ptype_full
vec_ptype_abbr <- function(x, ..., prefix_named = FALSE, suffix_shape = TRUE) {
check_dots_empty0(...)
method <- s3_method_specific(x, "vec_ptype_abbr", ns = "vctrs")
abbr <- method(x, ...)
named <- if ((prefix_named || is_bare_list(x)) && !is.null(vec_names(x))) "named "
shape <- if (suffix_shape) vec_ptype_shape(x)
abbr <- paste0(named, abbr, shape)
return(abbr)
UseMethod("vec_ptype_abbr")
}
#' @export
vec_ptype_full.NULL <- function(x, ...) "NULL"
#' @export
vec_ptype_abbr.NULL <- function(x, ...) "NULL"
# Default: base types and fallback for S3/S4 ------------------------------
#' @export
vec_ptype_full.default <- function(x, ...) {
if (is.data.frame(x)) {
vec_ptype_full_data_frame(x, ...)
} else if (is.object(x)) {
class(x)[[1]]
} else if (is_vector(x)) {
paste0(typeof(x), vec_ptype_shape(x))
} else {
abort("Not a vector.")
}
}
#' @export
vec_ptype_abbr.default <- function(x, ...) {
if (is.object(x)) {
type <- class(x)[[1]]
} else if (is_vector(x)) {
type <- vec_ptype_abbr_bare(x, ...)
} else {
abort("Not a vector.")
}
unname(abbreviate(type, 8))
}
vec_ptype_full_data_frame <- function(x, ...) {
if (length(x) == 0) {
return(paste0(class(x)[[1]], "<>"))
} else if (length(x) == 1) {
return(paste0(class(x)[[1]], "<", names(x), ":", vec_ptype_full(x[[1]]), ">"))
}
# Needs to handle recursion with indenting
types <- map_chr(x, vec_ptype_full)
needs_indent <- grepl("\n", types)
types[needs_indent] <- map(types[needs_indent], function(x) indent(paste0("\n", x), 4))
names <- paste0(" ", format(names(x)))
paste0(
class(x)[[1]], "<\n",
paste0(names, ": ", types, collapse = "\n"),
"\n>"
)
}
vec_ptype_abbr_bare <- function(x, ...) {
switch(typeof(x),
list = "list",
logical = "lgl",
integer = "int",
double = "dbl",
character = "chr",
complex = "cpl",
list = "list",
expression = "expr",
raw = "raw",
typeof(x)
)
}
# Helpers -----------------------------------------------------------------
vec_ptype_shape <- function(x) {
dim <- dim2(x)
if (length(dim) == 1) {
if (is_null(dim(x))) {
""
} else {
"[1d]"
}
} else {
paste0("[,", paste(dim[-1], collapse = ","), "]")
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.