Project

General

Profile

Feature #18788

Updated by janosch-x (Janosch Müller) almost 2 years ago

## Current situation 

 `Regexp.new` takes an integer as second argument which needs to be ORed together from multiple constants: 

 ```ruby ``` 
 Regexp.new('foo', Regexp::IGNORECASE | Regexp::MULTILINE | Regexp::EXTENDED) # => /foo/imx 
 ``` 

 Any other non-nil value is treated as `i` flag: 

 ```ruby ``` 
 Regexp.new('foo', Object.new) # => /foo/i 
 ``` 

 ## Suggestion 

 `Regexp.new` should support passing the regexp flags not only as an Integer, but also as a String, String or Symbol, like so: 

 ```ruby ``` 
 Regexp.new('foo', 'i')     # => /foo/i 
 Regexp.new('foo', :i)      # => /foo/i 
 Regexp.new('foo', 'imx') # => /foo/imx 
 Regexp.new('foo', :imx)    # => /foo/imx 

 # edge cases 
 Regexp.new('foo', 'iii') # => /foo/i 
 Regexp.new('foo', :iii)    # => /foo/i 
 Regexp.new('foo', '')      # => /foo/ 
 Regexp.new('foo', :'')     # => /foo/ 

 # unsupported flags should probably emit a warning could be ignored - 
 # or raise an ArgumentError to reveal changed behavior? 
 Regexp.new('foo', 'jmq') # => /foo/m 
 Regexp.new('foo', :jmq)    # => /foo/m 
 Regexp.new('foo', '-m')    # => /foo/m 
 Regexp.new('foo', :'-m') # => /foo/m 
 ``` 

 ## Reasons 

 1. The constants are a bit cumbersome to use, particularly when building the regexp from variable data: 

 ```ruby ``` 
 def make_regexp(regexp_body, opt_string) 
   opt_int = 0 
   opt_int |= Regexp::IGNORECASE if opt_string.include?('i') 
   opt_int |= Regexp::MULTILINE    if opt_string.include?('m') 
   opt_int |= Regexp::EXTENDED     if opt_string.include?('x') 

   Regexp.new(regexp_body, opt_int) 
 end 
 ``` 

 2. Passing a String or Symbol is already silently accepted, and people might get the wrong impression that it works: 

 ```ruby ``` 
 Regexp.new('foo', 'i') # => /foo/i 
 Regexp.new('foo', :i)    # => /foo/i 
 ``` 

 ... but it doesn't really work: 

 ```ruby ``` 
 Regexp.new('foo', 'x') # => /foo/i 
 Regexp.new('foo', :x)    # => /foo/i 
 ``` 

 ## Backwards compatibility 

 This change would not be fully backwards compatible. 

 Code that relies on the second argument being either a String which does not contain "i" in order String/Symbol or nil to make decide whether the Regexp should be case insensitive would break. break (unless the String or Symbol contains "i"). 

 *Note: originally I suggested supporting Symbols in the same way as Strings, but removed that in light of the discussion.* can't come up with a scenario where one would write such code, though - except maybe code golfing? 

Back