From ee35980ce1f127ac8f757e6d193091e89eb22f74 Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Sat, 2 Jan 2021 02:29:55 +0100 Subject: [PATCH 01/11] search registered S3 method for melt generic --- R/fmelt.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/fmelt.R b/R/fmelt.R index 12dd9fa5ac..9cb377108e 100644 --- a/R/fmelt.R +++ b/R/fmelt.R @@ -4,9 +4,9 @@ # redirection as well melt <- function(data, ..., na.rm = FALSE, value.name = "value") { - if (is.data.table(data)) { + if (inherits(data, sub("melt\\.", "", as.character(methods(melt))))) { UseMethod("melt", data) - # if data is not data.table and reshape2 is installed, this won't dispatch to reshape2's method; + # if no method is registered for data and reshape2 is installed, this won't dispatch to reshape2's method; # CRAN package edarf and others fail without the else branch # nocov start } else { From 279637179406401961a9d4f72b3b6cab43057fb7 Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Sat, 2 Jan 2021 06:41:48 +0100 Subject: [PATCH 02/11] redirect to reshape2 in melt.default --- R/fmelt.R | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/R/fmelt.R b/R/fmelt.R index 9cb377108e..16ca96699b 100644 --- a/R/fmelt.R +++ b/R/fmelt.R @@ -3,19 +3,19 @@ # reshape2 package is deprecated since December 2017, so we'll deprecate our # redirection as well -melt <- function(data, ..., na.rm = FALSE, value.name = "value") { - if (inherits(data, sub("melt\\.", "", as.character(methods(melt))))) { - UseMethod("melt", data) - # if no method is registered for data and reshape2 is installed, this won't dispatch to reshape2's method; - # CRAN package edarf and others fail without the else branch +melt = function(data, ..., na.rm = FALSE, value.name = "value") { + 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) - stop("The melt generic in data.table has been passed a ",class(data)[1L],", but data.table::melt currently only has a method for data.tables. Please confirm your input is a data.table, with setDT(", data_name, ") or as.data.table(", data_name, "). If you intend to use a method from reshape2, try installing that package first, but do note that reshape2 is deprecated and you should be migrating your code away from using it.")) - warning("The melt generic in data.table has been passed a ", class(data)[1L], " and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is deprecated, and this redirection is now deprecated as well. To continue using melt methods from reshape2 while both libraries are attached, e.g. melt.list, you can prepend the namespace like reshape2::melt(", data_name, "). In the next version, this warning will become an error.") - ns$melt(data, ..., na.rm=na.rm, value.name=value.name) - } + data_name = deparse(substitute(data)) + ns = tryCatch(getNamespace("reshape2"), error=function(e) + stop("The melt generic in data.table has been passed a ", class(data)[1L],", but data.table::melt currently only has a method for data.tables. Please confirm your input is a data.table, with setDT(", data_name, ") or as.data.table(", data_name, "). If you intend to use a method from reshape2, try installing that package first, but do note that reshape2 is deprecated and you should be migrating your code away from using it.")) + warning("The melt generic in data.table has been passed a ", class(data)[1L], " and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is deprecated, and this redirection is now deprecated as well. To continue using melt methods from reshape2 while both libraries are attached, e.g. melt.list, you can prepend the namespace like reshape2::melt(", data_name, "). In the next version, this warning will become an error.") + ns$melt(data, ..., na.rm=na.rm, value.name=value.name) # nocov end } From cfed0a485d1a92325991ba9fa0693b44f4e9bd13 Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Sat, 2 Jan 2021 06:42:37 +0100 Subject: [PATCH 03/11] redirect to reshape2 in melt.default --- NAMESPACE | 1 + 1 file changed, 1 insertion(+) diff --git a/NAMESPACE b/NAMESPACE index 57271aa04d..93aae7769c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -120,6 +120,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 From 8c505c511106efdae7ee65bf9c4c97d72e85efb4 Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Thu, 8 Apr 2021 09:45:51 +0200 Subject: [PATCH 04/11] Update tests.Rraw --- inst/tests/tests.Rraw | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 8f32278523..eaad1e0bc0 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -3190,6 +3190,10 @@ 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 + test(1038.001, 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 From ea657daa9b127aabc3567a74e4933376d021cd8b Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Thu, 8 Apr 2021 09:46:29 +0200 Subject: [PATCH 05/11] Update NEWS.md --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3db78f46c9..beaea2ecb6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -23,6 +23,8 @@ nafill(x, fill=3.14) # warns that precision has been lost nafill(x, fill=as.integer(3.14)) # no warning; the as. conveys intent ``` + +2. `melt` is now a generic function and will dispatch to `melt.data.table` for `data.table` objects [#3594](https://github.com/Rdatatable/data.table/pull/4864). For non-`data.table` object, the default method attempts to redirect towards `reshape2` methods. This change has no effect for users but enable the development of `melt` methods in other packages. Thanks to @odelmarcelle for suggesting the change. # data.table [v1.14.0](https://github.com/Rdatatable/data.table/milestone/23?closed=1) (21 Feb 2021) From fa0ba876bee6389f395b1c90e9ecda275273066a Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Thu, 8 Apr 2021 10:30:54 +0200 Subject: [PATCH 06/11] Update tests.Rraw --- inst/tests/tests.Rraw | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index eaad1e0bc0..d9a41939a1 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -3191,9 +3191,9 @@ Sep,33.5,19.4,15.7,11.9,0,100.8,100.8,0,12.7,12.7,0,174.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 + # 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), 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") + error="The melt generic in data.table has been passed a data.frame") } # sorting and grouping of Inf, -Inf, NA and NaN, #117, #112 & #105 From a2b8874f555de5eb88638b3b74026f03dcf0ee09 Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Thu, 8 Apr 2021 11:17:24 +0200 Subject: [PATCH 07/11] Update tests.Rraw --- inst/tests/tests.Rraw | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index d9a41939a1..fccb9380e2 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -3192,8 +3192,13 @@ Sep,33.5,19.4,15.7,11.9,0,100.8,100.8,0,12.7,12.7,0,174.1") 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), as.data.frame(melt(DT, id.vars=1:2, measure.vars=5:6)), + 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 From 40b3691bb7dee1d967abba2f9070d4d363100beb Mon Sep 17 00:00:00 2001 From: odelmarcelle <66041410+odelmarcelle@users.noreply.github.com> Date: Thu, 8 Apr 2021 11:18:54 +0200 Subject: [PATCH 08/11] Update NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index beaea2ecb6..6efa831d42 100644 --- a/NEWS.md +++ b/NEWS.md @@ -24,7 +24,7 @@ nafill(x, fill=as.integer(3.14)) # no warning; the as. conveys intent ``` -2. `melt` is now a generic function and will dispatch to `melt.data.table` for `data.table` objects [#3594](https://github.com/Rdatatable/data.table/pull/4864). For non-`data.table` object, the default method attempts to redirect towards `reshape2` methods. This change has no effect for users but enable the development of `melt` methods in other packages. Thanks to @odelmarcelle for suggesting the change. +2. `melt` is now a generic function and will dispatch to `melt.data.table` for `data.table` objects [#4864](https://github.com/Rdatatable/data.table/pull/4864). For non-`data.table` object, the default method attempts to redirect towards `reshape2` methods. This change has no effect for users but enable the development of `melt` methods in other packages. Thanks to @odelmarcelle for suggesting the change. # data.table [v1.14.0](https://github.com/Rdatatable/data.table/milestone/23?closed=1) (21 Feb 2021) From 38fec8173d336501d79d420f7ff027df04be645f Mon Sep 17 00:00:00 2001 From: Matt Dowle Date: Thu, 19 Aug 2021 01:28:36 -0600 Subject: [PATCH 09/11] I missed a paren when merging --- R/fmelt.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/fmelt.R b/R/fmelt.R index d4e8a3ff01..243480445b 100644 --- a/R/fmelt.R +++ b/R/fmelt.R @@ -13,7 +13,7 @@ melt.default = function(data, ..., na.rm = FALSE, value.name = "value") { # nocov start 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) + 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 From 82ee4f79b0f94c97231d17de9496cc68e08fb10f Mon Sep 17 00:00:00 2001 From: Matt Dowle Date: Thu, 19 Aug 2021 01:54:37 -0600 Subject: [PATCH 10/11] news item tweak --- NEWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 89f498e3ca..48192c232b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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. @@ -188,8 +190,6 @@ nafill(x, fill=3.14) # warns that precision has been lost nafill(x, fill=as.integer(3.14)) # no warning; the as. conveys intent ``` - -2. `melt` is now a generic function and will dispatch to `melt.data.table` for `data.table` objects [#4864](https://github.com/Rdatatable/data.table/pull/4864). For non-`data.table` object, the default method attempts to redirect towards `reshape2` methods. This change has no effect for users but enable the development of `melt` methods in other packages. Thanks to @odelmarcelle for suggesting the change. 2. `CsubsetDT` exported C function has been renamed to `DT_subsetDT`. This requires `R_GetCCallable("data.table", "CsubsetDT")` to be updated to `R_GetCCallable("data.table", "DT_subsetDT")`. Additionally there is now a dedicated header file for data.table C exports `include/datatableAPI.h`, [#4643](https://github.com/Rdatatable/data.table/issues/4643), thanks to @eddelbuettel, which makes it easier to _import_ data.table C functions. From f06bbc5993fd0c395ad5f82fd2e416b36a5a7fcf Mon Sep 17 00:00:00 2001 From: Matt Dowle Date: Thu, 19 Aug 2021 02:14:53 -0600 Subject: [PATCH 11/11] add to contributor list --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b8439044c9..69e1eb9147 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -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