うちのチームに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
を繰り返し入力するのはダルいというのは、プログラマの三大美徳的の「怠惰」的に、自然な感情であるとはいえます。しかし、ひとのニックネームをプログラマの都合で変えるのは誤りです。かといって、ただその誤りを精神論的に責めてもしかたありません。プログラマなら技術で対抗するべきでしょう。そのため、わたくしたちはこのようなライブラリを実装したのでした。
この記事が、みなさまの参考になれば幸いです。