From 58e99aa483902f1bdb9b24315ad4cd96ba4b4d05 Mon Sep 17 00:00:00 2001 From: Erik Berlin Date: Mon, 19 Oct 2026 20:04:20 -0700 Subject: [PATCH] Fix Range#include? of an empty range of single characters A range whose ends are both single ASCII characters said it included its end even when the range was empty, so ("z".."a").include?("a") returned true while to_a was empty and cover?("a") returned false. RubyString.includeRange compares the characters directly for this kind of range instead of iterating, and its last check returned true when the value equaled the end without checking that the begin isn't after the end. Add that check, so include? and member? agree with to_a, each and cover?. This ports https://github.com/ruby/ruby/pull/19313 from CRuby, which fixes https://bugs.ruby-lang.org/issues/22432, including its tests. --- core/src/main/java/org/jruby/RubyString.java | 2 +- test/mri/ruby/test_range.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/jruby/RubyString.java b/core/src/main/java/org/jruby/RubyString.java index bf311e6a16f..b1d91b0a151 100644 --- a/core/src/main/java/org/jruby/RubyString.java +++ b/core/src/main/java/org/jruby/RubyString.java @@ -7191,7 +7191,7 @@ public static IRubyObject includeRange(ThreadContext context, RubyString _beg, R (e = eByteList.get(0)) < 128 && (v = vByteList.get(0)) < 128) { if (b <= v && v < e) return context.tru; - if (!exclusive && v == e) return context.tru; + if (!exclusive && b <= v && v == e) return context.tru; return context.fals; } } diff --git a/test/mri/ruby/test_range.rb b/test/mri/ruby/test_range.rb index ff17dca69ee..7f097903d14 100644 --- a/test/mri/ruby/test_range.rb +++ b/test/mri/ruby/test_range.rb @@ -1034,6 +1034,11 @@ def test_include assert_include("a"..."z", "y") assert_not_include("a"..."z", "z") assert_not_include("a".."z", "cc") + assert_not_include("z".."a", "a") + assert_not_include("z".."a", "z") + assert_not_include("z".."a", "m") + assert_include("a".."a", "a") + assert_not_include("a"..."a", "a") assert_raise(TypeError) {("a"..).include?("c")} assert_raise(TypeError) {("a"..).include?("5")}