Spec-Zone.ru › Ruby 4.0

модуль Marshal

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

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

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, которую Marshal.loaded обработает в _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 не может сохранить следующие объекты:

  • анонимные Class/Module.

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

  • экземпляры MatchData, 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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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