defmodule Dsv.Length do
use Dsv.Validator
@moduledoc """
Dsv.Length module provides a functions to check if the length of an input value meets specified criteria.
Value can be of the type: `String`, `List`, `Map`, `Tuple`, `Integer`, `Float`. To use values of different type this type need to implement `DataLength` protocol.
"""
message({:min, "Value <%= inspect data %> is to short. Minimum lenght is <%= options[:min] %>"})
message({:max, "Value <%= inspect data %> is to long. Maximum length is <%= options[:max] %>"})
message(
{[:min, :max],
"Value <%= inspect data %> has wrong length. Minimum lenght is <%= options[:min] %>, maximum length is <%= options[:max] %>"}
)
message(
{:range,
"Value <%= inspect data %> has wrong length. Minimum lenght is <%= elem(options[:range], 0) %>, maximum length is <%= elem(options[:range], 1) %>"}
)
@doc """
The `valid?/2` function checks if the length of a given input value meets the specified criteria.
## Parameters
* `value` - The input value to be checked for length.
* `rules` - A list of validation rules. Each rule is represented as a keyword list containing:
- `:min` - The minimum allowed length.
- `:max` - The maximum allowed length.
- `:range` - A range of acceptable lengths.
## Returns
A boolean value:
- `true` if the length of `value` meets all of the specified criteria.
- `false` if the length of `value` does not meet any of the specified criteria.
## Examples
`:min` example:
iex> Dsv.Length.valid?("abcd", min: 3)
:true
iex> Dsv.Length.valid?("abcd", min: 4)
:true
iex> Dsv.Length.valid?("abcd", min: 5)
:false
`:max` example:
iex> Dsv.Length.valid?("ab", max: 3)
:true
iex> Dsv.Length.valid?("abcd", max: 4)
:true
iex> Dsv.Length.valid?("abcdef", max: 5)
:false
`:min & :max` example:
iex> Dsv.Length.valid?("abcd", min: 3, max: 5)
:true
iex> Dsv.Length.valid?("abcd", min: 4, max: 5)
:true
iex> Dsv.Length.valid?("abcd", min: 2, max: 4)
:true
iex> Dsv.Length.valid?("a", min: 2, max: 4)
:false
iex> Dsv.Length.valid?("abcde", min: 2, max: 4)
:false
`:range` example:
iex> Dsv.Length.valid?("abcd", range: {3, 5})
:true
iex> Dsv.Length.valid?("abcd", range: {4, 5})
:true
iex> Dsv.Length.valid?("abcd", range: {2, 4})
:true
iex> Dsv.Length.valid?("a", range: {2, 4})
:false
iex> Dsv.Length.valid?("abcde", range: {2, 4})
:false
iex> Dsv.Length.valid?("abcde", range: {4, 2})
** (RuntimeError) Min length (4) can't be greater that max length (2).
"""
def valid?(data, [{:min, min_length}, {:max, max_length} | _]),
do: valid?(data, range: {min_length, max_length})
def valid?(data, [{:max, max_length} | _]), do: DataLength.len(data) <= max_length
def valid?(data, [{:min, min_length} | _]), do: DataLength.len(data) >= min_length
def valid?(data, [{:range, {min, max}} | _]) do
validate_options(min, max)
valid?(data, min: min) and valid?(data, max: max)
end
@doc """
The `valid?/2` function checks if the length of a given input value meets the specified criteria.
## Parameters
* `value` - The input value to be checked for length.
* `rules` - A list of validation rules. Each rule is represented as a keyword list containing:
- `:min` - The minimum allowed length.
- `:max` - The maximum allowed length.
- `:range` - A range of acceptable lengths.
* `message` - An optional options to provide custom message that will be returned on error.
## Returns
- `:ok` if the length of `value` meets all of the specified criteria.
- `{:error, message}` if the length of `value` does not meet any of the specified criteria.
## Examples
`:min` example:
iex> Dsv.Length.validate("abcd", min: 3)
:ok
iex> Dsv.Length.validate("abcd", min: 4)
:ok
iex> Dsv.Length.validate("abcd", min: 5)
{:error, ~s(Value "abcd" is to short. Minimum lenght is 5)}
iex> Dsv.Length.validate("abcd", min: 5, message: "This value should not be shorter than 5.")
{:error, "This value should not be shorter than 5."}
`:max` example:
iex> Dsv.Length.validate("ab", max: 3)
:ok
iex> Dsv.Length.validate("abcd", max: 4)
:ok
iex> Dsv.Length.validate("abcdef", max: 5)
{:error, ~s(Value "abcdef" is to long. Maximum length is 5)}
iex> Dsv.Length.validate("abcdef", max: 5, message: "This value should not be longer that 5.")
{:error, "This value should not be longer that 5."}
`:min & :max` example:
iex> Dsv.Length.validate("abcd", min: 3, max: 5)
:ok
iex> Dsv.Length.validate("abcd", min: 4, max: 5)
:ok
iex> Dsv.Length.validate("abcd", min: 2, max: 4)
:ok
iex> Dsv.Length.validate("a", min: 2, max: 4)
{:error, ~s(Value "a" has wrong length. Minimum lenght is 2, maximum length is 4)}
iex> Dsv.Length.validate("abcde", min: 2, max: 4)
{:error, ~s(Value "abcde" has wrong length. Minimum lenght is 2, maximum length is 4)}
iex> Dsv.Length.validate("a", min: 2, max: 4, message: "This value must have length between 2 and 4.")
{:error, "This value must have length between 2 and 4."}
iex> Dsv.Length.validate("abcde", min: 2, max: 4, message: "This value must have length between 2 and 4.")
{:error, "This value must have length between 2 and 4."}
`:range` example:
iex> Dsv.Length.validate("abcd", range: {3, 5})
:ok
iex> Dsv.Length.validate("abcd", range: {4, 5})
:ok
iex> Dsv.Length.validate("abcd", range: {2, 4})
:ok
iex> Dsv.Length.validate("a", range: {2, 4})
{:error, ~s(Value "a" has wrong length. Minimum lenght is 2, maximum length is 4)}
iex> Dsv.Length.validate("abcde", range: {2, 4})
{:error, ~s(Value "abcde" has wrong length. Minimum lenght is 2, maximum length is 4)}
iex> Dsv.Length.validate("a", range: {2, 4}, message: "This value must have length between 2 and 4.")
{:error, "This value must have length between 2 and 4."}
iex> Dsv.Length.validate("abcde", range: {2, 4}, message: "This value must have length between 2 and 4.")
{:error, "This value must have length between 2 and 4."}
iex> Dsv.Length.validate("abcde", range: {4, 2})
** (RuntimeError) Min length (4) can't be greater that max length (2).
"""
def validate(data, options), do: super(data, options)
defp validate_options(min_length, max_length),
do:
if(min_length > max_length,
do: raise("Min length (#{min_length}) can't be greater that max length (#{max_length}).")
)
end