Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mrbgems/mruby-regexp/mrblib/string_regexp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,13 @@ def split(pattern = nil, *args)
# could steer itself around the check below and reach `__split` instead.
# `Module#===` reads the real type and cannot be redefined.
if NilClass === pattern || String === pattern
# `__split` is core's `split`, which reaches no search of this gem's, so
# the subject would go unread on this path where every other one refuses
# it. CRuby refuses a String or nil pattern too, unlike the literal a
# search is given, which is why this is not the exemption `sub` takes.
# A limit of 1 hands the subject back whole without looking into it, and
# CRuby answers for that as well, so the check waits behind it.
Regexp.__check_encoding(self) unless limit == 1
return limit_given ? __split(pattern, limit) : __split(pattern)
end
return self.empty? ? [] : [self] if limit == 1
Expand Down
19 changes: 19 additions & 0 deletions mrbgems/mruby-regexp/src/regexp.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,24 @@ regexp_binary_string_p(mrb_state *mrb, mrb_value self)
return mrb_bool_value(re_binary_string_p(str));
}

/*
* Regexp.__check_encoding(str)
*
* Internal: the check above, for the one caller that reaches no search of this
* gem's. `String#split` hands a String or nil pattern to core's `split`, which
* this gem keeps under `__split`, so nothing on that path passes an entry
* point that would ask the question.
*/
static mrb_value
regexp_check_encoding(mrb_state *mrb, mrb_value self)
{
(void)self;
mrb_value str;
mrb_get_args(mrb, "S", &str);
re_check_encoding(mrb, str);
return mrb_nil_value();
}

/* Publish `obj` and the thirteen names derived from its offsets, the
counterpart of clear_match_globals(). Kept apart from create_matchdata() so
that an existing MatchData can be republished without rebuilding it. */
Expand Down Expand Up @@ -1392,6 +1410,7 @@ mrb_mruby_regexp_gem_init(mrb_state *mrb)
mrb_define_class_method(mrb, re, "escape", regexp_escape, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, re, "quote", regexp_escape, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, re, "__binary_string?", regexp_binary_string_p, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, re, "__check_encoding", regexp_check_encoding, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, re, "__check_pattern", regexp_check_pattern, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, re, "__search", regexp_s_search, MRB_ARGS_ARG(2, 2));
mrb_define_class_method(mrb, re, "__byte_search", regexp_s_byte_search, MRB_ARGS_ARG(2, 2));
Expand Down
19 changes: 19 additions & 0 deletions mrbgems/mruby-regexp/test/regexp_utf8.rb
Original file line number Diff line number Diff line change
Expand Up @@ -617,11 +617,30 @@
assert_equal broken.index("b"), $~.begin(0)
assert_raise(ArgumentError) { broken.scan("b") }

# `split` is the other exception, and it takes every pattern with it: CRuby
# refuses a String, a nil and the awk form as well as a Regexp. A String
# pattern reaches core's `split` here, which searches for a literal without
# this gem in the way, so the refusal is asked for at the entry instead.
assert_raise(ArgumentError) { broken.split("b") }
assert_raise(ArgumentError) { broken.split }
assert_raise(ArgumentError) { broken.split(" ") }
assert_raise(ArgumentError) { broken.split("b", -1) }
assert_raise(ArgumentError) { broken.split("b", 2) }
# A limit of 1 hands the subject back whole without reading it, whatever the
# pattern, and CRuby answers for that too.
assert_equal [broken], broken.split("b", 1)
assert_equal [broken], broken.split(nil, 1)
assert_equal [broken], broken.split(" ", 1)
assert_equal [broken], broken.split(/b/, 1)
# The limit is converted before the subject is read, as in CRuby.
assert_raise(TypeError) { broken.split("b", "x") }

# A byte-indexed subject is indexed by byte throughout, so its bytes make no
# claim that could be broken and it goes through as it always did.
assert_equal 4, (broken.b =~ /b/)
assert_equal 4, broken.b.match(/b/).begin(0)
assert_equal "あ\x80!".b, broken.b.sub(/b/, "!")
assert_equal ["あ\x80".b], broken.b.split("b")

# A whole subject is untouched, including one the walk reads to the end.
assert_equal 2, ("あいb" =~ /b/)
Expand Down
Loading