うちのチームにkenkenというニックネームのメンバーがいて、日々がんばっています。
今日、pyamaさんというひとが「kenkenってタイプするの面倒だからkenにしなよ」と横暴なことをいいだして、「こりゃマズい、kenkenの入力を効率化しないと勝手に名前を変えられてしまう!」というわけで、みんなで知恵をふりしぼりました。
既存手法
kenkenという文字列は、kenという文字列がふたつ並んでいます。つまり、プログラマの三大美徳のひとつ「怠惰」という観点からすると、同じ文字列の入力を2回繰り返すのは、とてもダルいことです。
これを解決するために、まずはストレートに以下の案がでました。
2.times { print "ken" }
確かに、2回同じ文字列の入力を繰り返すことは避けられました、しかし、繰り返しは避けられたものの、puts "kenken"に比べて、総入力文字数という観点では、むしろダルくなっているのは否めません。
そこで、以下のようなやり方が提案されました。
puts "ken" * 2
確かに、これならそこそこ短い入力で、kenkenという文字列を出力できます。しかし、当たり前過ぎて、特に面白い回答とはいえません。
提案手法
わたくしたちは考えました。以下のような書き方で文字列kenkenを出力できるとしたら、かっこいいのではないかと。
puts ken ^ 2 #=> "kenken"
そこで作成したのが https://github.com/kentaro/kenken です。このライブラリを使うと、文字列kenkenの出力を以下のように書けます。
Kenkenクラスを使う場合
ken = Kenken.new("ken")
puts ken ^ 2 #=> "kenken"
Stringクラス拡張を使う場合
ken = "ken"
puts ken ^ 2 #=> "kenken"
これだけだと、「まあそうだよね」的な感じですよね。しかし、上記はあえてミスリーディングな例を示しています。このモジュールの真の力はここから発揮されます。以下の例をご覧ください。
Kenkenクラスを使う場合
ken = Kenken.new("hayapi")
puts ken ^ 2 #=> "kenken"
Stringクラス拡張を使う場合
ken = "hayapi"
puts ken ^ 2 #=> "kenken"
おわかりでしょうか。つまり、引数にわたされた文字列によってkenkenという文字列を出力しているのではなく、変数名によって文字列を出力していることが。ここまでやれば、pyamaさんといえども、kenkenというニックネームを認めざるを得ないでしょう。
技術的な解説
Kenkenクラス、および、拡張されているStringクラスともに、上記の処理を実装したKenkenizerモジュールをmixinしています。Kenkenizerモジュールの実装は以下の通りです。
module Kenkenizer
def ^(count = 1)
b = binding.of_caller(1)
var = b.eval('local_variables').find do |v|
var = b.eval(v.to_s)
self == var
end
var.to_s * count
end
end
ポイントは、binding.of_caller(1)という箇所です。これはbinding_of_callerというgemの提供するメソッドです。呼び出し元をさかのぼって、レベルごとのbinding、すなわち環境をいい感じにとってこれるというものです。
binding.of_caller(1)でひとつ上の環境をとってきたあとにb.eval('local_variables')とすることで、その環境での変数名(Symbol)の一覧を取り出し、さらにそれらをその環境で評価することでオブジェクトにします。それらのオブジェクトと自分自身を比較して、一致するものを自分自身を表す変数として判定します。
これで、無事に変数名から動的に、Kenkenizeするべき文字列を取り出せました。すなわち、Kenkenizeとは、
- 変数名から出力に使う文字列を動的に取り出す
-
^メソッドにより、その文字列を繰り返す
という処理のことをいいます。それを実現するためにわたくしたちが開発したのが https://github.com/kentaro/kenken ということになります。
おわりに
kenkenと、kenを繰り返し入力するのはダルいというのは、プログラマの三大美徳的の「怠惰」的に、自然な感情であるとはいえます。しかし、ひとのニックネームをプログラマの都合で変えるのは誤りです。かといって、ただその誤りを精神論的に責めてもしかたありません。プログラマなら技術で対抗するべきでしょう。そのため、わたくしたちはこのようなライブラリを実装したのでした。
この記事が、みなさまの参考になれば幸いです。