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

Suggestion: cli_abort_if_not() #672

Open
wurli opened this issue Feb 21, 2024 · 3 comments
Open

Suggestion: cli_abort_if_not() #672

wurli opened this issue Feb 21, 2024 · 3 comments
Labels
feature a feature request or enhancement

Comments

@wurli
Copy link

wurli commented Feb 21, 2024

If I'm using cli in a package, often I avoid stopifnot() because the unformatted error messages feel jarring compared with those produced by cli_abort() and friends. I'm guessing cli has no stopifnot() equivalent because {rlang} doesn't have one either, but I would really like to see something like this added as I often just end up implementing it myself:

cli_abort_if_not <- function(..., .call = .envir, .envir = parent.frame(), .frame = .envir) {
  for (i in seq_len(...length())) {
    if (!all(...elt(i))) {
      cli::cli_abort(
        ...names()[i], 
        .call = .call, 
        .envir = .envir, 
        .frame = .frame
      )
    }
  }
  invisible(NULL)
}

cli_abort_if_not(
  "No problem" = TRUE,
  "Some {.emph important} issue" = FALSE,
  "Another issue" = FALSE
)
#> Error:
#> ! Some important issue
#> Backtrace:
#>     ▆
#>  1. └─global cli_abort_if_not(...)
#>  2.   └─cli::cli_abort(...)
#>  3.     └─rlang::abort(...)

Created on 2024-02-21 with reprex v2.0.2

Many thanks for all the work on this amazing package!

@wurli wurli changed the title Suggestion: cli_abortifnot() Suggestion: cli_abort_if_not() Feb 21, 2024
@JosiahParry
Copy link

I agree. I would love to see something like this made available in cli. stopifnot() simplifies the process of doing multiple validations for function arguments. The current way to achieve the same functionality with cli is to create multiple if statements which can become quite unruly.

Here for example is some cli I wrote today that migrates off of stopifnot()

if (!rlang::inherits_any(x, "data.frame")) {
  cli::cli_abort(
    "Expected {.cls data.frame} found {.obj_type_friendly {x}}",
    call = call
  )
} else if (!rlang::is_scalar_character(name)) {
  cli::cli_abort(
    "{.arg name} must be a scalar character vector.",
    call = call
  )
} else if (!rlang::is_scalar_character(title)) {
  cli::cli_abort(
    "{.arg title} must be a scalar character vector.",
    call = call
  )
} else if (!nzchar(name)) {
  cli::cli_abort(
    "{.arg name} must not be empty.",
    call = call
  )
} else if (!nzchar(title)) {
  cli::cli_abort(
    "{.arg name} must not be empty.",
    call = call
  )
}

If a cli_stopifnot() were made available it could look something like this instead which I think would be very nice!

cli_stopifnot(
  "Expected {.cls data.frame} found {class(x)}" = rlang::inherits_any(x, "data.frame"), 
  "{.arg name} must be a scalar character vector." = rlang::is_scalar_character(name),
  "{.arg title} must be a scalar character vector." = rlang::is_scalar_character(title),
  "{.arg name} must not be empty." = nzchar(name),
  "{.arg name} must not be empty." = nzchar(title),
  call = call
)

@wurli
Copy link
Author

wurli commented Feb 21, 2024

Worth noting that rlang has an open (albeit fairly old) issue about whether to implement something like this.

@gaborcsardi gaborcsardi added the feature a feature request or enhancement label Feb 21, 2024
@gaborcsardi
Copy link
Member

This is a good idea, and we might have something like this at some point, but not in the short term, unfortunately.

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

No branches or pull requests

3 participants