Skip to content

[Feature Request]: Use common check for parameters c(value, min, max) #685

Open
@averissimo

Description

@averissimo

Add an internal function to {tmg} that performs checks for numeric vectors that have the structure: c(value, min, max).

Some examples are plot_height, alpha, ...

The goal is to replace repetitive logic (represented in real examples from {tmg} below)

  checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE)
  checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height")
  
  # Identical to above, but it accepts null
  checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE)
  checkmate::assert_numeric(plot_width[1], lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width")

  # This accepts both `alpha = 0.5` and `c(0.5, 0, 1)`
  if (length(alpha) == 1) {
    checkmate::assert_numeric(alpha, any.missing = FALSE, finite = TRUE)
  } else {
    checkmate::assert_numeric(alpha, len = 3, any.missing = FALSE, finite = TRUE)
    checkmate::assert_numeric(alpha[1], lower = alpha[2], upper = alpha[3], .var.name = "alpha")
  }

With:

  checkmate::assert(check_range_slider(plot_height), .var.name = "plot_height")

  checkmate::assert(
    .var.name = "plot_width"
    check_range_slider(plot_width),
    checkmate::check_null(plot_width)
  )

  checkmate::assert(
    .var.name = "alpha"
    check_range_slider(alpha),
    checkmate::check_number(alpha)
  )

check_range_slider source

#' Check if an argument is a bounded numeric vector of length 3
#'
#' Must follow form `c(value, min, max)` and `test_fun` must be a function that
#' supports checks on vectorized input
#' @noRd
#'
check_range_slider <- function(value,
                               lower = -Inf,
                               upper = Inf,
                               finite = TRUE,
                               test_fun = checkmate::test_numeric) {
  checkmate::assert_flag(finite)
  checkmate::assert_function(test_fun)
  checkmate::assert_number(lower)
  checkmate::assert_number(upper)

  is_numeric <- test_fun(
    value,
    len = 3,
    any.missing = FALSE
  )

  # Finite is not available in integer tests
  if ("finite" %in% names(formals(test_fun))) {
    test_fun(value, finite = finite)
  }

  is_bounded <- is_numeric && test_fun(
    value[[1]],
    len = 1,
    lower = max(lower, value[[2]]),
    upper = min(upper, value[[3]])
  )
  if (isFALSE(is_numeric) || isFALSE(is_bounded)) {
    return(
      paste(
        "Must be a numeric vector of length 3 with `c(value, min, max)`",
        "where the `value` must be between `min` and `max`"
      )
    )
  }
  TRUE
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions