Comparableモジュールを使って松竹梅を比較するモジュールを作ってみた

Comparableモジュールって何?

Comparableモジュールをincludeすると、< <= == > >= between?がそのクラスでも使えるようになります。
IntegerStringはこのComparableをincludeしているので比較演算ができるということです。

Integer.include?(Comparable) #=> true
String.include?(Comparable) #=> true

数値でも文字列でもなくて比較したくなるのってどんな時かというと、役職、ランク、漢数字などを実装したいときとか。

今回は和風なランク分けに使う松竹梅をモジュールとして実装してみたいと思います。

松竹梅で考えるComparable

Comparableを使えるようにする

Comparableモジュールを使えるようにするためには、<=>演算子(宇宙船演算子)を実装する必要があります。
<=>演算子が実装されているとsortが使えるようになるというのも大きなメリットです。

p [2,8,7,3,6].sort #=> [2, 3, 6, 7, 8]

a <=> bが次の結果を返すように実装する必要があります。

  • aがbより大きいなら正の整数
  • aとbが等しいなら0
  • aがbより小さいなら負の整数
  • aとbが比較できない場合はnil

コード化する

module Shochikubai
  include Comparable

  def digitizing_rank(rank)
    case rank
    when '' then 3
    when '' then 2
    when '' then 1
    else 0
    end
  end

  def <=>(other)
    if other.is_a?(Shochikubai)
      digitizing_rank(rank) <=> digitizing_rank(other.rank)
    else
      nil
    end
  end
end

インクルード先でattr_accessor :rankしてもらうのを前提にしています。
<=>メソッド定義の中で<=>を使っているのはややこしいですがdigitizing_rankの結果必ず数値が返ってくるので、Integerクラスの<=>を呼んでいることになります。 integerクラスの<=>を利用すれば、松と梅なら松の方が大きいみたいな処理を実装する必要はありません。とても便利です。

次に、実際にShochikubaiモジュールをincludeしてみます。

includeする

class Unaju
  include Shochikubai
  attr_accessor :rank

  def initialize(rank)
    @rank = rank
  end

  def return_unagi_num
    case rank
    when '' then 6
    when '' then 4
    when '' then 2
    else 1
    end
  end
end

うな重クラスを実装してShochikubaiをインクルードしました。
うな重クラスにはランクに応じてうなぎの数を返すreturn_unagi_numメソッドを実装しました。
実際に動かしてみます。

うな重を比較する

rich_unaju = Unaju.new('')
middle_unaju = Unaju.new('')
cheap_unaju = Unaju.new("")
unatama = Unaju.new('うな玉丼')

p rich_unaju > cheap_unaju #=>true
p rich_unaju == cheap_unaju #=> false
p rich_unaju < cheap_unaju #=>false

うな重をソートする

ranking = [middle_unaju,rich_unaju,unatama,cheap_unaju].sort.reverse
ranking.each do|unaju|
  puts "#{unaju.rank}にはうなぎが#{unaju.return_unagi_num}切れ載っている"
end

#=>松にはうなぎが6切れ載っている
#  竹にはうなぎが4切れ載っている
#  梅にはうなぎが2切れ載っている
#  うな玉丼にはうなぎが1切れ載っている

無事うな重をランクごとに比較、ソートできました!

以上です

同じ要領でやれば"警視総監から巡査までを序列順でソート"や"SABCでランク付け"みたいなことが簡単にできますね。
うなぎ食べたいなー。