Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

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を使えばワンライナーでも鬼のように入り組んだ文字列だって楽に作れます。