require_relative '../spec_helper' require_relative 'fixtures/classes' describe "Literal Regexps" do it "matches against $_ (last input) in a conditional if no explicit matchee provided" do -> { eval <<-EOR $_ = nil (true if /foo/).should_not == true $_ = "foo" (true if /foo/).should == true EOR }.should complain(/regex literal in condition/) end it "yields a Regexp" do /Hello/.should be_kind_of(Regexp) end ruby_version_is "3.0" do it "is frozen" do /Hello/.should.frozen? end end it "caches the Regexp object" do rs = [] 2.times do |i| rs << /foo/ end rs[0].should equal(rs[1]) end it "throws SyntaxError for malformed literals" do -> { eval('/(/') }.should raise_error(SyntaxError) end ############################################################################# # %r ############################################################################# it "supports paired delimiters with %r" do LanguageSpecs.paired_delimiters.each do |p0, p1| eval("%r#{p0} foo #{p1}").should == / foo / end end it "supports grouping constructs that are also paired delimiters" do LanguageSpecs.paired_delimiters.each do |p0, p1| eval("%r#{p0} () [c]{1} #{p1}").should == / () [c]{1} / end end it "allows second part of paired delimiters to be used as non-paired delimiters" do LanguageSpecs.paired_delimiters.each do |p0, p1| eval("%r#{p1} foo #{p1}").should == / foo / end end it "disallows first part of paired delimiters to be used as non-paired delimiters" do LanguageSpecs.paired_delimiters.each do |p0, p1| -> { eval("%r#{p0} foo #{p0}") }.should raise_error(SyntaxError) end end it "supports non-paired delimiters delimiters with %r" do LanguageSpecs.non_paired_delimiters.each do |c| eval("%r#{c} foo #{c}").should == / foo / end end it "disallows alphabets as non-paired delimiter with %r" do -> { eval('%ra foo a') }.should raise_error(SyntaxError) end it "disallows spaces after %r and delimiter" do -> { eval('%r !foo!') }.should raise_error(SyntaxError) end it "allows unescaped / to be used with %r" do %r[/].to_s.should == /\//.to_s end ############################################################################# # Specs for the matching semantics ############################################################################# it "supports . (any character except line terminator)" do # Basic matching /./.match("foo").to_a.should == ["f"] # Basic non-matching /./.match("").should be_nil /./.match("\n").should be_nil /./.match("\0").to_a.should == ["\0"] end it "supports | (alternations)" do /a|b/.match("a").to_a.should == ["a"] end it "supports (?> ) (embedded subexpression)" do /(?>foo)(?>bar)/.match("foobar").to_a.should == ["foobar"] /(?>foo*)obar/.match("foooooooobar").should be_nil # it is possessive end it "supports (?# )" do /foo(?#comment)bar/.match("foobar").to_a.should == ["foobar"] /foo(?#)bar/.match("foobar").to_a.should == ["foobar"] end it "supports (?<= ) (positive lookbehind)" do /foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"] end ruby_bug "#13671", ""..."3.3" do # https://bugs.ruby-lang.org/issues/13671 it "handles a lookbehind with ss characters" do r = Regexp.new("(?foo.)bar\g/.match("foo1barfoo2").to_a.should == ["foo1barfoo2", "foo2"] end it "supports character class composition" do /[a-z&&[^a-c]]+/.match("abcdef").to_a.should == ["def"] /[a-z&&[^d-i&&[^d-f]]]+/.match("abcdefghi").to_a.should == ["abcdef"] end it "supports possessive quantifiers" do /fooA++bar/.match("fooAAAbar").to_a.should == ["fooAAAbar"] /fooA++Abar/.match("fooAAAbar").should be_nil /fooA?+Abar/.match("fooAAAbar").should be_nil /fooA*+Abar/.match("fooAAAbar").should be_nil end it "supports conditional regular expressions with positional capture groups" do pattern = /\A(foo)?(?(1)(T)|(F))\z/ pattern.should =~ 'fooT' pattern.should =~ 'F' pattern.should_not =~ 'fooF' pattern.should_not =~ 'T' end it "supports conditional regular expressions with named capture groups" do pattern = /\A(?foo)?(?()(T)|(F))\z/ pattern.should =~ 'fooT' pattern.should =~ 'F' pattern.should_not =~ 'fooF' pattern.should_not =~ 'T' end escapable_terminators = ['!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`'] it "supports escaping characters when used as a terminator" do escapable_terminators.each do |c| ref = "(?-mix:#{c})" pattern = eval("%r" + c + "\\" + c + c) pattern.to_s.should == ref end end it "treats an escaped non-escapable character normally when used as a terminator" do all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")] special_cases = ['(', '{', '[', '<', '\\', '=', '~'] (all_terminators - special_cases - escapable_terminators).each do |c| ref = "(?-mix:\\#{c})" pattern = eval("%r" + c + "\\" + c + c) pattern.to_s.should == ref end end it "support handling unicode 9.0 characters with POSIX bracket expressions" do char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A /[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase char_uppercase = "\u{104B0}" # OSAGE CAPITAL LETTER A /[[:upper:]]/.match(char_uppercase).to_s.should == char_uppercase end end