mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix bug in Range comparisons when comparing to excluded-end Range
Before: ```ruby (1..10).cover?(1...11) => false ``` After: ```ruby (1..10).cover?(1...11) => true ``` See https://git.io/fjTtz for the commit against Ruby core that added support for Range arguments, with similar handling of this case.
This commit is contained in:
parent
5f043c0094
commit
ca2a3bcaad
3 changed files with 41 additions and 14 deletions
|
@ -1,3 +1,17 @@
|
|||
* Fix bug in Range comparisons when comparing to an excluded-end Range
|
||||
|
||||
Before:
|
||||
|
||||
(1..10).cover?(1...11) => false
|
||||
|
||||
After:
|
||||
|
||||
(1..10).cover?(1...11) => true
|
||||
|
||||
With the same change for `Range#include?` and `Range#===`.
|
||||
|
||||
*Owen Stephens*
|
||||
|
||||
* Use weak references in descendants tracker to allow anonymous subclasses to
|
||||
be garbage collected.
|
||||
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
module ActiveSupport
|
||||
module CompareWithRange
|
||||
# Extends the default Range#=== to support range comparisons.
|
||||
# (1..5) === (1..5) # => true
|
||||
# (1..5) === (2..3) # => true
|
||||
# (1..5) === (2..6) # => false
|
||||
# (1..5) === (1..5) # => true
|
||||
# (1..5) === (2..3) # => true
|
||||
# (1..5) === (1...6) # => true
|
||||
# (1..5) === (2..6) # => false
|
||||
#
|
||||
# The native Range#=== behavior is untouched.
|
||||
# ('a'..'f') === ('c') # => true
|
||||
|
@ -13,17 +14,20 @@ module ActiveSupport
|
|||
def ===(value)
|
||||
if value.is_a?(::Range)
|
||||
# 1...10 includes 1..9 but it does not include 1..10.
|
||||
# 1..10 includes 1...11 but it does not include 1...12.
|
||||
operator = exclude_end? && !value.exclude_end? ? :< : :<=
|
||||
super(value.first) && value.last.send(operator, last)
|
||||
value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
|
||||
super(value.first) && value_max.send(operator, last)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Extends the default Range#include? to support range comparisons.
|
||||
# (1..5).include?(1..5) # => true
|
||||
# (1..5).include?(2..3) # => true
|
||||
# (1..5).include?(2..6) # => false
|
||||
# (1..5).include?(1..5) # => true
|
||||
# (1..5).include?(2..3) # => true
|
||||
# (1..5).include?(1...6) # => true
|
||||
# (1..5).include?(2..6) # => false
|
||||
#
|
||||
# The native Range#include? behavior is untouched.
|
||||
# ('a'..'f').include?('c') # => true
|
||||
|
@ -31,17 +35,20 @@ module ActiveSupport
|
|||
def include?(value)
|
||||
if value.is_a?(::Range)
|
||||
# 1...10 includes 1..9 but it does not include 1..10.
|
||||
# 1..10 includes 1...11 but it does not include 1...12.
|
||||
operator = exclude_end? && !value.exclude_end? ? :< : :<=
|
||||
super(value.first) && value.last.send(operator, last)
|
||||
value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
|
||||
super(value.first) && value_max.send(operator, last)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Extends the default Range#cover? to support range comparisons.
|
||||
# (1..5).cover?(1..5) # => true
|
||||
# (1..5).cover?(2..3) # => true
|
||||
# (1..5).cover?(2..6) # => false
|
||||
# (1..5).cover?(1..5) # => true
|
||||
# (1..5).cover?(2..3) # => true
|
||||
# (1..5).cover?(1...6) # => true
|
||||
# (1..5).cover?(2..6) # => false
|
||||
#
|
||||
# The native Range#cover? behavior is untouched.
|
||||
# ('a'..'f').cover?('c') # => true
|
||||
|
@ -49,8 +56,10 @@ module ActiveSupport
|
|||
def cover?(value)
|
||||
if value.is_a?(::Range)
|
||||
# 1...10 covers 1..9 but it does not cover 1..10.
|
||||
# 1..10 covers 1...11 but it does not cover 1...12.
|
||||
operator = exclude_end? && !value.exclude_end? ? :< : :<=
|
||||
super(value.first) && value.last.send(operator, last)
|
||||
value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
|
||||
super(value.first) && value_max.send(operator, last)
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -57,7 +57,7 @@ class RangeTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_should_include_other_with_exclusive_end
|
||||
assert((1..10).include?(1...10))
|
||||
assert((1..10).include?(1...11))
|
||||
end
|
||||
|
||||
def test_should_compare_identical_inclusive
|
||||
|
@ -69,7 +69,7 @@ class RangeTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_should_compare_other_with_exclusive_end
|
||||
assert((1..10) === (1...10))
|
||||
assert((1..10) === (1...11))
|
||||
end
|
||||
|
||||
def test_exclusive_end_should_not_include_identical_with_inclusive_end
|
||||
|
@ -93,6 +93,10 @@ class RangeTest < ActiveSupport::TestCase
|
|||
assert range.method(:include?) != range.method(:cover?)
|
||||
end
|
||||
|
||||
def test_should_cover_other_with_exclusive_end
|
||||
assert((1..10).cover?(1...11))
|
||||
end
|
||||
|
||||
def test_overlaps_on_time
|
||||
time_range_1 = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30)
|
||||
time_range_2 = Time.utc(2005, 12, 10, 17, 00)..Time.utc(2005, 12, 10, 18, 00)
|
||||
|
|
Loading…
Reference in a new issue