1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/ruby/language/regexp_spec.rb

190 lines
5.7 KiB
Ruby

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("(?<!dss)", Regexp::IGNORECASE)
r.should =~ ""
end
end
it "supports (?<! ) (negative lookbehind)" do
/foo.(?<!\d)/.match("foo1 fooA").to_a.should == ["fooA"]
end
it "supports \\g (named backreference)" do
/(?<foo>foo.)bar\g<foo>/.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(?<word>foo)?(?(<word>)(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