Allow returning a custom error message from Lambda Definitions
Closed this issue · 3 comments
If a Lambda definition fails then it currently returns a rather generic error message that only mentions the name of the lambda. This is not providing enough information to users to correct the bad input in some cases though. for example when building a definition that checks if a provided array includes only uniqe values then you might want to point out which value is not unique:
::Definition::Lambda(:unique_values) do |array|
next unless array.uniq.size == array.size
conform_with(array)
end
In this case something like this would be nice:
::Definition::Lambda(:unique_values) do |array|
duplicates = array.select{ |e| array.count(e) > 1 }.uniq
if duplicates.empty?
conform_with(array)
else
fail_with("Array contains duplicate values: #{duplicates.join(', ')}")
end
end
At the same time the version without fail_with
should still work
Other usecases that come to mind:
- An array needs to contain some specific items and you want to tell the user which ones are missing
- You do validation across multiple fields, e.g. If field A is present, then field B must be present as well
Imagine there's a party Definition
which requires
- unique guests lists (you don't want to send multiple invitations to the same recipient)
- unique gifts (since every guest should receive the unique present)
Assuming we make use of the unique_values
lambda you described above, a simple Definition
could look like this
party = Definition.Keys do
required :guests, unique_values
required :gifts, uniq_values
end
When I think of custom error messages in that party context, I would like to set the custom error messages on the Key level rather than the Lambda level:
party = Definition.Keys do
required :guests, unique_values(error_message: "No guest should receive multiple invitations")
required :gifts, uniq_values(error_message: "Don't give away the same present multiple times")
end
I like the way you proposed it on the Lambda level, but maybe configuring it on the Key level is also worth a consideration.
you can achieve such a multipurpose definition with this simple trick:
def UniqueArrayElements(error_message)
::Definition.Lambda do |array|
duplicates = array.select{ |e| array.count(e) > 1 }.uniq
if duplicates.empty?
conform_with(array)
else
fail_with(error_message)
end
end
end
party = Definition.Keys do
required :guests, UniqueArrayElements("No guest should receive multiple invitations")
required :gifts, UniqueArrayElements("Don't give away the same present multiple times")
end
error messages on a key level (as part of the keys definition) is hard because the definition behind the key could be a deeply nested composed definition. then you'd have the issue that all the sub errors and the custom error would need to be brought together somehow in a meaningful way