Bye Bye Moore

猫マンション建築の野望を胸に零細事業主として資本主義の荒波に漕ぎ出したアラサー男の技術メモ

Procクラスを使って多変数な文字列を楽に生成する

今日はProcを使って文字列を作ります。

> b = proc {|x, y, z| "%s %s %s" % [(x||"0"),(y||"0"),(z||"0")] }
=> #<Proc:0x007fb063c00dd0@(irb):10>
> b.("as","you","like")
=> "as you like"
> b.("as","you")
=> "as you 0"

これがlambdaだと、引数チェックが厳密なので上手く行きません。

> b = lambda {|x, y, z| "%s %s %s" % [(x||"0"),(y||"0"),(z||"0")] }
=> #<Proc:0x007fb063bee720@(irb):13 (lambda)>
> b.("as","you")
ArgumentError: wrong number of arguments (2 for 3)
	from (irb):13:in `block in irb_binding'
	from (irb):14:in `call'
	from (irb):14
	from /Users/shuzo/.rbenv/versions/1.9.3-p448/bin/irb:12:in `<main>'

変数がバラつくようなら、ブロックの引数を工夫してあげればどちらでも行けます。

> proc {|*a| "%s %s %s" % [(a[0]||"0"),(a[1]||"0"),(a[2]||"0")] }.call("1","2")
=> "1 2 0"

> lambda {|*a| "%s %s %s" % [(a[0]||"0"),(a[1]||"0"),(a[2]||"0")] }.call("1","2")
=> "1 2 0"

何が何でも一行で収めたい場合はcallを使います。

proc {|x, y, z| "%s %s %s" % [(x||"0"),(y||"0"),(z||"0")] }.call(nil, "you", Time.now)
=> "0 you 2013-11-10 20:56:49 +0900"

とできます。

結果をを文字列として取得したい場合は、

> b =  Proc.new {|x, y, z| "%s %s %s" % [(x||"0"),(y||"0"),(z||"0")] }
=> #<Proc:0x007fb063b72d78@(irb):23>
> str = b.("as", "you", "like")
=> "as you like"


いかがでしたか?
procを使えばワンライナーでも鬼のように入り組んだ文字列だって楽に作れます。