Skip to content

Commit

Permalink
Accept options argument to Regexp#{new,compile} of String; Warn for…
Browse files Browse the repository at this point in the history
… unknown types
  • Loading branch information
rwstauner authored and andrykonchin committed Jan 29, 2024
1 parent 394532f commit a2dd42b
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Compatibility:
* Implement `MatchData#{byteoffset,deconstruct,deconstruct_keys}` from Ruby 3.2 (#3039, @rwstauner).
* Add `Integer#ceildiv` method (#3039, @simonlevasseur, @nirvdrum).
* Implement `Class#attached_object` method (#3039, @andrykonchin).
* Accept options argument to `Regexp.{new,compile}` of String and warn for unknown types (#3039, @rwstauner).

Performance:

Expand Down
40 changes: 28 additions & 12 deletions spec/ruby/core/regexp/shared/new.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,30 @@ def obj.to_str() [] end
(r.options & Regexp::EXTENDED).should_not == 0
end

it "does not try to convert the second argument to Integer with #to_int method call" do
ScratchPad.clear
obj = Object.new
def obj.to_int() ScratchPad.record(:called) end
ruby_version_is ""..."3.2" do
it "does not try to convert the second argument to Integer with #to_int method call" do
ScratchPad.clear
obj = Object.new
def obj.to_int() ScratchPad.record(:called) end

Regexp.send(@method, "Hi", obj)

Regexp.send(@method, "Hi", obj)
ScratchPad.recorded.should == nil
end
end

ScratchPad.recorded.should == nil
ruby_version_is "3.2" do
it "does not try to convert the second argument to Integer with #to_int method call" do
ScratchPad.clear
obj = Object.new
def obj.to_int() ScratchPad.record(:called) end

-> {
Regexp.send(@method, "Hi", obj)
}.should complain(/expected true or false as ignorecase/, {verbose: true})

ScratchPad.recorded.should == nil
end
end

ruby_version_is ""..."3.2" do
Expand Down Expand Up @@ -188,12 +204,12 @@ def obj.to_int() ScratchPad.record(:called) end
end

it "raises an Argument error if the second argument contains unsupported chars" do
-> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError)
-> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
-> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
-> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
-> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
-> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
-> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
end
end

Expand Down
3 changes: 0 additions & 3 deletions spec/tags/core/regexp/compile_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
fails(immutable regexp):Regexp.compile works by default for subclasses with overridden #initialize
fails:Regexp.compile given a String warns any non-Integer, non-nil, non-false second argument
fails:Regexp.compile given a String accepts a String of supported flags as the second argument
fails:Regexp.compile given a String raises an Argument error if the second argument contains unsupported chars
3 changes: 0 additions & 3 deletions spec/tags/core/regexp/new_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
fails(immutable regexp):Regexp.new works by default for subclasses with overridden #initialize
fails:Regexp.new given a String warns any non-Integer, non-nil, non-false second argument
fails:Regexp.new given a String accepts a String of supported flags as the second argument
fails:Regexp.new given a String raises an Argument error if the second argument contains unsupported chars
24 changes: 22 additions & 2 deletions src/main/ruby/truffleruby/core/regexp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,28 @@ def self.new(pattern, opts = undefined, encoding = nil)

if Primitive.is_a?(opts, Integer)
opts = opts & (OPTION_MASK | KCODE_MASK) if opts > 0
elsif !Primitive.undefined?(opts) && opts
opts = IGNORECASE
elsif Primitive.is_a?(opts, String)
opts = opts.chars.reduce(0) do |result, char|
case char
when 'i'
result | IGNORECASE
when 'm'
result | MULTILINE
when 'x'
result | EXTENDED
else
raise ArgumentError, "unknown regexp option: #{opts}"
end
end
elsif !Primitive.undefined?(opts)
# Valid values are true, false, nil.
# Other values warn but treat as true.
if Primitive.false?(opts) || Primitive.nil?(opts)
opts = 0
else
warn "expected true or false as ignorecase: #{opts}" unless Primitive.true?(opts)
opts = IGNORECASE
end
else
opts = 0
end
Expand Down
1 change: 0 additions & 1 deletion test/mri/excludes/TestRegexp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
exclude :test_rindex_regexp, "needs investigation"
exclude :test_yoshidam_net_20041111_1, "needs investigation"
exclude :test_match_control_meta_escape, "<0> expected but was"
exclude :test_initialize_option, "<//m> expected but was"
exclude :test_initialize_bool_warning, "expected: /expected true or false as ignorecase/"
exclude :test_linear_time_p, "NoMethodError: undefined method `linear_time?' for Regexp:Class"
exclude :test_extended_comment_invalid_escape_bug_18294, "assert_separately failed with error message"
Expand Down

0 comments on commit a2dd42b

Please sign in to comment.