- Ruby / Rails関連
[Rails5] Active Support Core ExtensionsのIntegerクラス: ordinalize、multiple_of?など
こんにちは、hachi8833です。ActiveSupport探訪シリーズ、Durationが当初の予想より長くて深く、しかもCore Extensionsの外に出てしまっていました。
そこで久しぶりに、Core Extensionsの中から小粒でかわいらしいIntegerクラスにお邪魔いたします。? ?
条件
- Railsバージョン: 5.0.1(5-0-stable)
- Rubyバージョン: 2.4.0
active_support/core_ext/integer/
active_support/core_ext/integerの以下のファイルが対象です。
例によってコメントを取り除いてあります。
inflector.rb
require 'active_support/inflector'
class Integer
def ordinalize
ActiveSupport::Inflector.ordinalize(self)
end
def ordinal
ActiveSupport::Inflector.ordinal(self)
end
end
開けてみれば、ActiveSupport::Inflector
に丸投げ委譲しています。以下の表はIntegerクラスのメソッドで表します。
- Integer#ordinalize
- 数値に序数の接尾語(suffix)を追加する
ordinalize(1) # => "1st"
ordinalize(2) # => "2nd"
ordinalize(1002) # => "1002nd"
ordinalize(1003) # => "1003rd"
ordinalize(-11) # => "-11th"
ordinalize(-1021) # => "-1021st"
- Integerr#ordinal
- 数値に対応する序数の接尾語(suffix)を返す
ordinal(1) # => "st"
ordinal(2) # => "nd"
ordinal(1002) # => "nd"
ordinal(1003) # => "rd"
ordinal(-11) # => "th"
ordinal(-1021) # => "st"
いかにも英語圏で欲しいヘルパーメソッドという感じですね。活用(Inflection)系メソッドのうち、数値をIntegerクラスで扱うのは納得です。
0th
に一瞬ぎょっとしてしまいましたが、一応Wikipediaにも記載があります。考えてみれば数学や工学などの専門用語としての「ゼロ次数」は普通にありますね。熱力学第零法則なんてものもあります。
なお、専門用語でないzerothにはやや異なるニュアンスがこもるようです。
参考: 序数の国際化について
Railsで英語以外の言語の序数を活用できるかどうかネットで探してみましたが、それらしいものは見当たりませんでした。
単語の単数形複数形をinitializers/inflections.rbに記述したり、locales/ロケール名.ymlで月名や日時フォーマットを記述する、といったことならある程度まで可能ですが、アルゴリズムによる国際化の困難な言語要素はいろいろとあり、序数もそのひとつです。
たとえばスペイン語では序数にジェンダー(男性形・女性形)があるために、序数を機械的に活用できません。数値が使われるコンテキストを人間や人工知能が読み取らないと序数のジェンダーを決定できないので実に厄介です。
Railsに限らず国際化にはさまざまな困難がともないます。日本語は数値に「番目」さえつければ序数になるのでありがたいですね。
time.rb
require 'active_support/duration'
require 'active_support/core_ext/numeric/time'
class Integer
def months
ActiveSupport::Duration.months(self)
end
alias :month :months
def years
ActiveSupport::Duration.years(self)
end
alias :year :years
end
こちらは以前のTechRacho記事でおなじみのActiveSupport::Duration
にまるっと委譲しています。
multiple.rb
class Integer
def multiple_of?(number)
number != 0 ? self % number == 0 : zero?
end
end
三項演算子を使ったワンライナーです。引数がゼロの場合はレシーバを#zero?
でチェックすることで、ゼロ除算を回避しています。
個人的には、これ以上複雑になったら三項演算子はやめたい気がします。
Integer#multiple_of?
- レシーバのIntegerが引数で割り切れるかどうかを論理値で返す
0.multiple_of?(0) # => true
6.multiple_of?(5) # => false
10.multiple_of?(2) # => true