LoginSignup
2
0

More than 3 years have passed since last update.

rubyの機能を活用し、a~zを繋げた文字列を取得するために冗長に書く

Posted at

***注意***

以下のコードは かなり冗長 となっています。
「これ(a..z).to_a.joinでええやん^^;」はなしでお願いします。

本題

最近友人にRubyを教えていて、これが読めればいいんじゃないかな?ってコードを考えてみたところいい感じのが出来たので置いときます。

コード

# 可読性上げるためインデント調整してます。
__send__(
  define_method(
    25.times
      .inject(false.to_s[1]) { |s| s + s[s.size.pred].next }.to_sym,
    -> { __method__.to_s }
  )
)

pryでの実行結果

スクリーンショット 2019-12-14 20.45.18.png

ワンライナーでの実行

スクリーンショット 2019-12-14 21.24.47.png

解説

コード貼り付けただけだとしょっぱいので、内側から解説していきますw

25.times

define_methodの第一引数であるメソッド名(シンボル)を作成していきます。
25.timesEnumeratorオブジェクトを作り、自身をレシーバとしたEnumerableメソッドの実行回数を決めています。
これにより、inject25回実行させることができます。

inject(false.to_s[1]) { |s| s + s[s.size.pred].next }.to_sym

ここで(a..z).to_a.join.to_symと同様のコードとなるようにします。

引数に'a'を与え、ブロックの中で「現在の文字列 + (現在の文字列の最後の文字)の次の文字」を行なっています。

# 中身はこのイメージ
inject('a') {|'a'| 'a' + 'b'}
# 'a'の次は'b'   
inject('ab') {|'ab'| 'ab' + 'c'}
# 'b'の次は'c'
# ..., zを取得するまで繰り返す

これにより、次の文字を取得してくっつける処理が25回実行されるためa~zが得られます。

最後にto_symでシンボル化し第一引数は完成です。

-> { __method__.to_s }

difine_methodへ渡す第二引数であるProcオブジェクトを作成しています。
__method__でこのメソッドを呼び出したメソッド名(シンボル)を取得し、Stringオブジェクトに変換します。

define_method(name, proc)

第一引数にa~zを繋げた文字列のシンボル、プロックを渡しレシーバへメソッド定義をさせます。
そのままでは定義するだけで終わるので何かしらのメソッドで実行させます。

__send__(symbol)

レシーバに対して引数のメソッド名を実行します。
define_methodの戻り値が定義したメソッド名のシンボルであることを利用しそのまま渡します。

結果として-> { __method__.to_s }が呼ばれ、ここでa~zの文字列が得られました。

他の手段ですが、method(...).()でも同じようにできます。
この辺は好みだと思うのでどちらでも大丈夫ですねw

まとめ

解説は以上です。
このコードでは簡易的ですが、メソッドチェーン、メタプロ、リフレクション、Enumerable、Procオブジェクトが登場します。
脱初心者を目指すにはいい足掛かりにはなるんじゃないでしょうか?(主観100%)

2
0
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
2
0