I've got smth for you! May be it is a bit outdated but nevertheless – do you you Range#include? or Range#cover? when you want to check if the value is inside the range?

The spoiler is use Range#cover?. Some benchmarks under the cut.

Benchmark

Here is a piece of code that performs benchmark:

require 'benchmark'
require 'benchmark/ips'
require 'date'

TEST_METHODS = %w(include? cover?)

def test_range power
  (Date.today - 10 ** power)..Date.today
end

def report_name range, test_method
  "#{(range.max - range.min).to_i}_#{test_method}"
end

def benchmark! powers = 1..5, date = Date.today
  Benchmark.ips do |report|
    powers.each do |power|
      TEST_METHODS.each do |test_method|
        range = test_range(power)

        report.report(report_name(range, test_method)) do
          range.send(test_method, date)
        end
      end
    end
  end
end

benchmark!

# -------------------------------------------------
#          10_include?   115259.6 (±20.8%) i/s -     556149 in   5.057327s
#            10_cover?  1753269.8 (±12.9%) i/s -    8638700 in   5.034635s
#         100_include?    14864.8 (±16.9%) i/s -      72750 in   5.032755s
#           100_cover?  1798267.7 (±6.5%) i/s -    8970676 in   5.013039s
#        1000_include?     1482.4 (±18.2%) i/s -       7203 in   5.021981s
#          1000_cover?  1812622.5 (±5.8%) i/s -    9037590 in   5.005734s
#       10000_include?      160.4 (±17.5%) i/s -        784 in   5.037745s
#         10000_cover?  1791249.5 (±6.6%) i/s -    8909254 in   4.997718s
#      100000_include?       15.8 (±25.3%) i/s -         75 in   5.048941s
#        100000_cover?  1854601.5 (±3.6%) i/s -    9290084 in   5.016394s

range benchmark

As you can see cover? is much faster and its speed is independent of range size. Why it is so?

Explanation

Range#cover?

Range#cover?

Take a look at the method source and you will see that it simply compares input value with min (left) and max (right) values of range. So it is obvious that speed of method is independent of range size – it is just several comparisons which need constant time.

Range#include?

Range#include?

From the first view it is obvious that there are more work inside include? – 45 vs 18 LOC. The thing is that inside include? method every point of range gets instantiated and compared to value. So as you can see there is perfect O(N) on the graph.

include? is optimized for numbers and strings but if you have more complex range (with Date for example) you should be careful.

Conclusion

Be careful when using include? and cover? simply because of that:

('a'..'z').include?('blah')
# => false 
('a'..'z').cover?('blah')
# => true 
'a' < 'blah'
# => true 
'blah' < 'z'
# => true 

Great thx to @Mik-die for reviewing this post.

Good luck with factoring fast code!

#ruby #benchmark