module ULID::Generator

Constants

BITS_PER_B32_CHAR
BIT_LENGTH
ENCODED_LENGTH
ENCODING
MASK
RANDOM_BYTES
ZERO

Public Instance Methods

generate(time = Time.now) click to toggle source
# File lib/ulid/generator.rb, line 20
def generate(time = Time.now)
  input = octo_word(time)

  encode(input, ENCODED_LENGTH)
end
generate_bytes(time = Time.now) click to toggle source
# File lib/ulid/generator.rb, line 26
def generate_bytes(time = Time.now)
  time_48bit(time) + random_bytes
end

Private Instance Methods

encode(input, length) click to toggle source
# File lib/ulid/generator.rb, line 32
def encode(input, length)
  e = Array.new(length, ZERO)
  i = length - 1

  while input > 0
    e[i] = ENCODING[input & MASK]
    input >>= 5
    i -= 1
  end

  e.pack('c*')
end
octo_word(time = Time.now) click to toggle source
# File lib/ulid/generator.rb, line 45
def octo_word(time = Time.now)
  (hi, lo) = generate_bytes(time).unpack('Q>Q>')
  (hi << 64) | lo
end
random_bytes() click to toggle source
# File lib/ulid/generator.rb, line 66
def random_bytes
  SecureRandom.random_bytes(RANDOM_BYTES)
end
time_48bit(time = Time.now) click to toggle source
# File lib/ulid/generator.rb, line 50
def time_48bit(time = Time.now)
  # Avoid `time.to_f` since we want to accurately represent a whole number of milliseconds:
  #
  # > time = Time.new(2020, 1, 5, 7, 3, Rational(2, 1000))
  # => 2020-01-05 07:03:00 +0000
  # > (time.to_f * 1000).to_i
  # => 1578207780001
  #
  # vs
  #
  # > (time.to_r * 1000).to_i
  # => 1578207780002
  time_ms = (time.to_r * 1000).to_i
  [time_ms].pack('Q>')[2..-1]
end