***注意***
以下のコードは かなり冗長 となっています。
「これ(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での実行結果
ワンライナーでの実行
解説
コード貼り付けただけだとしょっぱいので、内側から解説していきますw
25.times
define_method
の第一引数であるメソッド名(シンボル)を作成していきます。
25.times
でEnumerator
オブジェクトを作り、自身をレシーバとしたEnumerable
メソッドの実行回数を決めています。
これにより、inject
を25回実行させることができます。
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%)