Skip to content

Commit

Permalink
Separate ::Range check from other logic
Browse files Browse the repository at this point in the history
Also add specs to show the difference between `===` and `.include?`.
  • Loading branch information
AlexMooney committed Mar 11, 2024
1 parent 2c7f6e6 commit 6c79a33
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
16 changes: 10 additions & 6 deletions activesupport/lib/active_support/core_ext/range/compare_range.rb
Expand Up @@ -12,7 +12,7 @@ module CompareWithRange
# ('a'..'f') === ('c') # => true
# (5..9) === (11) # => false
def ===(other)
compare_with_range(other) { |arg_for_comparison| super(arg_for_comparison) }
compare(other) { |arg_for_comparison| super(arg_for_comparison) }
end

# Extends the default Range#include? to support range comparisons.
Expand All @@ -25,20 +25,24 @@ def ===(other)
# ('a'..'f').include?('c') # => true
# (5..9).include?(11) # => false
def include?(other)
compare_with_range(other) { |arg_for_comparison| super(arg_for_comparison) }
compare(other) { |arg_for_comparison| super(arg_for_comparison) }
end

private
def compare_with_range(other, &block)
def compare(other, &block)
if other.is_a?(::Range)
return false if other_is_backwards?(other)

begin_includes_other_begin?(other, &block) && end_includes_other_end?(other)
compare_with_range(other, &block)
else
block.call(other)
end
end

def compare_with_range(other, &block)
return false if other_is_backwards?(other)

begin_includes_other_begin?(other, &block) && end_includes_other_end?(other)
end

def other_is_backwards?(other)
is_backwards_op = other.exclude_end? ? :>= : :>
other.begin && other.end && other.begin.public_send(is_backwards_op, other.end)
Expand Down
14 changes: 14 additions & 0 deletions activesupport/test/core_ext/range_ext_test.rb
Expand Up @@ -131,6 +131,13 @@ def test_overlap_behaves_like_ruby
assert_not_operator((...3), :overlap?, (3..))
end

def test_include_uses_ruby_include
assert((1..3).include?(1.5))
assert(("a".."d").include?("c"))

assert_not(("a".."d").include?("cc")) # As opposed to `=== 'cc'` => `true`
end

def test_should_include_identical_inclusive
assert((1..10).include?(1..10))
end
Expand Down Expand Up @@ -183,6 +190,13 @@ def test_should_not_include_range_with_beginless_range
assert_not((-1..1).include?(..2))
end

def test_case_equality_uses_ruby_case_equality
assert((1..3) === 1.5)
assert(("a".."d") === "c")

assert(("a".."d") === "cc") # As opposed to `.include?('cc')` => `false`
end

def test_should_compare_identical_inclusive
assert((1..10) === (1..10))
end
Expand Down

0 comments on commit 6c79a33

Please sign in to comment.