Update : This has been added to Rails’ active_support .
The past several days I’ve found myself repeatedly writing the following lines to check if two events are conflicting:
window = course . begin_at ... course . end_at
window . include? ( event . begin_at ) || window . include? ( event . end_at? )
It finally donned on me that all I’m really doing is checking if two ranges overlap. What I really wanted to be doing is:
( course . begin_at ... course . end_at ). overlap? ( event . begin_at ... event . end_at )
While I was at it, I decided that it only made sense that Range\#include?
should be able to take a range:
class Range
def overlap? ( range )
self . include? ( range . first ) || range . include? ( self . first )
end
def include_with_range? ( value )
if value . is_a? ( Range )
last = value . exclude_end? ? value . last - 1 : value . last
self . include? ( value . first ) && self . include? ( last )
else
include_without_range? ( value )
end
end
alias_method_chain :include? , :range
end
update : thanks to Daniel Schierbeck for the better implementation of overlap?
So now, I can do things like:
( 1 .. 5 ). include? ( 2 .. 3 ) #=> true
( 1 .. 5 ). include? ( 4 .. 8 ) #=> false
( 1 .. 5 ). overlap? ( 4 .. 8 ) #=> true
( 1 ... 5 ). overlap? ( 5 .. 10 ) #=> false
I love this language!