Help us understand the problem. What is going on with this article?

Rubyで文字列を `Kenkenization` する

More than 1 year has passed since last update.

うちのチームに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とは、

  1. 変数名から出力に使う文字列を動的に取り出す
  2. ^メソッドにより、その文字列を繰り返す

という処理のことをいいます。それを実現するためにわたくしたちが開発したのが https://github.com/kentaro/kenken ということになります。

おわりに

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

この記事が、みなさまの参考になれば幸いです。

kentaro
PerlとEmacsが好きです。
pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away