This blog is part of our Ruby 2.7 series.
Ruby 2.7 added support for Beginless Range which makes the start of range an optional parameter.
(..100) is a Beginless Range and it is equivalent to (nil..100).
Let's see how Beginless Range could be used.
1> array = (1..10).to_a 2 3# Select first 6 elements 4> array[..5] 5=> [1, 2, 3, 4, 5, 6] 6 7# Select first 5 elements 8> array[...5] 9=> [1, 2, 3, 4, 5] 10 11# grep (INFINITY..5) in (1..5) 12> (1..10).grep(..5) 13=> [1, 2, 3, 4, 5] 14 15# (..100) is equivalent to (nil..100) 16> (..100) == (nil..100) 17=> true
Here is another example where in the case statement the condition can be read as below the specified level.
1case temperature 2when ..-15 3 puts "Deep Freeze" 4when -15..8 5 puts "Refrigerator" 6when 8..15 7 puts "Cold" 8when 15..25 9 puts "Room Temperature" 10when (25..) # Kindly notice the brackets here 11 puts "Hot" 12end
It can also be used for defining constants for ranges.
1TEMPERATURE = { 2 ..-15 => :deep_freeze, 3 -15..8 => :refrigerator, 4 8..15 => :cold, 5 15..25 => :room_temperature, 6 25.. => :hot 7end
Using Beginless Range in DSL makes it easier to write conditions and it looks more natural.
1 2# In Rails 3User.where(created_at: (..DateTime.now)) 4# User Load (2.2ms) SELECT "users".* FROM "users" WHERE "users"."created_at" <= $1 LIMIT $2 [["created_at", "2020-08-05 15:00:19.111217"], ["LIMIT", 11]] 5 6 7# In RubySpec 8ruby_version(..'1.9') do 9# Tests for old Ruby 10end
Here is the relevant commit and discussion regarding this change.