re2 2.15.0.rc1-x86-linux-musl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +11 -0
- data/LICENSE-DEPENDENCIES.txt +237 -0
- data/LICENSE.txt +28 -0
- data/README.md +396 -0
- data/Rakefile +94 -0
- data/dependencies.yml +7 -0
- data/ext/re2/extconf.rb +332 -0
- data/ext/re2/re2.cc +2254 -0
- data/ext/re2/recipes.rb +54 -0
- data/lib/3.1/re2.so +0 -0
- data/lib/3.2/re2.so +0 -0
- data/lib/3.3/re2.so +0 -0
- data/lib/3.4/re2.so +0 -0
- data/lib/re2/regexp.rb +72 -0
- data/lib/re2/scanner.rb +26 -0
- data/lib/re2/string.rb +38 -0
- data/lib/re2/version.rb +14 -0
- data/lib/re2.rb +20 -0
- data/re2.gemspec +47 -0
- data/spec/kernel_spec.rb +37 -0
- data/spec/re2/match_data_spec.rb +411 -0
- data/spec/re2/regexp_spec.rb +911 -0
- data/spec/re2/scanner_spec.rb +275 -0
- data/spec/re2/set_spec.rb +231 -0
- data/spec/re2/string_spec.rb +62 -0
- data/spec/re2_spec.rb +201 -0
- data/spec/spec_helper.rb +31 -0
- metadata +129 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe RE2::Scanner do
|
4
|
+
describe "#regexp" do
|
5
|
+
it "returns the original pattern for the scanner" do
|
6
|
+
re = RE2::Regexp.new('(\w+)')
|
7
|
+
scanner = re.scan("It is a truth")
|
8
|
+
|
9
|
+
expect(scanner.regexp).to equal(re)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#string" do
|
14
|
+
it "returns the original text for the scanner" do
|
15
|
+
re = RE2::Regexp.new('(\w+)')
|
16
|
+
text = "It is a truth"
|
17
|
+
scanner = re.scan(text)
|
18
|
+
|
19
|
+
expect(scanner.string).to equal(text)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#scan" do
|
24
|
+
it "returns the next array of matches", :aggregate_failures do
|
25
|
+
r = RE2::Regexp.new('(\w+)')
|
26
|
+
scanner = r.scan("It is a truth universally acknowledged")
|
27
|
+
|
28
|
+
expect(scanner.scan).to eq(["It"])
|
29
|
+
expect(scanner.scan).to eq(["is"])
|
30
|
+
expect(scanner.scan).to eq(["a"])
|
31
|
+
expect(scanner.scan).to eq(["truth"])
|
32
|
+
expect(scanner.scan).to eq(["universally"])
|
33
|
+
expect(scanner.scan).to eq(["acknowledged"])
|
34
|
+
expect(scanner.scan).to be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "supports scanning inputs with null bytes", :aggregate_failures do
|
38
|
+
r = RE2::Regexp.new("(\\w\0\\w)")
|
39
|
+
scanner = r.scan("a\0b c\0d e\0f")
|
40
|
+
|
41
|
+
expect(scanner.scan).to eq(["a\0b"])
|
42
|
+
expect(scanner.scan).to eq(["c\0d"])
|
43
|
+
expect(scanner.scan).to eq(["e\0f"])
|
44
|
+
expect(scanner.scan).to be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns UTF-8 matches if the pattern is UTF-8" do
|
48
|
+
r = RE2::Regexp.new('(\w+)')
|
49
|
+
scanner = r.scan("It")
|
50
|
+
matches = scanner.scan
|
51
|
+
|
52
|
+
expect(matches.first.encoding).to eq(Encoding::UTF_8)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns ISO-8859-1 matches if the pattern is not UTF-8" do
|
56
|
+
r = RE2::Regexp.new('(\w+)', utf8: false)
|
57
|
+
scanner = r.scan("It")
|
58
|
+
matches = scanner.scan
|
59
|
+
|
60
|
+
expect(matches.first.encoding).to eq(Encoding::ISO_8859_1)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns multiple capturing groups at a time", :aggregate_failures do
|
64
|
+
r = RE2::Regexp.new('(\w+) (\w+)')
|
65
|
+
scanner = r.scan("It is a truth universally acknowledged")
|
66
|
+
|
67
|
+
expect(scanner.scan).to eq(["It", "is"])
|
68
|
+
expect(scanner.scan).to eq(["a", "truth"])
|
69
|
+
expect(scanner.scan).to eq(["universally", "acknowledged"])
|
70
|
+
expect(scanner.scan).to be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns an empty array if there are no capturing groups" do
|
74
|
+
r = RE2::Regexp.new('\w+')
|
75
|
+
scanner = r.scan("Foo bar")
|
76
|
+
|
77
|
+
expect(scanner.scan).to eq([])
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns nil if there is no match" do
|
81
|
+
r = RE2::Regexp.new('\d+')
|
82
|
+
scanner = r.scan("Foo bar")
|
83
|
+
|
84
|
+
expect(scanner.scan).to be_nil
|
85
|
+
end
|
86
|
+
|
87
|
+
it "returns nil if the regexp is invalid" do
|
88
|
+
r = RE2::Regexp.new('???', log_errors: false)
|
89
|
+
scanner = r.scan("Foo bar")
|
90
|
+
|
91
|
+
expect(scanner.scan).to be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns an empty array if the input is empty", :aggregate_failures do
|
95
|
+
r = RE2::Regexp.new("")
|
96
|
+
scanner = r.scan("")
|
97
|
+
|
98
|
+
expect(scanner.scan).to eq([])
|
99
|
+
expect(scanner.scan).to be_nil
|
100
|
+
end
|
101
|
+
|
102
|
+
it "returns an array of nil with an empty input and capture", :aggregate_failures do
|
103
|
+
r = RE2::Regexp.new("()")
|
104
|
+
scanner = r.scan("")
|
105
|
+
|
106
|
+
expect(scanner.scan).to eq([nil])
|
107
|
+
expect(scanner.scan).to be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns an empty array for every match if the pattern is empty", :aggregate_failures do
|
111
|
+
r = RE2::Regexp.new("")
|
112
|
+
scanner = r.scan("Foo")
|
113
|
+
|
114
|
+
expect(scanner.scan).to eq([])
|
115
|
+
expect(scanner.scan).to eq([])
|
116
|
+
expect(scanner.scan).to eq([])
|
117
|
+
expect(scanner.scan).to eq([])
|
118
|
+
expect(scanner.scan).to be_nil
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns an array of nil if the pattern is an empty capturing group", :aggregate_failures do
|
122
|
+
r = RE2::Regexp.new("()")
|
123
|
+
scanner = r.scan("Foo")
|
124
|
+
|
125
|
+
expect(scanner.scan).to eq([nil])
|
126
|
+
expect(scanner.scan).to eq([nil])
|
127
|
+
expect(scanner.scan).to eq([nil])
|
128
|
+
expect(scanner.scan).to eq([nil])
|
129
|
+
expect(scanner.scan).to be_nil
|
130
|
+
end
|
131
|
+
|
132
|
+
it "returns array of nils with multiple empty capturing groups", :aggregate_failures do
|
133
|
+
r = RE2::Regexp.new("()()()")
|
134
|
+
scanner = r.scan("Foo")
|
135
|
+
|
136
|
+
expect(scanner.scan).to eq([nil, nil, nil])
|
137
|
+
expect(scanner.scan).to eq([nil, nil, nil])
|
138
|
+
expect(scanner.scan).to eq([nil, nil, nil])
|
139
|
+
expect(scanner.scan).to eq([nil, nil, nil])
|
140
|
+
expect(scanner.scan).to be_nil
|
141
|
+
end
|
142
|
+
|
143
|
+
it "supports empty groups with multibyte characters", :aggregate_failures do
|
144
|
+
r = RE2::Regexp.new("()€")
|
145
|
+
scanner = r.scan("€")
|
146
|
+
|
147
|
+
expect(scanner.scan).to eq([nil])
|
148
|
+
expect(scanner.scan).to be_nil
|
149
|
+
end
|
150
|
+
|
151
|
+
it "raises a Type Error if given input that can't be coerced to a String" do
|
152
|
+
r = RE2::Regexp.new('(\w+)')
|
153
|
+
|
154
|
+
expect { r.scan(0) }.to raise_error(TypeError)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "accepts input that can be coerced to a String", :aggregate_failures do
|
158
|
+
r = RE2::Regexp.new('(\w+)')
|
159
|
+
scanner = r.scan(StringLike.new("Hello world"))
|
160
|
+
|
161
|
+
expect(scanner.scan).to eq(["Hello"])
|
162
|
+
expect(scanner.scan).to eq(["world"])
|
163
|
+
expect(scanner.scan).to be_nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it "is enumerable" do
|
168
|
+
r = RE2::Regexp.new('(\d)')
|
169
|
+
scanner = r.scan("There are 1 some 2 numbers 3")
|
170
|
+
|
171
|
+
expect(scanner).to be_a(Enumerable)
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#each" do
|
175
|
+
it "yields each match" do
|
176
|
+
r = RE2::Regexp.new('(\d)')
|
177
|
+
scanner = r.scan("There are 1 some 2 numbers 3")
|
178
|
+
|
179
|
+
expect { |b| scanner.each(&b) }.to yield_successive_args(["1"], ["2"], ["3"])
|
180
|
+
end
|
181
|
+
|
182
|
+
it "returns an enumerator when not given a block" do
|
183
|
+
r = RE2::Regexp.new('(\d)')
|
184
|
+
scanner = r.scan("There are 1 some 2 numbers 3")
|
185
|
+
|
186
|
+
expect(scanner.each).to be_a(Enumerator)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#rewind" do
|
191
|
+
it "resets any consumption", :aggregate_failures do
|
192
|
+
r = RE2::Regexp.new('(\d)')
|
193
|
+
scanner = r.scan("There are 1 some 2 numbers 3")
|
194
|
+
|
195
|
+
expect(scanner.to_enum.first).to eq(["1"])
|
196
|
+
expect(scanner.to_enum.first).to eq(["2"])
|
197
|
+
|
198
|
+
scanner.rewind
|
199
|
+
|
200
|
+
expect(scanner.to_enum.first).to eq(["1"])
|
201
|
+
end
|
202
|
+
|
203
|
+
it "supports inputs with null bytes", :aggregate_failures do
|
204
|
+
r = RE2::Regexp.new("(\\w\0\\w)")
|
205
|
+
scanner = r.scan("a\0b c\0d")
|
206
|
+
|
207
|
+
expect(scanner.to_enum.first).to eq(["a\0b"])
|
208
|
+
expect(scanner.to_enum.first).to eq(["c\0d"])
|
209
|
+
|
210
|
+
scanner.rewind
|
211
|
+
|
212
|
+
expect(scanner.to_enum.first).to eq(["a\0b"])
|
213
|
+
end
|
214
|
+
|
215
|
+
it "resets the eof? check", :aggregate_failures do
|
216
|
+
r = RE2::Regexp.new('(\d)')
|
217
|
+
scanner = r.scan("1")
|
218
|
+
scanner.scan
|
219
|
+
|
220
|
+
expect(scanner).to be_eof
|
221
|
+
|
222
|
+
scanner.rewind
|
223
|
+
|
224
|
+
expect(scanner).not_to be_eof
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#eof?" do
|
229
|
+
it "returns false if the input has not been consumed" do
|
230
|
+
r = RE2::Regexp.new('(\d)')
|
231
|
+
scanner = r.scan("1 2 3")
|
232
|
+
|
233
|
+
expect(scanner).not_to be_eof
|
234
|
+
end
|
235
|
+
|
236
|
+
it "returns true if the input has been consumed" do
|
237
|
+
r = RE2::Regexp.new('(\d)')
|
238
|
+
scanner = r.scan("1")
|
239
|
+
scanner.scan
|
240
|
+
|
241
|
+
expect(scanner).to be_eof
|
242
|
+
end
|
243
|
+
|
244
|
+
it "returns false if no match is made" do
|
245
|
+
r = RE2::Regexp.new('(\d)')
|
246
|
+
scanner = r.scan("a")
|
247
|
+
scanner.scan
|
248
|
+
|
249
|
+
expect(scanner).not_to be_eof
|
250
|
+
end
|
251
|
+
|
252
|
+
it "returns false with an empty input that has not been scanned" do
|
253
|
+
r = RE2::Regexp.new("")
|
254
|
+
scanner = r.scan("")
|
255
|
+
|
256
|
+
expect(scanner).not_to be_eof
|
257
|
+
end
|
258
|
+
|
259
|
+
it "returns false with an empty input that has not been matched" do
|
260
|
+
r = RE2::Regexp.new('(\d)')
|
261
|
+
scanner = r.scan("")
|
262
|
+
scanner.scan
|
263
|
+
|
264
|
+
expect(scanner).not_to be_eof
|
265
|
+
end
|
266
|
+
|
267
|
+
it "returns true with an empty input that has been matched" do
|
268
|
+
r = RE2::Regexp.new("")
|
269
|
+
scanner = r.scan("")
|
270
|
+
scanner.scan
|
271
|
+
|
272
|
+
expect(scanner).to be_eof
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe RE2::Set do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "returns an instance given no args" do
|
6
|
+
set = RE2::Set.new
|
7
|
+
|
8
|
+
expect(set).to be_a(RE2::Set)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns an instance given only an anchor of :unanchored" do
|
12
|
+
set = RE2::Set.new(:unanchored)
|
13
|
+
|
14
|
+
expect(set).to be_a(RE2::Set)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns an instance given only an anchor of :anchor_start" do
|
18
|
+
set = RE2::Set.new(:anchor_start)
|
19
|
+
|
20
|
+
expect(set).to be_a(RE2::Set)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns an instance given only an anchor of :anchor_both" do
|
24
|
+
set = RE2::Set.new(:anchor_both)
|
25
|
+
|
26
|
+
expect(set).to be_a(RE2::Set)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns an instance given an anchor and options" do
|
30
|
+
set = RE2::Set.new(:unanchored, case_sensitive: false)
|
31
|
+
|
32
|
+
expect(set).to be_a(RE2::Set)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "raises an error if given an inappropriate type" do
|
36
|
+
expect { RE2::Set.new(0) }.to raise_error(TypeError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "raises an error if given an invalid anchor" do
|
40
|
+
expect { RE2::Set.new(:not_a_valid_anchor) }.to raise_error(
|
41
|
+
ArgumentError,
|
42
|
+
"anchor should be one of: :unanchored, :anchor_start, :anchor_both"
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "raises an error if given an invalid anchor and options" do
|
47
|
+
expect { RE2::Set.new(:not_a_valid_anchor, case_sensitive: false) }.to raise_error(
|
48
|
+
ArgumentError,
|
49
|
+
"anchor should be one of: :unanchored, :anchor_start, :anchor_both"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#add" do
|
55
|
+
it "allows multiple patterns to be added", :aggregate_failures do
|
56
|
+
set = RE2::Set.new
|
57
|
+
|
58
|
+
expect(set.add("abc")).to eq(0)
|
59
|
+
expect(set.add("def")).to eq(1)
|
60
|
+
expect(set.add("ghi")).to eq(2)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "rejects invalid patterns when added" do
|
64
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
65
|
+
|
66
|
+
expect { set.add("???") }.to raise_error(ArgumentError, /str rejected by RE2::Set->Add\(\)/)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "truncates error messages to 100 characters" do
|
70
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
71
|
+
|
72
|
+
expect { set.add("(?P<#{'o' * 200}") }.to raise_error(ArgumentError, "str rejected by RE2::Set->Add(): invalid named capture group: (?P<oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "raises an error if called after #compile" do
|
76
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
77
|
+
set.add("abc")
|
78
|
+
set.compile
|
79
|
+
|
80
|
+
silence_stderr do
|
81
|
+
expect { set.add("def") }.to raise_error(ArgumentError)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "raises an error if given a pattern that can't be coerced to a String" do
|
86
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
87
|
+
|
88
|
+
expect { set.add(0) }.to raise_error(TypeError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "accepts a pattern that can be coerced to a String" do
|
92
|
+
set = RE2::Set.new
|
93
|
+
|
94
|
+
expect(set.add(StringLike.new("abc"))).to eq(0)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#compile" do
|
99
|
+
it "compiles the set without error" do
|
100
|
+
set = RE2::Set.new
|
101
|
+
set.add("abc")
|
102
|
+
set.add("def")
|
103
|
+
set.add("ghi")
|
104
|
+
|
105
|
+
expect(set.compile).to be_truthy
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "#match" do
|
110
|
+
it "matches against multiple patterns" do
|
111
|
+
set = RE2::Set.new
|
112
|
+
set.add("abc")
|
113
|
+
set.add("def")
|
114
|
+
set.add("ghi")
|
115
|
+
set.compile
|
116
|
+
|
117
|
+
expect(set.match("abcdefghi", exception: false)).to eq([0, 1, 2])
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns an empty array if there is no match" do
|
121
|
+
set = RE2::Set.new
|
122
|
+
set.add("abc")
|
123
|
+
set.compile
|
124
|
+
|
125
|
+
expect(set.match("def", exception: false)).to be_empty
|
126
|
+
end
|
127
|
+
|
128
|
+
it "supports matching null bytes", :aggregate_failures do
|
129
|
+
set = RE2::Set.new
|
130
|
+
set.add("a\0b")
|
131
|
+
set.compile
|
132
|
+
|
133
|
+
expect(set.match("a\0b", exception: false)).to eq([0])
|
134
|
+
end
|
135
|
+
|
136
|
+
it "returns an empty array if there is no match when :exception is true" do
|
137
|
+
skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
|
138
|
+
|
139
|
+
set = RE2::Set.new
|
140
|
+
set.add("abc")
|
141
|
+
set.compile
|
142
|
+
|
143
|
+
expect(set.match("def")).to be_empty
|
144
|
+
end
|
145
|
+
|
146
|
+
it "raises an error if called before #compile by default" do
|
147
|
+
skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
|
148
|
+
|
149
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
150
|
+
|
151
|
+
silence_stderr do
|
152
|
+
expect { set.match("") }.to raise_error(RE2::Set::MatchError)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "raises an error if called before #compile when :exception is true" do
|
157
|
+
skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
|
158
|
+
|
159
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
160
|
+
|
161
|
+
silence_stderr do
|
162
|
+
expect { set.match("", exception: true) }.to raise_error(RE2::Set::MatchError)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
it "returns an empty array if called before #compile when :exception is false" do
|
167
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
168
|
+
|
169
|
+
silence_stderr do
|
170
|
+
expect(set.match("", exception: false)).to be_empty
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it "raises an error if :exception is true and RE2 does not support it" do
|
175
|
+
skip "Underlying RE2::Set::Match outputs error information" if RE2::Set.match_raises_errors?
|
176
|
+
|
177
|
+
set = RE2::Set.new(:unanchored, log_errors: false)
|
178
|
+
|
179
|
+
silence_stderr do
|
180
|
+
expect { set.match("", exception: true) }.to raise_error(RE2::Set::UnsupportedError)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "raises an error if given non-hash options" do
|
185
|
+
set = RE2::Set.new
|
186
|
+
|
187
|
+
expect { set.match("", 0) }.to raise_error(TypeError)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "raises a Type Error if given input that can't be coerced to a String" do
|
191
|
+
set = RE2::Set.new
|
192
|
+
set.add("abc")
|
193
|
+
set.compile
|
194
|
+
|
195
|
+
expect { set.match(0, exception: false) }.to raise_error(TypeError)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "accepts input if it can be coerced to a String" do
|
199
|
+
set = RE2::Set.new
|
200
|
+
set.add("abc")
|
201
|
+
set.compile
|
202
|
+
|
203
|
+
expect(set.match(StringLike.new("abcdef"), exception: false)).to contain_exactly(0)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def silence_stderr
|
208
|
+
original_stream = STDERR
|
209
|
+
|
210
|
+
if File.const_defined?(:NULL)
|
211
|
+
STDERR.reopen(File::NULL)
|
212
|
+
else
|
213
|
+
platform = RUBY_PLATFORM == 'java' ? RbConfig::CONFIG['host_os'] : RUBY_PLATFORM
|
214
|
+
|
215
|
+
case platform
|
216
|
+
when /mswin|mingw/i
|
217
|
+
STDERR.reopen('NUL')
|
218
|
+
when /amiga/i
|
219
|
+
STDERR.reopen('NIL')
|
220
|
+
when /openvms/i
|
221
|
+
STDERR.reopen('NL:')
|
222
|
+
else
|
223
|
+
STDERR.reopen('/dev/null')
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
yield
|
228
|
+
ensure
|
229
|
+
STDERR.reopen(original_stream)
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "re2/string"
|
4
|
+
|
5
|
+
class String
|
6
|
+
include RE2::String
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec.describe RE2::String do
|
10
|
+
describe "#re2_sub" do
|
11
|
+
it "delegates to RE2.Replace to perform replacement" do
|
12
|
+
expect("My name is Robert Paulson".re2_sub('Robert', 'Crobert')).to eq("My name is Crobert Paulson")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't perform an in-place replacement" do
|
16
|
+
string = "My name is Robert Paulson"
|
17
|
+
|
18
|
+
expect(string.re2_sub('Robert', 'Crobert')).not_to equal(string)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#re2_gsub" do
|
23
|
+
it "delegates to RE2.GlobalReplace to perform replacement" do
|
24
|
+
expect("My name is Robert Paulson".re2_gsub('a', 'e')).to eq("My neme is Robert Peulson")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "doesn't perform an in-place replacement" do
|
28
|
+
string = "My name is Robert Paulson"
|
29
|
+
|
30
|
+
expect(string.re2_gsub('a', 'e')).not_to equal(string)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#re2_match" do
|
35
|
+
it "delegates to RE2::Regexp#match to perform matches", :aggregate_failures do
|
36
|
+
md = "My name is Robert Paulson".re2_match('My name is (\S+) (\S+)')
|
37
|
+
|
38
|
+
expect(md).to be_a(RE2::MatchData)
|
39
|
+
expect(md[0]).to eq("My name is Robert Paulson")
|
40
|
+
expect(md[1]).to eq("Robert")
|
41
|
+
expect(md[2]).to eq("Paulson")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "supports limiting the number of matches" do
|
45
|
+
md = "My name is Robert Paulson".re2_match('My name is (\S+) (\S+)', 0)
|
46
|
+
|
47
|
+
expect(md).to eq(true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#re2_escape" do
|
52
|
+
it "escapes the string for use in regular expressions" do
|
53
|
+
expect("1.5-2.0?".re2_escape).to eq('1\.5\-2\.0\?')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#re2_quote" do
|
58
|
+
it "escapes the string for use in regular expressions" do
|
59
|
+
expect("1.5-2.0?".re2_quote).to eq('1\.5\-2\.0\?')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|