Packages

Zodish is a validation library heavily inspired by JavaScript's Zod and ArkType.

Current section

Files

Jump to
zodish lib zodish helpers.ex
Raw

lib/zodish/helpers.ex

defmodule Zodish.Helpers do
@moduledoc ~S"""
Common utility functions.
"""
import Keyword, only: [keyword?: 1]
import String, only: [slice: 2, ends_with?: 2]
@doc ~S"""
Pluralizes a given word based on common English rules.
"""
@spec pluralize(word :: String.t()) :: String.t()
def pluralize(word) do
cond do
ends_with?(word, "y") -> slice(word, 0..-2//1) <> "ies"
ends_with?(word, "o") -> word <> "es"
ends_with?(word, "s") -> word <> "es"
ends_with?(word, "x") -> word <> "es"
ends_with?(word, "z") -> word <> "es"
ends_with?(word, "ch") -> word <> "es"
ends_with?(word, "sh") -> word <> "es"
ends_with?(word, "f") -> slice(word, 0..-2//1) <> "ves"
ends_with?(word, "fe") -> slice(word, 0..-3//1) <> "ves"
ends_with?(word, "man") -> slice(word, 0..-4//1) <> "men"
true -> word <> "s"
end
end
@doc ~S"""
Pluralizes a word based on the given count.
iex> Zodish.Helpers.pluralize(1, "cat")
"cat"
iex> Zodish.Helpers.pluralize(0, "cat")
"cats"
iex> Zodish.Helpers.pluralize(2, "cat")
"cats"
"""
@spec pluralize(count :: non_neg_integer(), word :: String.t()) :: String.t()
def pluralize(1, <<word::binary>>), do: word
def pluralize(count, <<word::binary>>) when is_integer(count) and count >= 0, do: pluralize(word)
@doc ~S"""
Same as `Keyword.take/2` but the keys are sorted in the same order
you provided them.
iex> value =[foo: 1, bar: 2, baz: 3]
iex> Zodish.Helpers.take_sorted(value, [:bar, :baz, :foo])
[bar: 2, baz: 3, foo: 1]
"""
def take_sorted([], _), do: []
def take_sorted(_, []), do: []
def take_sorted([{_, _} | _] = keyword, [_ | _] = keys) do
keys
|> Enum.reduce([], &fetch_prepend(keyword, &1, &2))
|> :lists.reverse()
end
defp fetch_prepend(keyword, key, acc) do
case Keyword.fetch(keyword, key) do
{:ok, value} -> [{key, value} | acc]
:error -> acc
end
end
@doc ~S"""
Returns the name of the given module without the "Elixir." prefix.
iex> to_string(Zodish.Type.Map)
"Elixir.Zodish.Type.Map"
iex> Zodish.Helpers.to_mod_name(Zodish.Type.Map)
"Zodish.Type.Map"
"""
@spec to_mod_name(mod :: module()) :: String.t()
def to_mod_name(mod)
when is_atom(mod),
do: String.replace(to_string(mod), ~r/^Elixir\./, "")
@doc ~S"""
Returns the type of the given value.
"""
@spec typeof(value) :: String.t()
when value:
nil
| boolean()
| atom()
| binary()
| bitstring()
| float()
| integer()
| list()
| keyword()
| struct()
| map()
| tuple()
| function()
| pid()
| port()
| reference()
def typeof(nil), do: "nil"
def typeof(value) when is_boolean(value), do: "boolean"
def typeof(value) when is_atom(value), do: "atom"
def typeof(value) when is_binary(value), do: "string"
def typeof(value) when is_bitstring(value), do: "bitstring"
def typeof(value) when is_float(value), do: "float"
def typeof(value) when is_integer(value), do: "integer"
def typeof(value) when is_list(value), do: if(keyword?(value), do: "keyword", else: "list")
def typeof(%mod{}), do: "%#{to_mod_name(mod)}{}"
def typeof(%{__struct__: mod}), do: "%#{to_mod_name(mod)}{}"
def typeof(value) when is_map(value), do: "map"
def typeof(value) when is_tuple(value), do: "tuple"
def typeof(value) when is_function(value), do: "function"
def typeof(value) when is_pid(value), do: "pid"
def typeof(value) when is_port(value), do: "port"
def typeof(value) when is_reference(value), do: "reference"
end