Comparable を include しても <=> が無いと比較演算子は使えない
Comparableモジュールをincludeするだけでは <、>、between? などのメソッドは動きません。これらのメソッドは内部で<=>(UFO演算子)を呼び出す仕組みなので、クラス自身に<=>を定義しておく必要があります。
エラーメッセージの読み方
main.rb:11:in `<': comparison of Money with Money failed (ArgumentError)
main.rb- ファイル名
11- 行番号 — 実際にクラッシュした行
<- 発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
ArgumentError- 例外クラス — 何が起きたか。ここを検索するのが最短です
comparison of Money with Money failed- 詳細メッセージ — どの値が問題だったか
このエラーが出る典型パターン
パターン1
1 class Money 2 include Comparable 3 attr_reader :amount 4 def initialize(amount) 5 @amount = amount 6 end 7 8 ^ 9 end 10 11 puts Money.new(100) < Money.new(200)
Comparableはincludeするだけでは動きません。比較の基準となる<=>を自分で定義する必要があります。
直し方: (空) を def <=>(other)
amount <=> other.amount
end にします。
パターン2
1 class Weight 2 include Comparable 3 attr_reader :grams 4 def initialize(grams) 5 @grams = grams 6 end 7 8 ^ 9 end 10 11 puts Weight.new(100) < Weight.new(200)
<、>、between?などのメソッドはすべて内部で<=>を呼び出す仕組みです。<=>が無ければどれも動きません。
直し方: (空) を def <=>(other)
grams <=> other.grams
end にします。
パターン3
1 class Score 2 include Comparable 3 attr_reader :points 4 def initialize(points) 5 @points = points 6 end 7 8 ^ 9 end 10 11 puts Score.new(10) < Score.new(20)
「includeした時点で比較演算子が使えるようになるはず」という思い込みは誤りです。<=>の実装は自分の責任です。
直し方: (空) を def <=>(other)
points <=> other.points
end にします。
パターン4
1 class Distance 2 include Comparable 3 attr_reader :meters 4 def initialize(meters) 5 @meters = meters 6 end 7 8 ^ 9 end 10 11 puts Distance.new(5) < Distance.new(10)
<=>は「自分がotherより小さいか同じか大きいか」を-1・0・1で返すメソッドです。これがComparableの土台になります。
直し方: (空) を def <=>(other)
meters <=> other.meters
end にします。
パターン5
1 class Rank 2 include Comparable 3 attr_reader :value 4 def initialize(value) 5 @value = value 6 end 7 8 ^ 9 end 10 11 puts Rank.new(1) < Rank.new(2)
<=>を実装すれば、<や>だけでなくbetween?やclampなどComparableの全メソッドが一度に使えるようになります。
直し方: (空) を def <=>(other)
value <=> other.value
end にします。
よくある誤解
「Comparableをincludeした時点で比較演算子が自動的に使えるようになるはず」という思い込みは誤りです。Comparableは<=>の結果を使って他の比較メソッドを組み立てる仕組みにすぎず、<=>自体は自分で実装しなければなりません。
まとめ
Comparable を include しても <=> が無いと比較演算子は使えないは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。