tools.cli

Support multiple validations

Details

  • Type: Enhancement Enhancement
  • Status: Open Open
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

In many cases, I have input arguments where I want to perform multiple validations, and return different error messages based upon that. Would it be reasonable to have multiple validation functions, or being able to have a validation function returning nil if no errors exists, and an error string if not?

If this seems like an interesting idea, I believe that the easiest and simplest solution would be to support a single validation function returning the actual error message. The reationale for this is that multiple validations may require a complex rule system (ordering? should it short-circuit, or should it return multiple error messages?), and as such, it's better to have those rules evident in the validation function.

Activity

Hide
Sung Pae added a comment -

My apologies for this delayed response. I thought that I would be emailed on creation of new issues, but this does not appear to be the case. This is the second time this has happened, so I will clearly have to rig something up to keep on top of this board.

> In many cases, I have input arguments where I want to perform multiple validations, and return different error messages based upon that. Would it be reasonable to have multiple validation functions, or being able to have a validation function returning nil if no errors exists, and an error string if not?

> If this seems like an interesting idea, I believe that the easiest and simplest solution would be to support a single validation function returning the actual error message. The reationale for this is that multiple validations may require a complex rule system (ordering? should it short-circuit, or should it return multiple error messages?), and as such, it's better to have those rules evident in the validation function.

The single largest reason I opted against implementing validations like this was that I dislike the corresponding linguistic and syntactic awkwardness of inverting the logic:

:validate [pred "Must satisfy pred"] ;; Error message is optional

vs

:validate #(when-not (pred %) "Must satisfy pred")

The first approach looks like a standard assertion, while the second requires an explicit branch and must return a truthy value to register a failure.¹

Now, the second example is more powerful for the reasons you outline, but since the vast majority of command line option arguments are semantically simple values such as numbers, filenames, and hostnames, I chose to optimize for the common case in order to have the terser syntax.

That said, I am happy to be convinced otherwise. Could you please provide an example of an option specification where returning different error messages for different failures is significantly better than something like the following?

["o" "-option EXAMPLE"
:validate [#(and (foo? %) (bar? %) (baz? %))
"Must be a foo that is also a bar and a baz"]]

I am currently of the mind that a per-option error summary is sufficient for an advanced user interface like the command line, and becomes complete with a link to a documentation URL (or man page).

Thank you.

¹ I usually name functions of the second type `validation-errors` instead of `validate` because I find this confusing:

(when-not (validate input) "This seems awkward.")

Show
Sung Pae added a comment - My apologies for this delayed response. I thought that I would be emailed on creation of new issues, but this does not appear to be the case. This is the second time this has happened, so I will clearly have to rig something up to keep on top of this board. > In many cases, I have input arguments where I want to perform multiple validations, and return different error messages based upon that. Would it be reasonable to have multiple validation functions, or being able to have a validation function returning nil if no errors exists, and an error string if not? > If this seems like an interesting idea, I believe that the easiest and simplest solution would be to support a single validation function returning the actual error message. The reationale for this is that multiple validations may require a complex rule system (ordering? should it short-circuit, or should it return multiple error messages?), and as such, it's better to have those rules evident in the validation function. The single largest reason I opted against implementing validations like this was that I dislike the corresponding linguistic and syntactic awkwardness of inverting the logic: :validate [pred "Must satisfy pred"] ;; Error message is optional vs :validate #(when-not (pred %) "Must satisfy pred") The first approach looks like a standard assertion, while the second requires an explicit branch and must return a truthy value to register a failure.¹ Now, the second example is more powerful for the reasons you outline, but since the vast majority of command line option arguments are semantically simple values such as numbers, filenames, and hostnames, I chose to optimize for the common case in order to have the terser syntax. That said, I am happy to be convinced otherwise. Could you please provide an example of an option specification where returning different error messages for different failures is significantly better than something like the following? ["o" "-option EXAMPLE" :validate [#(and (foo? %) (bar? %) (baz? %)) "Must be a foo that is also a bar and a baz"]] I am currently of the mind that a per-option error summary is sufficient for an advanced user interface like the command line, and becomes complete with a link to a documentation URL (or man page). Thank you. ¹ I usually name functions of the second type `validation-errors` instead of `validate` because I find this confusing: (when-not (validate input) "This seems awkward.")
Hide
Jean Niklas L'orange added a comment - - edited

Hello Sung,

No worries about the response time.

It's not necessarily the fact that it is more verbose, just that I would like to give good, descriptive error messages back. While it's easy for each of the different errors, I think it's better to say exactly what the problem is. For instance, if I want to take in an input directory path, I want to ensure that is is a legal path, and if the file already exists, it must be a directory:

["-i" "--input-directory DIR"
 :validate 
 #(if-not (ok-path? %)
    (format "Input directory path '%s' is malformed" %)
    (let [f (File. %)]
      (if (and (.exists f) (not (.isDirectory f)))
        (format "Input directory '%s' is a file, not a directory" %))))]

However, I can understand that such functionality can be a bit over the top for a CLI library. As long as you've compared/considered the different possibilities, I am content with whatever choice you take.

Show
Jean Niklas L'orange added a comment - - edited Hello Sung, No worries about the response time. It's not necessarily the fact that it is more verbose, just that I would like to give good, descriptive error messages back. While it's easy for each of the different errors, I think it's better to say exactly what the problem is. For instance, if I want to take in an input directory path, I want to ensure that is is a legal path, and if the file already exists, it must be a directory:
["-i" "--input-directory DIR"
 :validate 
 #(if-not (ok-path? %)
    (format "Input directory path '%s' is malformed" %)
    (let [f (File. %)]
      (if (and (.exists f) (not (.isDirectory f)))
        (format "Input directory '%s' is a file, not a directory" %))))]
However, I can understand that such functionality can be a bit over the top for a CLI library. As long as you've compared/considered the different possibilities, I am content with whatever choice you take.
Hide
Sung Pae added a comment - - edited

Saying yes to this kind of enhancement should be quite easy, but I only have a single reservation: adding a second type of validation function that is a logical inverse of the existing type seems confusing.

What do you think about using exceptions to carry error messages?

https://gist.github.com/guns/9065033
(gaah I don't know how to use JIRA at all)

The existing implementation already catches Exceptions, throws away the error message, and returns nil. This is more verbose than fn -> optarg -> nil | String, but it is aligned to the current logical convention.

Show
Sung Pae added a comment - - edited Saying yes to this kind of enhancement should be quite easy, but I only have a single reservation: adding a second type of validation function that is a logical inverse of the existing type seems confusing. What do you think about using exceptions to carry error messages? https://gist.github.com/guns/9065033 (gaah I don't know how to use JIRA at all) The existing implementation already catches Exceptions, throws away the error message, and returns nil. This is more verbose than fn -> optarg -> nil | String, but it is aligned to the current logical convention.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated: