It should be possible to give rules a custom explanation.
Starting with considering the root, there is multiple ways to provide this syntactically, e.g.
// Option 1:
When("name", Is.Defined())
.Then(It, Must.Be.String() & Have.MaxLength(256), "when name is provided, name must be a string and be max 256 characters long");
// Option 2:
When("name", Is.Defined())
.Then(It, Must.Be.String() & Have.MaxLength(256))
.Explain("when name is provided, name must be a string and be max 256 characters long");
If possible, the ability to give partial explanations may also be interesting, here option 2 are probably likely to be easier to implement as it allows for a more generic pattern in general and wrapper rules etc.
This could then be allowed to use on any construct in the framework from a single constraint to grouped constraints, field rules and all the way up to the when.
// Option 1:
When("name", Is.Defined())
.Then(It, Must.Be.String() & Have.MaxLength(256, "max 256 characters"));
// Option 2:
When("name", Is.Defined())
.Then(It, Must.Be.String() & Have.MaxLength(256).Explain("max 256 characters"));
Although this raises the question on how these should interact with each other in cases where custom explains has been attacked both at a outer and inner level.
// Option 2:
When("name", Is.Defined())
.Then(It, Must.Be.String() & Have.MaxLength(256).Explain("max 256 characters"))
.Explain("must be a string and be max 256 characters long");
// ???
Another challenge is that we can actually rationalize about which rules we should display to the user during validations when it fails.
E.g. given the object: { name: "John", surname: "Doe", age: 500 }
When(Any)
.Then(Field("name", Must.Match("^[A-Za-z]*$")
& Field("surname", Must.Match("^[A-Za-z]*$")
& Field("age", Must.Be.Between(0, 150));
We can actually settle for displaying the failed "age" constraint rather than all of them, but this becomes tricky given a custom explanation. We can give a general rule that just says it will go as deep as it can until it hits a custom explanation and then it uses that, then the following would work reasonably:
When(Any)
.Then(Field("name", Must.Match("^[A-Za-z]*$")).Explain("name must consist of alphabetic characters only")
& Field("surname", Must.Match("^[A-Za-z]*$")).Explain("surname must consist of alphabetic characters only")
& Field("age", Must.Be.Between(0, 150)).Explain("age must be a positive number and max 150"));
It should be possible to give rules a custom explanation.
Starting with considering the root, there is multiple ways to provide this syntactically, e.g.
If possible, the ability to give partial explanations may also be interesting, here option 2 are probably likely to be easier to implement as it allows for a more generic pattern in general and wrapper rules etc.
This could then be allowed to use on any construct in the framework from a single constraint to grouped constraints, field rules and all the way up to the when.
Although this raises the question on how these should interact with each other in cases where custom explains has been attacked both at a outer and inner level.
Another challenge is that we can actually rationalize about which rules we should display to the user during validations when it fails.
E.g. given the object:
{ name: "John", surname: "Doe", age: 500 }We can actually settle for displaying the failed "age" constraint rather than all of them, but this becomes tricky given a custom explanation. We can give a general rule that just says it will go as deep as it can until it hits a custom explanation and then it uses that, then the following would work reasonably: