module Bundler::Random::Formatter
def alphanumeric(n = nil, chars: ALPHANUMERIC)
prng = Random.new
# or
Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
prng.alphanumeric(10) #=> "i6K93NdqiH"
prng = Random.new
# or
Random.alphanumeric #=> "2BuBuLf3WfSKyQbR"
require 'bundler/vendor/securerandom/lib/random/formatter'
The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
It may be larger in the future.
If _n_ is not specified or is nil, 16 is assumed.
consist of.
The argument _chars_ specifies the character list which the result is
string to be generated.
The argument _n_ specifies the length, in characters, of the alphanumeric
Generate a random alphanumeric string.
def alphanumeric(n = nil, chars: ALPHANUMERIC) n = 16 if n.nil? choose(chars, n) end
def base64(n=nil)
prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
prng = Random.new
# or
Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
require 'bundler/vendor/securerandom/lib/random/formatter'
The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
It may be larger in the future.
If _n_ is not specified or is nil, 16 is assumed.
to be generated. The length of the result string is about 4/3 of _n_.
The argument _n_ specifies the length, in bytes, of the random number
Generate a random base64 string.
def base64(n=nil) [random_bytes(n)].pack("m0") end
def choose(source, n)
prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
require 'bundler/vendor/securerandom/lib/random/formatter'
The result may contain whatever characters are in the source array.
generated.
The argument _n_ specifies the length, in characters, of the string to be
to generate the string.
The argument _source_ specifies the array of characters from which
source array of characters.
Generate a string that randomly draws from a
def choose(source, n) source.size = size limit * size <= 0x100000000 t *= size 1 = ''.dup m <= n random_number(limit) rs.digits(size) s.length).times { is << 0 } lt << source.values_at(*is).join('') m n random_number(limit) rs.digits(size) s.length < n -is.length).times { is << 0 } .pop while n < is.length lt.concat source.values_at(*is).join('')
def gen_random(n)
def gen_random(n) ytes(n)
def hex(n=nil)
prng = Random.new
# or
Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
require 'bundler/vendor/securerandom/lib/random/formatter'
The result may contain 0-9 and a-f.
It may be larger in the future.
If _n_ is not specified or is nil, 16 is assumed.
The length of the resulting hexadecimal string is twice of _n_.
The argument _n_ specifies the length, in bytes, of the random number to be generated.
Generate a random hexadecimal string.
def hex(n=nil) random_bytes(n).unpack1("H*") end
def random_bytes(n=nil)
prng = Random.new
# or
Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
require 'bundler/vendor/securerandom/lib/random/formatter'
The result may contain any byte: "\x00" - "\xff".
It may be larger in future.
If _n_ is not specified or is nil, 16 is assumed.
The argument _n_ specifies the length of the result string.
Generate a random binary string.
def random_bytes(n=nil) n = n ? n.to_int : 16 gen_random(n) end
def urlsafe_base64(n=nil, padding=false)
prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
prng = Random.new
# or
Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
require 'bundler/vendor/securerandom/lib/random/formatter'
"=" is also used if _padding_ is true.
The result may contain A-Z, a-z, 0-9, "-" and "_".
By default, padding is not generated because "=" may be used as a URL delimiter.
Otherwise padding is generated.
If it is false or nil, padding is not generated.
The boolean argument _padding_ specifies the padding.
It may be larger in the future.
If _n_ is not specified or is nil, 16 is assumed.
to be generated. The length of the result string is about 4/3 of _n_.
The argument _n_ specifies the length, in bytes, of the random number
Generate a random URL-safe base64 string.
def urlsafe_base64(n=nil, padding=false) s = [random_bytes(n)].pack("m0") s.tr!("+/", "-_") s.delete!("=") unless padding s end
def uuid
See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
The result contains 122 random bits (15.25 random bytes).
It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
The version 4 UUID is purely random (except the version).
prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
prng = Random.new
# or
Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
require 'bundler/vendor/securerandom/lib/random/formatter'
Generate a random v4 UUID (Universally Unique IDentifier).
def uuid ary = random_bytes(16).unpack("NnnnnN") ary[2] = (ary[2] & 0x0fff) | 0x4000 ary[3] = (ary[3] & 0x3fff) | 0x8000 "%08x-%04x-%04x-%04x-%04x%08x" % ary end
def uuid_v7(extra_timestamp_bits: 0)
of the specification.
{Section 6.2}[https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-07.html#monotonicity_counters]
not implemented. Applications with stricter requirements should follow
Counters and other mechanisms for stronger guarantees of monotonicity are
across distributed nodes.
a "leap smear" approach. NTP or PTP will also be needed to synchronize
this, the system clock can synchronize with an NTP server configured to use
on UTC, which excludes leap seconds and can rollback the clock. To avoid
Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
# |<--- sorted -->||<---- random --->|
"0188d4c7-3333-7af9-87c3-8f612edac82e"]
"0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
"0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
["0188d4c7-3333-7a95-850a-de6edb858f7e",
# =>
Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
# |<--- sorted --->| |<-- random --->|
"0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
"0188d4c7-13da-754a-88ea-ac0baeedd8db",
"0188d4c7-13da-753b-83a5-7fb9b2afaeea",
["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
# =>
Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
prng = Random.new
of precision, but only 62 random bits (7.75 random bytes).
of random bits. Setting extra_timestamp_bits: 12 provides ~244ns
+extra_timestamp_bits+. The extra timestamp precision comes at the expense
precision, up to 12 bits of additional timestamp may added with
order. To create UUIDs that are time-ordered with sub-millisecond
within the same millisecond are not issued in monotonically increasing
UUIDv7 has millisecond precision by default, so multiple UUIDs created
==== Monotonicity
for details of UUIDv7.
See draft-ietf-uuidrev-rfc4122bis[https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/]
includes not only random bits but also timestamp.
Note that this method cannot be made reproducable because its output
The result contains 74 random bits (9.25 random bytes).
data inserts.
records, which may have a significant performance benefit compared to random
UUIDs can be used for better database index locality of newly inserted
This allows version 7 UUIDs to be sorted by creation time. Time ordered
with random data, excluding the version and variant bits.
Unix timestamp (milliseconds since the epoch) and fills the remaining bits
The version 7 UUID starts with the least significant 48 bits of a 64 bit
prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
prng = Random.new
# or
# |<--sorted-->| |<----- random ---->|
Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
require 'bundler/vendor/securerandom/lib/random/formatter'
Generate a random v7 UUID (Universally Unique IDentifier).
def uuid_v7(extra_timestamp_bits: 0) case (extra_timestamp_bits = Integer(extra_timestamp_bits)) when 0 # min timestamp precision ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond) rand = random_bytes(10) rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant "%08x-%04x-%s" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), rand.unpack("H4H4H12").join("-") ] when 12 # max timestamp precision ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) .divmod(1_000_000) extra_bits = ns * 4096 / 1_000_000 rand = random_bytes(8) rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant "%08x-%04x-7%03x-%s" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), extra_bits, rand.unpack("H4H12").join("-") ] when (0..12) # the generic version is slower than the special cases above rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN") rand_mask_bits = 12 - extra_timestamp_bits ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) .divmod(1_000_000) "%08x-%04x-%04x-%04x-%04x%08x" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), 0x7000 | ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) | rand_a & ((1 << rand_mask_bits) - 1), 0x8000 | (rand_b1 & 0x3fff), rand_b2, rand_b3 ] else raise ArgumentError, "extra_timestamp_bits must be in 0..12" end end