defmodule Dsv.All do
use Dsv.Validator
@moduledoc """
`Dsv.All` validator provides functions to validate that all elements in the given `List` or `String` meets all validation criteria.
> #### Validate other types of data {: .tip}
>
> To validate arguments of other data types `FindAll` protocol must be implemented for this type.
"""
message("Not all elements match all validators.")
e_message("Not all elements match all validators.")
@doc """
Ensure that all validators pass the check for the given data.
In the case of a string, this validator will iterate through all graphemes and check if each one passes the validation for all validators.
In the case of a list, this validator will iterate through all elements in the list and check if each one passes the validation for all validators.
Returns `:true` if all validators pass for all elements; otherwise, returns `:false`.
## Example
iex> Dsv.All.valid?("abcd", format: ~r/^[a-z]$/, equal: "w")
:false
iex> Dsv.All.valid?("abcd", format: ~r/^[a-z]$/, equal: "a")
:false
iex> Dsv.All.valid?("abcd", format: ~r/^[a-d]$/, custom: &is_bitstring/1)
:true
iex> Dsv.All.valid?("abcd", format: ~r/^[a-c]$/, custom: &is_bitstring/1)
:false
iex> Dsv.All.valid?([1, 2, 3, "hello"], custom: &is_number/1, number: [gt: 2])
:false
iex> Dsv.All.valid?([1, 2, 3, "hello"], number: [gt: 0])
:false
iex> Dsv.All.valid?([1, 2, 3], custom: &is_number/1, number: [gte: 0, lte: 10])
:true
"""
def valid?(data, options),
do:
Iterable.iterate(data, :cont, fn elem ->
if Dsv.valid?(elem, options), do: :cont, else: :halt
end)
|> (&(elem(&1, 1) == :empty)).()
@doc """
Ensure that all validators pass the check for the given data.
In the case of a string, this validator will iterate through all graphemes and check if each one passes the validation for all validators.
In the case of a list, this validator will iterate through all elements in the list and check if each one passes the validation for all validators.
Returns `:ok` if all validators pass for all elements; otherwise, returns error tuple with the error message or custome message if provided.
## Options
* any validator name like
* `:format`
* `:custom`
* `:number`
* `:length`
* `:equal`
* `:data`
* `:message` - (EEx string) message used in error tuple in case of validation failure.
## Example
iex> Dsv.All.validate("abcd", format: ~r/^[a-z]$/, equal: "w")
{:error, "Not all elements match all validators."}
iex> Dsv.All.validate("abcd", format: ~r/^[a-z]$/, equal: "a")
{:error, "Not all elements match all validators."}
iex> Dsv.All.validate("abcd", format: ~r/^[a-d]$/, custom: &is_bitstring/1)
:ok
iex> Dsv.All.validate("abcd", format: ~r/^[a-c]$/, custom: &is_bitstring/1)
{:error, "Not all elements match all validators."}
iex> Dsv.All.validate([1, 2, 3, "hello"], custom: &is_number/1, number: [gt: 2])
{:error, "Not all elements match all validators."}
iex> Dsv.All.validate([1, 2, 3, "hello"], number: [gt: 0])
{:error, "Not all elements match all validators."}
iex> Dsv.All.validate([1, 2, 3], custom: &is_number/1, number: [gte: 0, lte: 10])
:ok
iex> Dsv.All.validate([1, 2, 3, "hello"], number: [gt: 0], format: ~r/^[a-z]$/)
{:error, "Not all elements match all validators."}
## Example with custom message
iex> Dsv.All.validate("abcd", format: ~r/^[a-z]$/, equal: "w", message: "All elements must be small letter 'w'.")
{:error, "All elements must be small letter 'w'."}
iex> Dsv.All.validate("abcd", format: ~r/^[a-z]$/, equal: "a", message: "All elements must be small letter 'a'.")
{:error, "All elements must be small letter 'a'."}
iex> Dsv.All.validate("abcd", format: ~r/^[a-d]$/, custom: &is_bitstring/1, message: "All elements must be one of the letter: 'a', 'b', 'c', 'd'.")
:ok
iex> Dsv.All.validate("abcd", format: ~r/^[a-c]$/, custom: &is_bitstring/1, message: "All elements must be one of the letter: 'a', 'b', 'c'.")
{:error, "All elements must be one of the letter: 'a', 'b', 'c'."}
iex> Dsv.All.validate([1, 2, 3, "hello"], custom: &is_number/1, number: [gt: 2], message: "All values must be a number greater that 2.")
{:error, "All values must be a number greater that 2."}
iex> Dsv.All.validate([1, 2, 3, "hello"], number: [gt: 0], message: "All values must be a number greater that 0.")
{:error, "All values must be a number greater that 0."}
iex> Dsv.All.validate([1, 2, 3], custom: &is_number/1, number: [gte: 0, lte: 10], message: "All values must be a number between 0 and 10.")
:ok
"""
def validate(data, options), do: super(data, options)
end