今回は Active Support の core_ext の Integer の拡張メソッド をコードリーディングしていきます。
※Active Support 5.2.2 で実行してます。
Integer の拡張メソッドとして挙げられているのは以下になります。
- multiple_of?
- ordinal
- ordinalize
- Time クラス(この記事ではやりません)
時間に纏わるメソッドを複数生やしている
上述するように、Time クラスは時間の計算をする複数のメソッドを拡張しており、それだけで記事が書けそうなボリュームなので、今回のコードリーディングの対象は multiple_of
, ordinal
, ordinalize
にします。
Time クラスは気力が残ってれば別で書きます。。
RAILS GUIDE はこちら railsguides.jp
それでは、早速各メソッドを読んでいきます。
multiple_of?
レシーバが引数の倍数かどうか判定するメソッドです。
# multiple_of? puts 4.multiple_of?(2) # => true puts 3.multiple_of?(2) # => false puts 0.multiple_of?(2) # => true
実装はたった3行です。
def multiple_of?(number) number != 0 ? self % number == 0 : zero? end
- 引数に与えられた整数
number
を三項演算子で評価し結果を返す
number
が 0 以外だと、レシーバをnumber
で除算の結果、剰余の有無で真理値を返す
一方number
が 0 の場合zero?
メソッドのレスポンスにより true を返す
※また、6.0.0.beta1では少しコードが変わっているみたいで、早くなっているそう?
Faster multiple_of? method by rigani · Pull Request #33854 · rails/rails · GitHub
ordinal
レシーバに対応する序数の接尾辞の文字列を返すメソッドです。
# ordinal puts 14444444444.ordinalize # => th puts 3.ordinalize # => rd
lib/active_support/core_ext/integer/inflections.rb
のordinal
メソッドでActiveSupport::Inflector#ordinal
が呼ばれる
実装はActiveSupport::Inflector#ordinal
で行われている
Inflect は変化させるという意味があるので、ActiveSupport::Inflector
クラスでは言葉を変化させるようなメソッドが実装されている
https://github.com/rails/rails/blob/5-2-2/activesupport/lib/active_support/inflector/methods.rb#L343レシーバの絶対値を 100 で除算した剰余 =
abs_number
を引数にinclude?
を呼ぶ
https://github.com/rails/rails/blob/5-2-2/activesupport/lib/active_support/inflector/methods.rb#L346本来
Range#include?
が呼ばれるがActiveSupport::IncludeTimeWithZone#include?
でオーバーライドされているActiveSupport::IncludeTimeWithZone#include?
では、レシーバ(11..13
)がTimeZone
クラスか判定しており、該当しないためsuper
メソッドが呼ばれ、親クラスであるActiveSupport::IncludeWithRange#include?
が呼ばれる
https://github.com/rails/rails/blob/5-2-2/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rbActiveSupport::IncludeWithRange#include?
でabs_number
がRange
クラスかどうか判定されるが Integer クラスなので、またsuper
が呼ばれる
https://github.com/rails/rails/blob/5-2-2/activesupport/lib/active_support/core_ext/range/include_range.rb最後に
Range#include?
が呼ばれ、abs_number
が11..13
の範囲に該当していれば、th
が返され、それ以外であればさらにabs_number
を 10 で除算した剰余によって値が返される
ordinalize
レシーバに対応する序数を返すメソッドです
# ordinalize puts 11.ordinal # => true
lib/active_support/core_ext/integer/inflections.rb
のordinalize
メソッドでActiveSupport::Inflector#ordinalize
が呼ばれる
https://github.com/rails/rails/blob/5-2-2/activesupport/lib/active_support/inflector/methods.rb#L367あとは先ほどの
ordinal
が呼ばれ、その結果をレシーバに結合させて序数として返しているだけ
まとめ
今回コードリーディングした部分は、難易度もとても易しく読みやすいので、Ruby 始めたての方でも理解できると思います。
とはいえ、オープンクラスなども取り入れられており、実際のコードから学ぶことができるのでオススメです。