Packages

Shapex is a library for validating data structures in Elixir.

Current section

Files

Jump to
shapex lib types float.ex
Raw

lib/types/float.ex

defmodule Shapex.Types.Float do
@moduledoc """
This module provides a type for validating floats.
Existing validations:
- :gt - greater than
- :gte - greater than or equal to
- :lt - less than
- :lte - less than or equal to
- :eq - equal
- :neq - not equal
- :in - checks if the value is in a list
- :not_in - checks if the value is not in a list
It's better to use the Shapex.Types.float/1 function to create a schema,
since it covers implementation details and provides a more user-friendly API.
"""
@behaviour Shapex.Type
@type float_or_tuple :: float() | {float(), String.t()}
@type float_list_or_tuple :: list(float()) | {list(float()), String.t()}
@type validations ::
{:lt, float_or_tuple()}
| {:lte, float_or_tuple()}
| {:gt, float_or_tuple()}
| {:gte, float_or_tuple()}
| {:eq, float_or_tuple()}
| {:neq, float_or_tuple()}
| {:in, float_list_or_tuple()}
| {:not_in, float_list_or_tuple()}
@type t :: %__MODULE__{
validations: [validations()]
}
defstruct [:validations]
@spec validate(t(), float()) :: {:ok, :valid} | {:error, map()}
def validate(%__MODULE__{} = schema, value) when is_float(value) do
validation_results =
Enum.reduce(schema.validations, %{}, fn
{rule, {target, message}}, acc ->
case do_validate(rule, value, target, message) do
nil -> acc
message -> Map.put(acc, rule, message)
end
{rule, target}, acc ->
case do_validate(rule, value, target, nil) do
nil -> acc
message -> Map.put(acc, rule, message)
end
end)
if validation_results == %{} do
{:ok, :valid}
else
{:error, validation_results}
end
end
def validate(_, _) do
{:error, %{"type" => "Value must be a float"}}
end
defp do_validate(:gt, value, target, message) when value <= target do
message || "Value must be greater than #{target}"
end
defp do_validate(:gte, value, target, message) when value < target do
message || "Value must be greater than or equal to #{target}"
end
defp do_validate(:lt, value, target, message) when value >= target do
message || "Value must be less than #{target}"
end
defp do_validate(:lte, value, target, message) when value > target do
message || "Value must be less than or equal to #{target}"
end
defp do_validate(:eq, value, target, message) when value != target do
message || "Value must be equal to #{target}"
end
defp do_validate(:neq, value, target, message) when value == target do
message || "Value must not be equal to #{target}"
end
defp do_validate(:in, value, target, message) do
unless Enum.member?(target, value) do
message || "Value must be one of #{inspect(target)}"
end
end
defp do_validate(:not_in, value, target, message) do
if Enum.member?(target, value) do
message || "Value must not be one of #{inspect(target)}"
end
end
defp do_validate(_, _, _, _), do: nil
end