Spec-Zone.ru › Ruby 3.4
  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=="

Определение URL-безопасного base64 см. в 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 (универсальный уникальный идентификатор).

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 (универсальный уникальный идентификатор).

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

Результат содержит 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