Skip to content

Commit

Permalink
Random letter prefix to CUID2
Browse files Browse the repository at this point in the history
This commit introduces a random letter prefix to the CUID2 generation
process. This change is intended to reduce the likelihood of CUID2
collisions. The random letter is generated from the range 'a' to 'z'.

The tests have been updated to reflect this change. A new test has been
added to ensure that CUID2s do not have the same first character. The
collision test run and CUID2s per run values have been reduced for
testing purposes.

The version of the library has been bumped to 1.0.1.
  • Loading branch information
stulzer committed Mar 27, 2024
1 parent b1a7f0f commit 26f5ca5
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 7 deletions.
5 changes: 1 addition & 4 deletions lib/cuid2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def self.create(input, length = BIG_LENGTH)

class << self
def call(length = DEFAULT_LENGTH)
random_letter = ('a'..'z').to_a[(rand * 26).floor]
hash_input = (time + Entropy.create(length) + count + fingerprint).to_s

"#{random_letter}#{Cuid2::Hash.create(hash_input, length)[2..length]}"
Expand All @@ -67,10 +68,6 @@ def counter
(rand + 1) * 2057
end

def random_letter
('a'..'z').to_a[(random * 26).floor]
end

def fingerprint
Cuid2::Hash.create("#{((random + 1) * 2063).floor} #{Object.constants.map(&:to_s)}")
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cuid2/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Cuid2
VERSION = '1.0.0'
VERSION = '1.0.1'
end
27 changes: 25 additions & 2 deletions spec/cuid2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

require 'cuid2'

COLISION_TEST_RUN = ENV.fetch('COLISION_TEST_RUN', 10).to_i
CUIDS_PER_RUN = ENV.fetch('CUIDS_PER_RUN', 100).to_i
COLISION_TEST_RUN = ENV.fetch('COLISION_TEST_RUN', 1).to_i
CUIDS_PER_RUN = ENV.fetch('CUIDS_PER_RUN', 10).to_i

RSpec.describe Cuid2 do
it 'has a version number' do
Expand All @@ -25,4 +25,27 @@
expect(cuids.uniq.sort).to eq(cuids.sort)
expect(cuids.sample).to match(/[a-z0-9]{24}/)
end

it 'should not collide with prefix' do
cuids = []
COLISION_TEST_RUN.times do
CUIDS_PER_RUN.times do
cuids << Cuid2.call(prefix: 'test')
end
end
expect(cuids.uniq.size).to eq(cuids.size)
expect(cuids.size).to eq(COLISION_TEST_RUN * CUIDS_PER_RUN)
expect(cuids.uniq.size).to eq(COLISION_TEST_RUN * CUIDS_PER_RUN)
expect(cuids.uniq.sort).to eq(cuids.sort)
expect(cuids.sample).to match(/test[a-z0-9]{24}/)
end

it 'should not have the same first character' do
cuids = []
5000.times do
cuids << Cuid2.call[0]
end

expect(cuids.uniq.size).to be > 1
end
end

0 comments on commit 26f5ca5

Please sign in to comment.