Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I destructure a range in Ruby?

Tags:

ruby

Is it possible to use destructuring in ruby to extract the end and beginning from a range?

module PriceHelper
  def price_range_human( range )
    "$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
  end
end

I know that I can use array coercion as a really bad hack:

first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)

But is there a syntactical way to get begin and end without actually manually creating an array?

min, max = (1..10)

Would have been awesome.

like image 835
max Avatar asked Oct 12 '16 00:10

max


2 Answers

The beginning and end? I'd use:

foo = 1..2
foo.min # => 1
foo.max # => 2

Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.


end is not the same as max: in 1...10, end is 10, but max is 9

That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):

start_value = 1
end_value = 2

foo = start_value...end_value
foo.end # => 2
foo.max # => 1

foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1

max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.

In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.

... is more confusing and leads to increased maintenance problems so its use is not recommended.

like image 105
the Tin Man Avatar answered Oct 12 '22 02:10

the Tin Man


You can use minmax to destructure ranges:

min, max = (1..10).minmax
min # => 1
max # => 10

If you are using Ruby before 2.7, avoid using this on large ranges.

like image 28
Sunny Avatar answered Oct 12 '22 02:10

Sunny