如何有条件地从另一个包中为 S3 泛型提供 S3 方法?

bre*_*auv 4 r r-s3 r-package

我正在制作一个数据操作包,它在幕后使用了一些其他库。假设我的数据总是有一个类"custom",并且我有一个custom_select()选择某些列的函数。

\n

我希望我的包具有很少的依赖项,但也具有与dplyr. 由于多个dplyr函数是泛型,因此我可以对不同的输入类型使用相同的函数名称。在我的情况下,我可以创建一个方法select.custom(),以便用户可以传递一个data.frame或一个custom对象select(),并且两者都可以工作。

\n

现在根据我的理解,这需要放入,dplyr因为Imports我需要访问它的select()泛型。我想避免这样做,因为我想限制硬依赖项的数量。

\n

我想到的场景是:

\n
    \n
  • 无论如何,用户已经加载dplyr,然后他们可以使用select()类的数据custom,它应该可以工作
  • \n
  • 用户没有dplyr安装/加载,我不想强​​迫他们拥有它,所以他们可以使用该功能custom_select()
  • \n
\n

理想情况下,我想把它放进dplyrSuggests,这样它就不是绝对必要的,但如果用户有的话它会添加一些东西。

\n
\n

例子

\n

custom.R

\n
#\' @export\n#\' @importFrom dplyr select\ncustom_select <- function(data, select) {\n  print("Hello, world!")\n}\n\n#\' @export\nselect.custom <- custom_select\n
Run Code Online (Sandbox Code Playgroud)\n

NAMESPACE

\n
# Generated by roxygen2: do not edit by hand\n\nexport(custom_select)\nexport(select.custom)\nimportFrom(dplyr,select)\n
Run Code Online (Sandbox Code Playgroud)\n

如果我不输入,R CMD 检查错误dplyrImports并且输入Suggests也不起作用(两种情况都有相同的错误):

\n
\xe2\x9d\xaf checking package dependencies ... ERROR\n  Namespace dependency missing from DESCRIPTION Imports/Depends entries: \'dplyr\'\n
Run Code Online (Sandbox Code Playgroud)\n
\n

总之,有没有一种方法可以避免dplyr硬依赖,同时仍然为dplyr\ 的泛型提供方法(如果可用)?

\n
\n
\n

编辑:我尝试了@VonC的答案,但无法使其工作。在下面的示例中,dplyr在我的自定义包之前加载,因此select.custom()应该可用,但不可用:

\n
# Generated by roxygen2: do not edit by hand\n\nexport(custom_select)\nexport(select.custom)\nimportFrom(dplyr,select)\n
Run Code Online (Sandbox Code Playgroud)\n

以下是重要文件:

\n

custom.R

\n
\xe2\x9d\xaf checking package dependencies ... ERROR\n  Namespace dependency missing from DESCRIPTION Imports/Depends entries: \'dplyr\'\n
Run Code Online (Sandbox Code Playgroud)\n

NAMESPACE

\n
# Generated by roxygen2: do not edit by hand\n\nexport(custom_select)\n
Run Code Online (Sandbox Code Playgroud)\n

DESCRIPTION(不Imports

\n
[...]\nSuggests:\n  dplyr\n
Run Code Online (Sandbox Code Playgroud)\n

Mik*_*gan 5

您需要放入dplyrEnhances使用它来有条件地在dplyr.onLoad命名空间中注册您的方法,具体取决于加载时是否安装了dplyr

\n
nm <- package <- "TestPackage"\ndir.create(file.path(package,     "R"), recursive = TRUE)\ndir.create(file.path(package,   "man"), recursive = TRUE)\ndir.create(file.path(package, "tests"), recursive = TRUE)\n\ncat(file = file.path(package, "DESCRIPTION"), "\nPackage: TestPackage\nVersion: 0.0-0\nLicense: GPL (>= 2)\nDescription: A (one paragraph) description of what\n  the package does and why it may be useful.\nTitle: My First Collection of Functions\nAuthor: First Last [aut, cre]\nMaintainer: First Last <First.Last@some.domain.net>\nEnhances: dplyr\n")\n\ncat(file = file.path(package, "NAMESPACE"), "\nexport(selectDotZzz)\n")\n\ncat(file = file.path(package, "R", paste0(nm, ".R")), "\nselectDotZzz <- function(.data, ...) 0\n.onLoad <- function(libname, pkgname) {\n    if(requireNamespace(\\"dplyr\\", quietly = TRUE))\n        registerS3method(\\"select\\", \\"zzz\\", selectDotZzz,\n                         envir = asNamespace(\\"dplyr\\"))\n}\n")\n\ncat(file = file.path(package, "man", paste0(nm, ".Rd")), "\n\\\\name{whatever}\n\\\\alias{selectDotZzz}\n\\\\title{whatever}\n\\\\description{whatever}\n")\n\ncat(file = file.path(package, "tests", paste0(nm, ".R")),\n    sprintf("library(%s)", nm))\ncat(file = file.path(package, "tests", paste0(nm, ".R")), append = TRUE, "\nif(requireNamespace(\\"dplyr\\", quietly = TRUE))\n    stopifnot(identical(dplyr::select(structure(0, class = \\"zzz\\")), 0))\n")\n\ngetRversion()\npackageVersion("dplyr")\ntools:::Rcmd(c("build", package))\ntools:::Rcmd(c("check", Sys.glob(paste0(nm, "_*.tar.gz"))))\n\nunlink(Sys.glob(paste0(nm, "*")), recursive = TRUE)\n
Run Code Online (Sandbox Code Playgroud)\n

相关输出:

\n
> getRversion()\n[1] \'4.3.1\'\n
Run Code Online (Sandbox Code Playgroud)\n
> packageVersion("dplyr")\n[1] \'1.1.2\'\n
Run Code Online (Sandbox Code Playgroud)\n
> tools:::Rcmd(c("build", package))\n* checking for file \'TestPackage/DESCRIPTION\' ... OK\n* preparing \'TestPackage\':\n* checking DESCRIPTION meta-information ... OK\n* checking for LF line-endings in source and make files and shell scripts\n* checking for empty or unneeded directories\n* building \'TestPackage_0.0-0.tar.gz\'\n
Run Code Online (Sandbox Code Playgroud)\n
> tools:::Rcmd(c("check", Sys.glob(paste0(nm, "_*.tar.gz"))))\n* using log directory \'/Users/mikael/Desktop/R-experiments/codetools/TestPackage.Rcheck\'\n* using R version 4.3.1 Patched (2023-06-19 r84580)\n* using platform: aarch64-apple-darwin22.5.0 (64-bit)\n* R was compiled by\n    Apple clang version 14.0.3 (clang-1403.0.22.14.1)\n    GNU Fortran (GCC) 12.2.0\n* running under: macOS Ventura 13.4\n* using session charset: UTF-8\n* checking for file \'TestPackage/DESCRIPTION\' ... OK\n* this is package \'TestPackage\' version \'0.0-0\'\n* checking package namespace information ... OK\n* checking package dependencies ... OK\n* checking if this is a source package ... OK\n* checking if there is a namespace ... OK\n* checking for executable files ... OK\n* checking for hidden files and directories ... OK\n* checking for portable file names ... OK\n* checking for sufficient/correct file permissions ... OK\n* checking whether package \'TestPackage\' can be installed ... OK\n* checking installed package size ... OK\n* checking package directory ... OK\n* checking DESCRIPTION meta-information ... OK\n* checking top-level files ... OK\n* checking for left-over files ... OK\n* checking index information ... OK\n* checking package subdirectories ... OK\n* checking R files for non-ASCII characters ... OK\n* checking R files for syntax errors ... OK\n* checking whether the package can be loaded ... OK\n* checking whether the package can be loaded with stated dependencies ... OK\n* checking whether the package can be unloaded cleanly ... OK\n* checking whether the namespace can be loaded with stated dependencies ... OK\n* checking whether the namespace can be unloaded cleanly ... OK\n* checking loading without being on the library search path ... OK\n* checking startup messages can be suppressed ... OK\n* checking dependencies in R code ... OK\n* checking S3 generic/method consistency ... OK\n* checking replacement functions ... OK\n* checking foreign function calls ... OK\n* checking R code for possible problems ... OK\n* checking Rd files ... OK\n* checking Rd metadata ... OK\n* checking Rd cross-references ... OK\n* checking for missing documentation entries ... OK\n* checking for code/documentation mismatches ... OK\n* checking Rd \\usage sections ... OK\n* checking Rd contents ... OK\n* checking for unstated dependencies in examples ... OK\n* checking examples ... NONE\n* checking for unstated dependencies in \'tests\' ... OK\n* checking tests ...\n  Running \xe2\x80\x98TestPackage.R\xe2\x80\x99\n OK\n* checking PDF version of manual ... OK\n* DONE\n\nStatus: OK\n\n
Run Code Online (Sandbox Code Playgroud)\n