Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

[Rails5] Active Support Core ExtensionsのIntegerクラス: ordinalize、multiple_of?など

こんにちは、hachi8833です。ActiveSupport探訪シリーズ、Durationが当初の予想より長くて深く、しかもCore Extensionsの外に出てしまっていました。
そこで久しぶりに、Core Extensionsの中から小粒でかわいらしいIntegerクラスにお邪魔いたします。? ?

条件

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

関連記事

[Rails5] Railsの主要なライブラリ構成

Rails: ビューのHTMLエスケープは#link_toなどのヘルパーメソッドで解除されることがある


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。