active support その2

こんばんは、先週に引き続き久保田です。

今週もactivesupportを見て行きたいと思います。
今回は、いつも使っているメソッドたちがどのように定義されているかを見て、テクを盗もうと思います。

今回取り上げるメソッドは、blank?, present?の2つと
second, third, fourth, fifthのArrayにアクセスするためのメソッド達です。

今回もバージョンはactivesupport 5.0.0beta3を見ていきます。

まずは、blank?からです。

こちらはおなじみ、
レシーバが nil, false, 空文字, 空配列, 空ハッシュの時にtrueを返してくれます。

このメソッド最高ですよね。使い勝手もそうですが、名前が最高ですね。配列の空判定をするときはめちゃくちゃ気持ちよく書けますね。

そんな最高なメソッドはこう定義されています。

# activesupport-5.0.0.beta3/lib/active_support/core_ext/object/blank.rb
class Object

...

def blank?
respond_to?(:empty?) ? !!empty? : !self
end

...

end

objectクラスをオープンクラスしていますね。なので基本的にどんなオブジェクトからでも呼べるんですかねー。

さて、メソッドの中身ですが、なんと一行ですね。
この一行だけでRailsユーザーのプログラミングライフを彩っていると思うと興奮を抑えられません。

ただよく見ると短い中にかなりテクニックが詰まっていそうですね。

まず、三項演算子の条件式で、レシーバに対してempty?を持っているかどうか尋ねています。
レシーバが配列やハッシュのコレクションならばここでtrueが返ります、そうでなければfalseですね。
ここはいいでしょう。

そして注目すべきは三項演算子のtrueの評価式ですね。!が二個ついています。

!!empty?

これは、よく使われるテクニックで、オブジェクトをtruefalseにして返したい時に使います。

たとえば!!'hoge'としたとしましょう。

!!'hoge'
1. まず!'hoge'が実行され、trueもしくはfalseが返る。
2. 1の戻り値に対して!をする。つまり真偽値が逆転する。
'hoge' => false => true
'hoge' => true => false

こういうことですね。

ここではempty?の戻り値に対して!!です。いや、empty?も真偽値返すじゃんと思ったあなた。僕も全く同じことを思っています。
まぁここは絶対に真偽値を返すということなんですかね。
たとえば独自クラスでempty?を定義していてそれが真偽値を返していない場合とか。。。ありえないと思いますが。。。

さて少し長くなってしまいましたが、falseの場合の評価式も見てみます。

!self

selfを逆転していますね。つまりselfがfalseやnilならばtrueにしています。
ここで疑問が生まれます。これでは空文字はtrueになりません。

!'' #=> false

おいおいと。どういう事でしょう。
しかしここからが面白いところです。

このファイルを下に下に見て行くと、、、

# activesupport-5.0.0.beta3/lib/active_support/core_ext/object/blank.rb
class NilClass
def blank?
true
end
end

class FalseClass
def blank?
true
end
end

...

class Array
alias_method :blank?, :empty?
end

...

class String
BLANK_RE = /\A[[:space:]]*\z/
def blank?
BLANK_RE === self
end
end

...

class Numeric #:nodoc:
def blank?
false
end
end

...

そう、このようにほとんどのコアライブラリがオープンされ、blank?が定義されています。
実際にいつも使うような、コレクションや文字列に対してのblank?はこちらが使われているんです。

これなら空文字もtrueになるのも納得ですね!

つまり最初に見ていたObjectクラスのblank?はこれらの標準クラス以外の独自クラスやモジュール、標準ライブラリで使われているようです。そして使われるときは、基本的には三項演算子のfalseの評価式を見そうですね。そして基本的にはfalseを返しそうですね。NilClassも拡張されていますから。

長くなりましたが、blank?は以上です。

さぁどんどん行きましょう。次はpresent?です。

こちらはblank?の逆を返してくれますね。つまりnil, false, 空文字,空配列,空ハッシュ以外はtrueを返します。

これもblank?と同じファイルに定義されています。

そして定義はこのようになっています。

class Object
def present?
!blank?
end
end

これで終わりです。本当に動作と同じように、blank?の反対ですね。。。
Objectにしか定義されていないので、すべてのblank?の結果の反対を返していますね。

非常にシンプルで、かつ合理的で、動作が表現されており、ぞくぞくしますね。。。
これを作った方はめちゃくちゃ楽しかったでしょうね。僕ならニヤニヤしながら作ります。

次はArrayのsecond, third, fourth, fifth系のメソッドたちです。
これは単純に配列の2番目と3番目と4番目と5番目にアクセスするためのメソッドです。

こういう細かい配慮みたいなのはすごく好きで、
arr[2]よりも、arr.secondの方がかっこいいですよね。

実装も非常に簡単で、

class Array
...
def second
self[1]
end
...
end

self[]の数字が変わっていくだけです。

fifthまでしかないのですが、下を見て行くと、なぜかこんなものがあります。

  def forty_two
self[41]
end

42?
なんだろうこれは、と思って先輩に聞いてみると、
ダグラス・アダムズの小説で書かれているコンピュータが「生命、宇宙、そして万物についての究極の疑問の答え」を問われ、出した答えが「42」
らしいです。

何でこんなのを作ったんだろうと調べてみると、DHH(Railsの生みの親)が、redditという掲示板のようなところで、「もっと便利なヘルパーを作ってくれよ!」と言われまくり、ジョークで追加したのがArray#forty_twoらしいです。

こんなのもあるんですね、初めて知りました。

いつかこういうのも使ってみたいですね。笑

今回は以上です。
今回みたのはActiveSupportの中でも氷山の一角中の一角なので、今後も時間があるときに便利なメソッド探し&テクの勉強のために見てみようと思います。

ではまた。次はRailsのルーティングを担っているActionPackを見てみたいなと思います。

ありがとうございました。