mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
ffd0820ab3
This removes the related tests, and puts the related specs behind version guards. This affects all code in lib, including some libraries that may want to support older versions of Ruby.
708 lines
22 KiB
Ruby
708 lines
22 KiB
Ruby
# -*- encoding: utf-8 -*-
|
|
require_relative '../../spec_helper'
|
|
require_relative 'fixtures/classes'
|
|
|
|
describe :string_gsub_named_capture, shared: true do
|
|
it "replaces \\k named backreferences with the regexp's corresponding capture" do
|
|
str = "hello"
|
|
|
|
str.gsub(/(?<foo>[aeiou])/, '<\k<foo>>').should == "h<e>ll<o>"
|
|
str.gsub(/(?<foo>.)/, '\k<foo>\k<foo>').should == "hheelllloo"
|
|
end
|
|
end
|
|
|
|
describe "String#gsub with pattern and replacement" do
|
|
it "inserts the replacement around every character when the pattern collapses" do
|
|
"hello".gsub(//, ".").should == ".h.e.l.l.o."
|
|
end
|
|
|
|
it "respects unicode when the pattern collapses" do
|
|
str = "こにちわ"
|
|
reg = %r!!
|
|
|
|
str.gsub(reg, ".").should == ".こ.に.ち.わ."
|
|
end
|
|
|
|
it "doesn't freak out when replacing ^" do
|
|
"Text\n".gsub(/^/, ' ').should == " Text\n"
|
|
"Text\nFoo".gsub(/^/, ' ').should == " Text\n Foo"
|
|
end
|
|
|
|
it "returns a copy of self with all occurrences of pattern replaced with replacement" do
|
|
"hello".gsub(/[aeiou]/, '*').should == "h*ll*"
|
|
|
|
str = "hello homely world. hah!"
|
|
str.gsub(/\Ah\S+\s*/, "huh? ").should == "huh? homely world. hah!"
|
|
|
|
str = "¿por qué?"
|
|
str.gsub(/([a-z\d]*)/, "*").should == "*¿** **é*?*"
|
|
end
|
|
|
|
it "ignores a block if supplied" do
|
|
"food".gsub(/f/, "g") { "w" }.should == "good"
|
|
end
|
|
|
|
it "supports \\G which matches at the beginning of the remaining (non-matched) string" do
|
|
str = "hello homely world. hah!"
|
|
str.gsub(/\Gh\S+\s*/, "huh? ").should == "huh? huh? world. hah!"
|
|
end
|
|
|
|
it "supports /i for ignoring case" do
|
|
str = "Hello. How happy are you?"
|
|
str.gsub(/h/i, "j").should == "jello. jow jappy are you?"
|
|
str.gsub(/H/i, "j").should == "jello. jow jappy are you?"
|
|
end
|
|
|
|
it "doesn't interpret regexp metacharacters if pattern is a string" do
|
|
"12345".gsub('\d', 'a').should == "12345"
|
|
'\d'.gsub('\d', 'a').should == "a"
|
|
end
|
|
|
|
it "replaces \\1 sequences with the regexp's corresponding capture" do
|
|
str = "hello"
|
|
|
|
str.gsub(/([aeiou])/, '<\1>').should == "h<e>ll<o>"
|
|
str.gsub(/(.)/, '\1\1').should == "hheelllloo"
|
|
|
|
str.gsub(/.(.?)/, '<\0>(\1)').should == "<he>(e)<ll>(l)<o>()"
|
|
|
|
str.gsub(/.(.)+/, '\1').should == "o"
|
|
|
|
str = "ABCDEFGHIJKLabcdefghijkl"
|
|
re = /#{"(.)" * 12}/
|
|
str.gsub(re, '\1').should == "Aa"
|
|
str.gsub(re, '\9').should == "Ii"
|
|
# Only the first 9 captures can be accessed in MRI
|
|
str.gsub(re, '\10').should == "A0a0"
|
|
end
|
|
|
|
it "treats \\1 sequences without corresponding captures as empty strings" do
|
|
str = "hello!"
|
|
|
|
str.gsub("", '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub("h", '<\1>').should == "<>ello!"
|
|
|
|
str.gsub(//, '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub(/./, '\1\2\3').should == ""
|
|
str.gsub(/.(.{20})?/, '\1').should == ""
|
|
end
|
|
|
|
it "replaces \\& and \\0 with the complete match" do
|
|
str = "hello!"
|
|
|
|
str.gsub("", '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub("", '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub("he", '<\0>').should == "<he>llo!"
|
|
str.gsub("he", '<\&>').should == "<he>llo!"
|
|
str.gsub("l", '<\0>').should == "he<l><l>o!"
|
|
str.gsub("l", '<\&>').should == "he<l><l>o!"
|
|
|
|
str.gsub(//, '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub(//, '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
|
|
str.gsub(/../, '<\0>').should == "<he><ll><o!>"
|
|
str.gsub(/../, '<\&>').should == "<he><ll><o!>"
|
|
str.gsub(/(.)./, '<\0>').should == "<he><ll><o!>"
|
|
end
|
|
|
|
it "replaces \\` with everything before the current match" do
|
|
str = "hello!"
|
|
|
|
str.gsub("", '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
|
|
str.gsub("h", '<\`>').should == "<>ello!"
|
|
str.gsub("l", '<\`>').should == "he<he><hel>o!"
|
|
str.gsub("!", '<\`>').should == "hello<hello>"
|
|
|
|
str.gsub(//, '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
|
|
str.gsub(/../, '<\`>').should == "<><he><hell>"
|
|
end
|
|
|
|
it "replaces \\' with everything after the current match" do
|
|
str = "hello!"
|
|
|
|
str.gsub("", '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
|
|
str.gsub("h", '<\\\'>').should == "<ello!>ello!"
|
|
str.gsub("ll", '<\\\'>').should == "he<o!>o!"
|
|
str.gsub("!", '<\\\'>').should == "hello<>"
|
|
|
|
str.gsub(//, '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
|
|
str.gsub(/../, '<\\\'>').should == "<llo!><o!><>"
|
|
end
|
|
|
|
it "replaces \\+ with the last paren that actually matched" do
|
|
str = "hello!"
|
|
|
|
str.gsub(/(.)(.)/, '\+').should == "el!"
|
|
str.gsub(/(.)(.)+/, '\+').should == "!"
|
|
str.gsub(/(.)()/, '\+').should == ""
|
|
str.gsub(/(.)(.{20})?/, '<\+>').should == "<h><e><l><l><o><!>"
|
|
|
|
str = "ABCDEFGHIJKLabcdefghijkl"
|
|
re = /#{"(.)" * 12}/
|
|
str.gsub(re, '\+').should == "Ll"
|
|
end
|
|
|
|
it "treats \\+ as an empty string if there was no captures" do
|
|
"hello!".gsub(/./, '\+').should == ""
|
|
end
|
|
|
|
it "maps \\\\ in replacement to \\" do
|
|
"hello".gsub(/./, '\\\\').should == '\\' * 5
|
|
end
|
|
|
|
it "leaves unknown \\x escapes in replacement untouched" do
|
|
"hello".gsub(/./, '\\x').should == '\\x' * 5
|
|
"hello".gsub(/./, '\\y').should == '\\y' * 5
|
|
end
|
|
|
|
it "leaves \\ at the end of replacement untouched" do
|
|
"hello".gsub(/./, 'hah\\').should == 'hah\\' * 5
|
|
end
|
|
|
|
it_behaves_like :string_gsub_named_capture, :gsub
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "taints the result if the original string or replacement is tainted" do
|
|
hello = "hello"
|
|
hello_t = "hello"
|
|
a = "a"
|
|
a_t = "a"
|
|
empty = ""
|
|
empty_t = ""
|
|
|
|
hello_t.taint; a_t.taint; empty_t.taint
|
|
|
|
hello_t.gsub(/./, a).tainted?.should == true
|
|
hello_t.gsub(/./, empty).tainted?.should == true
|
|
|
|
hello.gsub(/./, a_t).tainted?.should == true
|
|
hello.gsub(/./, empty_t).tainted?.should == true
|
|
hello.gsub(//, empty_t).tainted?.should == true
|
|
|
|
hello.gsub(//.taint, "foo").tainted?.should == false
|
|
end
|
|
end
|
|
|
|
it "handles pattern collapse" do
|
|
str = "こにちわ"
|
|
reg = %r!!
|
|
str.gsub(reg, ".").should == ".こ.に.ち.わ."
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "untrusts the result if the original string or replacement is untrusted" do
|
|
hello = "hello"
|
|
hello_t = "hello"
|
|
a = "a"
|
|
a_t = "a"
|
|
empty = ""
|
|
empty_t = ""
|
|
|
|
hello_t.untrust; a_t.untrust; empty_t.untrust
|
|
|
|
hello_t.gsub(/./, a).untrusted?.should == true
|
|
hello_t.gsub(/./, empty).untrusted?.should == true
|
|
|
|
hello.gsub(/./, a_t).untrusted?.should == true
|
|
hello.gsub(/./, empty_t).untrusted?.should == true
|
|
hello.gsub(//, empty_t).untrusted?.should == true
|
|
|
|
hello.gsub(//.untrust, "foo").untrusted?.should == false
|
|
end
|
|
end
|
|
|
|
it "tries to convert pattern to a string using to_str" do
|
|
pattern = mock('.')
|
|
def pattern.to_str() "." end
|
|
|
|
"hello.".gsub(pattern, "!").should == "hello!"
|
|
end
|
|
|
|
it "raises a TypeError when pattern can't be converted to a string" do
|
|
-> { "hello".gsub([], "x") }.should raise_error(TypeError)
|
|
-> { "hello".gsub(Object.new, "x") }.should raise_error(TypeError)
|
|
-> { "hello".gsub(nil, "x") }.should raise_error(TypeError)
|
|
end
|
|
|
|
it "tries to convert replacement to a string using to_str" do
|
|
replacement = mock('hello_replacement')
|
|
def replacement.to_str() "hello_replacement" end
|
|
|
|
"hello".gsub(/hello/, replacement).should == "hello_replacement"
|
|
end
|
|
|
|
it "raises a TypeError when replacement can't be converted to a string" do
|
|
-> { "hello".gsub(/[aeiou]/, []) }.should raise_error(TypeError)
|
|
-> { "hello".gsub(/[aeiou]/, Object.new) }.should raise_error(TypeError)
|
|
-> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
|
|
end
|
|
|
|
it "returns subclass instances when called on a subclass" do
|
|
StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString)
|
|
StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
|
|
StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
|
|
StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString)
|
|
end
|
|
|
|
# Note: $~ cannot be tested because mspec messes with it
|
|
|
|
it "sets $~ to MatchData of last match and nil when there's none" do
|
|
'hello.'.gsub('hello', 'x')
|
|
$~[0].should == 'hello'
|
|
|
|
'hello.'.gsub('not', 'x')
|
|
$~.should == nil
|
|
|
|
'hello.'.gsub(/.(.)/, 'x')
|
|
$~[0].should == 'o.'
|
|
|
|
'hello.'.gsub(/not/, 'x')
|
|
$~.should == nil
|
|
end
|
|
end
|
|
|
|
describe "String#gsub with pattern and Hash" do
|
|
it "returns a copy of self with all occurrences of pattern replaced with the value of the corresponding hash key" do
|
|
"hello".gsub(/./, 'l' => 'L').should == "LL"
|
|
"hello!".gsub(/(.)(.)/, 'he' => 'she ', 'll' => 'said').should == 'she said'
|
|
"hello".gsub('l', 'l' => 'el').should == 'heelelo'
|
|
end
|
|
|
|
it "ignores keys that don't correspond to matches" do
|
|
"hello".gsub(/./, 'z' => 'L', 'h' => 'b', 'o' => 'ow').should == "bow"
|
|
end
|
|
|
|
it "returns an empty string if the pattern matches but the hash specifies no replacements" do
|
|
"hello".gsub(/./, 'z' => 'L').should == ""
|
|
end
|
|
|
|
it "ignores non-String keys" do
|
|
"tattoo".gsub(/(tt)/, 'tt' => 'b', tt: 'z').should == "taboo"
|
|
end
|
|
|
|
it "uses a key's value as many times as needed" do
|
|
"food".gsub(/o/, 'o' => '0').should == "f00d"
|
|
end
|
|
|
|
it "uses the hash's default value for missing keys" do
|
|
hsh = {}
|
|
hsh.default='?'
|
|
hsh['o'] = '0'
|
|
"food".gsub(/./, hsh).should == "?00?"
|
|
end
|
|
|
|
it "coerces the hash values with #to_s" do
|
|
hsh = {}
|
|
hsh.default=[]
|
|
hsh['o'] = 0
|
|
obj = mock('!')
|
|
obj.should_receive(:to_s).and_return('!')
|
|
hsh['!'] = obj
|
|
"food!".gsub(/./, hsh).should == "[]00[]!"
|
|
end
|
|
|
|
it "uses the hash's value set from default_proc for missing keys" do
|
|
hsh = {}
|
|
hsh.default_proc = -> k, v { 'lamb' }
|
|
"food!".gsub(/./, hsh).should == "lamblamblamblamblamb"
|
|
end
|
|
|
|
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
|
'hello.'.gsub('l', 'l' => 'L')
|
|
$~.begin(0).should == 3
|
|
$~[0].should == 'l'
|
|
|
|
'hello.'.gsub('not', 'ot' => 'to')
|
|
$~.should == nil
|
|
|
|
'hello.'.gsub(/.(.)/, 'o' => ' hole')
|
|
$~[0].should == 'o.'
|
|
|
|
'hello.'.gsub(/not/, 'z' => 'glark')
|
|
$~.should == nil
|
|
end
|
|
|
|
it "doesn't interpolate special sequences like \\1 for the block's return value" do
|
|
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
|
|
"hello".gsub(/(.+)/, 'hello' => repl ).should == repl
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "untrusts the result if the original string is untrusted" do
|
|
str = "Ghana".untrust
|
|
str.gsub(/[Aa]na/, 'ana' => '').untrusted?.should be_true
|
|
end
|
|
|
|
it "untrusts the result if a hash value is untrusted" do
|
|
str = "Ghana"
|
|
str.gsub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
|
|
end
|
|
|
|
it "taints the result if the original string is tainted" do
|
|
str = "Ghana".taint
|
|
str.gsub(/[Aa]na/, 'ana' => '').tainted?.should be_true
|
|
end
|
|
|
|
it "taints the result if a hash value is tainted" do
|
|
str = "Ghana"
|
|
str.gsub(/a$/, 'a' => 'di'.taint).tainted?.should be_true
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "String#gsub! with pattern and Hash" do
|
|
|
|
it "returns self with all occurrences of pattern replaced with the value of the corresponding hash key" do
|
|
"hello".gsub!(/./, 'l' => 'L').should == "LL"
|
|
"hello!".gsub!(/(.)(.)/, 'he' => 'she ', 'll' => 'said').should == 'she said'
|
|
"hello".gsub!('l', 'l' => 'el').should == 'heelelo'
|
|
end
|
|
|
|
it "ignores keys that don't correspond to matches" do
|
|
"hello".gsub!(/./, 'z' => 'L', 'h' => 'b', 'o' => 'ow').should == "bow"
|
|
end
|
|
|
|
it "replaces self with an empty string if the pattern matches but the hash specifies no replacements" do
|
|
"hello".gsub!(/./, 'z' => 'L').should == ""
|
|
end
|
|
|
|
it "ignores non-String keys" do
|
|
"hello".gsub!(/(ll)/, 'll' => 'r', ll: 'z').should == "hero"
|
|
end
|
|
|
|
it "uses a key's value as many times as needed" do
|
|
"food".gsub!(/o/, 'o' => '0').should == "f00d"
|
|
end
|
|
|
|
it "uses the hash's default value for missing keys" do
|
|
hsh = {}
|
|
hsh.default='?'
|
|
hsh['o'] = '0'
|
|
"food".gsub!(/./, hsh).should == "?00?"
|
|
end
|
|
|
|
it "coerces the hash values with #to_s" do
|
|
hsh = {}
|
|
hsh.default=[]
|
|
hsh['o'] = 0
|
|
obj = mock('!')
|
|
obj.should_receive(:to_s).and_return('!')
|
|
hsh['!'] = obj
|
|
"food!".gsub!(/./, hsh).should == "[]00[]!"
|
|
end
|
|
|
|
it "uses the hash's value set from default_proc for missing keys" do
|
|
hsh = {}
|
|
hsh.default_proc = -> k, v { 'lamb' }
|
|
"food!".gsub!(/./, hsh).should == "lamblamblamblamblamb"
|
|
end
|
|
|
|
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
|
'hello.'.gsub!('l', 'l' => 'L')
|
|
$~.begin(0).should == 3
|
|
$~[0].should == 'l'
|
|
|
|
'hello.'.gsub!('not', 'ot' => 'to')
|
|
$~.should == nil
|
|
|
|
'hello.'.gsub!(/.(.)/, 'o' => ' hole')
|
|
$~[0].should == 'o.'
|
|
|
|
'hello.'.gsub!(/not/, 'z' => 'glark')
|
|
$~.should == nil
|
|
end
|
|
|
|
it "doesn't interpolate special sequences like \\1 for the block's return value" do
|
|
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
|
|
"hello".gsub!(/(.+)/, 'hello' => repl ).should == repl
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "keeps untrusted state" do
|
|
str = "Ghana".untrust
|
|
str.gsub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true
|
|
end
|
|
|
|
it "untrusts self if a hash value is untrusted" do
|
|
str = "Ghana"
|
|
str.gsub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
|
|
end
|
|
|
|
it "keeps tainted state" do
|
|
str = "Ghana".taint
|
|
str.gsub!(/[Aa]na/, 'ana' => '').tainted?.should be_true
|
|
end
|
|
|
|
it "taints self if a hash value is tainted" do
|
|
str = "Ghana"
|
|
str.gsub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "String#gsub with pattern and block" do
|
|
it "returns a copy of self with all occurrences of pattern replaced with the block's return value" do
|
|
"hello".gsub(/./) { |s| s.succ + ' ' }.should == "i f m m p "
|
|
"hello!".gsub(/(.)(.)/) { |*a| a.inspect }.should == '["he"]["ll"]["o!"]'
|
|
"hello".gsub('l') { 'x'}.should == 'hexxo'
|
|
end
|
|
|
|
it "sets $~ for access from the block" do
|
|
str = "hello"
|
|
str.gsub(/([aeiou])/) { "<#{$~[1]}>" }.should == "h<e>ll<o>"
|
|
str.gsub(/([aeiou])/) { "<#{$1}>" }.should == "h<e>ll<o>"
|
|
str.gsub("l") { "<#{$~[0]}>" }.should == "he<l><l>o"
|
|
|
|
offsets = []
|
|
|
|
str.gsub(/([aeiou])/) do
|
|
md = $~
|
|
md.string.should == str
|
|
offsets << md.offset(0)
|
|
str
|
|
end.should == "hhellollhello"
|
|
|
|
offsets.should == [[1, 2], [4, 5]]
|
|
end
|
|
|
|
it "restores $~ after leaving the block" do
|
|
[/./, "l"].each do |pattern|
|
|
old_md = nil
|
|
"hello".gsub(pattern) do
|
|
old_md = $~
|
|
"ok".match(/./)
|
|
"x"
|
|
end
|
|
|
|
$~[0].should == old_md[0]
|
|
$~.string.should == "hello"
|
|
end
|
|
end
|
|
|
|
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
|
'hello.'.gsub('l') { 'x' }
|
|
$~.begin(0).should == 3
|
|
$~[0].should == 'l'
|
|
|
|
'hello.'.gsub('not') { 'x' }
|
|
$~.should == nil
|
|
|
|
'hello.'.gsub(/.(.)/) { 'x' }
|
|
$~[0].should == 'o.'
|
|
|
|
'hello.'.gsub(/not/) { 'x' }
|
|
$~.should == nil
|
|
end
|
|
|
|
it "doesn't interpolate special sequences like \\1 for the block's return value" do
|
|
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
|
|
"hello".gsub(/(.+)/) { repl }.should == repl
|
|
end
|
|
|
|
it "converts the block's return value to a string using to_s" do
|
|
replacement = mock('hello_replacement')
|
|
def replacement.to_s() "hello_replacement" end
|
|
|
|
"hello".gsub(/hello/) { replacement }.should == "hello_replacement"
|
|
|
|
obj = mock('ok')
|
|
def obj.to_s() "ok" end
|
|
|
|
"hello".gsub(/.+/) { obj }.should == "ok"
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "untrusts the result if the original string or replacement is untrusted" do
|
|
hello = "hello"
|
|
hello_t = "hello"
|
|
a = "a"
|
|
a_t = "a"
|
|
empty = ""
|
|
empty_t = ""
|
|
|
|
hello_t.untrust; a_t.untrust; empty_t.untrust
|
|
|
|
hello_t.gsub(/./) { a }.untrusted?.should == true
|
|
hello_t.gsub(/./) { empty }.untrusted?.should == true
|
|
|
|
hello.gsub(/./) { a_t }.untrusted?.should == true
|
|
hello.gsub(/./) { empty_t }.untrusted?.should == true
|
|
hello.gsub(//) { empty_t }.untrusted?.should == true
|
|
|
|
hello.gsub(//.untrust) { "foo" }.untrusted?.should == false
|
|
end
|
|
end
|
|
|
|
it "uses the compatible encoding if they are compatible" do
|
|
s = "hello"
|
|
s2 = "#{195.chr}#{192.chr}#{195.chr}"
|
|
|
|
s.gsub(/l/) { |bar| 195.chr }.encoding.should == Encoding::BINARY
|
|
s2.gsub("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::BINARY
|
|
end
|
|
|
|
it "raises an Encoding::CompatibilityError if the encodings are not compatible" do
|
|
s = "hllëllo"
|
|
s2 = "hellö"
|
|
|
|
-> { s.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
|
|
-> { s2.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
|
|
end
|
|
|
|
it "replaces the incompatible part properly even if the encodings are not compatible" do
|
|
s = "hllëllo"
|
|
|
|
s.gsub(/ë/) { |bar| "Русский".force_encoding("iso-8859-5") }.encoding.should == Encoding::ISO_8859_5
|
|
end
|
|
|
|
not_supported_on :opal do
|
|
it "raises an ArgumentError if encoding is not valid" do
|
|
x92 = [0x92].pack('C').force_encoding('utf-8')
|
|
-> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "String#gsub with pattern and without replacement and block" do
|
|
it "returns an enumerator" do
|
|
enum = "abca".gsub(/a/)
|
|
enum.should be_an_instance_of(Enumerator)
|
|
enum.to_a.should == ["a", "a"]
|
|
end
|
|
|
|
describe "returned Enumerator" do
|
|
describe "size" do
|
|
it "should return nil" do
|
|
"abca".gsub(/a/).size.should == nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "String#gsub! with pattern and replacement" do
|
|
it "modifies self in place and returns self" do
|
|
a = "hello"
|
|
a.gsub!(/[aeiou]/, '*').should equal(a)
|
|
a.should == "h*ll*"
|
|
end
|
|
|
|
it "modifies self in place with multi-byte characters and returns self" do
|
|
a = "¿por qué?"
|
|
a.gsub!(/([a-z\d]*)/, "*").should equal(a)
|
|
a.should == "*¿** **é*?*"
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "taints self if replacement is tainted" do
|
|
a = "hello"
|
|
a.gsub!(/./.taint, "foo").tainted?.should == false
|
|
a.gsub!(/./, "foo".taint).tainted?.should == true
|
|
end
|
|
|
|
it "untrusts self if replacement is untrusted" do
|
|
a = "hello"
|
|
a.gsub!(/./.untrust, "foo").untrusted?.should == false
|
|
a.gsub!(/./, "foo".untrust).untrusted?.should == true
|
|
end
|
|
end
|
|
|
|
it "returns nil if no modifications were made" do
|
|
a = "hello"
|
|
a.gsub!(/z/, '*').should == nil
|
|
a.gsub!(/z/, 'z').should == nil
|
|
a.should == "hello"
|
|
end
|
|
|
|
# See [ruby-core:23666]
|
|
it "raises a #{frozen_error_class} when self is frozen" do
|
|
s = "hello"
|
|
s.freeze
|
|
|
|
-> { s.gsub!(/ROAR/, "x") }.should raise_error(frozen_error_class)
|
|
-> { s.gsub!(/e/, "e") }.should raise_error(frozen_error_class)
|
|
-> { s.gsub!(/[aeiou]/, '*') }.should raise_error(frozen_error_class)
|
|
end
|
|
end
|
|
|
|
describe "String#gsub! with pattern and block" do
|
|
it "modifies self in place and returns self" do
|
|
a = "hello"
|
|
a.gsub!(/[aeiou]/) { '*' }.should equal(a)
|
|
a.should == "h*ll*"
|
|
end
|
|
|
|
ruby_version_is ''...'2.7' do
|
|
it "taints self if block's result is tainted" do
|
|
a = "hello"
|
|
a.gsub!(/./.taint) { "foo" }.tainted?.should == false
|
|
a.gsub!(/./) { "foo".taint }.tainted?.should == true
|
|
end
|
|
|
|
it "untrusts self if block's result is untrusted" do
|
|
a = "hello"
|
|
a.gsub!(/./.untrust) { "foo" }.untrusted?.should == false
|
|
a.gsub!(/./) { "foo".untrust }.untrusted?.should == true
|
|
end
|
|
end
|
|
|
|
it "returns nil if no modifications were made" do
|
|
a = "hello"
|
|
a.gsub!(/z/) { '*' }.should == nil
|
|
a.gsub!(/z/) { 'z' }.should == nil
|
|
a.should == "hello"
|
|
end
|
|
|
|
# See [ruby-core:23663]
|
|
it "raises a #{frozen_error_class} when self is frozen" do
|
|
s = "hello"
|
|
s.freeze
|
|
|
|
-> { s.gsub!(/ROAR/) { "x" } }.should raise_error(frozen_error_class)
|
|
-> { s.gsub!(/e/) { "e" } }.should raise_error(frozen_error_class)
|
|
-> { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(frozen_error_class)
|
|
end
|
|
|
|
it "uses the compatible encoding if they are compatible" do
|
|
s = "hello"
|
|
s2 = "#{195.chr}#{192.chr}#{195.chr}"
|
|
|
|
s.gsub!(/l/) { |bar| 195.chr }.encoding.should == Encoding::BINARY
|
|
s2.gsub!("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::BINARY
|
|
end
|
|
|
|
it "raises an Encoding::CompatibilityError if the encodings are not compatible" do
|
|
s = "hllëllo"
|
|
s2 = "hellö"
|
|
|
|
-> { s.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
|
|
-> { s2.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
|
|
end
|
|
|
|
it "replaces the incompatible part properly even if the encodings are not compatible" do
|
|
s = "hllëllo"
|
|
|
|
s.gsub!(/ë/) { |bar| "Русский".force_encoding("iso-8859-5") }.encoding.should == Encoding::ISO_8859_5
|
|
end
|
|
|
|
not_supported_on :opal do
|
|
it "raises an ArgumentError if encoding is not valid" do
|
|
x92 = [0x92].pack('C').force_encoding('utf-8')
|
|
-> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "String#gsub! with pattern and without replacement and block" do
|
|
it "returns an enumerator" do
|
|
enum = "abca".gsub!(/a/)
|
|
enum.should be_an_instance_of(Enumerator)
|
|
enum.to_a.should == ["a", "a"]
|
|
end
|
|
|
|
describe "returned Enumerator" do
|
|
describe "size" do
|
|
it "should return nil" do
|
|
"abca".gsub!(/a/).size.should == nil
|
|
end
|
|
end
|
|
end
|
|
end
|