Marshal

Ruby オブジェクトをファイル(または文字列)に書き出したり、読み戻したり する機能を提供するモジュール。大部分のクラスのインスタンスを書き出す事 ができますが、書き出しの不可能なクラスも存在します(後述)。

ここで「マーシャルデータ」と言う用語は、Marshal.dump が出力する文字列 を指すものとします。

モジュール関数:

Marshal.dump(obj[,port][,limit])

obj を再帰的にファイルに書き出します。ファイルに書き出せない オブジェクトをファイルに書き出そうとすると例外 TypeError が 発生します。ファイルに書き出せないオブジェクトは以下の通りです。

また、これらのオブジェクトを間接的に指すオブジェクトなども書き出せ ません。例えば、デフォルト値を求めるブロックを持った HashProc を間接的に指していることになります。

p Marshal.dump(Hash.new {})
=> -:1:in `dump': cannot dump hash with default proc (TypeError)

port には IO(またはそのサブクラス)のインスタンスを指定 します。この場合、port を返します。省略した場合には dump はそのオブジェクトをダンプした文字列を返します。

limit を指定した場合、limit 段以上深くリンクしたオブジェ クトをダンプできません(デフォルトは 100 レベル)。負の limit を指定すると深さチェックを行いません。

マーシャルの動作を任意に定義することもできます。詳細は、 ユーザ定義のMarshal を参照してください。

Marshal.load(port[,proc])
Marshal.restore(port[,proc])

port からマーシャルデータを読み込んで、元のオブジェクトと同 じ状態をもつオブジェクトを生成します。port は文字列か IO(またはそのサブクラス)のインスタンスを指定します。

proc として手続きオブジェクトが与えられた場合には読み込んだ オブジェクトを引数にその手続きを呼び出します。 *1

str = Marshal.dump(["a", 1, 10 ** 10, 1.0, :foo])
p Marshal.load(str, proc {|obj| p obj})

=> "a"
   1
   10000000000
   1.0
   :foo
   ["a", 1, 10000000000, 1.0, :foo]
   ["a", 1, 10000000000, 1.0, :foo]

定数:

MAJOR_VERSION ((<ruby 1.7 feature>))
MINOR_VERSION ((<ruby 1.7 feature>))

Marshal.dump が出力するデータフォーマットのバージョ ン番号です。

Marshal.load は、メジャーバージョンが異なるか、バー ジョンの大きなマーシャルデータを読み込んだとき例外 TypeError を発生させます。

マイナーバージョンが古いだけのフォーマットは読み込み可能ですが、 $VERBOSE = true のときには警告メッセージが 出力されます

マーシャルされたデータのバージョン番号は以下のようにして取得するこ とができます。

obj = Object.new
major, minor = Marshal.dump(obj).unpack("cc")
p [major, minor]

ユーザ定義のMarshal

Object#_dump(limit)
Class#_load(str)

Marshal.dump において出力するオブジェクトがメソッド `_dump' を定義している場合には、そのメソッドの結果が書き出されます。メソッ ド `_dump' は引数として再帰を制限するレベル limit を受 け取り、オブジェクトを文字列化したものを返します。

インスタンスがメソッド `_dump' を持つクラスは必ず同じフォー マットを読み戻すクラスメソッド `_load' を定義する必要があり ます。`_load' はオブジェクトを表現した文字列を受け取り、それ をオブジェクトに戻したものを返す必要があります。

class Foo
  def initialize(obj)
    p "initialize() called"
    @foo = obj
  end
  def _dump(limit)
    Marshal.dump(@foo, limit)
  end
  def self._load(obj)
    Foo.new(Marshal.load(obj))
  end
end

p Marshal.load(Marshal.dump(Foo.new(['foo', 'bar'])))

=> "initialize() called"
   "initialize() called"
   #<Foo:0x4019eb88 @foo=["foo", "bar"]>

インスタンス変数の情報は普通マーシャルデータに含まれるので、この例 のように _dump を定義する必要はありません(ただし _dump を定義すると インスタンス変数の情報は dump されなくなります)。 _dump/_load はより高度な制御を行いたい場合や拡張ライブラリで定義し たクラスのインスタンスがインスタンス変数以外に情報を保持する場合に 利用します。(例えば、クラス Time は、_dump/_load を定義して います)

Object#marshal_dump ((<ruby 1.8 feature>))
Object#marshal_load ((<ruby 1.8 feature>))

*2

Marshal.dump において、出力するオブジェクトがメソッド `marshal_dump' を定義している場合には、その戻り値が dump されます。 メソッド marshal_dump は任意のオブジェクトを返すメソッドとし て定義します。

このようなオブジェクトを load するにはメソッド `marshal_load' が定 義されていなくてはならず、load 時に利用されます。 marshal_load は marshal_dump の戻り値のコピーを引数に受け取 ります。marshal_load 時の self は、生成されたばかり (allocate されたばかり)の状態です。 なお、marshal_load の戻り値は無視されます。

dump するオブジェクトが _dump と marshal_dump の両方のメソッドを持 つ場合 marshal_dump が利用されます。

class Foo
  def initialize
    p "initialize() called"
    @foo = ['foo', 'bar']
  end
  def marshal_dump
    @foo
  end
  def marshal_load(obj)
    @foo = obj
  end
end

p Marshal.load(Marshal.dump(Foo.new))

"initialize() called"
#<Foo:0x4019ed2c @foo=["foo", "bar"]>

インスタンス変数の情報は普通マーシャルデータに含まれるので、この例 のように marshal_dump を定義する必要はありません(ただし marsahl_dump を定義するとインスタンス変数の情報は dump されなくな りますので、marshal_dump/marshal_load で扱う必要があります)。 marshal_dump/marshal_load はより高度な制御を行いたい場合や 拡張ライブラリで定義したクラスのインスタンスがインスタンス変数以外 に情報を保持する場合に利用します。

特に、marshal_dump/marshal_load を定義したオブジェクトは特異メソッドが 定義されていてもマーシャルできるようになります。 (特異メソッドの情報が自動的に dump されるようになるわけではなく、 marshal_dump/marshal_load によりそれを実現する余地があるということ です)


*1以前 Fixnum, Symbol が渡されない不具合があったが、 1.6.7 2002-03-15 ごろに改修済み
*2ruby 1.8 feature: marshal_dump/marshal_load の仕組みは ruby 1.8.0 から導入されました。_dump/_load よりも使いやすいので、 こちらの利用が推奨されます。_dump/_load はまだ obsolete にはなって いませんが、遠い将来そうなるかもしれません。 [ruby-dev:21088]



rubyist ML