модуль 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
-
второстепенная версия
Публичные методы класса
static VALUE
marshal_dump(int argc, VALUE *argv)
{
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 -
объекты, которые определяют одиночные методы
static VALUE
marshal_load(int argc, VALUE *argv)
{
VALUE port, proc;
rb_check_arity(argc, 1, 2);
port = argv[0];
proc = argc > 1 ? argv[1] : Qnil;
return rb_marshal_load_with_proc(port, proc);
} Возвращает результат преобразования сериализованных данных в source в объект Ruby (возможно, с ассоциированными подчиненными объектами). source может быть экземпляром IO или объектом, который отвечает на to_str. Если proc указан, каждый объект будет передан в proc по мере десериализации.
Никогда не передавайте ненадежные данные (включая введенные пользователем) в этот метод. Более подробная информация приведена в обзоре.
static VALUE
marshal_load(int argc, VALUE *argv)
{
VALUE port, proc;
rb_check_arity(argc, 1, 2);
port = argv[0];
proc = argc > 1 ? argv[1] : Qnil;
return rb_marshal_load_with_proc(port, proc);
} Возвращает результат преобразования сериализованных данных в source в объект Ruby (возможно, с ассоциированными подчиненными объектами). source может быть экземпляром IO или объектом, который отвечает на to_str. Если proc указан, каждый объект будет передан в proc по мере десериализации.
Никогда не передавайте ненадежные данные (включая введенные пользователем) в этот метод. Более подробная информация приведена в обзоре.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.