rubyのYAMLによるシリアライズについて
全く中身を把握していなかった事に気づかされたので、少しだけ調べてみました。
以下は Object#to_yaml のソース。
# yaml/rubytypes.rb class Object yaml_as "tag:ruby.yaml.org,2002:object" def to_yaml_style; end def to_yaml_properties; instance_variables.sort; end def to_yaml( opts = {} ) YAML::quick_emit( self, opts ) do |out| out.map( taguri, to_yaml_style ) do |map| to_yaml_properties.each do |m| map.add( m[1..-1], instance_variable_get( m ) ) end end end end end
クラス名とインスタンス変数を記録している様です。
(001): >> require 'yaml' => true (002): >> class Hoge def initialize(a, b, c) @a, @b, @c = a, b, c end end => nil (007): >> puts Hoge.new(1, 2, 3).to_yaml --- !ruby/object:Hoge a: 1 b: 2 c: 3 => nil (008): >> YAML.load(Hoge.new(1, 2, 3).to_yaml).instance_eval{ p @a, @b, @c } 1 2 3 => nil
確かに、インスタンス変数が記録され、復元するとその値がインスタンス変数にセットされています。
肝心の復元方法ですが、ぱっとソースを眺めた感じよく分かりませんでした。挙動から想像する限り、Class.allocate して instance_variable_set とかしてるんだろうと思います。
以下は allocate で grep した結果見つかったソースです。
def YAML.object_maker( obj_class, val ) if Hash === val o = obj_class.allocate val.each_pair { |k,v| o.instance_variable_set("@#{k}", v) } o else raise YAML::Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect end end
ユーザ定義のクラスをYAMLでシリアライズする場合、allocateによるインスタンス化とインスタンス変数の代入によってオブジェクトが復元出来る様にしておく必要があるという事でしょうか。
そうだとすれば、initialize による初期化処理が必要な場合に困る事があるのでしょうかね?