Skip to content

riipandi/memorable-ids-ex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MemorableIds

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

Components Total IDs Example
1 78 bright
2 5,304 cute-rabbit
3 212,160 large-fox-swim
4 5,728,320 happy-owl-dance-quietly
5 148,936,320 clever-fox-run-quickly-through

Suffix Multipliers

Suffix Type Multiplier Example
3-digit number ×1,000 cute-rabbit-042
4-digit number ×10,000 cute-rabbit-1337
2-digit hex ×256 cute-rabbit-a7
Single letter ×26 cute-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 Case Recommendation Capacity Example
Small apps (<1K IDs) 2 components 5,304 cute-rabbit
Medium apps (1K-50K IDs) 3 components 212,160 large-fox-swim
Large apps (50K-500K IDs) 2-3 components + suffix 5M+ cute-rabbit-042
Enterprise (500K+ IDs) 4+ components + suffix 50M+ 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.

About

A flexible library for generating human-readable, memorable identifiers for Elixir.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages