Skip to content

Instantly share code, notes, and snippets.

@senorprogrammer
Created July 1, 2011 12:07
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save senorprogrammer/1058413 to your computer and use it in GitHub Desktop.
Save senorprogrammer/1058413 to your computer and use it in GitHub Desktop.
Range intersections in Ruby
#!/usr/bin/env ruby
# From my blog post at http://www.postal-code.com/binarycode/2009/06/06/better-range-intersection-in-ruby/
class Range
def intersection(other)
raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)
my_min, my_max = first, exclude_end? ? max : last
other_min, other_max = other.first, other.exclude_end? ? other.max : other.last
new_min = self === other_min ? other_min : other === my_min ? my_min : nil
new_max = self === other_max ? other_max : other === my_max ? my_max : nil
new_min && new_max ? new_min..new_max : nil
end
alias_method :&, :intersection
end
if __FILE__ == $0
def do_test( range, other, expected )
result = range.intersection(other)
result_status = ( result == expected ) ? "passed" : "failed"
puts "#{range.inspect} #{other.inspect} result #{result_status}: #{result.inspect} (#{expected.inspect})"
end
# Test an inclusive range
range = 5..10
tests = {
1..4 => nil, # before
11..15 => nil, # after
1..6 => 5..6, # overlap_begin
9..15 => 9..10, # overlap_end
1..5 => 5..5, # overlap_begin_edge
10..15 => 10..10, # overlap_end_edge
5..10 => 5..10, # overlap_all
6..9 => 6..9, # overlap_inner
1...5 => nil, # before (exclusive range)
1...7 => 5..6, # overlap_begin (exclusive range)
1...6 => 5..5, # overlap_begin_edge (exclusive range)
5...11 => 5..10, # overlap_all (exclusive range)
6...10 => 6..9, # overlap_inner (exclusive range)
}
tests.each do |other, expected|
do_test( range, other, expected )
end
# Test an exclusive range
# This covers a bug found by Montgomery Kosma in the original code
range = 1...10
tests = {
5..15 => 5..9 #overlap_end
}
tests.each do |other, expected|
do_test( range, other, expected )
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment