defmodule DryValidation.Types.Func do @moduledoc """ Provides a way to define custom validation functions. It is a struct with: * `fn` that stores a function with one argument, that is used validate the input value * `type` is optional, used for casting values against that type before validating * `error_message` is error message returned in case of failed validation ``` DryValidation.schema do required :pet, Types.Func.member_of(["dog", "cat", "bird"]) end ``` """ defstruct [:fn, :type, :error_message] @doc """ Validates that the input value is equal to the first argument. ``` DryValidation.schema do required :type, Types.Func.equal("user") end ``` """ def equal(expected) do %__MODULE__{ fn: fn v -> v == expected end, error_message: "is not equal to #{inspect(expected)}" } end @doc """ Validates that the value is part of the list. ``` DryValidation.schema do required :pet, Types.Func.member_of(["dog", "cat", "bird"]) end ``` """ def member_of(list) when is_list(list) do %__MODULE__{ fn: fn v -> Enum.member?(list, v) end, error_message: "is not a member of #{inspect(list)}" } end @doc false def call(%__MODULE__{} = func, value) do func.fn.(value) end def cast(%__MODULE__{type: nil}, value) do value end def cast(%__MODULE__{type: type}, value) do type.cast(value) end end