mruby-regexp: accept a Symbol on the Regexp side of a match - #6995
Merged
Conversation
📝 WalkthroughWalkthroughRegexp matching methods now accept Symbols by matching their names. Tests cover captures, offsets, blocks, case dispatch, buffer isolation, and unsupported operands. Documentation describes the new behavior and remaining limitations. ChangesRegexp Symbol operands
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant RegexpMethods
participant match_operand
participant Symbol
Caller->>RegexpMethods: pass Symbol operand
RegexpMethods->>match_operand: normalize operand
match_operand->>Symbol: obtain symbol name
Symbol-->>match_operand: return name string
match_operand-->>RegexpMethods: return matchable string
RegexpMethods-->>Caller: return match result
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CRuby matches a Symbol against its name wherever a Regexp is given a subject, through `reg_operand()`. mruby-regexp took strings only, so all four entry points refused a symbol: ```ruby /a/ =~ :ab # CRuby: 0, mruby: TypeError /a/.match(:ab) # CRuby: MatchData, mruby: TypeError /a/.match?(:ab) # CRuby: true, mruby: TypeError /a/ === :ab # CRuby: true, mruby: false ``` `#===` is the one that matters most. It answers false instead of raising, so a `case` over symbols quietly falls through to `else` and `Enumerable#grep` returns an empty array, with nothing to show that the pattern was never given a chance to run. Convert the operand with `mrb_sym_str()` in one helper and call it from `regexp_match()`, `regexp_match_p()` and `regexp_match_op()` in place of `mrb_ensure_string_type()`. `regexp_case_match()` uses the same helper behind a type test, because `#===` has to keep answering false for a type it cannot match rather than start raising. `__byte_match` is left alone: it is internal, is only reached from mrblib with `self` as the subject, and its argument spec already pins the type. For a symbol too long for the inline representation, `mrb_sym_str()` returns an `mrb_str_new_static()` string sharing the symbol table's buffer. Mutating the `MatchData#string` that comes out of one is safe, because `str_modify()` copies an `RSTR_NOFREE` buffer before writing, but a test pins that. This is the Regexp-side half of the symbol support mruby#6993 adds on the Symbol side, and neither closes the other. mruby#6993 delegates `Symbol#match` and friends through `to_s`, so it never reaches the C code changed here; the two are independent and can land in either order. If mruby#6993 lands first, its "Symbols only on the left of a match" entry in the gem README becomes stale and should be dropped as part of the merge. `sym[/re/]` stays a third gap, waiting on the regexp form of `String#[]`.
`match_operand()` converts a Symbol on the Regexp side, so `re =~ sym`, `re.match(sym)`, `re.match?(sym)` and `re === sym` all match against the symbol's name. The "Symbols only on the left of a match" entry still described the behaviour from before that, down to `syms.grep(re)` answering `[]`. `sym[/re/]` stays unsupported, and the entry on the regexp form of `String#[]` already covers it.
The comment on the delegating Symbol methods claimed the Regexp side rejects symbols, with `syms.grep(/^to_/)` as the example that does not work. It does now: `match_operand()` converts the operand, and none of that reaches the mrblib file the comment sits in. `sym[/re/]` is the direction that really is still missing, so keep it and drop the rest.
takumin
force-pushed
the
regexp-symbol-argument
branch
from
August 2, 2026 23:04
0215ac9 to
fa9163f
Compare
This was referenced Aug 3, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CRuby matches a Symbol against its name wherever a Regexp is given a subject,
through
reg_operand(). mruby-regexp took strings only, so all four entrypoints refused a symbol:
#===is the one that matters most. It answers false instead of raising, so acaseover symbols quietly falls through toelseandEnumerable#grepreturns an empty array, with nothing to show that the pattern was never given
a chance to run:
Convert the operand with
mrb_sym_str()in one helper and call it fromregexp_match(),regexp_match_p()andregexp_match_op()in place ofmrb_ensure_string_type().regexp_case_match()uses the same helper behinda type test, because
#===has to keep answering false for a type it cannotmatch rather than start raising.
__byte_matchis left alone: it is internal,is only reached from mrblib with
selfas the subject, and its argument specalready pins the type.
For a symbol too long for the inline representation,
mrb_sym_str()returnsan
mrb_str_new_static()string sharing the symbol table's buffer. Mutatingthe
MatchData#stringthat comes out of one is safe, becausestr_modify()copies an
RSTR_NOFREEbuffer before writing, but a test pins that.Relation to #6993
This is the Regexp-side half of the symbol support #6993 adds on the Symbol
side, and neither closes the other. #6993 delegates
Symbol#matchand friendsthrough
to_s, so it never reaches the C code changed here; the two areindependent and can land in either order.
One merge-order detail: if #6993 lands first, its "Symbols only on the left of
a match" entry in the gem README becomes stale and should be dropped as part of
merging this one.
Updated the README and comments following the merge of #6993.
sym[/re/]stays a third gap, waiting on the regexp form ofString#[]. Noneof the three closes the others.
Testing
Seven
assertblocks inmrbgems/mruby-regexp/test/regexp.rb, one per entrypoint plus the cases the conversion is responsible for:
#match: MatchData, captures,#string,#pre_match,$~, named captures,the block form, and nil on no match
#matchwithpos, so the offset argument is reached through a Symbolalways takes the shared-buffer path into the offset conversion
MatchData#stringleaves the symbol table intact#match?with and withoutpos, both polarities#=~, including$~cleared on no match#===viaEnumerable#grepand viacase/when#===answers false forthem rather than raising
Every expected value was taken from CRuby 4.0.6. A 23-case comparison against
it leaves four differences, all of them pre-existing and outside this change:
MatchData#inspect, the wording of mruby's TypeError messages,MatchData#stringnot being frozen, and
String#matchwith a Symbol pattern (#6994).rake testis green in both string modes:MRB_UTF8_STRINGNo existing test changed.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation