defmodule Fakererer do
@moduledoc """
Main module to start application with some helper functions.
"""
@doc """
Starts Faker with default locale.
"""
@spec start() :: :ok
def start do
:application.start(:fakererer)
end
@doc """
Starts Faker with `lang` locale.
"""
@spec start(atom) :: :ok
def start(lang) when is_atom(lang) do
:application.start(:fakererer)
locale(lang)
:ok
end
@doc """
Internal function to format string.
It replaces `"#"` to random number and `"?"` to random Latin letter.
"""
@spec format(String.t()) :: String.t()
def format(str) when is_binary(str) do
format(str, "")
end
defp format(<<"#"::utf8, tail::binary>>, acc) do
format(tail, <<acc::binary, "#{random_between(0, 9)}">>)
end
defp format(<<"?"::utf8, tail::binary>>, acc) do
format(tail, <<acc::binary, letter()>>)
end
defp format(<<other::utf8, tail::binary>>, acc) do
format(tail, <<acc::binary, other>>)
end
defp format("", acc) do
acc
end
@alphabet ~c"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
defp letter do
Enum.at(@alphabet, random_between(0, Enum.count(@alphabet) - 1))
end
@doc """
Returns application locale ready for module construct.
"""
@spec mlocale() :: String.t()
def mlocale do
Fakererer.country()
|> mlocale()
end
defp mlocale(nil) do
mlocale("")
end
defp mlocale(suffix) do
Fakererer.locale()
|> locale_module()
|> Atom.to_string()
|> String.trim_leading("Elixir.")
|> Kernel.<>(suffix)
end
@doc """
Returns application locale.
"""
@spec locale() :: atom
def locale do
Application.get_env(:fakererer, :locale)
end
@doc """
Returns application country.
"""
@spec country() :: atom
def country do
Application.get_env(:fakererer, :country)
end
@doc """
Sets application locale.
"""
@spec locale(atom) :: :ok
def locale(lang) when is_atom(lang) do
Application.put_env(:fakererer, :locale, lang)
end
@doc """
Returns a random float in the value range 0.0 =< x < 1.0.
## Examples
iex> is_float(random_uniform())
true
"""
@spec random_uniform() :: float
def random_uniform() do
Application.get_env(:fakererer, :random_module).random_uniform()
end
@doc """
Returns a (pseudo) random number as an integer between the range intervals.
## Examples
iex> random_between(3, 7) in [3, 4, 5, 6, 7]
true
"""
@spec random_between(integer, integer) :: integer
def random_between(left, right) do
Application.get_env(:fakererer, :random_module).random_between(left, right)
end
@doc """
Returns a random bytes.
"""
@spec random_bytes(pos_integer) :: binary
def random_bytes(total) do
Application.get_env(:fakererer, :random_module).random_bytes(total)
end
@doc """
Returns a shuffled enum.
"""
@spec shuffle(Enum.t()) :: list()
def shuffle(enum) do
Application.get_env(:fakererer, :random_module).shuffle(enum)
end
defmacro localize(function) do
quote do
def unquote(function)() do
caller = unquote(__CALLER__.module)
fn_impl = unquote(function)
fn_args = []
fallback = Module.concat(caller, En)
[Fakererer.mlocale(), EnUs]
|> Stream.map(&Module.concat(caller, &1))
|> Enum.find(fallback, fn mod ->
Code.ensure_loaded?(mod) and function_exported?(mod, fn_impl, 0)
end)
|> apply(fn_impl, fn_args)
end
end
end
@doc """
Returns the locale module suffix for the given locale atom.
"""
@spec locale_module(atom) :: atom
def locale_module(:vi), do: Vi
def locale_module(:da), do: Da
def locale_module(:en), do: En
def locale_module(:es), do: Es
def locale_module(:fr), do: Fr
def locale_module(:hy), do: Hy
def locale_module(:it), do: It
def locale_module(:pt_br), do: PtBr
def locale_module(:ru), do: Ru
def locale_module(:de), do: De
def locale_module(:pt_pt), do: PtPt
def locale_module(:en_us), do: EnUs
def locale_module(:en_gb), do: EnGb
def locale_module(_), do: En
defmacro sampler(name, data) do
count = Enum.count(data)
mapped_data =
data |> Enum.with_index() |> Enum.into(%{}, fn {k, v} -> {v, k} end) |> Macro.escape()
quote do
def unquote(name)() do
unquote(mapped_data)
|> Map.get(Fakererer.random_between(0, unquote(count - 1)))
end
end
end
defmacro samplerp(name, data) do
count = Enum.count(data)
mapped_data =
data |> Enum.with_index() |> Enum.into(%{}, fn {k, v} -> {v, k} end) |> Macro.escape()
quote do
defp unquote(name)() do
unquote(mapped_data)
|> Map.get(Fakererer.random_between(0, unquote(count - 1)))
end
end
end
end