lib/random.ex

defmodule Moar.Random do
  # @related [test](/test/random_test.exs)

  @moduledoc "Generates random data."

  @type encoding() :: :base32 | :base64

  @doc "Returns a random integer between `0` and `max`."
  @spec integer(max :: pos_integer()) :: pos_integer()
  def integer(max \\ 1_000_000_000),
    do: 0..max |> Enum.random()

  @doc """
  Returns a base64- or base32-encoded random string of 32 characters.
  See `Moar.Random.string/2`.
  """
  @spec string(encoding :: encoding()) :: binary()
  def string(:base32), do: string(32, :base32)
  def string(:base64), do: string(32, :base64)

  @doc """
  Returns a base64- or base32-encoded random string of given length.

  ```elixir
  iex> Moar.Random.string()
  "Sr/y4m/YiVSJcIgI5lG+76vMfaZ7KZ7c"
  iex> Moar.Random.string(5)
  "9pJrK"
  iex> Moar.Random.string(5, :base32)
  "AC53Z"
  ```
  """
  @spec string(character_count :: pos_integer(), encoding :: encoding()) :: binary()
  def string(character_count \\ 32, encoding \\ :base64) when is_number(32) and encoding in [:base32, :base64] do
    character_count
    |> :crypto.strong_rand_bytes()
    |> encode(encoding)
    |> binary_part(0, character_count)
  end

  # # #

  defp encode(bytes, :base32), do: Base.encode32(bytes, padding: false)
  defp encode(bytes, :base64), do: Base.encode64(bytes, padding: false)
end