diff --git a/R/helpers.R b/R/helpers.R index 67963a6..4baa37e 100644 --- a/R/helpers.R +++ b/R/helpers.R @@ -6,6 +6,11 @@ #' Provided for incompatible functions that do not preserve units. The user is #' responsible for ensuring the correctness of the output. #' +#' If \code{x} is not a \code{units} object +#' and \code{unit} is not provided by the user, +#' a warning is issued, and the output will also have no units +#' (see examples). +#' #' @param FUN the function to be applied. #' @param x first argument of \code{FUN}, of class \code{units}. #' @param ... optional arguments to \code{FUN}. @@ -17,9 +22,29 @@ #' x <- set_units(1:5, m) #' keep_units(drop_units, x) #' +#' # An example use case is with random number generating functions: +#' mu <- as_units(10, "years") +#' keep_units(rnorm, n = 1, x = mu) +#' +#' # units can be directly specified if needed; for example, with +#' # `rexp()`, the units of the rate parameter are the inverse of +#' # the units of the output: +#' rate <- as_units(3, "1/year") +#' keep_units(rexp, n = 1, x = rate, unit = units(1/rate)) +#' +#' # if `x` does not actually have units, a warning is issued, +#' # and the output has no units: +#' rate2 <- 3 +#' keep_units(rexp, n = 1, x = rate2) +#' #' @export keep_units <- function(FUN, x, ..., unit=units(x)) { - set_units(do.call(FUN, list(x, ...)), unit, mode="standard") + if (inherits(try(unit, silent = TRUE), "symbolic_units")) { + set_units(do.call(FUN, list(x, ...)), unit, mode = "standard") + } else { + warning("wrong `unit` specification.") + do.call(FUN, list(x, ...)) + } } dfapply <- function(X, FUN, ...) { diff --git a/man/keep_units.Rd b/man/keep_units.Rd index 7e7d4df..5b05a4e 100644 --- a/man/keep_units.Rd +++ b/man/keep_units.Rd @@ -25,9 +25,29 @@ the original units. \details{ Provided for incompatible functions that do not preserve units. The user is responsible for ensuring the correctness of the output. + +If \code{x} is not a \code{units} object +and \code{unit} is not provided by the user, +a warning is issued, and the output will also have no units +(see examples). } \examples{ x <- set_units(1:5, m) keep_units(drop_units, x) +# An example use case is with random number generating functions: +mu <- as_units(10, "years") +keep_units(rnorm, n = 1, x = mu) + +# units can be directly specified if needed; for example, with +# `rexp()`, the units of the rate parameter are the inverse of +# the units of the output: +rate <- as_units(3, "1/year") +keep_units(rexp, n = 1, x = rate, unit = units(1/rate)) + +# if `x` does not actually have units, a warning is issued, +# and the output has no units: +rate2 <- 3 +keep_units(rexp, n = 1, x = rate2) + } diff --git a/tests/testthat/test_helpers.R b/tests/testthat/test_helpers.R index 37b1d33..4bfff58 100644 --- a/tests/testthat/test_helpers.R +++ b/tests/testthat/test_helpers.R @@ -3,3 +3,18 @@ test_that("keep_units restores units", { expect_identical(x, keep_units(drop_units, x)) }) + +test_that("keep_units warns when no units are provided", { + x <- 1:5 + + expect_warning(keep_units(sum, x)) + + expect_identical(suppressWarnings(keep_units(sum, x)), sum(x)) +}) + +test_that("keep_units sets user-provided units", { + rate <- set_units(3, "1/min") + x <- keep_units(rexp, 3, rate, unit=units(1/rate)) + expect_identical(units(x), units(1/rate)) + +})