lib/validators/custom_function.ex

defmodule Dsv.Custom do
  use Dsv.Validator

  @moduledoc """
  Dsv.Custom module provides functions to validate data using a custom validation function.
  """

  @doc """
  Validates the provided data using the given validation function.

  ## Parameters

    * `data` - The data value to validate.
    * `func` - A validation function that takes the data as input and returns a boolean.
      This function should return true if the data passes validation; otherwise, false.

  ## Returns

  - `:true` if the data passes validation.
  - `:false` if the data fails validation.

  ## Examples

      iex> Dsv.Custom.valid?({:ok, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end)
      :true

      iex> Dsv.Custom.valid?({:error, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end)
      :false

      iex> Dsv.Custom.valid?("test", &(&1 |> String.upcase() === "TEST"))
      :true

      iex> Dsv.Custom.valid?("tset", &(&1 |> String.upcase() === "TEST"))
      :false

  """
  def valid?(data, function: func) when is_function(func), do: func.(data)
  def valid?(data, func) when is_function(func), do: valid?(data, function: func)

  @doc """
  Validates the provided data using the given validation function.

  > #### Default error message {: .warning}
  >
  > This function will return "Unknown validation error" message in case of validation failure. Please consider using `Dsv.Custom.validate/3` with your own meaningful message.


  ## Parameters

    * `data` - The data value to validate.
    * `options` - A validation function that takes the data as input and returns a boolean.
      This function should return true if the data passes validation; otherwise, false.

  ## Returns

  - `:ok` if the data passes validation.
  - `{:error, "Unknown validation error"}` if the data fails validation.

  To get more significant message, use `Dsv.Custom.validate/3` function.

  ## Examples

      iex> Dsv.Custom.validate({:ok, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end)
      :ok

      iex> Dsv.Custom.validate({:error, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end)
      {:error, "Unknown validation error"}

  """
  def validate(data, function), do: super(data, function)

  @doc """
  Validates the provided data using the given validation function and return a custom error message in case of validation failure.


  ## Parameters

    * `data` (any) - The data value to be validated. This can encompass various data types such as strings,
      numbers, lists, or more complex data structures.
    * `function` (function) - A user-defined validation function that operates on the `data` parameter.
      The validation function should return a boolean value, where `true` indicates successful validation
      and `false` denotes validation failure.
    * `message` (string) - A customized error message to be returned in the event of validation failure.


  ## Returns

  - `:ok` - Represents a successful validation, where the data meets the criteria set by the validation function.
  - `{:error, message}` - Signifies validation failure, where the data does not fulfill the requirements
    outlined by the validation function.

  ## Examples

      iex> Dsv.Custom.validate({:ok, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end, message: "Tuple must contain :ok value")
      :ok

      iex> Dsv.Custom.validate({:error, "hello"}, function: fn data -> case data do
      ...>   {:ok, _} -> :true
      ...>   _ -> false
      ...>  end
      ...>  end, message: "Tuple must contain :ok value")
      {:error, "Tuple must contain :ok value"}


      iex> Dsv.Custom.validate("test", &(&1 |> String.upcase() === "TEST"), "Value must be equal `TEST`")
      :ok

      iex> Dsv.Custom.validate("tset", &(&1 |> String.upcase() === "TEST"), "Value must be equal `TEST`")
      {:error, "Value must be equal `TEST`"}

  """
  def validate(data, function, message) when is_function(function),
    do: validate(data, function: function, message: message)
end