2008年 01月 08日

Perl の YAML と Ruby の YAML の相互運用

Ruby は標準添付の yaml で、Perl は YAML::Syck にします。でもって、Syck のオプションを

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote    = 1;

にするとたぶん互換になるみたいです。ImplicitTyping は POD にも「こうすると互換になるよ」って書いてあるやつです。SingleQuote は 8 進数みたいな文字列 (/0[0-7]+/) をよみかきするときに必要になります。

use strict;
use warnings;
use Data::Dumper;
sub p { print Dumper shift }

use YAML::Syck;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '--- 
foo: 0100
';

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote = 1;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '--- 
"foo": \'0100\'
';

$YAML::Syck::ImplicitTyping = 1;
$YAML::Syck::SingleQuote = 0;
p YAML::Syck::Load(YAML::Syck::Dump({foo=>"0100"}));
p YAML::Syck::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => 64
        };
$VAR1 = '--- 
foo: 0100
';

use YAML;

p YAML::Load(YAML::Dump({foo=>"0100"}));
p YAML::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '---
foo: 0100
';

use YAML::XS;

p YAML::XS::Load(YAML::XS::Dump({foo=>"0100"}));
p YAML::XS::Dump({foo=>"0100"});
$VAR1 = {
          'foo' => '0100'
        };
$VAR1 = '---
foo: 0100
';

Ruby の YAML.load の挙動は YAML::Syck の $YAML::Syck::ImplicitTyping = 1; のときの挙動と一緒です。すなわちクオートしない /0[0-7]+/ は8進数の数値になります。YAML.dump は数値っぽい文字列を自動でクオートします。

require "yaml"

p YAML.load(<<EOS) #=> {"foo"=>64}
---
foo: 0100
EOS

p YAML.load(<<EOS) #=> {"foo"=>"0100"}
---
foo: "0100"
EOS

puts YAML.dump({"foo" => "0100"})
# --- 
# foo: "0100"
#
puts YAML.dump({"foo" => "aaa"})
# --- 
# foo: aaaa

ポイントは結局のところ

  • Dump 時に8進数っぽい文字列がクオートされるか
  • Ruby の yaml は特にオプションとかがない (なので、クオートされないものはつかえない)

みたいですね。あと、Perl しか使わない場合でも、$YAML::Syck::ImplicitTyping = 1 で使うときは必ず $YAML::Syck::SingleQuote = 1; も指定しないとデータがこわれてしまうみたいです。

Perl については調べきれてないかもしれないです (Syck 以外でもクオートできるのかな……)。もしかするともっといい方法があったりするのかもしれない……