Spec-Zone.ru › Ruby 4.0
  1. Random::
  2. Formatter

module Random::Formatter

Форматировщик случайных чисел.

Форматирует сгенерированные случайные числа различными способами. При подключении 'random/formatter' в пустой базовый модуль Random::Formatter добавляется несколько методов, которые становятся доступны как методы экземпляра и модуля Random.

Стандартная библиотека SecureRandom также расширяется этим модулем, и описанные ниже методы доступны в ней как методы модуля.

Примеры

Генерация случайных шестнадцатеричных строк:

require 'random/formatter'

prng = Random.new
prng.hex(10) #=> "52750b30ffbc7de3b362"
prng.hex(10) #=> "92b15d6c8dc4beb5f559"
prng.hex(13) #=> "39b290146bea6ce975c37cfc23"
# or just
Random.hex #=> "1aed0c631e41be7f77365415541052ee"

Генерация случайных строк в кодировке base64:

prng.base64(10) #=> "EcmTPZwWRAozdA=="
prng.base64(10) #=> "KO1nIU+p9DKxGg=="
prng.base64(12) #=> "7kJSM/MzBJI+75j8"
Random.base64(4) #=> "bsQ3fQ=="

Генерация случайных двоичных строк:

prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"

Генерация буквенно-цифровых строк:

prng.alphanumeric(10) #=> "S8baxMJnPl"
prng.alphanumeric(10) #=> "aOxAg8BAJe"
Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"

Генерация UUID:

prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"

Все методы также доступны в стандартной библиотеке SecureRandom:

SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"

Генерация случайного числа в заданном диапазоне, как это делает Random

prng.random_number       #=> 0.5816771641321361
prng.random_number(1000) #=> 485
prng.random_number(1..6) #=> 3
prng.rand                #=> 0.5816771641321361
prng.rand(1000)          #=> 485
prng.rand(1..6)          #=> 3

Константы

ALPHANUMERIC

Список символов по умолчанию для alphanumeric.

Открытые методы экземпляра

alphanumeric (n = nil, chars: ALPHANUMERIC) Показать исходный код
# File lib/random/formatter.rb, line 367
def alphanumeric(n = nil, chars: ALPHANUMERIC)
  n = 16 if n.nil?
  choose(chars, n)
end

Генерирует случайную буквенно-цифровую строку.

Аргумент n задаёт длину генерируемой буквенно-цифровой строки в символах. Аргумент chars задаёт список символов, из которых состоит результат.

Если аргумент n не указан или равен nil, предполагается значение 16. В будущем оно может быть увеличено.

Результат может содержать символы A-Z, a-z и 0-9, если не указан аргумент chars.

require 'random/formatter'

Random.alphanumeric     #=> "2BuBuLf3WfSKyQbR"
# or
prng = Random.new
prng.alphanumeric(10) #=> "i6K93NdqiH"

Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
# or
prng = Random.new
prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
base64 (n=nil) Показать исходный код
# File lib/random/formatter.rb, line 114
def base64(n=nil)
  [random_bytes(n)].pack("m0")
end

Генерирует случайную строку в кодировке base64.

Аргумент n задаёт длину генерируемого случайного числа в байтах. Длина результирующей строки составляет примерно 4/3 от n.

Если аргумент n не указан или равен nil, предполагается значение 16. В будущем оно может быть увеличено.

Результат может содержать символы A-Z, a-z, 0-9, «+», «/» и «=».

require 'random/formatter'

Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
# or
prng = Random.new
prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="

Определение base64 см. в RFC 3548.

hex (n=nil) Показать исходный код
# File lib/random/formatter.rb, line 92
def hex(n=nil)
  random_bytes(n).unpack1("H*")
end

Генерирует случайную шестнадцатеричную строку.

Аргумент n задаёт длину генерируемого случайного числа в байтах. Длина результирующей шестнадцатеричной строки вдвое превышает n.

Если аргумент n не указан или равен nil, предполагается значение 16. В будущем оно может быть увеличено.

Результат может содержать символы 0-9 и a-f.

require 'random/formatter'

Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
# or
prng = Random.new
prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
rand → float
rand(max) → number
rand(range) → number

Генерирует форматированное случайное число на основе необработанных случайных байтов. См. Random#rand.

Псевдоним для: random_number
random_bytes (n=nil) Показать исходный код
# File lib/random/formatter.rb, line 71
def random_bytes(n=nil)
  n = n ? n.to_int : 16
  gen_random(n)
end

Генерирует случайную двоичную строку.

Аргумент n задаёт длину результирующей строки.

Если аргумент n не указан или равен nil, предполагается значение 16. В будущем оно может быть увеличено.

Результат может содержать любой байт: «x00» — «xff».

require 'random/formatter'

Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
# or
prng = Random.new
prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
random_number → float Показать исходный код
random_number(max) → number
random_number(range) → number
static VALUE
rand_random_number(int argc, VALUE *argv, VALUE obj)
{
    rb_random_t *rnd = try_get_rnd(obj);
    VALUE v = rand_random(argc, argv, obj, rnd);
    if (NIL_P(v)) v = rand_random(0, 0, obj, rnd);
    else if (!v) invalid_argument(argv[0]);
    return v;
}

Генерирует форматированное случайное число на основе необработанных случайных байтов. См. Random#rand.

Также имеет псевдоним: rand
urlsafe_base64 (n=nil, padding=false) Показать исходный код
# File lib/random/formatter.rb, line 145
def urlsafe_base64(n=nil, padding=false)
  s = [random_bytes(n)].pack("m0")
  s.tr!("+/", "-_")
  s.delete!("=") unless padding
  s
end

Генерирует случайную строку в кодировке base64, безопасную для URL.

Аргумент n задаёт длину генерируемого случайного числа в байтах. Длина результирующей строки составляет примерно 4/3 от n.

Если аргумент n не указан или равен nil, предполагается значение 16. В будущем оно может быть увеличено.

Логический аргумент padding задаёт заполнение. Если он равен false или nil, заполнение не добавляется. В противном случае оно добавляется. По умолчанию заполнение не добавляется, поскольку «=» может использоваться как разделитель URL.

Результат может содержать символы A-Z, a-z, 0-9, «-» и «_». Символ «=» также используется, если padding равен true.

require 'random/formatter'

Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
# or
prng = Random.new
prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"

prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="

Определение base64, безопасной для URL, см. в RFC 3548.

uuid () Показать исходный код
# File lib/random/formatter.rb, line 169
def uuid
  ary = random_bytes(16)
  ary.setbyte(6, (ary.getbyte(6) & 0x0f) | 0x40)
  ary.setbyte(8, (ary.getbyte(8) & 0x3f) | 0x80)
  ary.unpack("H8H4H4H4H12").join(?-)
end

Генерирует случайный UUID версии 4 (Universally Unique IDentifier — универсальный уникальный идентификатор).

require 'random/formatter'

Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
# or
prng = Random.new
prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"

UUID версии 4 является полностью случайным (за исключением версии). Он не содержит такой значимой информации, как MAC-адреса, временные метки и т. д.

Результат содержит 122 случайных бита (15,25 случайного байта).

Подробнее о UUIDv4 см. в RFC9562.

Также имеет псевдоним: uuid_v4
uuid_v4 ()
Псевдоним для: uuid
uuid_v7 (extra_timestamp_bits: 0) Показать исходный код
# File lib/random/formatter.rb, line 246
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

Генерирует случайный UUID версии 7 (Universally Unique IDentifier — универсальный уникальный идентификатор).

require 'random/formatter'

Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
#                    |<--sorted-->| |<----- random ---->|

# or
prng = Random.new
prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"

UUID версии 7 начинается с 48 младших бит 64-битной временной метки Unix (миллисекунды с начала эпохи), а оставшиеся биты заполняются случайными данными, за исключением битов версии и варианта.

Это позволяет сортировать UUID версии 7 по времени создания. Упорядоченные по Time UUID можно использовать для повышения локальности индексов базы данных при добавлении новых записей, что может значительно повысить производительность по сравнению со вставкой случайных данных.

Результат содержит 74 случайных бита (9,25 случайного байта).

Обратите внимание, что этот метод не может быть воспроизводимым, поскольку его результат включает не только случайные биты, но и временную метку.

Подробнее о UUIDv7 см. в RFC9562.

Монотонность

По умолчанию UUIDv7 имеет точность до миллисекунд, поэтому несколько UUID, созданных в течение одной миллисекунды, не выдаются в строго возрастающем порядке. Чтобы создавать упорядоченные по времени UUID с точностью до долей миллисекунды, можно добавить до 12 дополнительных бит временной метки с помощью extra_timestamp_bits. Дополнительная точность временной метки достигается за счёт случайных битов. Значение extra_timestamp_bits: 12 обеспечивает точность около 244 нс, но оставляет лишь 62 случайных бита (7,75 случайного байта).

prng = Random.new
Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
# =>
["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
 "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
 "0188d4c7-13da-754a-88ea-ac0baeedd8db",
 "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
# |<--- sorted --->| |<-- random --->|

Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
# =>
["0188d4c7-3333-7a95-850a-de6edb858f7e",
 "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9",  # <- out of order
 "0188d4c7-3333-7ae2-995a-9f135dc44ead",  # <- out of order
 "0188d4c7-3333-7af9-87c3-8f612edac82e"]
# |<--- sorted -->||<---- random --->|

Любой откат системных часов нарушит монотонность. UUIDv7 основан на UTC, где не учитываются високосные секунды и возможен откат часов. Чтобы этого избежать, системные часы можно синхронизировать с NTP-сервером, настроенным на использование подхода «leap smear». Для синхронизации распределённых узлов также потребуется NTP или PTP.

Счётчики и другие механизмы для более строгого обеспечения монотонности не реализованы. Приложениям с более строгими требованиями следует руководствоваться разделом 6.2 спецификации.

Закрытые методы экземпляра

choose (source, n) Показать исходный код
# File lib/random/formatter.rb, line 312
        def choose(source, n)
  size = source.size
  m = 1
  limit = size
  while limit * size <= 0x100000000
    limit *= size
    m += 1
  end
  result = ''.dup
  while m <= n
    rs = random_number(limit)
    is = rs.digits(size)
    (m-is.length).times { is << 0 }
    result << source.values_at(*is).join('')
    n -= m
  end
  if 0 < n
    rs = random_number(limit)
    is = rs.digits(size)
    if is.length < n
      (n-is.length).times { is << 0 }
    else
      is.pop while n < is.length
    end
    result.concat source.values_at(*is).join('')
  end
  result
end

Генерирует строку, случайным образом выбирая символы из исходного массива.

Аргумент source задаёт массив символов, из которого генерируется строка. Аргумент n задаёт длину генерируемой строки в символах.

Результат может содержать любые символы из исходного массива.

require 'random/formatter'

prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
prng.choose([*'0'..'9'], 5)  #=> "27309"
gen_random (n) Показать исходный код
# File lib/random/formatter.rb, line 294
        def gen_random(n)
  self.bytes(n)
end

Внутренний интерфейс к Random; генерирует случайные данные длиной n байт.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API