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
ポイントは結局のところ
みたいですね。あと、Perl しか使わない場合でも、$YAML::Syck::ImplicitTyping = 1 で使うときは必ず $YAML::Syck::SingleQuote = 1; も指定しないとデータがこわれてしまうみたいです。
Perl については調べきれてないかもしれないです (Syck 以外でもクオートできるのかな……)。もしかするともっといい方法があったりするのかもしれない……
String.prototype.repeat = function (n, sep) { if (n < 1) return ""; return Array(n).join(this + (sep || "")) + this; }; print("hoge".repeat(-1, '+')); //=> "" print("hoge".repeat(0, '+')); //=> "" print("hoge".repeat(1, '+')); //=> "hoge" print("hoge".repeat(3, '+')); //=> "hoge+hoge+hoge" print("fuga".repeat(4, '-')); //=> "fuga-fuga-fuga-fuga" print("foo".repeat(4)); //=> "foofoofoofoo"
Rakeのタスクに引数が取れるようになったけど…ひどい - (rubikitch loves (Emacs Ruby CUI Books)) をみてて、使えるようになったノカーとか思いつつ、このままだとちょっと使えないなぁと思ったので、Rakefile で対応できる範囲でつかいやすくしてみた
def args(hash) name = hash.keys.first args = hash[name] task name, *args end desc "foo task" args :foo => [:bar, :baz] task :foo do |t,a| p t.arg_names p a.bar p a.baz end desc "bar task" task :bar do |t| puts "this is bar." end # ARGV は Rakefile が実行される時には既に rake 自体への引数は全てとりのぞかれている Rake.application.top_level_tasks.replace(ARGV.map {|a| name, vals = *a.split(/@/, 2) vals ? "#{name}[#{vals}]" : a })
これで
$ rake 'foo[aaa,bbb]' (in /Users/cho45/tmp) [:bar, :baz] "aaa" "bbb" $ rake foo@aaa,bbb (in /Users/cho45/tmp) [:bar, :baz] "aaa" "bbb"
になって、どっちでもいけるようになる。
あと引数の宣言の DSL がめちゃくちゃわかりにくいと思うのでオレオレメソッドを定義してみた (あの DSL で、後ろに書いてあるのが引数だと想像できる人はどれほどいるんだろう……)。先に args の宣言がくるのはちょっとキモいけど、task メソッドうわがきせずやるとこんなもんなのかなぁ。
でもそんなに引数めちゃくちゃとりたいケースってないのかもしれない……
いまさらだけど別に ARGV みなくても top_level_tasks.map! でいいのだった。(最初は ARGV をもっといじくるコードを書いてたなごり)