Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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の場合)。

参考資料

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away