Why ([1]..[10]).cover?([9,11,335]) returns true
Let take a look at the source . In Ruby 1.9.3, we can see the following definition.
static VALUE range_cover(VALUE range, VALUE val) { VALUE beg, end; beg = RANGE_BEG(range); end = RANGE_END(range); if (r_le(beg, val)) { if (EXCL(range)) { if (r_lt(val, end)) return Qtrue; } else { if (r_le(val, end)) return Qtrue; } } return Qfalse; }
If the beginning of the range is not less than or equal to the specified value of cover? returns false . Here, lesser or equal is defined in terms of the r_lt function, which uses the <=> operator for comparison. Let's see how it behaves in the case of arrays
[1] <=> [9,11,335] # => -1
Thus, obviously, [1] really smaller [9,11,335] . As a result, we enter the body of the first if . Internally, we check to see if the range excludes its end and performs a second comparison using the <=> operator again.
[10] <=> [9,11,335] # => 1
Therefore, [10] greater than [9,11,335] . The method returns true .
Why do you see ArgumentError: bad value for range
The function responsible for raising this error is range_failed . It is called only when range_check returns a nil . When does this happen? When the beginning and end of the range are incomparable (yes, again from the point of view of our dear friend, the operator <=> ).
true <=> false
true and false comparable. Range cannot be created and ArgumentError raised.
In a final note, the Range.cover? dependency Range.cover? from <=> is actually expected and documented behavior. See the RubySpec specification for cover? .