🦁
[Feature #20669] Marshal.load 用の例外を追加する提案
[Feature #20669] Add Marshal::MarshalError class to differentiate ArgumentErrors
-
marshalはいろんなデータをファイル(文字列)に変換し、そのデータを復元するためのライブラリ
# データを文字列に変換
data = Marshal.dump({ id: 1, name: "homu", age: 14 })
pp data
# => "\x04\b{\b:\aidi\x06:\tnameI\"\thomu\x06:\x06ET:\bagei\x13"
# そのデータを復元する
pp Marshal.load(data)
# => {:id=>1, :name=>"homu", :age=>14}
- このときに
Marshal.loadにフォーマットが不正なデータや破損したデータを渡すと次のようにTypeErrorやArgumentErrorが発生する
begin
# 復元できるフォーマットではない場合
Marshal.load("foobar")
rescue
pp $!
# => #<TypeError:"incompatible marshal file format (can't be read)\n\tformat version 4.8 required; 102.111 given">
end
begin
# データが途中で破損している場合
Marshal.load(Marshal.dump(Object.new).slice(0, 10))
rescue
pp $!
# => #<ArgumentError: marshal data too short>
end
begin
# 以下のように MyThing に依存するようなデータを復元する場合
# MyThing = Struct.new(:name, :age)
# Marshal.dump(MyThing.new("Alice", 20))
# => "\x04\bS:\fMyThing\a:\tnameI\"\nAlice\x06:\x06ET:\bagei\x19"
Marshal.load "\x04\bS:\fMyThing\a:\tnameI\"\nAlice\x06:\x06ET:\bagei\x19"
rescue
pp $!
# => #<ArgumentError: undefined class/module MyThing>
end
-
TypeErrorやArgumentErrorは通常以下のような場合に発生することを期待するがMarshal.loadの場合はそれ以外でも同エラーが発生するのでそれを区別できるようにしたい、というのがこのチケットの内容-
TypeError: 引数の型が異なる場合 -
ArgumentError: 引数の数が異なる場合
-
- これを回避するために
Marshal::LoadErrorを追加する提案が書かれている-
Marshalの内部でエラーが発生した場合はこの例外を返す想定
-
- この提案の問題として互換性の話が上がっています
- いままで
ArgumentErrorだったものがMarshal::LoadErrorに変わるのでrescue ArgumentErrorしている箇所が非互換になってしまう
- いままで
- これに限らず
ArgumentErrorとするのかは難しそうですねえ
Discussion