mirror of
https://github.com/sensebox/opensensmapr
synced 2025-02-21 21:53:57 +01:00
move methods for external generics into one place
This commit is contained in:
parent
c89cd274a5
commit
80dc58a298
5 changed files with 128 additions and 123 deletions
|
@ -16,15 +16,6 @@ utc_date = function (date) {
|
||||||
# NOTE: cannot handle mixed vectors of POSIXlt and POSIXct
|
# NOTE: cannot handle mixed vectors of POSIXlt and POSIXct
|
||||||
date_as_isostring = function (date) format.Date(date, format = '%FT%TZ')
|
date_as_isostring = function (date) format.Date(date, format = '%FT%TZ')
|
||||||
|
|
||||||
#' Simple factory function meant to implement dplyr functions for other classes,
|
|
||||||
#' which call an callback to attach the original class again after the fact.
|
|
||||||
#'
|
|
||||||
#' @param callback The function to call after the dplyr function
|
|
||||||
#' @noRd
|
|
||||||
dplyr_class_wrapper = function(callback) {
|
|
||||||
function(.data, ..., .dots) callback(NextMethod())
|
|
||||||
}
|
|
||||||
|
|
||||||
#' Checks for an interactive session using interactive() and a knitr process in
|
#' Checks for an interactive session using interactive() and a knitr process in
|
||||||
#' the callstack. See https://stackoverflow.com/a/33108841
|
#' the callstack. See https://stackoverflow.com/a/33108841
|
||||||
#'
|
#'
|
||||||
|
|
|
@ -71,8 +71,6 @@ summary.sensebox = function(object, ...) {
|
||||||
invisible(object)
|
invisible(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
#
|
|
||||||
#' Converts a foreign object to a sensebox data.frame.
|
#' Converts a foreign object to a sensebox data.frame.
|
||||||
#' @param x A data.frame to attach the class to
|
#' @param x A data.frame to attach the class to
|
||||||
#' @export
|
#' @export
|
||||||
|
@ -81,39 +79,3 @@ osem_as_sensebox = function(x) {
|
||||||
class(ret) = c('sensebox', class(x))
|
class(ret) = c('sensebox', class(x))
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Return rows with matching conditions, while maintaining class & attributes
|
|
||||||
#' @param .data A sensebox data.frame to filter
|
|
||||||
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
|
||||||
#' @param ... other arguments
|
|
||||||
#' @seealso \code{\link[dplyr]{filter}}
|
|
||||||
filter.sensebox = dplyr_class_wrapper(osem_as_sensebox)
|
|
||||||
|
|
||||||
#' Add new variables to the data, while maintaining class & attributes
|
|
||||||
#' @param .data A sensebox data.frame to mutate
|
|
||||||
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
|
||||||
#' @param ... other arguments
|
|
||||||
#' @seealso \code{\link[dplyr]{mutate}}
|
|
||||||
mutate.sensebox = dplyr_class_wrapper(osem_as_sensebox)
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
#
|
|
||||||
#' maintains class / attributes after subsetting
|
|
||||||
#' @noRd
|
|
||||||
#' @export
|
|
||||||
`[.sensebox` = function(x, i, ...) {
|
|
||||||
s = NextMethod('[')
|
|
||||||
mostattributes(s) = attributes(s)
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
#
|
|
||||||
#' Convert a \code{sensebox} dataframe to an \code{\link[sf]{st_sf}} object.
|
|
||||||
#'
|
|
||||||
#' @param x The object to convert
|
|
||||||
#' @param ... maybe more objects to convert
|
|
||||||
#' @return The object with an st_geometry column attached.
|
|
||||||
st_as_sf.sensebox = function (x, ...) {
|
|
||||||
NextMethod(x, ..., coords = c('lon', 'lat'), crs = 4326)
|
|
||||||
}
|
|
||||||
|
|
126
R/external_generics.R
Normal file
126
R/external_generics.R
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
# helpers for the dplyr & co related functions
|
||||||
|
# also delayed method registration
|
||||||
|
#
|
||||||
|
# Methods for external generics (except when from `base`) should be registered,
|
||||||
|
# but not exported: see https://github.com/klutometis/roxygen/issues/796
|
||||||
|
# Until roxygen supports this usecase properly, we're using a different
|
||||||
|
# workaround than suggested, copied from edzer's sf package:
|
||||||
|
# dynamically register the methods only when the related package is loaded as well.
|
||||||
|
|
||||||
|
|
||||||
|
# ====================== base generics =========================
|
||||||
|
|
||||||
|
#' maintains class / attributes after subsetting
|
||||||
|
#' @noRd
|
||||||
|
#' @export
|
||||||
|
`[.sensebox` = function(x, i, ...) {
|
||||||
|
s = NextMethod('[')
|
||||||
|
mostattributes(s) = attributes(s)
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
#' maintains class / attributes after subsetting
|
||||||
|
#' @noRd
|
||||||
|
#' @export
|
||||||
|
`[.osem_measurements` = function(x, i, ...) {
|
||||||
|
s = NextMethod()
|
||||||
|
mostattributes(s) = attributes(x)
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ====================== dplyr generics =========================
|
||||||
|
|
||||||
|
#' Simple factory function meant to implement dplyr functions for other classes,
|
||||||
|
#' which call an callback to attach the original class again after the fact.
|
||||||
|
#'
|
||||||
|
#' @param callback The function to call after the dplyr function
|
||||||
|
#' @noRd
|
||||||
|
dplyr_class_wrapper = function(callback) {
|
||||||
|
function(.data, ..., .dots) callback(NextMethod())
|
||||||
|
}
|
||||||
|
|
||||||
|
#' Return rows with matching conditions, while maintaining class & attributes
|
||||||
|
#' @param .data A sensebox data.frame to filter
|
||||||
|
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
||||||
|
#' @param ... other arguments
|
||||||
|
#' @seealso \code{\link[dplyr]{filter}}
|
||||||
|
filter.sensebox = dplyr_class_wrapper(osem_as_sensebox)
|
||||||
|
|
||||||
|
#' Add new variables to the data, while maintaining class & attributes
|
||||||
|
#' @param .data A sensebox data.frame to mutate
|
||||||
|
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
||||||
|
#' @param ... other arguments
|
||||||
|
#' @seealso \code{\link[dplyr]{mutate}}
|
||||||
|
mutate.sensebox = dplyr_class_wrapper(osem_as_sensebox)
|
||||||
|
|
||||||
|
#' Return rows with matching conditions, while maintaining class & attributes
|
||||||
|
#' @param .data A osem_measurements data.frame to filter
|
||||||
|
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
||||||
|
#' @param ... other arguments
|
||||||
|
#' @seealso \code{\link[dplyr]{filter}}
|
||||||
|
filter.osem_measurements = dplyr_class_wrapper(osem_as_measurements)
|
||||||
|
|
||||||
|
#' Add new variables to the data, while maintaining class & attributes
|
||||||
|
#' @param .data A osem_measurements data.frame to mutate
|
||||||
|
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
||||||
|
#' @param ... other arguments
|
||||||
|
#' @seealso \code{\link[dplyr]{mutate}}
|
||||||
|
mutate.osem_measurements = dplyr_class_wrapper(osem_as_measurements)
|
||||||
|
|
||||||
|
|
||||||
|
# ====================== sf generics =========================
|
||||||
|
|
||||||
|
#' Convert a \code{sensebox} dataframe to an \code{\link[sf]{st_sf}} object.
|
||||||
|
#'
|
||||||
|
#' @param x The object to convert
|
||||||
|
#' @param ... maybe more objects to convert
|
||||||
|
#' @return The object with an st_geometry column attached.
|
||||||
|
st_as_sf.sensebox = function (x, ...) {
|
||||||
|
NextMethod(x, ..., coords = c('lon', 'lat'), crs = 4326)
|
||||||
|
}
|
||||||
|
|
||||||
|
#' Convert a \code{osem_measurements} dataframe to an \code{\link[sf]{st_sf}} object.
|
||||||
|
#'
|
||||||
|
#' @param x The object to convert
|
||||||
|
#' @param ... maybe more objects to convert
|
||||||
|
#' @return The object with an st_geometry column attached.
|
||||||
|
st_as_sf.osem_measurements = function (x, ...) {
|
||||||
|
NextMethod(x, ..., coords = c('lon', 'lat'), crs = 4326)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# from: https://github.com/tidyverse/hms/blob/master/R/zzz.R
|
||||||
|
# Thu Apr 19 10:53:24 CEST 2018
|
||||||
|
register_s3_method <- function(pkg, generic, class, fun = NULL) {
|
||||||
|
stopifnot(is.character(pkg), length(pkg) == 1)
|
||||||
|
stopifnot(is.character(generic), length(generic) == 1)
|
||||||
|
stopifnot(is.character(class), length(class) == 1)
|
||||||
|
|
||||||
|
if (is.null(fun)) {
|
||||||
|
fun <- get(paste0(generic, ".", class), envir = parent.frame())
|
||||||
|
} else {
|
||||||
|
stopifnot(is.function(fun))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg %in% loadedNamespaces()) {
|
||||||
|
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Always register hook in case package is later unloaded & reloaded
|
||||||
|
setHook(
|
||||||
|
packageEvent(pkg, "onLoad"),
|
||||||
|
function(...) {
|
||||||
|
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
.onLoad = function(libname, pkgname) {
|
||||||
|
register_s3_method('dplyr', 'filter', 'sensebox')
|
||||||
|
register_s3_method('dplyr', 'mutate', 'sensebox')
|
||||||
|
register_s3_method('dplyr', 'filter', 'osem_measurements')
|
||||||
|
register_s3_method('dplyr', 'mutate', 'osem_measurements')
|
||||||
|
register_s3_method('sf', 'st_as_sf', 'sensebox')
|
||||||
|
register_s3_method('sf', 'st_as_sf', 'osem_measurements')
|
||||||
|
}
|
|
@ -14,44 +14,11 @@ print.osem_measurements = function (x, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Converts a foreign object to an osem_measurements data.frame.
|
#' Converts a foreign object to an osem_measurements data.frame.
|
||||||
#' @param x A data.frame to attach the class to
|
#' @param x A data.frame to attach the class to.
|
||||||
|
#' Should have at least a `value` and `createdAt` column.
|
||||||
#' @export
|
#' @export
|
||||||
osem_as_measurements = function(x) {
|
osem_as_measurements = function(x) {
|
||||||
ret = tibble::as.tibble(x)
|
ret = tibble::as.tibble(x)
|
||||||
class(ret) = c('osem_measurements', class(ret))
|
class(ret) = c('osem_measurements', class(ret))
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Return rows with matching conditions, while maintaining class & attributes
|
|
||||||
#' @param .data A osem_measurements data.frame to filter
|
|
||||||
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
|
||||||
#' @param ... other arguments
|
|
||||||
#' @seealso \code{\link[dplyr]{filter}}
|
|
||||||
filter.osem_measurements = dplyr_class_wrapper(osem_as_measurements)
|
|
||||||
|
|
||||||
#' Add new variables to the data, while maintaining class & attributes
|
|
||||||
#' @param .data A osem_measurements data.frame to mutate
|
|
||||||
#' @param .dots see corresponding function in package \code{\link{dplyr}}
|
|
||||||
#' @param ... other arguments
|
|
||||||
#' @seealso \code{\link[dplyr]{mutate}}
|
|
||||||
mutate.osem_measurements = dplyr_class_wrapper(osem_as_measurements)
|
|
||||||
|
|
||||||
#' maintains class / attributes after subsetting
|
|
||||||
#' @noRd
|
|
||||||
#' @export
|
|
||||||
`[.osem_measurements` = function(x, i, ...) {
|
|
||||||
s = NextMethod()
|
|
||||||
mostattributes(s) = attributes(x)
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
#
|
|
||||||
#' Convert a \code{osem_measurements} dataframe to an \code{\link[sf]{st_sf}} object.
|
|
||||||
#'
|
|
||||||
#' @param x The object to convert
|
|
||||||
#' @param ... maybe more objects to convert
|
|
||||||
#' @return The object with an st_geometry column attached.
|
|
||||||
st_as_sf.osem_measurements = function (x, ...) {
|
|
||||||
NextMethod(x, ..., coords = c('lon', 'lat'), crs = 4326)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
# helpers for the dplyr & co related functions
|
|
||||||
# also custom method registration
|
|
||||||
|
|
||||||
# they need to be registered, but not exported, see https://github.com/klutometis/roxygen/issues/796
|
|
||||||
# we're using a different workaround than suggested, copied from edzer's sf package:
|
|
||||||
# dynamically register the methods only when the related package is loaded as well.
|
|
||||||
|
|
||||||
# from: https://github.com/tidyverse/hms/blob/master/R/zzz.R
|
|
||||||
# Thu Apr 19 10:53:24 CEST 2018
|
|
||||||
register_s3_method <- function(pkg, generic, class, fun = NULL) {
|
|
||||||
stopifnot(is.character(pkg), length(pkg) == 1)
|
|
||||||
stopifnot(is.character(generic), length(generic) == 1)
|
|
||||||
stopifnot(is.character(class), length(class) == 1)
|
|
||||||
|
|
||||||
if (is.null(fun)) {
|
|
||||||
fun <- get(paste0(generic, ".", class), envir = parent.frame())
|
|
||||||
} else {
|
|
||||||
stopifnot(is.function(fun))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg %in% loadedNamespaces()) {
|
|
||||||
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
|
||||||
}
|
|
||||||
|
|
||||||
# Always register hook in case package is later unloaded & reloaded
|
|
||||||
setHook(
|
|
||||||
packageEvent(pkg, "onLoad"),
|
|
||||||
function(...) {
|
|
||||||
registerS3method(generic, class, fun, envir = asNamespace(pkg))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
.onLoad = function(libname, pkgname) {
|
|
||||||
register_s3_method('dplyr', 'filter', 'sensebox')
|
|
||||||
register_s3_method('dplyr', 'mutate', 'sensebox')
|
|
||||||
register_s3_method('dplyr', 'filter', 'osem_measurements')
|
|
||||||
register_s3_method('dplyr', 'mutate', 'osem_measurements')
|
|
||||||
register_s3_method('sf', 'st_as_sf', 'sensebox')
|
|
||||||
register_s3_method('sf', 'st_as_sf', 'osem_measurements')
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue