Current section
Files
Jump to
Current section
Files
lib/ex_random_string.ex
defmodule ExRandomString do
@moduledoc """
Library for generating random strings. Based on NodeJS library
[randomstring](https://www.npmjs.com/package/randomstring).
## Installation
The package can be installed by adding `ex_random_string` to your list of
dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_random_string, "~> 1.0.0"}
]
end
```
## Usage
```elixir
ExRandomString.generate()
# "XwPp9xazJ0ku5CZnlmgAx2Dld8SHkAeT"
ExRandomString.generate(7);
# "xqm5wXX"
ExRandomString.generate(length: 12, charset: :alphabetic)
# "AqoTIzKurxJi"
ExRandomString.generate(charset: ~w(a b c));
# "accbaabbbbcccbccccaacacbbcbbcbbc"
```
"""
@numeric ~w(1 2 3 4 6 7 8 9 0)
@alpha ~w(a b c d e f g h i j k l m n o p q r s t u v w x y z)
@hex @numeric ++ ~w(a b c d e f)
@alphanumeric @alpha ++ @numeric
@default_options [charset: :alphanumeric, length: 32]
@doc """
Generates a random string that is 32 characters long and alphanumeric.
"""
def generate do
generate(@default_options[:length])
end
@doc """
When provided an integer, it generates a random string with the provided
integer as length. String returned will be alphanumeric.
When provided a Keyword list, it generates a random string with properties
based on the provided options.
## Options
Listed below are the supported options. Each of the options are optional.
* `length` -- the length of the random string. (default: 32)
* `charset` -- define the character set for the string. (default: `:alphanumeric`)
* `:alphanumeric` -- [0-9a-zA-Z]
* `:alphabetic` -- [a-zA-Z]
* `:numeric` -- [0-9]
* `:hex` -- [0-9a-f]
* any string -- will generate based on the string's set of characters
* `case` -- define whether the output should be lowercase / uppercase only.
(default: `nil`)
* `:lower` -- forces all characters to use lower case
* `:upper` -- forces all characters to use upper case
* `:mix` -- randomizes the case of each character
## Examples
```
ExRandomString.generate(7)
# "xqm5wXX"
ExRandomString.generate(length: 12, charset: :alphabetic)
# "AqoTIzKurxJi"
ExRandomString.generate(charset: "ABC", case: :lower)
# "abaccabaacbaabcccabacbacccacbbbb"
```
"""
def generate(options)
def generate(length) when is_integer(length) do
generate(length: length)
end
def generate(options) do
options = with_default_options(options)
characters = characters_for_charset(options[:charset])
character_count = Enum.count(characters)
Stream.repeatedly(fn -> random_character(characters, character_count) end)
|> Stream.map(case_modifier(options))
|> Stream.take(options[:length])
|> Enum.join("")
end
defp characters_for_charset(charset) do
case charset do
:alphanumeric -> @alphanumeric
:alphabetic -> @alpha
:numeric -> @numeric
:hex -> @hex
characters -> String.graphemes(characters)
end
end
defp random_character(characters, character_count) do
random_index = :rand.uniform(character_count) - 1
Enum.at(characters, random_index)
end
defp case_modifier(options) do
case options[:case] do
:upper -> &String.upcase/1
:lower -> &String.downcase/1
:mix -> &randomize_case/1
_ -> case_modifier_for_charset(options[:charset])
end
end
defp case_modifier_for_charset(charset) do
identity = &(&1)
case charset do
:alphanumeric -> &randomize_case/1
:alphabetic -> &randomize_case/1
:numeric -> identity
:hex -> identity
_ -> identity
end
end
defp randomize_case(character) do
case :rand.uniform(2) do
1 -> String.downcase(character)
2 -> String.upcase(character)
end
end
defp with_default_options(options) do
Keyword.merge(@default_options, options)
end
end