Spec-Zone.ru › Ruby 3.3

модуль 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 368
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=="

См. RFC 3548 для определения формата Base64.

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) → число
rand(диапазон) → число

Генерирует отформатированное случайное число из сырых случайных байтов. См. 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) → число
random_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

Генерирует случайную строку URL-безопасного Base64.

Аргумент 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=="

См. RFC 3548 для определения URL-безопасного Base64.

uuid() Показать исходный код
# File lib/random/formatter.rb, line 169
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

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

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 случайных байтов).

См. RFC4122 для получения подробностей о UUID.

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

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 по времени создания. Отсортированные по времени UUID могут использоваться для лучшей локальности индекса базы данных для вновь вставленных записей, что может обеспечить значительное улучшение производительности по сравнению с вставкой случайных данных.

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

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

См. draft-ietf-uuidrev-rfc4122bis для получения подробностей о UUIDv7.

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

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, настроенным с использованием подхода «размазывание високосных секунд». Для синхронизации между распределёнными узлами также потребуется NTP или PTP.

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

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

choose(source, n) Показать исходный код
# File lib/random/formatter.rb, line 313
        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 задаёт длину генерируемой строки в символах.

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

require 'random/formatter'

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

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

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

Spec-Zone.ru

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