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.