Question
An answer to a question I posed yesterday on here was the following piece of Ruby code:
def overlap?(r1,r2)
r1.include?(r2.begin) || r2.include?(r1.begin)
end
def any_overlap?(ranges)
ranges.sort_by(&:begin).each_cons(2).any? do |r1,r2|
overlap?(r1, r2)
end
end
I get each_cons
, but what's the strange &:begin
notation? Save me from
syntax hell!
Thanks!
Answer
When you prefix the last argument of a call with &
you are making clear that
you are sending a block and not a normal argument. Ok, in
method(&:something)
, :something
is a symbol, not a proc , so Ruby
automatically calls the method to_proc
to get a real block. And Rails guys
(and now also vanilla Ruby) cleverly defined it as:
class Symbol
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
end
That's why you can do:
>> [1, 2, 3].map(&:to_s) # instead of [1, 2, 3].map { |n| n.to_s }
=> ["1", "2", "3"]
[edit] Note: when you realize that this construction is no syntatic sugar but
generic infrastructure that Ruby provides, nothing stops you from implementing
your own to_proc
for other classes. Never felt limited because &:method
allowed no arguments?
class Array
def to_proc
proc { |obj, *args| obj.send(*(self + args)) }
end
end
>> ["1", "F", "FF"].map(&[:to_i, 16])
=> [1, 15, 255]