Module: Philiprehberger::IdGen::Ulid

Defined in:
lib/philiprehberger/id_gen/ulid.rb

Constant Summary collapse

CROCKFORD_BASE32 =
'0123456789ABCDEFGHJKMNPQRSTVWXYZ'
TIMESTAMP_LENGTH =
10
RANDOM_LENGTH =
16
ULID_LENGTH =
TIMESTAMP_LENGTH + RANDOM_LENGTH

Class Method Summary collapse

Class Method Details

.generateObject



16
17
18
19
# File 'lib/philiprehberger/id_gen/ulid.rb', line 16

def generate
  timestamp_ms = (Time.now.to_f * 1000).to_i
  encode_timestamp(timestamp_ms) + encode_random
end

.monotonicObject



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/philiprehberger/id_gen/ulid.rb', line 21

def monotonic
  thread_state = Thread.current[:philiprehberger_ulid_monotonic] ||= { timestamp: 0, random: nil }

  timestamp_ms = (Time.now.to_f * 1000).to_i

  if timestamp_ms == thread_state[:timestamp] && thread_state[:random]
    thread_state[:random] += 1
  else
    thread_state[:timestamp] = timestamp_ms
    random_bytes = SecureRandom.random_bytes(10)
    thread_state[:random] = bytes_to_integer(random_bytes)
  end

  random_part = encode_integer(thread_state[:random], RANDOM_LENGTH)
  encode_timestamp(timestamp_ms) + random_part
end

.timestamp(ulid_string) ⇒ Object

Raises:



38
39
40
41
42
43
44
# File 'lib/philiprehberger/id_gen/ulid.rb', line 38

def timestamp(ulid_string)
  raise Error, "ULID must be #{ULID_LENGTH} characters" unless ulid_string.length == ULID_LENGTH

  timestamp_part = ulid_string[0, TIMESTAMP_LENGTH]
  timestamp_ms = decode_crockford(timestamp_part)
  Time.at(timestamp_ms / 1000.0)
end