9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rubyで文字列を `Kenkenization` する

Last updated at Posted at 2019-09-04

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

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

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?