Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search registered S3 method for melt before redirecting to reshape2 #4864

Merged
merged 13 commits into from
Aug 19, 2021
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ Authors@R: c(
person("Hadley","Wickham", role="ctb"),
person("Bennet","Becker", role="ctb"),
person("Kyle","Haynes", role="ctb"),
person("Boniface Christian","Kamgang", role="ctb"))
person("Boniface Christian","Kamgang", role="ctb"),
person("Odel","Marcelle", role="ctb"))
Depends: R (>= 3.1.0)
Imports: methods
Suggests: bit64 (>= 4.0.0), bit (>= 4.0.4), curl, R.utils, xts, nanotime, zoo (>= 1.8-1), yaml, knitr, rmarkdown, markdown
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ S3method(split, data.table)
export(dcast, melt)
S3method(dcast, data.table)
S3method(melt, data.table)
S3method(melt, default)

# exported for historical reasons -- if reshape2 is higher on search path,
# dcast(DT) will not dispatch since reshape2::dcast is not generic. So users
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@

20. `dcast()` now supports complex values in `value.var`, [#4855](https://github.com/Rdatatable/data.table/issues/4855). This extends earlier support for complex values in `formula`. Thanks Elio Campitelli for the request, and Michael Chirico for the PR.

21. `melt()` was pseudo generic in that `melt(DT)` would dispatch to the `melt.data.table` method but `melt(not-DT)` would explicitly redirect to `reshape2`. Now `melt()` is standard generic so that methods can be developed in other packages, [#4864](https://github.com/Rdatatable/data.table/pull/4864). Thanks to @odelmarcelle for suggesting and implementing.

## BUG FIXES

1. `by=.EACHI` when `i` is keyed but `on=` different columns than `i`'s key could create an invalidly keyed result, [#4603](https://github.com/Rdatatable/data.table/issues/4603) [#4911](https://github.com/Rdatatable/data.table/issues/4911). Thanks to @myoung3 and @adamaltmejd for reporting, and @ColeMiller1 for the PR. An invalid key is where a `data.table` is marked as sorted by the key columns but the data is not sorted by those columns, leading to incorrect results from subsequent queries.
Expand Down
22 changes: 11 additions & 11 deletions R/fmelt.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
# redirection as well

melt = function(data, ..., na.rm = FALSE, value.name = "value") {
if (is.data.table(data)) {
UseMethod("melt", data)
# if data is not data.table and reshape2 is installed, this won't dispatch to reshape2's method;
# CRAN package edarf and others fail without the else branch
UseMethod("melt", data)
}

melt.default = function(data, ..., na.rm = FALSE, value.name = "value") {
# if no registered method exists for data, attempts to redirect data to reshape2::melt;
# CRAN package edarf and others fail without the redirection
# nocov start
} else {
data_name = deparse(substitute(data))
ns = tryCatch(getNamespace("reshape2"), error=function(e)
stopf("The %1$s generic in data.table has been passed a %2$s, but data.table::%1$s currently only has a method for data.tables. Please confirm your input is a data.table, with setDT(%3$s) or as.data.table(%3$s). If you intend to use a method from reshape2, try installing that package first, but do note that reshape2 is superseded and is no longer actively developed.", "melt", class(data)[1L], data_name))
warningf("The %1$s generic in data.table has been passed a %2$s and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is superseded and is no longer actively developed, and this redirection is now deprecated. Please do this redirection yourself like reshape2::%1$s(%3$s). In the next version, this warning will become an error.", "melt", class(data)[1L], data_name)
ns$melt(data, ..., na.rm=na.rm, value.name=value.name)
}
data_name = deparse(substitute(data))
ns = tryCatch(getNamespace("reshape2"), error=function(e)
stopf("The %1$s generic in data.table has been passed a %2$s, but data.table::%1$s currently only has a method for data.tables. Please confirm your input is a data.table, with setDT(%3$s) or as.data.table(%3$s). If you intend to use a method from reshape2, try installing that package first, but do note that reshape2 is superseded and is no longer actively developed.", "melt", class(data)[1L], data_name))
warningf("The %1$s generic in data.table has been passed a %2$s and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is superseded and is no longer actively developed, and this redirection is now deprecated. To continue using melt methods from reshape2 while both libraries are attached, e.g. melt.list, you can prepend the namespace, i.e. reshape2::%1$s(%3$s). In the next version, this warning will become an error.", "melt", class(data)[1L], data_name)
ns$melt(data, ..., na.rm=na.rm, value.name=value.name)
# nocov end
}

Expand Down
9 changes: 9 additions & 0 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -3256,6 +3256,15 @@ Sep,33.5,19.4,15.7,11.9,0,100.8,100.8,0,12.7,12.7,0,174.1")
x[ , r := as.raw(c(0, 1))]
test(1037.414, melt(x, id.vars='x1', measure.vars='r'),
error="Unknown column type 'raw' for column 'r'")

# test dispatch for non-data.table objects. See #4864. Only possible to test the error message on CI.
test(1038.001, melt(as.data.frame(DT), id.vars=1:2, measure.vars=5:6),
error="The melt generic in data.table has been passed a data.frame")

# uncomment 1038.002 and comment 1308.001 if reshape2 is ever available on CI.
# test(1038.002, melt(as.data.frame(DT), id.vars=1:2, measure.vars=5:6), as.data.frame(melt(DT, id.vars=1:2, measure.vars=5:6)),
# warning="The melt generic in data.table has been passed a data.frame")

}

# sorting and grouping of Inf, -Inf, NA and NaN, #117, #112 & #105
Expand Down