I'm making a package for data manipulation that uses some other libraries under the hood. Let's say that my data always has a class "custom" and that I have a function custom_select() to select some columns.
I would like my package to have few dependencies but also a similar syntax as functions from dplyr. Because several dplyr functions are generics, I can use the same function names for a different input type. In my situation, I could make a method select.custom() so that the user can either pass a data.frame or a custom object to select() and both would work.
Now from my understanding, this requires putting dplyr in Imports because I need to have access to its select() generic. I'd like to avoid doing this because I want to limit the number of hard dependencies.
The scenario I have in mind is:
- the user already loads
dplyranyway, then they can useselect()with the data of classcustomand it should work - the user doesn't have
dplyrinstalled/loaded, and I don't want to force them to have it, so they can use the functioncustom_select()instead.
Ideally, I'd like to put dplyr in Suggests so that it's not strictly necessary but it adds something if the user has it.
Example
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 check errors if I don't put dplyr in Imports and putting it in Suggests also doesn't work (same error for both cases):
❯ checking package dependencies ... ERROR
Namespace dependency missing from DESCRIPTION Imports/Depends entries: 'dplyr'
In summary, is there a way to keep dplyr out of hard dependencies while still providing methods for dplyr's generics if it is available?
Edit: I tried @VonC's answer but couldn't make it work. In the example below, dplyr is loaded before my custom package so select.custom() should be available but isn't:
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"
Here are the important files:
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 (no Imports)
[...]
Suggests:
dplyr
You need to put dplyr in
Enhancesand use.onLoadto conditionally register your method in the dplyr namespace, depending on whether dplyr is installed at load time.The relevant output: