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

support shiny::validate(need()) type of validations #118

Open
maxheld83 opened this issue Aug 15, 2017 · 4 comments
Open

support shiny::validate(need()) type of validations #118

maxheld83 opened this issue Aug 15, 2017 · 4 comments

Comments

@maxheld83
Copy link

I think checkmate is a great standard for input validation, and I'd love to be able to also use it easily inside shiny.

Shiny has validate() for the purpose of validating inputs.
It accepts an arbitrary number of expressions which must evaluate to:

  1. NULL if the validation is successful,
  2. the error message as a string, if the object is invalid,
  3. FALSE if the validation itself fails (I'm a bit unclear on this one).

None of the checkmate family members fit right in here, but perhaps you guys could consider need_x() as a new family member.

My (bootstrapped) makeNeedFunction() looks like this:

makeNeedFunction <- function(check.fun) {
  function(x, ...) {
    if (is.null(x)) {
      return(FALSE)
    } else if (isTRUE(check.fun(x, ...))) {
      return(NULL)
    } else {
      return(check.fun(x, ...))
    }
  }
}

It works:

check_character(x = 1)
need_character <- makeNeedFunction(check.fun = check_character)
need_character(x = "a", min.chars = 2)

I'm aware that checkmate has a much superior design, but I got stuck trying to replicate it and don't know C, so I am worried a PR might be beyond my abilities.

Anyway, would you be be interested in such an extension?

I think it could make life a lot easier for shiny devs.

@mllg
Copy link
Owner

mllg commented Aug 18, 2017

Here is an example how to turn check functions into test functions: https://github.com/mllg/checkmate/blob/master/R/makeTest.R

No C required. A "need function" constructor would look something like this (w/o the third case which I don't get):

makeNeedFunction = function(check.fun, env = parent.frame()) {
  fn.name = if (!is.character(check.fun)) deparse(substitute(check.fun)) else check.fun
  check.fun = match.fun(check.fun)

  new.fun = function() TRUE
  formals(new.fun) = formals(check.fun)
  tmpl = "{ res = %s(%s); if (identical(res, TRUE)) NULL else res }"
  body(new.fun) = parse(text = sprintf(tmpl, fn.name, paste0(names(formals(check.fun)), collapse = ", ")))
  environment(new.fun) = env
  return(new.fun)
}

print(makeNeedFunction(checkCharacter))

I'll have a closer look if I find some spare time. But should be pretty straightforward to support.

@mllg
Copy link
Owner

mllg commented Sep 7, 2017

The third case would cover situations where the check* function fails because you've passed invalid arguments, like in

checkNames(letters, type = "notype")

Thus, the template should look like this:

tmpl = "{ 
  res = try(%s(%s), silent = TRUE); 
  if (inherits(res, "try-error")) return(FALSE); 
  if (identical(res, TRUE)) return(NULL); 
  return(res) 
}"

@danielinteractive
Copy link

This kind of validate*() functions would also be very helpful when working with S4 class validations.

@danielinteractive
Copy link

@mllg would you be open to PRs on the makeNeedFunction topic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants