defmodule Faker 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(:faker)
end
@doc """
Starts Faker with `lang` locale.
"""
@spec start(atom) :: :ok
def start(lang) when is_atom(lang) do
:application.start(:faker)
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
Faker.country()
|> mlocale()
end
defp mlocale(nil) do
mlocale("")
end
defp mlocale(suffix) do
Faker.locale()
|> to_string()
|> String.capitalize()
|> Kernel.<>(suffix)
end
@doc """
Returns application locale.
"""
@spec locale() :: atom
def locale do
Application.get_env(:faker, :locale)
end
@doc """
Returns application country.
"""
@spec country() :: atom
def country do
Application.get_env(:faker, :country)
end
@doc """
Sets application locale.
"""
@spec locale(atom) :: :ok
def locale(lang) when is_atom(lang) do
Application.put_env(:faker, :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(:faker, :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(:faker, :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(:faker, :random_module).random_bytes(total)
end
@doc """
Returns a shuffled enum.
"""
@spec shuffle(Enum.t()) :: list()
def shuffle(enum) do
Application.get_env(:faker, :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)
[Faker.mlocale(), EnUs]
|> Stream.map(&Module.concat(caller, &1))
|> Enum.find(fallback, &function_exported?(&1, fn_impl, 0))
|> apply(fn_impl, fn_args)
end
end
end
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(Faker.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(Faker.random_between(0, unquote(count - 1)))
end
end
end
end