ruby.onl / sorcery

Ranges: From Array Slicing to Infinite Sequences

2026-03-27

Ruby ranges do way more than Perl's (1..5). Inclusive, exclusive, endless, beginless, infinite. Use them for iteration, array slicing, condition checking, and case/when matching. They're one of Ruby's most versatile data types, and they're hiding in plain sight.

Part 1: Inclusive vs Exclusive

# Two dots (..) - inclusive (includes end) (1..5).to_a # => [1, 2, 3, 4, 5] # Three dots (...) - exclusive (excludes end) (1...5).to_a # => [1, 2, 3, 4]
Perl equivalent: (1..5) is always inclusive. No exclusive range in Perl. Ruby gives you the choice.

Part 2: Iteration

# Each (1..5).each { |n| puts n } # prints 1,2,3,4,5 # With string ranges ("a".."z").each { |c| print c } # prints alphabet # Step (0..100).step(10) { |n| puts n } # 0, 10, 20, ... 100

Part 3: Array Slicing

This is where ranges really shine:
arr = %w~a b c d e f~ arr[2..4] # => ["c", "d", "e"] (index 2,3,4) arr[2...4] # => ["c", "d"] (index 2,3 only) arr[2..-1] # => ["c", "d", "e", "f"] (2 to end) arr[2..] # => ["c", "d", "e", "f"] (Ruby 2.6+ shorthand) arr[..2] # => ["a", "b", "c"] (start to 2) arr[-3..] # => ["d", "e", "f"] (last 3)
Perl equivalent: @arr[2..4] (array slice). Ruby's arr[2..] for "everything from index 2 onward" is cleaner than any Perl equivalent.

Part 4: Endless and Beginless Ranges

# Endless ranges (Ruby 2.6+) (5..) # from 5 to infinity arr[2..] # from index 2 to end (cleaner than 2..-1) (1..).take(10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Beginless ranges (Ruby 2.7+) (..5) # up to and including 5 arr[..2] # first 3 elements (...5) # up to but not including 5
No Perl equivalent for infinite ranges.

Part 5: Ranges as Conditions

# Membership check (1..100).include?(42) # => true (1..100) === 42 # => true (used in case/when) ("a".."z").include?("m") # => true # In case statements case score when 90..100 then "A" when 80..89 then "B" when 70..79 then "C" else "F" end

Part 6: Range to Array

# Explicit conversion (1..5).to_a # => [1, 2, 3, 4, 5] [*1..5] # => [1, 2, 3, 4, 5] (splat) ("a".."f").to_a # => ["a", "b", "c", "d", "e", "f"] # Perl: my @arr = (1..5);

Part 7: Practical Examples

# Generate IP range ("192.168.1.1".."192.168.1.254").each { |ip| puts ip } # Note: this works because String implements <=> and succ # Date range (requires 'date') require 'date' (Date.today..Date.today+7).each { |d| puts d } # Line number range in one-liner ruby -ne 'puts $_ if (3..10) === $.' file.txt

Part 8: The Flip-Flop Context

In boolean context (like if), .. becomes the flip-flop operator instead of a range. These are different things that use the same syntax. Context determines which you get. See the flip-flop post for details.

Created By: Wildcard Wizard. Copyright 2026