@@ -458,18 +458,50 @@ validate_subclass <- function(x, subclass,
458458
459459 if (inherits(x , subclass )) {
460460 return (x )
461- } else if (is_scalar_character(x )) {
462- name <- paste0(subclass , camelize(x , first = TRUE ))
463- obj <- find_global(name , env = env )
461+ }
462+ if (! is_scalar_character(x )) {
463+ stop_input_type(x , as_cli(" either a string or a {.cls {subclass}} object" ), arg = x_arg )
464+ }
464465
465- if (is.null(obj ) || ! inherits(obj , subclass )) {
466- cli :: cli_abort(" Can't find {argname} called {.val {x}}." , call = call )
467- }
466+ # Try getting class object directly
467+ name <- paste0(subclass , camelize(x , first = TRUE ))
468+ obj <- find_global(name , env = env )
469+ if (inherits(obj , subclass )) {
470+ return (obj )
471+ }
472+
473+ # Try retrieving class via constructors
474+ name <- snakeize(name )
475+ obj <- find_global(name , env = env , mode = " function" )
476+ if (is.function(obj )) {
477+ obj <- try_fetch(
478+ obj(),
479+ error = function (cnd ) {
480+ # replace `obj()` call with name of actual constructor
481+ cnd $ call <- call(name )
482+ cli :: cli_abort(
483+ " Failed to retrieve a {.cls {subclass}} object from {.fn {name}}." ,
484+ parent = cnd , call = call
485+ )
486+ })
487+ }
488+ # Position constructors return classes directly
489+ if (inherits(obj , subclass )) {
490+ return (obj )
491+ }
492+ # Try prying the class from a layer
493+ if (inherits(obj , " Layer" )) {
494+ obj <- switch (
495+ subclass ,
496+ Geom = obj $ geom ,
497+ Stat = obj $ stat ,
498+ NULL
499+ )
500+ }
501+ if (inherits(obj , subclass )) {
468502 return (obj )
469- } else if (is.null(x )) {
470- cli :: cli_abort(" The {.arg {x_arg}} argument cannot be empty." , call = call )
471503 }
472- stop_input_type( x , as_cli( " either a string or a {.cls {subclass}} object " ) )
504+ cli :: cli_abort( " Can't find {argname} called {.val {x}}. " , call = call )
473505}
474506
475507# helper function to adjust the draw_key slot of a geom
0 commit comments