MemorableIds

View Source

A flexible Elixir library for generating human-readable, memorable identifiers. Uses combinations of adjectives, nouns, verbs, adverbs, and prepositions with optional numeric/custom suffixes.

TypeScript version of this library: memorable-ids

Features

  • đŸŽ¯ Human-readable - Generate IDs like cute-rabbit, quick-owl-dance-quietly, etc
  • 🔧 Flexible - 1-5 word components with customizable separators
  • 📊 Predictable - Built-in collision analysis and capacity planning
  • 🎲 Extensible - Custom suffix generators and vocabulary
  • 📝 Elixir - Full type specs and documentation
  • ⚡ Fast - High-performance ID generation
  • đŸĒļ Lightweight - Small vocabulary, zero dependencies

Installation

Add memorable_ids to your list of dependencies in mix.exs:

def deps do
  [
    {:memorable_ids, "~> 0.1.0"}
  ]
end

Quick Start

# Basic usage - 2 components
MemorableIds.generate() # "cute-rabbit"

# More components for uniqueness
MemorableIds.generate(%{components: 3}) # "large-fox-swim"

# Add numeric suffix for extra capacity
suffix_generators = MemorableIds.suffix_generators()
MemorableIds.generate(%{
  components: 2, 
  suffix: suffix_generators.number
}) # "quick-mouse-042"

# Custom separator
MemorableIds.generate(%{
  components: 2, 
  separator: "_"
}) # "warm_duck"

API Reference

generate(options \\ %{})

Generate a memorable ID with customizable options.

Parameters:

  • options.components (integer, 1-5): Number of word components (default: 2)
  • options.suffix (function): Suffix generator function (default: nil)
  • options.separator (string): Separator between parts (default: "-")

Returns: string - Generated memorable ID

Examples:

# Different component counts
MemorableIds.generate(%{components: 1}) # "bright"
MemorableIds.generate(%{components: 2}) # "cute-rabbit" 
MemorableIds.generate(%{components: 3}) # "large-fox-swim"
MemorableIds.generate(%{components: 4}) # "happy-owl-dance-quietly"
MemorableIds.generate(%{components: 5}) # "clever-fox-run-quickly-through"

# With suffixes
suffix_generators = MemorableIds.suffix_generators()
MemorableIds.generate(%{
  components: 2, 
  suffix: suffix_generators.number
}) # "safe-rabbit-042"

MemorableIds.generate(%{
  components: 2, 
  suffix: suffix_generators.hex
}) # "bright-owl-a7"

# Custom separators
MemorableIds.generate(%{separator: "_"}) # "warm_duck"
MemorableIds.generate(%{separator: "."}) # "cute.rabbit"

parse(id, separator \\ "-")

Parse a memorable ID back to its components.

Parameters:

  • id (string): The memorable ID to parse
  • separator (string): Separator used (default: "-")

Returns: map - Map with components list and suffix string

Examples:

MemorableIds.parse("cute-rabbit-042")
# %{components: ["cute", "rabbit"], suffix: "042"}

MemorableIds.parse("large-fox-swim")
# %{components: ["large", "fox", "swim"], suffix: nil}

MemorableIds.parse("warm_duck_123", "_")
# %{components: ["warm", "duck"], suffix: "123"}

Suffix Generators

Pre-built suffix generators for common use cases:

suffix_generators = MemorableIds.suffix_generators()

# 3-digit number (000-999) - adds 1,000x multiplier
suffix_generators.number.() # "042"

# 4-digit number (0000-9999) - adds 10,000x multiplier  
suffix_generators.number4.() # "1337"

# 2-digit hex (00-ff) - adds 256x multiplier
suffix_generators.hex.() # "a7"

# Timestamp (last 4 digits) - time-based
suffix_generators.timestamp.() # "8429"

# Single letter (a-z) - adds 26x multiplier
suffix_generators.letter.() # "k"

Analysis Functions

Plan capacity and understand collision probabilities:

# Calculate total possible combinations
MemorableIds.calculate_combinations(2) # 5,304 (2 components)
MemorableIds.calculate_combinations(2, 1000) # 5,304,000 (2 components + 3-digit suffix)
MemorableIds.calculate_combinations(3) # 212,160 (3 components)

# Calculate collision probability (Birthday Paradox)
MemorableIds.calculate_collision_probability(5304, 100) # 0.0093 (0.93% chance)

# Get comprehensive analysis
MemorableIds.get_collision_analysis(2)
# %{
#   total_combinations: 5304,
#   scenarios: [
#     %{ids: 50, probability: 0.0023, percentage: "0.23%"},
#     %{ids: 100, probability: 0.0093, percentage: "0.93%"},
#     %{ids: 200, probability: 0.037, percentage: "3.7%"},
#     %{ids: 500, probability: 0.218, percentage: "21.8%"}
#   ]
# }

Capacity & Collision Analysis

Total Combinations by Component Count

ComponentsTotal IDsExample
178bright
25,304cute-rabbit
3212,160large-fox-swim
45,728,320happy-owl-dance-quietly
5148,936,320clever-fox-run-quickly-through

Suffix Multipliers

Suffix TypeMultiplierExample
3-digit number×1,000cute-rabbit-042
4-digit number×10,000cute-rabbit-1337
2-digit hex×256cute-rabbit-a7
Single letter×26cute-rabbit-k

Collision Probability Examples

For 2 components (5,304 total combinations):

  • 50 IDs: 0.23% collision chance
  • 100 IDs: 0.93% collision chance
  • 200 IDs: 3.7% collision chance
  • 500 IDs: 21.8% collision chance

For 3 components (212,160 total combinations):

  • 1,000 IDs: 0.002% collision chance
  • 5,000 IDs: 0.059% collision chance
  • 10,000 IDs: 0.235% collision chance
  • 20,000 IDs: 0.94% collision chance

For 2 components + 3-digit suffix (5,304,000 total combinations):

  • 10,000 IDs: 0.0009% collision chance
  • 50,000 IDs: 0.023% collision chance
  • 100,000 IDs: 0.094% collision chance
  • 500,000 IDs: 2.35% collision chance

Configuration Recommendations

Choose the right configuration based on your expected ID volume:

Use CaseRecommendationCapacityExample
Small apps (<1K IDs)2 components5,304cute-rabbit
Medium apps (1K-50K IDs)3 components212,160large-fox-swim
Large apps (50K-500K IDs)2-3 components + suffix5M+cute-rabbit-042
Enterprise (500K+ IDs)4+ components + suffix50M+happy-owl-dance-042

Advanced Usage

Custom Suffix Generators

Create your own suffix logic:

# Custom timestamp suffix
timestamp_suffix = fn ->
  DateTime.utc_now()
  |> DateTime.to_unix(:millisecond)
  |> Integer.to_string()
  |> String.slice(-6..-1) # Last 6 digits
end

# Custom random string
random_string = fn ->
  :crypto.strong_rand_bytes(3)
  |> Base.encode32(case: :lower, padding: false)
  |> String.slice(0..2) # 3 random chars
end

# Use custom suffix
MemorableIds.generate(%{
  components: 2, 
  suffix: timestamp_suffix
}) # "cute-rabbit-123456"

Dictionary Access

Access the underlying word collections:

alias MemorableIds.Dictionary

IO.puts length(Dictionary.adjectives()) # 78
IO.puts length(Dictionary.nouns()) # 68
IO.puts length(Dictionary.verbs()) # 40
IO.puts length(Dictionary.adverbs()) # 27
IO.puts length(Dictionary.prepositions()) # 26

# Access individual words
IO.puts hd(Dictionary.adjectives()) # "cute"
IO.puts hd(Dictionary.nouns()) # "rabbit"

# Get statistics
stats = Dictionary.stats()
IO.inspect stats
# %{adjectives: 78, nouns: 68, verbs: 40, adverbs: 27, prepositions: 26}

Error Handling

try do
  MemorableIds.generate(%{components: 6}) # Invalid: max is 5
rescue
  ArgumentError -> IO.puts "Components must be between 1 and 5"
end

Performance Considerations

Generation Speed

  • High-performance ID generation suitable for production use
  • No significant performance difference between component counts
  • Suffix generation adds minimal overhead

Randomness Quality

  • Uses Erlang's :rand module - suitable for non-cryptographic purposes
  • For cryptographic security, replace with :crypto.strong_rand_bytes/1
  • Distribution is uniform across all vocabulary combinations

Security Notes

âš ī¸ Important Security Information:

  • IDs are NOT cryptographically secure
  • Predictable if random seed is known
  • Suitable for: user-friendly identifiers, temporary IDs, non-sensitive references
  • NOT suitable for: session tokens, passwords, security-critical identifiers

Development

Running Tests

# Run all tests
mix test

# Run with coverage
mix test --cover

# Run specific test file
mix test test/memorable_ids_test.exs

# Run doctests only
mix test --only doctest

Building Documentation

# Generate documentation
mix docs

# View documentation
open doc/index.html

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

# Clone repository
git clone <repository-url>
cd memorable_ids

# Install dependencies
mix deps.get

# Run tests
mix test

# Check formatting
mix format --check-formatted

# Run static analysis
mix credo

Adding Custom Vocabulary

  1. Extend existing lists in lib/dictionary.ex
  2. Ensure words are URL-safe and human-readable
  3. Avoid duplicates to maintain combination count accuracy
  4. Update tests and documentation
  5. Run mix test to verify changes

Documentation

Documentation can be generated with ExDoc and published on HexDocs.

Once published, the docs can be found at https://hexdocs.pm/memorable_ids.

License

This project is open-sourced software licensed under the MIT license.

Copyrights in this project are retained by their contributors. See the license file for more information.


đŸ¤Ģ Psst! If you like my work you can support me via [GitHub sponsors](https://github.com/sponsors/riipandi).