提交 ca2a3bca 编写于 作者: O Owen Stephens

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.
上级 5f043c00
* 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 * Use weak references in descendants tracker to allow anonymous subclasses to
be garbage collected. be garbage collected.
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
module ActiveSupport module ActiveSupport
module CompareWithRange module CompareWithRange
# Extends the default Range#=== to support range comparisons. # Extends the default Range#=== to support range comparisons.
# (1..5) === (1..5) # => true # (1..5) === (1..5) # => true
# (1..5) === (2..3) # => true # (1..5) === (2..3) # => true
# (1..5) === (2..6) # => false # (1..5) === (1...6) # => true
# (1..5) === (2..6) # => false
# #
# The native Range#=== behavior is untouched. # The native Range#=== behavior is untouched.
# ('a'..'f') === ('c') # => true # ('a'..'f') === ('c') # => true
...@@ -13,17 +14,20 @@ module CompareWithRange ...@@ -13,17 +14,20 @@ module CompareWithRange
def ===(value) def ===(value)
if value.is_a?(::Range) if value.is_a?(::Range)
# 1...10 includes 1..9 but it does not include 1..10. # 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? ? :< : :<= 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 else
super super
end end
end end
# Extends the default Range#include? to support range comparisons. # Extends the default Range#include? to support range comparisons.
# (1..5).include?(1..5) # => true # (1..5).include?(1..5) # => true
# (1..5).include?(2..3) # => true # (1..5).include?(2..3) # => true
# (1..5).include?(2..6) # => false # (1..5).include?(1...6) # => true
# (1..5).include?(2..6) # => false
# #
# The native Range#include? behavior is untouched. # The native Range#include? behavior is untouched.
# ('a'..'f').include?('c') # => true # ('a'..'f').include?('c') # => true
...@@ -31,17 +35,20 @@ def ===(value) ...@@ -31,17 +35,20 @@ def ===(value)
def include?(value) def include?(value)
if value.is_a?(::Range) if value.is_a?(::Range)
# 1...10 includes 1..9 but it does not include 1..10. # 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? ? :< : :<= 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 else
super super
end end
end end
# Extends the default Range#cover? to support range comparisons. # Extends the default Range#cover? to support range comparisons.
# (1..5).cover?(1..5) # => true # (1..5).cover?(1..5) # => true
# (1..5).cover?(2..3) # => true # (1..5).cover?(2..3) # => true
# (1..5).cover?(2..6) # => false # (1..5).cover?(1...6) # => true
# (1..5).cover?(2..6) # => false
# #
# The native Range#cover? behavior is untouched. # The native Range#cover? behavior is untouched.
# ('a'..'f').cover?('c') # => true # ('a'..'f').cover?('c') # => true
...@@ -49,8 +56,10 @@ def include?(value) ...@@ -49,8 +56,10 @@ def include?(value)
def cover?(value) def cover?(value)
if value.is_a?(::Range) if value.is_a?(::Range)
# 1...10 covers 1..9 but it does not cover 1..10. # 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? ? :< : :<= 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 else
super super
end end
......
...@@ -57,7 +57,7 @@ def test_should_include_identical_exclusive ...@@ -57,7 +57,7 @@ def test_should_include_identical_exclusive
end end
def test_should_include_other_with_exclusive_end def test_should_include_other_with_exclusive_end
assert((1..10).include?(1...10)) assert((1..10).include?(1...11))
end end
def test_should_compare_identical_inclusive def test_should_compare_identical_inclusive
...@@ -69,7 +69,7 @@ def test_should_compare_identical_exclusive ...@@ -69,7 +69,7 @@ def test_should_compare_identical_exclusive
end end
def test_should_compare_other_with_exclusive_end def test_should_compare_other_with_exclusive_end
assert((1..10) === (1...10)) assert((1..10) === (1...11))
end end
def test_exclusive_end_should_not_include_identical_with_inclusive_end def test_exclusive_end_should_not_include_identical_with_inclusive_end
...@@ -93,6 +93,10 @@ def test_cover_is_not_override ...@@ -93,6 +93,10 @@ def test_cover_is_not_override
assert range.method(:include?) != range.method(:cover?) assert range.method(:include?) != range.method(:cover?)
end end
def test_should_cover_other_with_exclusive_end
assert((1..10).cover?(1...11))
end
def test_overlaps_on_time def test_overlaps_on_time
time_range_1 = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30) 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) time_range_2 = Time.utc(2005, 12, 10, 17, 00)..Time.utc(2005, 12, 10, 18, 00)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册