我正在做一个数据操作包,它在引擎盖下使用了一些其他的库。假设我的数据总是有一个类"custom"
,我有一个函数custom_select()
来选择一些列。
我希望我的包有很少的依赖,但也有类似的语法从dplyr
的函数。因为有几个dplyr
函数是泛型,所以我可以对不同的输入类型使用相同的函数名。在我的情况下,我可以创建一个方法select.custom()
,这样用户就可以将data.frame
或custom
对象传递给select()
,两者都可以工作。
现在,根据我的理解,这需要将dplyr
放在Imports
中,因为我需要访问它的select()
泛型。我想避免这样做,因为我想限制硬依赖的数量。
我想到的场景是:
- 用户已经加载了
dplyr
,那么他们可以使用select()
和类custom
的数据,它应该工作 - 用户没有安装/加载
dplyr
,我不想强迫他们安装/加载,所以他们可以使用custom_select()
函数。
理想情况下,我想把dplyr
放在Suggests
中,这样就不是绝对必要的,但如果用户有它,它会增加一些东西。
示例
custom.R
:
#' @export
#' @importFrom dplyr select
custom_select <- function(data, select) {
print("Hello, world!")
}
#' @export
select.custom <- custom_select
NAMESPACE
:
# Generated by roxygen2: do not edit by hand
export(custom_select)
export(select.custom)
importFrom(dplyr,select)
R CMD检查错误,如果我没有把dplyr
放在Imports
中,把它放在Suggests
中也不起作用(两种情况下都是相同的错误):
❯ checking package dependencies ... ERROR
Namespace dependency missing from DESCRIPTION Imports/Depends entries: 'dplyr'
综上所述,如果dplyr
的泛型可用的话,有没有一种方法可以让dplyr
摆脱硬依赖,同时仍然为dplyr
的泛型提供方法?
**编辑:**我尝试了@VonC的答案,但无法使其工作。在下面的示例中,dplyr
在我的自定义包之前加载,因此select.custom()
应该可用,但实际上不是:
library(dplyr, warn.conflicts = FALSE)
library(custompackage)
foo <- letters
class(foo) <- "custom"
custom_select(foo)
#> [1] "Hello, world!"
select(foo)
#> Error in UseMethod("select"): no applicable method for 'select' applied to an object of class "custom"
以下是重要文件:custom.R
#' @export
custom_select <- function(data, select) {
print("Hello, world!")
}
if (requireNamespace("dplyr", quietly = TRUE)) {
select.custom <- function(data, select) {
custom_select(data, select)
}
utils::globalVariables("select.custom")
}
NAMESPACE
# Generated by roxygen2: do not edit by hand
export(custom_select)
DESCRIPTION
(无Imports
)
[...]
Suggests:
dplyr
2条答案
按热度按时间h9a6wy2h1#
你需要把dplyr放在
Enhances
中,然后使用.onLoad
在dplyr命名空间中有条件地注册你的方法,具体取决于dplyr是否在 load time 时安装。相关输出:
pbgvytdp2#
你可以通过在if语句中定义方法来检查包是否可用,并使用
utils::globalVariables()
来避免R CMD检查未定义的全局函数或变量。通常不允许改变另一个包的命名空间according to CRAN policies,并且尝试直接将函数分配给
dplyr::select.custom
可能是不可接受的。因此,我们的想法是在全局环境中将该方法分配给
select.custom
,这将允许它在加载dplyr
时用作通用select()
函数的方法。关键点是您没有直接修改dplyr
名称空间。您需要调整
custom.R
文件:对于
NAMESPACE
文件,您可以避免从dplyr
导入任何内容:在
DESCRIPTION
文件中,您应该在Suggests
下列出dplyr
:这样,如果用户加载了
dplyr
,则select.custom
方法将可用。如果未加载dplyr
,用户仍然可以使用custom_select()
功能。这种方法将dplyr
排除在硬依赖项之外,同时仍然为dplyr
的泛型提供方法(如果可用的话)。这将在包的命名空间中创建一个函数
select.custom
,当dplyr
包加载时,该函数将用作select()
的方法。请注意,这不会修改dplyr
名称空间本身。另外,最好说明
select.custom
功能只有在安装并加载了dplyr
时才可用,并且dplyr
是建议的依赖项,而不是必需的。在
DESCRIPTION
文件中,您应该在Suggests
下列出dplyr
:这种方法应该符合CRAN策略,因为您不会更改另一个包的名称空间,并且是基于
dplyr
包的可用性有条件地定义方法。话虽如此,Mikael Jagan在“编写R扩展/创建R包/包结构/包依赖/建议的包”的评论中指出
警告:如果你做的事情会在安装时运行,这取决于建议的软件包是否可用,这包括R代码文件中的顶级代码,
.onLoad
函数以及S4类和方法的定义,请非常小心。问题是,一旦加载了建议的包的命名空间,对它的引用可能会在安装的包中捕获(最常见的是在S4方法中),但是当使用安装的包时,建议的包可能不可用(特别是对于二进制包可能在不同的机器上)。
更糟糕的是,问题可能不仅限于您的包,因为您建议的包的名称空间也会在任何导入您的包的包安装时加载,因此可能会在那里被捕获。