有人可以解释为什么 R 为该对象的超级 class 而不是子 class 调度 S3 方法吗?

Can someone explain why R dispatches the S3 method for this object's super class rather than the sub class?

在这个例子中,包命名空间和 S3 调度有一些我无法理解的微妙之处。对这个问题有深入了解的人可以用简单的术语向我解释一下,为什么 R 为这个对象调度 as.tags.htmlwidget 而不是 as.tags.rdeckControls

library(rdeck.controls) ##remotes::install_github("qfes/rdeck.controls")
library(htmltools)
library(sloop)
library(purrr)

foo_widget <-
  structure(list(x = list(targetRDeckId = "mitigation_activity",
    controlType = "dropdown", controlData = list(layerNames = c("Mitigation activity: All",
    "Mitigation activity: Community Education", "Mitigation activity: Fire Breaks or Trails",
    "Mitigation activity: Hazard Reduction"), layerGroupNames = character(0),
        initialSelection = "Mitigation activity: All", label = "")),
    width = "100%", height = "1em !important", sizingPolicy = list(
        defaultWidth = NULL, defaultHeight = NULL, padding = 
NULL,
        viewer = list(defaultWidth = NULL, defaultHeight = NULL,
            padding = NULL, fill = TRUE, suppress = FALSE, paneHeight = NULL),
        browser = list(defaultWidth = NULL, defaultHeight = NULL,
            padding = NULL, fill = FALSE, external = FALSE), 
        knitr = list(defaultWidth = NULL, defaultHeight = NULL,
            figure = TRUE)), dependencies = NULL, elementId = NULL,
    preRenderHook = NULL, jsHooks = list()), class = c("rdeckControls",
"htmlwidget"), package = "rdeck.controls")

methods("as.tags")
#>  [1] as.tags.character*          as.tags.default*           
#>  [3] as.tags.html*               as.tags.html_dependency*   
#>  [5] as.tags.htmlwidget*         as.tags.list*              
#>  [7] as.tags.rdeckControls       as.tags.shiny.tag*         
#>  [9] as.tags.shiny.tag.function* as.tags.shiny.tag.list*    
#> see '?methods' for accessing help and source code
s3_dispatch(as.tags(foo_widget))
#> => as.tags.rdeckControls
#>  * as.tags.htmlwidget
#>  * as.tags.default
error <- purrr::safely(function(x) as.tags(foo_widget))(foo_widget)
error
#> $result
#> NULL
#> 
#> $error
#> <simpleError in validateCssUnit(sizeInfo$height): "1em !important" is not a valid CSS unit (e.g., "100%", "400px", "auto")>
#
# this means as.tags.htmlWidget was run
#
str(as.tags.rdeckControls(foo_widget))
#> List of 3
#>  $ :List of 3
#>   ..$ : NULL
#>   ..$ :List of 3
#>   .. ..$ name    : chr "div"
#>   .. ..$ attribs :List of 3
#>   .. .. ..$ id   : chr "htmlwidget-debd00a6269d494de569"
#>   .. .. ..$ style: chr "width:100%;height:1em !important;"
#>   .. .. ..$ class: chr "rdeckControls html-widget"
#>   .. ..$ children: list()
#>   .. ..- attr(*, "class")= chr "shiny.tag"
#>   ..$ : NULL
#>   ..- attr(*, "class")= chr [1:2] "shiny.tag.list" "list"
#>  $ :List of 3
#>   ..$ name    : chr "script"
#>   ..$ attribs :List of 2
#>   .. ..$ type    : chr "application/json"
#>   .. ..$ data-for: chr "htmlwidget-debd00a6269d494de569"
#>   ..$ children:List of 1
#>   .. ..$ : 'html' chr "{\"x\":{\"targetRDeckId\":\"mitigation_activity\",\"controlType\":\"dropdown\",\"controlData\":{\"layerNames\":"| __truncated__
#>   .. .. ..- attr(*, "html")= logi TRUE
#>   ..- attr(*, "class")= chr "shiny.tag"
#>  $ : NULL
#>  - attr(*, "class")= chr [1:2] "shiny.tag.list" "list"
#>  - attr(*, "html_dependencies")=List of 2
#>   ..$ :List of 10
#>   .. ..$ name      : chr "htmlwidgets"
#>   .. ..$ version   : chr "1.5.3"
#>   .. ..$ src       :List of 1
#>   .. .. ..$ file: chr "C:/Users/msmcbain/libs/R/htmlwidgets/www"
#>   .. ..$ meta      : NULL
#>   .. ..$ script    : chr "htmlwidgets.js"
#>   .. ..$ stylesheet: NULL
#>   .. ..$ head      : NULL
#>   .. ..$ attachment: NULL
#>   .. ..$ package   : NULL
#>   .. ..$ all_files : logi TRUE
#>   .. ..- attr(*, "class")= chr "html_dependency"
#>   ..$ :List of 10
#>   .. ..$ name      : chr "rdeckControls-binding"
#>   .. ..$ version   : chr "0.2.0"
#>   .. ..$ src       :List of 1
#>   .. .. ..$ file: chr "C:/Users/msmcbain/libs/R/rdeck.controls/htmlwidgets"
#>   .. ..$ meta      : NULL
#>   .. ..$ script    : chr "rdeckControls.js"
#>   .. ..$ stylesheet: NULL
#>   .. ..$ head      : NULL
#>   .. ..$ attachment: NULL
#>   .. ..$ package   : NULL
#>   .. ..$ all_files : logi FALSE
#>   .. ..- attr(*, "class")= chr "html_dependency"
#>  - attr(*, "browsable_html")= logi TRUE
#
# This works if called directly
#
as.tags.rdeckControls <- function(x) as.character(x)
as.tags(foo_widget)
#> [1] "list(targetRDeckId = \"mitigation_activity\", controlType = \"dropdown\", controlData = list(layerNames = c(\"Mitigation activity: All\", \"Mitigation activity: Community Education\", \"Mitigation activity: Fire Breaks or Trails\", \"Mitigation activity: Hazard Reduction\"), layerGroupNames = character(0), initialSelection = \"Mitigation activity: All\", label = \"\"))"
#> [2] "100%"                                                                                                                                                                                                                                                                                                                                                                               
#> [3] "1em !important"                                                                                                                                                                                                                                                                                                                                                                     
#> [4] "list(defaultWidth = NULL, defaultHeight = NULL, padding = NULL, viewer = list(defaultWidth = NULL, defaultHeight = NULL, padding = NULL, fill = TRUE, suppress = FALSE, paneHeight = NULL), browser = list(defaultWidth = NULL, defaultHeight = NULL, padding = NULL, fill = FALSE, external = FALSE), knitr = list(defaultWidth = NULL, defaultHeight = NULL, figure = TRUE))"     
#> [5] "NULL"                                                                                                                                                                                                                                                                                                                                                                               
#> [6] "NULL"                                                                                                                                                                                                                                                                                                                                                                               
#> [7] "NULL"                                                                                                                                                                                                                                                                                                                                                                               
#> [8] "list()"
#
# and if defined locally

reprex package (v2.0.0)

于 2021-07-08 创建

您的 NAMESPACE 文件没有将该方法声明为 S3 方法。也不需要显式导出它(大多数 S3 方法不导出)。

所以而不是

export(as.tags.rdeckControls)

你应该

S3method(as.tags, rdeckControls)

roxygen 应该会在大部分时间为您解决这个问题。这里的问题可能是它无法分辨什么是函数名和什么是 class 因为函数名中有额外的 . 。你应该能够用

来消除歧义
@method as.tags rdeckControls

记录该功能时。