Spec-Zone.ru › Ruby 3.4

модуль Marshal

Библиотека маршализации преобразует коллекции объектов Ruby в поток байтов, позволяя хранить их вне текущего активного скрипта. Эти данные могут быть затем прочитаны, и исходные объекты восстановлены.

Маршализованные данные содержат основные и второстепенные номера версии вместе с информацией об объекте. В обычном использовании маршализация может загружать только данные, записанные с тем же основным номером версии и равным или меньшим второстепенным номером версии. Если флаг «verbose» Ruby установлен (обычно с помощью -d, -v, -w или –verbose), основные и второстепенные номера должны точно совпадать. Marshal версия независима от номеров версии Ruby. Вы можете извлечь версию, прочитав первые два байта маршализованных данных.

str = Marshal.dump("thing")
RUBY_VERSION   #=> "1.9.0"
str[0].ord     #=> 4
str[1].ord     #=> 8

Некоторые объекты не могут быть сохранены: если объекты для сохранения включают связки, процедурные или объектные методы, экземпляры класса IO или одиночные объекты, будет поднята ошибка TypeError.

Если ваш класс имеет особые потребности в сериализации (например, если вы хотите сериализовать в определённом формате) или содержит объекты, которые иначе не могут быть сериализованы, вы можете реализовать собственную стратегию сериализации.

Существует два способа сделать это: ваш объект может определить либо marshal_dump и marshal_load, либо _dump и _load. marshal_dump будет иметь приоритет над _dump, если оба определены. marshal_dump может привести к более коротким Marshal строкам.

Безопасность

По своей сути, Marshal.load может десериализовать практически любой класс, загруженный в процесс Ruby. В многих случаях это может привести к выполнению удалённого кода, если данные Marshal загружаются из недоверенного источника.

В результате, Marshal.load не подходит в качестве универсального формата сериализации, и вы никогда не должны размаршализовывать входные данные пользователя или другие недоверенные данные.

Если вам нужно десериализовать недоверенные данные, используйте JSON или другой формат сериализации, способный загружать только простые, «примитивные» типы, такие как String, Array, Hash и т.д. Никогда не позволяйте входным данным пользователя указывать произвольные типы для десериализации.

marshal_dump и marshal_load

При сохранении объекта вызывается метод marshal_dump. marshal_dump должен возвращать результат, содержащий информацию, необходимую для marshal_load для восстановления объекта. Результатом может быть любой объект.

При загрузке объекта, сохранённого с помощью marshal_dump, объект сначала выделяется, затем вызывается marshal_load с результатом от marshal_dump. marshal_load должен воссоздать объект из информации в результате.

Пример:

class MyObj
  def initialize name, version, data
    @name    = name
    @version = version
    @data    = data
  end

  def marshal_dump
    [@name, @version]
  end

  def marshal_load array
    @name, @version = array
  end
end

_dump и _load

Используйте _dump и _load, когда вам нужно самостоятельно выделить объект, который вы восстанавливаете.

При сохранении объекта вызывается метод экземпляра _dump с Integer, который указывает максимальную глубину объектов для сохранения (значение -1 подразумевает отключение проверки глубины). _dump должен вернуть String содержащую информацию, необходимую для восстановления объекта.

Метод класса _load должен принять String и использовать его для возвращения объекта того же класса.

Пример:

class MyObj
  def initialize name, version, data
    @name    = name
    @version = version
    @data    = data
  end

  def _dump level
    [@name, @version].join ':'
  end

  def self._load args
    new(*args.split(':'))
  end
end

Так как Marshal.dump выводит строку, вы можете сделать так, чтобы _dump возвращал Marshal строку, которая будет загружена в _load для сложных объектов.

Константы

MAJOR_VERSION

основная версия

MINOR_VERSION

второстепенная версия

Публичные методы класса

dump( obj [, anIO] , limit=-1 ) → anIO
Исходный код
static VALUE
marshal_dump(int argc, VALUE *argv, VALUE _)
{
    VALUE obj, port, a1, a2;
    int limit = -1;

    port = Qnil;
    rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
    if (argc == 3) {
        if (!NIL_P(a2)) limit = NUM2INT(a2);
        if (NIL_P(a1)) io_needed();
        port = a1;
    }
    else if (argc == 2) {
        if (FIXNUM_P(a1)) limit = FIX2INT(a1);
        else if (NIL_P(a1)) io_needed();
        else port = a1;
    }
    return rb_marshal_dump_limited(obj, port, limit);
}

Сериализует obj и все дочерние объекты. Если anIO указан, сериализованные данные будут записаны в него, в противном случае данные будут возвращены как String. Если limit указан, обход подчинённых объектов будет ограничен этой глубиной. Если limit отрицательный, проверка глубины не будет выполнена.

class Klass
  def initialize(str)
    @str = str
  end
  def say_hello
    @str
  end
end

(не производит вывода)

o = Klass.new("hello\n")
data = Marshal.dump(o)
obj = Marshal.load(data)
obj.say_hello  #=> "hello\n"

Marshal не может сохранить следующие объекты:

  • анонимный класс/модуль.

  • объекты, связанные с системой (например: Dir, File::Stat, IO, File, Socket и так далее)

  • экземпляр MatchData, Data, Method, UnboundMethod, Proc, Thread, ThreadGroup, Continuation

  • объекты, которые определяют методы-синглтоны

load(source, proc = nil, freeze: false) → obj
Исходный код
# File marshal.rb, line 33
def self.load(source, proc = nil, freeze: false)
  Primitive.marshal_load(source, proc, freeze)
end

Возвращает результат преобразования сериализованных данных в source в объект Ruby (возможно, с ассоциированными подчиненными объектами). source может быть либо экземпляром IO, либо объектом, который отвечает на to_str. Если proc указан, каждый объект будет передан в proc при десериализации.

Никогда не передавайте недоверенные данные (включая пользовательский ввод) в этот метод. Подробнее см. обзор.

Если передано freeze: true аргумент, десериализованный объект будет глубоко заморожен. Обратите внимание, что это может привести к более эффективному использованию памяти из-за дедупликации замороженных строк:

serialized = Marshal.dump(['value1', 'value2', 'value1', 'value2'])

deserialized = Marshal.load(serialized)
deserialized.map(&:frozen?)
# => [false, false, false, false]
deserialized.map(&:object_id)
# => [1023900, 1023920, 1023940, 1023960] -- 4 different objects

deserialized = Marshal.load(serialized, freeze: true)
deserialized.map(&:frozen?)
# => [true, true, true, true]
deserialized.map(&:object_id)
# => [1039360, 1039380, 1039360, 1039380] -- only 2 different objects, object_ids repeating
Также известен как: restore
restore(source, proc = nil, freeze: false) → obj
Псевдоним для: load

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

Spec-Zone.ru

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