Ruby master (what may become 3.4) introduces a more robust formatting interface for SecureRandom. It's present in Ruby 3.3, but it does not appear to be fully baked. SecureRandom in 3.3.0 claims to have a bunch of Random::Formatter methods which Random::Formatter does not document. There is no guarantee it will continue to work in 3.3.x nor that 3.4 will work as currently documented in master. Use at your own risk. Unit test it to catch a breaking change quickly.
That new method makes this very simple...
COUPON_CHARS = '234679QWERTYUPADFGHX'.split(//)SecureRandom.alphanumeric(4, chars: COUPON_CHARS)
To be compatible,we can adapt Ruby on Rails' base58 method for compatibility.
ALPHANUMERIC = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_adef secure_alphanumeric(n, chars: ALPHANUMERIC) alphanumeric_size = chars.size return SecureRandom.random_bytes(n).unpack("C*").map do |byte| idx = byte % 64 idx = SecureRandom.random_number(alphanumeric_size) if idx >= alphanumeric_size chars[idx] end.joinend
Then use scan
+join
to add the dashes.
ALPHABET = '234679QWERTYUPADFGHX'.split(//)puts secure_alphanumeric(16, chars: ALPHABET).scan(/.{4}/).join('-')