diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java index 883d480c67..77842d1290 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java @@ -141,12 +141,14 @@ public class RubyRepeatedField extends RubyObject { } else if (arg instanceof RubyRange) { RubyRange range = ((RubyRange) arg); - int beg = RubyNumeric.num2int(range.first(context)); - int len = RubyNumeric.num2int(range.size(context)); + int first = normalizeArrayIndex(range.first(context)); + int last = normalizeArrayIndex(range.last(context)); - if (len == 0) return context.runtime.newEmptyArray(); + if (last - first < 0) { + return context.runtime.newEmptyArray(); + } - return this.storage.subseq(beg, len); + return this.storage.subseq(first, last - first + (range.isExcludeEnd() ? 0 : 1)); } } /* assume 2 arguments */ diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb index 0483efcf8c..881810cdc5 100755 --- a/ruby/tests/repeated_field_test.rb +++ b/ruby/tests/repeated_field_test.rb @@ -175,6 +175,51 @@ class RepeatedFieldTest < Test::Unit::TestCase check_self_modifying_method(m.repeated_string, reference_arr) do |arr| arr[0..2] end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[0..5] + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[0..-1] + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[0..-3] + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[0...-1] # Exclusive range + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[0...-3] # Exclusive range + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[-2..-1] + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + arr[-5..-1] + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + # Infinite range; introduce in Ruby 2.7. + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7') + eval "arr[0..]" + end + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + # Beginless range; introduced in Ruby 2.7. + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7') + eval "arr[..-1]" + end + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + # Infinite range; introduce in Ruby 2.7. + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7') + eval "arr[0...]" # Exclusive range + end + end + check_self_modifying_method(m.repeated_string, reference_arr) do |arr| + # Beginless range; introduced in Ruby 2.7. + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7') + eval "arr[...-1]" # Exclusive range + end + end check_self_modifying_method(m.repeated_string, reference_arr) do |arr| arr[-1, 1] end