33# Changelog
44# =========
55#
6+ # 2022-10-04:
7+ # - `obj_type_friendly(value = TRUE)` now shows numeric scalars
8+ # literally.
9+ # - `stop_friendly_type()` now takes `show_value`, passed to
10+ # `obj_type_friendly()` as the `value` argument.
11+ #
612# 2022-10-03:
713# - Added `allow_na` and `allow_null` arguments.
814# - `NULL` is now backticked.
3440
3541# ' Return English-friendly type
3642# ' @param x Any R object.
37- # ' @param value Whether to describe the value of `x`.
43+ # ' @param value Whether to describe the value of `x`. Special values
44+ # ' like `NA` or `""` are always described.
3845# ' @param length Whether to mention the length of vectors and lists.
3946# ' @return A string describing the type. Starts with an indefinite
4047# ' article, e.g. "an integer vector".
4148# ' @noRd
42- obj_type_friendly <- function (x , value = TRUE , length = FALSE ) {
49+ obj_type_friendly <- function (x , value = TRUE ) {
4350 if (is_missing(x )) {
4451 return (" absent" )
4552 }
@@ -59,44 +66,75 @@ obj_type_friendly <- function(x, value = TRUE, length = FALSE) {
5966
6067 n_dim <- length(dim(x ))
6168
62- if (value && ! n_dim ) {
63- if (is_na(x )) {
64- return (switch (
65- typeof(x ),
66- logical = " `NA`" ,
67- integer = " an integer `NA`" ,
68- double =
69- if (is.nan(x )) {
70- " `NaN`"
71- } else {
72- " a numeric `NA`"
69+ if (! n_dim ) {
70+ if (! is_list(x ) && length(x ) == 1 ) {
71+ if (is_na(x )) {
72+ return (switch (
73+ typeof(x ),
74+ logical = " `NA`" ,
75+ integer = " an integer `NA`" ,
76+ double =
77+ if (is.nan(x )) {
78+ " `NaN`"
79+ } else {
80+ " a numeric `NA`"
81+ },
82+ complex = " a complex `NA`" ,
83+ character = " a character `NA`" ,
84+ .rlang_stop_unexpected_typeof(x )
85+ ))
86+ }
87+
88+ show_infinites <- function (x ) {
89+ if (x > 0 ) {
90+ " `Inf`"
91+ } else {
92+ " `-Inf`"
93+ }
94+ }
95+ str_encode <- function (x , width = 30 , ... ) {
96+ if (nchar(x ) > width ) {
97+ x <- substr(x , 1 , width - 3 )
98+ x <- paste0(x , " ..." )
99+ }
100+ encodeString(x , ... )
101+ }
102+
103+ if (value ) {
104+ if (is.numeric(x ) && is.infinite(x )) {
105+ return (show_infinites(x ))
106+ }
107+
108+ if (is.numeric(x ) || is.complex(x )) {
109+ number <- as.character(round(x , 2 ))
110+ what <- if (is.complex(x )) " the complex number" else " the number"
111+ return (paste(what , number ))
112+ }
113+
114+ return (switch (
115+ typeof(x ),
116+ logical = if (x ) " `TRUE`" else " `FALSE`" ,
117+ character = {
118+ what <- if (nzchar(x )) " the string" else " the empty string"
119+ paste(what , str_encode(x , quote = " \" " ))
73120 },
74- complex = " a complex `NA`" ,
75- character = " a character `NA`" ,
76- .rlang_stop_unexpected_typeof(x )
77- ))
78- }
79- if (length(x ) == 1 && ! is_list(x )) {
121+ raw = paste(" the raw value" , as.character(x )),
122+ .rlang_stop_unexpected_typeof(x )
123+ ))
124+ }
125+
80126 return (switch (
81127 typeof(x ),
82- logical = if ( x ) " `TRUE` " else " `FALSE` " ,
128+ logical = " a logical value " ,
83129 integer = " an integer" ,
84- double =
85- if (is.infinite(x )) {
86- if (x > 0 ) {
87- " `Inf`"
88- } else {
89- " `-Inf`"
90- }
91- } else {
92- " a number"
93- },
130+ double = if (is.infinite(x )) show_infinites(x ) else " a number" ,
94131 complex = " a complex number" ,
95- character = if (nzchar(x )) " a string" else " ` \"\" ` " ,
132+ character = if (nzchar(x )) " a string" else " \"\" " ,
96133 raw = " a raw value" ,
97134 .rlang_stop_unexpected_typeof(x )
98135 ))
99136 }
137+
100138 if (length(x ) == 0 ) {
101139 return (switch (
102140 typeof(x ),
@@ -112,19 +150,29 @@ obj_type_friendly <- function(x, value = TRUE, length = FALSE) {
112150 }
113151 }
114152
115- type <- .rlang_as_friendly_vector_type(typeof(x ), n_dim )
153+ vec_type_friendly(x )
154+ }
116155
117- if (length && ! n_dim ) {
118- type <- paste0(type , sprintf(" of length %s" , length(x )))
156+ vec_type_friendly <- function (x , length = FALSE ) {
157+ if (! is_vector(x )) {
158+ abort(" `x` must be a vector." )
119159 }
160+ type <- typeof(x )
161+ n_dim <- length(dim(x ))
120162
121- type
122- }
163+ add_length <- function (type ) {
164+ if (length && ! n_dim ) {
165+ paste0(type , sprintf(" of length %s" , length(x )))
166+ } else {
167+ type
168+ }
169+ }
123170
124- .rlang_as_friendly_vector_type <- function (type , n_dim ) {
125171 if (type == " list" ) {
126172 if (n_dim < 2 ) {
127- return (" a list" )
173+ return (add_length(" a list" ))
174+ } else if (is.data.frame(x )) {
175+ return (" a data frame" )
128176 } else if (n_dim == 2 ) {
129177 return (" a list matrix" )
130178 } else {
@@ -151,7 +199,13 @@ obj_type_friendly <- function(x, value = TRUE, length = FALSE) {
151199 } else {
152200 kind <- " array"
153201 }
154- sprintf(type , kind )
202+ out <- sprintf(type , kind )
203+
204+ if (n_dim > = 2 ) {
205+ out
206+ } else {
207+ add_length(out )
208+ }
155209}
156210
157211.rlang_as_friendly_type <- function (type ) {
@@ -222,6 +276,7 @@ obj_type_oo <- function(x) {
222276# ' @param what The friendly expected type as a string. Can be a
223277# ' character vector of expected types, in which case the error
224278# ' message mentions all of them in an "or" enumeration.
279+ # ' @param show_value Passed to `value` argument of `obj_type_friendly()`.
225280# ' @param ... Arguments passed to [abort()].
226281# ' @inheritParams args_error_context
227282# ' @noRd
@@ -230,6 +285,7 @@ stop_input_type <- function(x,
230285 ... ,
231286 allow_na = FALSE ,
232287 allow_null = FALSE ,
288+ show_value = TRUE ,
233289 arg = caller_arg(x ),
234290 call = caller_env()) {
235291 # From compat-cli.R
@@ -254,7 +310,7 @@ stop_input_type <- function(x,
254310 " %s must be %s, not %s." ,
255311 cli $ format_arg(arg ),
256312 what ,
257- obj_type_friendly(x )
313+ obj_type_friendly(x , value = show_value )
258314 )
259315
260316 abort(message , ... , call = call , arg = arg )
0 commit comments