module Marshal
Die Marshaling-Bibliothek konvertiert Sammlungen von Ruby-Objekten in einen Byte-Stream, sodass sie außerhalb des aktuell aktiven Skripts gespeichert werden können. Diese Daten können anschließend gelesen und die ursprünglichen Objekte wiederhergestellt werden.
Marshaled-Daten enthalten neben den Objektinformationen auch Versionsnummern (Major und Minor). Im Normalfall kann Marshaling nur Daten laden, die mit derselben Major-Versionsnummer und einer gleich hohen oder niedrigeren Minor-Versionsnummer geschrieben wurden. Wenn Rubys „verbose“-Flag gesetzt ist (normalerweise mit -d, -v, -w oder –verbose), müssen die Major- und Minor-Nummern exakt übereinstimmen. Die Versionierung von Marshal ist unabhängig von den Ruby-Versionsnummern. Sie können die Version extrahieren, indem Sie die ersten beiden Bytes der marshaled-Daten lesen.
str = Marshal.dump("thing") RUBY_VERSION #=> "1.9.0" str[0].ord #=> 4 str[1].ord #=> 8
Einige Objekte können nicht gedumpt werden: Wenn die zu dumpenden Objekte Bindings, Prozedur- oder Method-Objekte, Instanzen der Klasse IO oder Singleton-Objekte enthalten, wird ein TypeError ausgelöst.
Wenn Ihre Klasse spezielle Serialisierungsanforderungen hat (z. B. wenn Sie in einem bestimmten Format serialisieren möchten) oder wenn sie Objekte enthält, die sonst nicht serialisierbar wären, können Sie Ihre eigene Serialisierungsstrategie implementieren.
Es gibt zwei Möglichkeiten, dies zu tun: Ihr Objekt kann entweder marshal_dump und marshal_load oder _dump und _load definieren. marshal_dump hat Vorrang vor _dump, wenn beide definiert sind. marshal_dump kann zu kleineren Marshal-Strings führen.
Sicherheitshinweise
Per Design kann Marshal.load fast jede Klasse deserialisieren, die in den Ruby-Prozess geladen wird. In vielen Fällen kann dies zur Ausführung von Remote-Code führen, wenn die Marshal-Daten aus einer nicht vertrauenswürdigen Quelle geladen werden.
Daher ist Marshal.load kein geeignetes Format für die allgemeine Serialisierung, und Sie sollten niemals Benutzereingaben oder andere nicht vertrauenswürdige Daten unmarshalen.
Wenn Sie nicht vertrauenswürdige Daten deserialisieren müssen, verwenden Sie JSON oder ein anderes Serialisierungsformat, das nur einfache, „primitive“ Typen wie String, Array, Hash usw. laden kann. Erlauben Sie niemals Benutzereingaben, um beliebige Typen für die Deserialisierung anzugeben.
marshal_dump und marshal_load
Beim Dumpten eines Objekts wird die Methode marshal_dump aufgerufen. marshal_dump muss ein Ergebnis zurückgeben, das die für marshal_load erforderlichen Informationen zur Wiederherstellung des Objekts enthält. Das Ergebnis kann jedes Objekt sein.
Beim Laden eines mit marshal_dump gedumpten Objekts wird das Objekt zuerst instanziiert, dann wird marshal_load mit dem Ergebnis von marshal_dump aufgerufen. marshal_load muss das Objekt aus den Informationen im Ergebnis neu erstellen.
Beispiel
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 und _load
Verwenden Sie _dump und _load, wenn Sie das Objekt, das Sie wiederherstellen, selbst instanziieren müssen.
Beim Dumpten eines Objekts wird die Instanzmethode _dump mit einer Integer aufgerufen, die die maximale Tiefe der zu dumpenden Objekte angibt (ein Wert von -1 bedeutet, dass Sie die Tiefenprüfung deaktivieren sollten). _dump muss einen String zurückgeben, der die für die Wiederherstellung des Objekts erforderlichen Informationen enthält.
Die Klassenmethode _load sollte einen String entgegennehmen und damit ein Objekt derselben Klasse zurückgeben.
Beispiel
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
Da Marshal.dump einen String ausgibt, kann _dump einen Marshal-String zurückgeben, der in _load mit Marshal.loaded für komplexe Objekte geladen wird.
Constants
- MAJOR_VERSION
-
Hauptversion
- MINOR_VERSION
-
Nebenversion
Öffentliche Klassenmethoden
Source
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);
}
Serialisiert obj und alle nachfolgenden Objekte. Wenn anIO angegeben ist, werden die serialisierten Daten dorthin geschrieben, andernfalls werden die Daten als String zurückgegeben. Wenn limit angegeben ist, wird die Durchquerung von Unterobjekten auf diese Tiefe beschränkt. Wenn limit negativ ist, wird keine Tiefenprüfung durchgeführt.
class Klass def initialize(str) @str = str end def say_hello @str end end
(erzeugt keine Ausgabe)
o = Klass.new("hello\n") data = Marshal.dump(o) obj = Marshal.load(data) obj.say_hello #=> "hello\n"
Marshal kann die folgenden Objekte nicht dumpen
-
anonyme Klasse/Modul.
-
objekte, die mit dem System zusammenhängen (z. B.
Dir,File::Stat,IO,File,Socketund so weiter) -
eine Instanz von
MatchData, Method,UnboundMethod,Proc,Thread,ThreadGroup,Continuation -
Objekte, die Singleton-Methoden definieren
Source
# File marshal.rb, line 33 def self.load(source, proc = nil, freeze: false) Primitive.marshal_load(source, proc, freeze) end
Gibt das Ergebnis der Konvertierung der serialisierten Daten in source in ein Ruby-Objekt zurück (möglicherweise mit zugehörigen untergeordneten Objekten). source kann entweder eine Instanz von IO oder ein Objekt sein, das auf to_str reagiert. Wenn proc angegeben ist, wird jedes Objekt an die Prozedur übergeben, während das Objekt deserialisiert wird.
Übergeben Sie niemals nicht vertrauenswürdige Daten (einschließlich Benutzereingaben) an diese Methode. Weitere Details finden Sie in der Übersicht.
Wenn das Argument freeze: true übergeben wird, wird das deserialisierte Objekt tiefgefroren. Beachten Sie, dass dies aufgrund der Deduplizierung von gefrorenen Strings zu einer effizienteren Speichernutzung führen kann.
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