Skip to content

Commit 8f85a84

Browse files
matzclaude
andcommitted
mruby-regexp: stop dispatching to_int for the String#split limit
This was the only `to_int` dispatch in mruby's Ruby code, so the gem accepted an object that `Array.new(obj)`, `ary[obj]` and `"s" * obj` all reject. mruby has no implicit conversion protocol in core to make that consistent, the same reason `String#match` does not honour `to_str`. Closes #7003 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6581212 commit 8f85a84

2 files changed

Lines changed: 12 additions & 10 deletions

File tree

mrbgems/mruby-regexp/mrblib/string_regexp.rb

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,13 @@ def split(pattern = nil, *args)
133133

134134
limit_given = args.length > 0
135135
limit = limit_given ? args[0] : 0
136+
# `__to_int` is `mrb_ensure_integer_type()`, which asks the object nothing.
137+
# mruby has no implicit conversion protocol in core, so `Array.new(obj)`,
138+
# `ary[obj]` and `"s" * obj` all reject an object that only defines
139+
# `to_int`; dispatching it here would leave this the one place in the tree
140+
# that accepts one, as the same reasoning keeps `match` off `to_str`.
136141
if limit_given && !limit.is_a?(Integer)
137-
if limit.respond_to?(:to_int)
138-
limit = limit.to_int
139-
unless limit.is_a?(Integer)
140-
raise TypeError, "no implicit conversion of #{limit.class} to Integer)"
141-
end
142-
else
143-
limit = limit.__to_int
144-
end
142+
limit = limit.__to_int
145143
end
146144
# `nil?` and `is_a?` are redefinable, so an argument answering either one
147145
# could steer itself around the check below and reach `__split` instead.

mrbgems/mruby-regexp/test/regexp.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,16 @@ class StringMatchHelperOverride < String
10691069
assert_raise(TypeError) { "a,b".split(/,/, nil) }
10701070
assert_equal ["a,b"], "a,b".split(/,/, 1.5)
10711071

1072+
# mruby has no implicit conversion protocol, so an object defining `to_int`
1073+
# is rejected here exactly as `Array.new(obj)` and `ary[obj]` reject it. The
1074+
# limit is never asked what it responds to, so an object overriding
1075+
# `respond_to?` reaches the same TypeError rather than a NoMethodError.
10721076
limit = Object.new
10731077
def limit.to_int; 2; end
1074-
assert_equal ["a", "b"], "a,b".split(/,/, limit)
1078+
assert_raise(TypeError) { "a,b".split(/,/, limit) }
10751079

10761080
limit = Object.new
1077-
def limit.to_int; 1.5; end
1081+
def limit.respond_to?(name, include_all = false); true; end
10781082
assert_raise(TypeError) { "a,b".split(/,/, limit) }
10791083
end
10801084

0 commit comments

Comments
 (0)