LoginSignup
2
2

More than 5 years have passed since last update.

Ruby で Range オブジェクトを生成するには、スペースシップ演算子「<=>」と succ メソッドが必要

Posted at

Range オブジェクトの条件

Range オブジェクトを生成するクラスには、スペースシップ演算子「<=>」と succ メソッドが必要。

class Range (Ruby 2.4.0)
https://docs.ruby-lang.org/ja/latest/class/Range.html

範囲演算子のオペランドは互いに <=> で比較できる必要があります。 さらに Range#each を実行するためには succ メソッ ドを実行できるものでなければいけません。

スペースシップ演算子「<=>」は順序を比較するための演算子。

module Comparable (Ruby 2.4.0) https://docs.ruby-lang.org/ja/latest/class/Comparable.html

self <=> other は

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

をそれぞれ返すことが期待されています。

succ メソッドは、「次のオブジェクト」を返すメソッド。
「次のオブジェクト」はクラスによってそれぞれ定義されている。

instance method Integer#next (Ruby 2.4.0)
https://docs.ruby-lang.org/ja/latest/method/Integer/i/next.html

self の次の整数を返します。

instance method String#next (Ruby 2.4.0) https://docs.ruby-lang.org/ja/latest/method/String/i/next.html

self の「次の」文字列を返します。

「次の」文字列は、対象の文字列の右端から アルファベットなら アルファベット順(aの次はb, zの次はa, 大文字も同様)に、 数字なら 10 進数(9 の次は 0)とみなして計算されます。

instance method Date#next (Ruby 2.4.0)
https://docs.ruby-lang.org/ja/latest/method/Date/i/next.html

翌日の日付オブジェクトを返します。

Range オブジェクトを生成できるクラスを実装する

スペースシップ演算子「<=>」と succ メソッドを実装したシンプルなクラスのコードを書いてみた。

class RangeImpl

  attr_reader :value

  def initialize(value)
    puts "initialize: #{value}"
    @value = value 
  end

  def <=>(other)
    puts "<=>: #{value}"
    @value <=> other.value
  end

  def succ()
    puts "succ: #{value}"
    RangeImpl.new(@value + 1)
  end

end

puts '[create range]'
r = RangeImpl.new(1)..RangeImpl.new(5)

puts '[to array]'
a = r.to_a

実行結果。
スペースシップ演算子「<=>」と succ メソッドがどのタイミングでコールされているかわかる。

$ ruby range.rb 
[create range]
initialize: 1
initialize: 5
<=>: 1
[to array]
<=>: 1
succ: 1
initialize: 2
<=>: 2
succ: 2
initialize: 3
<=>: 3
succ: 3
initialize: 4
<=>: 4
succ: 4
initialize: 5
<=>: 5

範囲演算子「..」の際に、最初と最後のオブジェクトが生成される。
その後、実際に使うタイミング (今回は to_a メソッドで配列化するとき) で succ メソッドを利用して、範囲内のオブジェクトが順番に生成されている。

ちなみに、スペースシップ演算子「<=>」が実装されていない場合は「bad value for range (ArgumentError)」という例外が発生し、 succ メソッドが実装されていない場合は「in `each': can't iterate from RangeImpl (TypeError)」という例外が発生した(Ruby 2.4.1の場合)。

参考資料

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2