Range 클래스

Range 클래스

Range 객체는 주어진 시작(begin) 값과 끝(end) 값 사이에 있는 값들의 모임을 나타내요. Array, 문자열 등 여러 타입의 연속 값을 나타내는 데 쓰여요.

출처: Ruby 4.0 API

본문

Range 만들기

리터럴로 만들 수 있어요. ..는 끝 값을 포함하고, ...는 끝 값을 제외해요.

# Ranges that use '..' to include the given end value.
(1..4).to_a      # => [1, 2, 3, 4]
('a'..'d').to_a  # => ["a", "b", "c", "d"]
# Ranges that use '...' to exclude the given end value.
(1...4).to_a     # => [1, 2, 3]
('a'...'d').to_a # => ["a", "b", "c"]

Range.new 메서드로도 만들 수 있어요. 세 번째 인자 exclude_end로 끝 값을 제외하도록 정해요.

# Ranges that by default include the given end value.
Range.new(1, 4).to_a     # => [1, 2, 3, 4]
Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
# Ranges that use third argument exclude_end to exclude the given end value.
Range.new(1, 4, true).to_a     # => [1, 2, 3]
Range.new('a', 'd', true).to_a # => ["a", "b", "c"]

시작 없는 범위 (Beginless Ranges)

beginless range는 명확한 끝 값은 있지만 시작 값이 nil이에요. 그러한 범위는 끝 값까지 모든 값을 포함해요.

r = (..4)               # => nil..4
r.begin                 # => nil
r.include?(-50)         # => true
r.include?(4)           # => true

r = (...4)              # => nil...4
r.include?(4)           # => false

Range.new(nil, 4)       # => nil..4
Range.new(nil, 4, true) # => nil...4

시작 없는 범위로 배열을 슬라이스할 수도 있어요:

a = [1, 2, 3, 4]
# Include the third array element in the slice
r = (..2)  # => nil..2
a[r]       # => [1, 2, 3]
# Exclude the third array element from the slice
r = (...2) # => nil...2
a[r]       # => [1, 2]

시작 없는 범위의 each 메서드는 예외를 발생시켜요.

끝 없는 범위 (Endless Ranges)

endless range는 명확한 시작 값은 있지만 끝 값이 nil이에요. 그러한 범위는 시작 값부터 모든 값을 포함해요.

r = (1..)         # => 1..
r.end             # => nil
r.include?(50)    # => true

Range.new(1, nil) # => 1..

끝 없는 범위 리터럴은 두 점이나 세 점으로 쓸 수 있어요. 어느 쪽이든 같은 요소를 갖지만, 둘은 같지 않아요(not equal).

r0 = (1..)           # => 1..
r1 = (1...)          # => 1...
r0.begin == r1.begin # => true
r0.end == r1.end     # => true
r0 == r1             # => false

끝 없는 범위로 배열을 슬라이스할 수도 있어요:

a = [1, 2, 3, 4]
r = (2..) # => 2..
a[r]      # => [3, 4]

끝 없는 범위의 each 메서드는 주어진 블록을 무한히 호출해요:

a = []
r = (1..)
r.each do |i|
  a.push(i) if i.even?
  break if i > 10
end
a # => [2, 4, 6, 8, 10]

범위는 시작과 끝이 모두 없을 수도 있어요. 리터럴로 시작도 끝도 없는 범위를 쓸 때는 시작이나 끝 중 적어도 하나를 명시적 nil로 줘야 해요. Ruby가 Range#inspect에 쓰는 형태인, 명시적 nil 시작과 끝을 권장해요:

(nil..)    # => (nil..nil)
(..nil)    # => (nil..nil)
(nil..nil) # => (nil..nil)

Range와 다른 클래스 (Ranges and Other Classes)

객체의 클래스가 인스턴스 메서드 <=>를 구현하면 그 객체를 범위에 넣을 수 있어요. 그렇게 하는 Ruby 코어 클래스로 Array, Complex, File::Stat, Float, Integer, Kernel, Module, Numeric, Rational, String, Symbol, Time이 있어요.

t0 = Time.now         # => 2021-09-19 09:22:48.4854986 -0500
t1 = Time.now         # => 2021-09-19 09:22:56.0365079 -0500
t2 = Time.now         # => 2021-09-19 09:23:08.5263283 -0500
(t0..t2).include?(t1) # => true
(t0..t1).include?(t2) # => false

범위의 요소들이 인스턴스 메서드 succ를 구현할 때만 범위를 반복(iterate)할 수 있어요. 그렇게 하는 Ruby 코어 클래스로 Integer, String, Symbol이 있어요(위에서 언급한 다른 클래스는 아님). 반복자 메서드에는 Range 자체의 each, step, %와, Enumerable 모듈에서 포함된 each_entry, each_with_index, each_with_object, each_slice, each_cons, reverse_each가 있어요.

a = []
(1..4).each {|i| a.push(i) }
a # => [1, 2, 3, 4]

Range와 사용자 정의 클래스 (Ranges and User-Defined Classes)

범위에 쓸 사용자 정의 클래스는 인스턴스 <=>를 구현해야 해요(Integer#<=> 참고). 반복을 가능하게 하려면 인스턴스 메서드 succ도 구현해야 해요(Integer#succ 참고). 아래 클래스는 <=>succ를 모두 구현해서, 범위를 만들고 반복하는 데 모두 쓸 수 있어요. Comparable 모듈이 포함되어 == 메서드가 <=>의 관점에서 정의된다는 점에 주의하세요.

# Represent a string of 'X' characters.
class Xs
  include Comparable
  attr_accessor :length
  def initialize(n)
    @length = n
  end
  def succ
    Xs.new(@length + 1)
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
  def inspect
    'X' * @length
  end
end

r = Xs.new(3)..Xs.new(6) #=> XXX..XXXXXX
r.to_a                   #=> [XXX, XXXX, XXXXX, XXXXXX]
r.include?(Xs.new(5))    #=> true
r.include?(Xs.new(7))    #=> false

Public Class Methods

json_create(object)

as_json을 참고하세요. JSON에서 Range 객체를 복원해요.

new(begin, end, exclude_end = false) → new_range

주어진 beginend 객체를 기반으로 새 범위를 반환해요. 선택 인자 exclude_end는 객체 end를 범위의 마지막 객체로 포함할지 정해요:

Range.new(2, 5).to_a            # => [2, 3, 4, 5]
Range.new(2, 5, true).to_a      # => [2, 3, 4]
Range.new('a', 'd').to_a        # => ["a", "b", "c", "d"]
Range.new('a', 'd', true).to_a  # => ["a", "b", "c"]

Public Instance Methods

%(n) {|element| ... } → self

step과 같지만 n의 기본값은 제공하지 않아요. Enumerator::ArithmeticSequence를 더 간결하게 만들어주는 데 편리해요.

array = [0, 1, 2, 3, 4, 5, 6]

# slice each second element:
seq = (0..) % 2 #=> ((0..).%(2))
array[seq] #=> [0, 2, 4, 6]
# or just
array[(0..) % 2] #=> [0, 2, 4, 6]

이 경우 Ruby의 연산자 우선순위 때문에 범위 주위에 괄호가 필수라는 점을 주의하세요:

(0..7) % 2 #=> ((0..7).%(2)) -- as expected
0..7 % 2 #=> 0..1 -- parsed as 0..(7 % 2)

self == other → true or false

다음 조건을 모두 만족할 때만 true를 반환해요:

  • other가 range이다.
  • other.begin == self.begin
  • other.end == self.end
  • other.exclude_end? == self.exclude_end?

그 외에는 false를 반환해요.

r = (1..5)
r == (1..5)                # => true
r = Range.new(1, 5)
r == 'foo'                 # => false
r == (2..5)                # => false
r == (1..4)                # => false
r == (1...5)               # => false
r == Range.new(1, 5, true) # => false

같은 인자라도 ==eql?의 반환값이 다를 수 있어요:

(1..2) == (1..2.0)   # => true
(1..2).eql? (1..2.0) # => false

self === object → true or false

objectself.beginself.end 사이에 있으면 true, 그렇지 않으면 false를 반환해요.

(1..4) === 2       # => true
(1..4) === 5       # => false
(1..4) === 'a'     # => false
(1..4) === 4       # => true
(1...4) === 4      # => false
('a'..'d') === 'c' # => true
('a'..'d') === 'e' # => false

case 문은 메서드 ===를 사용해요:

case 79
when (1..50)
  "low"
when (51..75)
  "medium"
when (76..100)
  "high"
end # => "high"

, ..`로 끝 없는 범위도 case 문에서 쓸 수 있어요:

case "2.6.5"
when ..."2.4"
  "EOL"
when "2.4"..."2.5"
  "maintenance"
when "2.5"..."3.0"
  "stable"
when "3.1"..
  "upcoming"
end # => "stable"

as_json(*)

Range#as_jsonRange.json_create 메서드는 Range 객체를 직렬화/역직렬화하는 데 쓸 수 있어요. Marshal을 참고하세요. Range#as_jsonself를 직렬화해서 2-요소 해시를 반환해요:

require 'json/add/range'
x = (1..4).as_json     # => {"json_class"=>"Range", "a"=>[1, 4, false]}
y = (1...4).as_json    # => {"json_class"=>"Range", "a"=>[1, 4, true]}
z = ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}

JSON.create는 그런 해시를 역직렬화해서 Range 객체를 반환해요:

Range.json_create(x) # => 1..4
Range.json_create(y) # => 1...4
Range.json_create(z) # => "a".."d"

begin → object

self의 시작을 정의하는 객체를 반환해요. Range#first, Range#end와 관련돼요.

(1..4).begin # => 1
(..2).begin  # => nil

bsearch {|obj| block } → value

이진 탐색(binary search)으로 self에서 요소를 선택해 반환해요. Binary Searching 섹션을 참고하세요.

count → integer

인자나 블록 기준(주어진 경우)에 따라 요소의 개수를 반환해요.

인자도 블록도 없으면 요소의 수를 반환해요:

(1..4).count      # => 4
(1...4).count     # => 3
('a'..'d').count  # => 4
('a'...'d').count # => 3
(1..).count       # => Infinity
(..4).count       # => Infinity

인자 object가 주어지면 self에서 찾은 object의 수를 반환해요(보통 0 또는 1):

(1..4).count(2)   # => 1
(1..4).count(5)   # => 0
(1..4).count('a') # => 0

블록이 주어지면 각 요소로 블록을 호출하고, 블록이 truthy 값을 반환한 요소의 수를 반환해요:

(1..4).count {|element| element < 3 } # => 2

Range#size와 관련돼요.

cover?(object) → true or false / cover?(range) → true or false

주어진 인자가 self 안에 있으면 true, 그렇지 않으면 false를 반환해요.

범위가 아닌 인자 object<=<로 평가해요. 끝 값을 포함하는 범위(#exclude_end? == false)는 이렇게 평가해요:

self.begin <= object <= self.end
r = (1..4)
r.cover?(1)     # => true
r.cover?(4)     # => true
r.cover?(0)     # => false
r.cover?(5)     # => false
r.cover?('foo') # => false

r = ('a'..'d')
r.cover?('a')     # => true
r.cover?('d')     # => true
r.cover?(' ')     # => false
r.cover?('e')     # => false
r.cover?(0)       # => false

끝 값을 제외하는 범위(#exclude_end? == true)는 이렇게 평가해요:

r.begin <= object < r.end
r = (1...4)
r.cover?(1)     # => true
r.cover?(3)     # => true
r.cover?(0)     # => false
r.cover?(4)     # => false
r.cover?('foo') # => false

r = ('a'...'d')
r.cover?('a')     # => true
r.cover?('c')     # => true
r.cover?(' ')     # => false
r.cover?('d')     # => false
r.cover?(0)       # => false

범위 인자 range가 주어지면 selfrange의 첫 번째·마지막 요소를 비교해요:

r = (1..4)
r.cover?(1..4)     # => true
r.cover?(0..4)     # => false
r.cover?(1..5)     # => false
r.cover?('a'..'d') # => false

r = (1...4)
r.cover?(1..3)     # => true
r.cover?(1..4)     # => false

시작과 끝이 숫자면 cover?include?처럼 동작해요. 하지만 숫자가 아니면 두 메서드는 다를 수 있어요:

(1..3).cover?(1.5) # => true
(1..3).include?(1.5) # => true

('a'..'d').cover?('cc')   # => true
('a'..'d').include?('cc') # => false

다음 중 하나면 false를 반환해요: self의 시작 값이 끝 값보다 큰 경우, 또는 내부 <=> 호출이 nil을 반환해 비교할 수 없는 경우. Range#include?와 관련돼요.

시작 없는 범위는 끝 값 전까지 같은 타입의 모든 값을 덮어요(배타 범위는 끝 값을 제외). inclusive 범위일 때 시작 없는 범위의 끝에서 끝나는 범위, 또는 그보다 일찍 끝나는 범위를 덮어요.

(..2).cover?(1)     # => true
(..2).cover?(2)     # => true
(..2).cover?(3)     # => false
(...2).cover?(2)    # => false
(..2).cover?("2")   # => false
(..2).cover?(..2)   # => true
(..2).cover?(...2)  # => true
(..2).cover?(.."2") # => false
(...2).cover?(..2)  # => false

끝 없는 범위는 시작 이후 같은 타입의 모든 값을 덮어요. 끝 없는 배타(exclusive) 범위는 끝 없는 inclusive 범위를 덮지 않아요.

(2..).cover?(1)     # => false
(2..).cover?(3)     # => true
(2...).cover?(3)    # => true
(2..).cover?(2)     # => true
(2..).cover?("2")   # => false
(2..).cover?(2..)   # => true
(2..).cover?(2...)  # => true
(2..).cover?("2"..) # => false
(2...).cover?(2..)  # => false
(2...).cover?(3...) # => true
(2...).cover?(3..)  # => false
(3..).cover?(2..)   # => false

시작도 끝도 없는 범위는 모든 값·범위를 덮어 모든 인자에 true를 반환하지만, 시작도 끝도 없는 배타 범위는 끝 없는 inclusive 범위를 덮지 않아요:

(nil...).cover?(Object.new) # => true
(nil...).cover?(nil...)     # => true
(nil..).cover?(nil...)      # => true
(nil...).cover?(nil..)      # => false
(nil...).cover?(1..)        # => false

each {|element| ... } → self / each → an_enumerator

블록이 주어지면 self의 각 요소를 블록으로 전달해요. self.first.respond_to?(:succ)가 아니면 예외를 발생시켜요. 블록이 없으면 enumerator를 반환해요.

a = []
(1..4).each {|element| a.push(element) } # => 1..4
a # => [1, 2, 3, 4]

end → object

self의 끝을 정의하는 객체를 반환해요. Range#begin, Range#last와 관련돼요.

(1..4).end  # => 4
(1...4).end # => 4
(1..).end   # => nil

entries

to_a의 별칭이에요.

eql?(other) → true or false

다음 조건을 모두 만족할 때만 true를 반환해요:

  • other가 range이다.
  • other.begin eql? self.begin
  • other.end eql? self.end
  • other.exclude_end? == self.exclude_end?
r = (1..5)
r.eql?(1..5)                  # => true
r = Range.new(1, 5)
r.eql?('foo')                 # => false
r.eql?(2..5)                  # => false
r.eql?(1..4)                  # => false
r.eql?(1...5)                 # => false
r.eql?(Range.new(1, 5, true)) # => false

exclude_end? → true or false

self가 자신의 끝 값을 제외하면 true, 아니면 false를 반환해요.

Range.new(2, 5).exclude_end?       # => false
Range.new(2, 5, true).exclude_end? # => true
(2..5).exclude_end?                # => false
(2...5).exclude_end?               # => true

first → object / first(n) → array

인자 없이 호출하면 self의 첫 번째 요소를 반환해요(있을 때). 음이 아닌 정수 n이 주어지면 배열에서 첫 n개 요소를 반환해요. 첫 요소가 없으면 예외를 발생시켜요.

(1..4).first     # => 1
('a'..'d').first # => "a"

(1..10).first(3) # => [1, 2, 3]
(1..10).first(0) # => []
(1..4).first(50) # => [1, 2, 3, 4]

(..4).first # Raises RangeError

hash → integer

self의 정수 해시 값을 반환해요. 두 range 객체 r0r1r0.eql?(r1)일 때만 같은 해시 값을 가져요. Range#eql?, Object#hash와 관련돼요.

include?(object) → true or false / member?

objectself의 요소면 true, 아니면 false를 반환해요:

(1..4).include?(2)        # => true
(1..4).include?(5)        # => false
(1..4).include?(4)        # => true
(1...4).include?(4)       # => false
('a'..'d').include?('b')  # => true
('a'..'d').include?('e')  # => false
('a'..'d').include?('B')  # => false
('a'..'d').include?('d')  # => true
('a'...'d').include?('d') # => false

시작과 끝이 숫자면 include?cover?처럼 동작하지만, 숫자가 아니면 두 메서드는 다를 수 있어요.

member?include?의 별칭이에요.

inspect → string

begin.inspectend.inspect를 포함해 self의 문자열 표현을 반환해요:

(1..4).inspect  # => "1..4"
(1...4).inspect # => "1...4"
(1..).inspect   # => "1.."
(..4).inspect   # => "..4"

to_sinspect의 반환은 다를 수 있어요:

('a'..'d').to_s    # => "a..d"
('a'..'d').inspect # => "\"a\"..\"d\""

last → object / last(n) → array

인자 없이 호출하면 self의 마지막 요소를 반환해요(있을 때). exclude_end?true여도 인자 없이 lastself의 끝 요소를 반환해요:

(1..4).last     # => 4
('a'..'d').last # => "d"
(1...4).last    # => 4
('a'...'d').last # => "d"

음이 아닌 정수 n이 주어지면 배열에서 마지막 n개 요소를 반환해요. exclude_end?true이면 인자와 함께 쓴 last는 끝 요소를 반환하지 않아요:

(1..10).last(3) # => [8, 9, 10]
(1..10).last(0) # => []
(1..4).last(50) # => [1, 2, 3, 4]
(1...4).last(3)     # => [1, 2, 3]
('a'...'d').last(3) # => ["a", "b", "c"]

마지막 요소가 없으면 (1..).last처럼 예외를 발생시켜요.

max → object / max(n) → array / max {|a, b| ... } → object / max(n) {|a, b| ... } → array

메서드 <=> 또는 주어진 블록을 비교에 사용해 self의 최댓값을 반환해요. 인자도 블록도 없으면 self의 최대값 요소를 반환해요:

(1..4).max     # => 4
('a'..'d').max # => "d"
(-4..-1).max   # => -1

음이 아닌 정수 n이 주어지고 블록이 없으면, 배열에서 n개의 최대값 요소를 반환해요:

(1..4).max(2)     # => [4, 3]
('a'..'d').max(2) # => ["d", "c"]
(-4..-1).max(2)   # => [-1, -2]
(1..4).max(50)    # => [4, 3, 2, 1]

블록이 주어지면 먼저 self의 처음 두 요소로, 그다음에는 지금까지의 최대값과 다음 요소로 순차적으로 호출돼요:

(1..4).max {|a, b| p [a, b]; a <=> b } # => 4
# Prints: [2, 1] / [3, 2] / [4, 3]

n이 0이면 빈 배열을 반환해요. 다음 중 하나면 nil이나 빈 배열을 반환해요: 시작 값이 끝 값보다 큰 경우((4..1).max # => nil), 배타 범위의 시작 값이 끝 값과 같은 경우((1...1).max # => nil). self가 endless 범위((1..))이거나, 블록이 주어졌는데 beginless 범위면 예외를 발생시켜요. Range#min, Range#minmax와 관련돼요.

min → object / min(n) → array / min {|a, b| ... } → object / min(n) {|a, b| ... } → array

메서드 <=> 또는 주어진 블록을 비교에 사용해 self의 최솟값을 반환해요. max와 대칭적으로 동작해요:

(1..4).min     # => 1
('a'..'d').min # => "a"
(-4..-1).min   # => -4

(1..4).min(2)     # => [1, 2]
('a'..'d').min(2) # => ["a", "b"]
(-4..-1).min(2)   # => [-4, -3]
(1..4).min(50)    # => [1, 2, 3, 4]

n이 0이면 빈 배열을 반환해요. 시작 값이 끝 값보다 큰 경우나 배타 범위의 시작 값이 끝 값과 같은 경우 nil이나 빈 배열을 반환해요. self가 beginless 범위((..4))이거나, 블록이 주어졌는데 endless 범위면 예외를 발생시켜요. Range#max, Range#minmax와 관련돼요.

minmax → [object, object] / minmax {|a, b| ... } → [object, object]

비교 메서드 <=> 또는 주어진 블록에 따라 self의 최솟값과 최댓값을 담은 2-요소 배열을 반환해요.

(1..4).minmax     # => [1, 4]
(1...4).minmax    # => [1, 3]
('a'..'d').minmax # => ["a", "d"]
(-4..-1).minmax   # => [-4, -1]

(1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]

시작 값이 끝 값보다 큰 경우나 배타 범위의 시작 값이 끝 값과 같은 경우 [nil, nil]을 반환해요. self가 beginless 또는 endless 범위면 예외를 발생시켜요. Range#min, Range#max와 관련돼요.

overlap?(range) → true or false

rangeself와 겹치면 true, 아니면 false를 반환해요:

(0..2).overlap?(1..3) #=> true
(0..2).overlap?(3..4) #=> false
(0..).overlap?(..0)   #=> true

범위가 아닌 인자에는 TypeError를 발생시켜요. 내부 <=> 호출이 nil을 반환하면 false를 반환해요:

(1..3).overlap?(1)        # TypeError
(1..3).overlap?('a'..'d') # => false

selfrange가 비어 있으면 false를 반환해요. "빈 범위"란 시작 값이 끝 값보다 크거나(또는 exclusive 범위일 때 같거나) 한 경우를 뜻해요.

(4..1).overlap?(2..3)  # => false
(2...2).overlap?(1..2) # => false
(1..2).overlap?(2...2) # => false

Range#cover?와 관련돼요. beginless 범위가 실제로 비어 있더라도(상한이 그 타입의 최솟값일 때) 그 결과는 참으로 보이는 경우가 있어요:

(...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true
(..."").overlap?(..."") # => true

reverse_each {|element| ... } → self / reverse_each → an_enumerator

블록이 주어지면 self의 각 요소를 역순으로 블록으로 전달해요. 블록이 없으면 enumerator를 반환해요.

a = []
(1..4).reverse_each {|element| a.push(element) } # => 1..4
a # => [4, 3, 2, 1]

a = []
(1...4).reverse_each {|element| a.push(element) } # => 1...4
a # => [3, 2, 1]

size → non_negative_integer or Infinity or nil

시작과 끝 값이 모두 숫자면 self의 요소 수를 반환하고, 아니면 nil을 반환해요:

(1..4).size      # => 4
(1...4).size     # => 3
(1..).size       # => Infinity
('a'..'z').size  # => nil

self가 반복 가능(iterable)이 아니면 예외를 발생시켜요:

(0.5..2.5).size  # TypeError
(..1).size       # TypeError

Range#count와 관련돼요.

step(s = 1) {|element| ... } → self / step(s = 1) → enumerator

s 단계로 범위의 요소들을 반복해요. 반복은 + 연산자로 수행돼요. 블록이 주어지면 self의 각 요소를 단계만큼 건너뛰며 블록으로 전달해요:

(0..6).step(2) { puts _1 }
# Prints: 0, 2, 4, 6

# Iterate between two dates in step of 1 day (24 hours)
(Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 }
# Prints:
#   2022-02-24 00:00:00 UTC
#   2022-02-25 00:00:00 UTC
#   2022-02-26 00:00:00 UTC
#   2022-02-27 00:00:00 UTC
#   2022-02-28 00:00:00 UTC
#   2022-03-01 00:00:00 UTC

+ step이 값을 줄이는 경우에도, 시작이 끝보다 높으면 반복은 여전히 수행돼요:

(0..6).step(-2) { puts _1 }
# Prints nothing

(6..0).step(-2) { puts _1 }
# Prints: 6, 4, 2, 0

(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 }
# Prints 2022-03-01부터 하루씩 2022-02-24까지

블록이 주어지지 않고 범위 경계와 단계가 모두 Numeric이면 Enumerator::ArithmeticSequence를 반환해요:

(1..5).step(2) # => ((1..5).step(2))
(1.0..).step(1.5) #=> ((1.0..).step(1.5))
(..3r).step(1/3r) #=> ((..3/1).step((1/3)))

Enumerator::ArithmeticSequence는 컬렉션 반복이나 슬라이싱의 값 객체로 쓸 수 있어요(Array#[] 참고). step과 비슷하지만 더 간결하게 산술 시퀀스를 만드는 편의 메서드 %도 있어요:

# Same as (1..5).step(2)
(1..5) % 2 # => ((1..5).%(2))

일반적인 경우, 블록이 없으면 Enumerator를 반환해요:

('a'..).step('b')         #=> #<Enumerator: "a"..:step("b")>
('a'..).step('b').take(3) #=> ["a", "ab", "abb"]

s가 주어지지 않으면 숫자 begin 범위에서는 1로 간주해요. 호환성(backward compatibility)을 위해 String 범위는 문자열 단계와 정수 단계 모두를 지원해요. 후자의 경우 String#succ로 다음 값을 계산해 반복해요:

(1..5).step { p _1 }
# Prints: 1, 2, 3, 4, 5

('a'..'e').step(2) { p _1 }
# Prints: a, c, e

to_a → array (entries의 원본)

self의 요소들을 배열로 반환해요. 유한한 컬렉션이 아니면 예외를 발생시켜요.

(1..4).to_a     # => [1, 2, 3, 4]
(1...4).to_a    # => [1, 2, 3]
('a'..'d').to_a # => ["a", "b", "c", "d"]

to_json(*args)

self를 나타내는 JSON 문자열을 반환해요:

require 'json/add/range'
puts (1..4).to_json
puts (1...4).to_json
puts ('a'..'d').to_json
# {"json_class":"Range","a":[1,4,false]}
# {"json_class":"Range","a":[1,4,true]}
# {"json_class":"Range","a":["a","d",false]}

to_s → string

begin.to_send.to_s를 포함해 self의 문자열 표현을 반환해요. inspect와 다를 수 있어요.

(1..4).to_s  # => "1..4"
(1...4).to_s # => "1...4"
(1..).to_s   # => "1.."
(..4).to_s   # => "..4"

to_set → set

self의 요소들을 담은 set을 반환해요. 유한한 컬렉션이 아니면 예외를 발생시켜요. require 'set'이 필요해요.

(1..4).to_set   # => Set[1, 2, 3, 4]
(1...4).to_set  # => Set[1, 2, 3]

(1..).to_set
# in 'Range#to_set': cannot convert endless range to a set (RangeError)