re2 2.9.0 → 2.27.0
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 +4 -4
- data/Gemfile +6 -0
- data/README.md +130 -22
- data/Rakefile +52 -90
- data/dependencies.yml +4 -4
- data/ext/re2/extconf.rb +256 -290
- data/ext/re2/re2.cc +1037 -318
- data/ext/re2/recipes.rb +24 -21
- data/lib/re2/regexp.rb +2 -0
- data/lib/re2/scanner.rb +2 -0
- data/lib/re2/string.rb +8 -6
- data/lib/re2/version.rb +1 -1
- data/lib/re2.rb +2 -0
- data/ports/archives/20260107.1.tar.gz +0 -0
- data/ports/archives/re2-2025-11-05.tar.gz +0 -0
- data/re2.gemspec +6 -4
- data/spec/kernel_spec.rb +2 -0
- data/spec/re2/match_data_spec.rb +520 -5
- data/spec/re2/regexp_spec.rb +342 -0
- data/spec/re2/scanner_spec.rb +185 -15
- data/spec/re2/set_spec.rb +123 -6
- data/spec/re2/string_spec.rb +2 -0
- data/spec/re2_spec.rb +219 -43
- data/spec/spec_helper.rb +2 -0
- metadata +17 -21
- data/ports/archives/20240116.1.tar.gz +0 -0
- data/ports/archives/re2-2024-03-01.tar.gz +0 -0
data/spec/re2/scanner_spec.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RSpec.describe RE2::Scanner do
|
|
4
4
|
describe "#regexp" do
|
|
@@ -8,16 +8,102 @@ RSpec.describe RE2::Scanner do
|
|
|
8
8
|
|
|
9
9
|
expect(scanner.regexp).to equal(re)
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
it "raises an error when called on an uninitialized object" do
|
|
13
|
+
expect { described_class.allocate.regexp }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#dup" do
|
|
18
|
+
it "returns a usable copy of the scanner at the same position" do
|
|
19
|
+
scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
|
|
20
|
+
scanner.scan
|
|
21
|
+
|
|
22
|
+
copy = scanner.dup
|
|
23
|
+
|
|
24
|
+
expect(copy.scan).to eq(["bar"])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "creates an independent copy" do
|
|
28
|
+
scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
|
|
29
|
+
scanner.scan
|
|
30
|
+
|
|
31
|
+
copy = scanner.dup
|
|
32
|
+
copy.scan
|
|
33
|
+
|
|
34
|
+
expect(scanner.scan).to eq(["bar"])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "copies the EOF state of the scanner" do
|
|
38
|
+
scanner = RE2::Regexp.new('(\w+)').scan("foo")
|
|
39
|
+
scanner.scan
|
|
40
|
+
scanner.scan
|
|
41
|
+
|
|
42
|
+
copy = scanner.dup
|
|
43
|
+
|
|
44
|
+
expect(copy).to be_eof
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "raises an error when called on an uninitialized object" do
|
|
48
|
+
expect { described_class.allocate.dup }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "#clone" do
|
|
53
|
+
it "returns a usable copy of the scanner at the same position" do
|
|
54
|
+
scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
|
|
55
|
+
scanner.scan
|
|
56
|
+
|
|
57
|
+
copy = scanner.clone
|
|
58
|
+
|
|
59
|
+
expect(copy.scan).to eq(["bar"])
|
|
60
|
+
end
|
|
11
61
|
end
|
|
12
62
|
|
|
13
63
|
describe "#string" do
|
|
14
|
-
it "returns the
|
|
64
|
+
it "returns the text for the scanner" do
|
|
65
|
+
re = RE2::Regexp.new('(\w+)')
|
|
66
|
+
text = "It is a truth"
|
|
67
|
+
scanner = re.scan(text)
|
|
68
|
+
|
|
69
|
+
expect(scanner.string).to eq("It is a truth")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "returns a frozen string" do
|
|
73
|
+
re = RE2::Regexp.new('(\w+)')
|
|
74
|
+
text = "It is a truth"
|
|
75
|
+
scanner = re.scan(text)
|
|
76
|
+
|
|
77
|
+
expect(scanner.string).to be_frozen
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "freezes unfrozen strings" do
|
|
81
|
+
re = RE2::Regexp.new('(\w+)')
|
|
82
|
+
text = +"It is a truth"
|
|
83
|
+
scanner = re.scan(text)
|
|
84
|
+
|
|
85
|
+
expect(scanner.string).to be_frozen
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "copies unfrozen strings" do
|
|
89
|
+
re = RE2::Regexp.new('(\w+)')
|
|
90
|
+
text = +"It is a truth"
|
|
91
|
+
scanner = re.scan(text)
|
|
92
|
+
|
|
93
|
+
expect(scanner.string).to_not equal(text)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "does not copy the string if it was already frozen" do
|
|
15
97
|
re = RE2::Regexp.new('(\w+)')
|
|
16
98
|
text = "It is a truth"
|
|
17
99
|
scanner = re.scan(text)
|
|
18
100
|
|
|
19
101
|
expect(scanner.string).to equal(text)
|
|
20
102
|
end
|
|
103
|
+
|
|
104
|
+
it "raises an error when called on an uninitialized object" do
|
|
105
|
+
expect { described_class.allocate.string }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
106
|
+
end
|
|
21
107
|
end
|
|
22
108
|
|
|
23
109
|
describe "#scan" do
|
|
@@ -99,11 +185,11 @@ RSpec.describe RE2::Scanner do
|
|
|
99
185
|
expect(scanner.scan).to be_nil
|
|
100
186
|
end
|
|
101
187
|
|
|
102
|
-
it "returns an array of
|
|
188
|
+
it "returns an array of empty strings with an empty input and capture", :aggregate_failures do
|
|
103
189
|
r = RE2::Regexp.new("()")
|
|
104
190
|
scanner = r.scan("")
|
|
105
191
|
|
|
106
|
-
expect(scanner.scan).to eq([
|
|
192
|
+
expect(scanner.scan).to eq([""])
|
|
107
193
|
expect(scanner.scan).to be_nil
|
|
108
194
|
end
|
|
109
195
|
|
|
@@ -118,25 +204,34 @@ RSpec.describe RE2::Scanner do
|
|
|
118
204
|
expect(scanner.scan).to be_nil
|
|
119
205
|
end
|
|
120
206
|
|
|
121
|
-
it "returns an array of
|
|
207
|
+
it "returns an array of empty strings if the pattern is an empty capturing group", :aggregate_failures do
|
|
122
208
|
r = RE2::Regexp.new("()")
|
|
123
209
|
scanner = r.scan("Foo")
|
|
124
210
|
|
|
125
|
-
expect(scanner.scan).to eq([
|
|
126
|
-
expect(scanner.scan).to eq([
|
|
127
|
-
expect(scanner.scan).to eq([
|
|
128
|
-
expect(scanner.scan).to eq([
|
|
211
|
+
expect(scanner.scan).to eq([""])
|
|
212
|
+
expect(scanner.scan).to eq([""])
|
|
213
|
+
expect(scanner.scan).to eq([""])
|
|
214
|
+
expect(scanner.scan).to eq([""])
|
|
129
215
|
expect(scanner.scan).to be_nil
|
|
130
216
|
end
|
|
131
217
|
|
|
132
|
-
it "returns array of
|
|
218
|
+
it "returns array of empty strings with multiple empty capturing groups", :aggregate_failures do
|
|
133
219
|
r = RE2::Regexp.new("()()()")
|
|
134
220
|
scanner = r.scan("Foo")
|
|
135
221
|
|
|
136
|
-
expect(scanner.scan).to eq([
|
|
137
|
-
expect(scanner.scan).to eq([
|
|
138
|
-
expect(scanner.scan).to eq([
|
|
139
|
-
expect(scanner.scan).to eq([
|
|
222
|
+
expect(scanner.scan).to eq(["", "", ""])
|
|
223
|
+
expect(scanner.scan).to eq(["", "", ""])
|
|
224
|
+
expect(scanner.scan).to eq(["", "", ""])
|
|
225
|
+
expect(scanner.scan).to eq(["", "", ""])
|
|
226
|
+
expect(scanner.scan).to be_nil
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it "distinguishes zero-length matches from unmatched groups", :aggregate_failures do
|
|
230
|
+
r = RE2::Regexp.new("()(a)?")
|
|
231
|
+
scanner = r.scan("b")
|
|
232
|
+
|
|
233
|
+
expect(scanner.scan).to eq(["", nil])
|
|
234
|
+
expect(scanner.scan).to eq(["", nil])
|
|
140
235
|
expect(scanner.scan).to be_nil
|
|
141
236
|
end
|
|
142
237
|
|
|
@@ -144,7 +239,53 @@ RSpec.describe RE2::Scanner do
|
|
|
144
239
|
r = RE2::Regexp.new("()€")
|
|
145
240
|
scanner = r.scan("€")
|
|
146
241
|
|
|
147
|
-
expect(scanner.scan).to eq([
|
|
242
|
+
expect(scanner.scan).to eq([""])
|
|
243
|
+
expect(scanner.scan).to be_nil
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "advances by whole characters with zero-width matches on 2-byte UTF-8 input", :aggregate_failures do
|
|
247
|
+
r = RE2::Regexp.new("")
|
|
248
|
+
scanner = r.scan("à")
|
|
249
|
+
|
|
250
|
+
expect(scanner.scan).to eq([])
|
|
251
|
+
expect(scanner.scan).to eq([])
|
|
252
|
+
expect(scanner.scan).to be_nil
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "advances by whole characters with zero-width matches on 3-byte UTF-8 input", :aggregate_failures do
|
|
256
|
+
r = RE2::Regexp.new("")
|
|
257
|
+
scanner = r.scan("\u20AC")
|
|
258
|
+
|
|
259
|
+
expect(scanner.scan).to eq([])
|
|
260
|
+
expect(scanner.scan).to eq([])
|
|
261
|
+
expect(scanner.scan).to be_nil
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it "advances by whole characters with zero-width matches on 4-byte UTF-8 input", :aggregate_failures do
|
|
265
|
+
r = RE2::Regexp.new("")
|
|
266
|
+
scanner = r.scan("\u{1F600}")
|
|
267
|
+
|
|
268
|
+
expect(scanner.scan).to eq([])
|
|
269
|
+
expect(scanner.scan).to eq([])
|
|
270
|
+
expect(scanner.scan).to be_nil
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it "advances by single bytes with zero-width matches on Latin-1 input", :aggregate_failures do
|
|
274
|
+
r = RE2::Regexp.new("", utf8: false)
|
|
275
|
+
scanner = r.scan("\xC3\xA0")
|
|
276
|
+
|
|
277
|
+
expect(scanner.scan).to eq([])
|
|
278
|
+
expect(scanner.scan).to eq([])
|
|
279
|
+
expect(scanner.scan).to eq([])
|
|
280
|
+
expect(scanner.scan).to be_nil
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it "handles truncated multi-byte sequences at the end of input", :aggregate_failures do
|
|
284
|
+
r = RE2::Regexp.new("")
|
|
285
|
+
scanner = r.scan("\xC3")
|
|
286
|
+
|
|
287
|
+
expect(scanner.scan).to eq([])
|
|
288
|
+
expect(scanner.scan).to eq([])
|
|
148
289
|
expect(scanner.scan).to be_nil
|
|
149
290
|
end
|
|
150
291
|
|
|
@@ -162,6 +303,27 @@ RSpec.describe RE2::Scanner do
|
|
|
162
303
|
expect(scanner.scan).to eq(["world"])
|
|
163
304
|
expect(scanner.scan).to be_nil
|
|
164
305
|
end
|
|
306
|
+
|
|
307
|
+
it "supports GC compaction" do
|
|
308
|
+
r = RE2::Regexp.new('(\w+)')
|
|
309
|
+
scanner = r.scan("Hello world" * 2)
|
|
310
|
+
GC.compact
|
|
311
|
+
|
|
312
|
+
expect(scanner.scan).to eq(["Hello"])
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "works even if the original input is mutated" do
|
|
316
|
+
r = RE2::Regexp.new('(\w+)')
|
|
317
|
+
text = +"It is a truth universally acknowledged"
|
|
318
|
+
scanner = r.scan(text)
|
|
319
|
+
text.upcase!
|
|
320
|
+
|
|
321
|
+
expect(scanner.scan).to eq(["It"])
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "raises an error when called on an uninitialized object" do
|
|
325
|
+
expect { described_class.allocate.scan }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
326
|
+
end
|
|
165
327
|
end
|
|
166
328
|
|
|
167
329
|
it "is enumerable" do
|
|
@@ -223,6 +385,10 @@ RSpec.describe RE2::Scanner do
|
|
|
223
385
|
|
|
224
386
|
expect(scanner).not_to be_eof
|
|
225
387
|
end
|
|
388
|
+
|
|
389
|
+
it "raises an error when called on an uninitialized object" do
|
|
390
|
+
expect { described_class.allocate.rewind }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
391
|
+
end
|
|
226
392
|
end
|
|
227
393
|
|
|
228
394
|
describe "#eof?" do
|
|
@@ -271,5 +437,9 @@ RSpec.describe RE2::Scanner do
|
|
|
271
437
|
|
|
272
438
|
expect(scanner).to be_eof
|
|
273
439
|
end
|
|
440
|
+
|
|
441
|
+
it "raises an error when called on an uninitialized object" do
|
|
442
|
+
expect { described_class.allocate.eof? }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
|
|
443
|
+
end
|
|
274
444
|
end
|
|
275
445
|
end
|
data/spec/re2/set_spec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
RSpec.describe RE2::Set do
|
|
2
4
|
describe "#initialize" do
|
|
3
5
|
it "returns an instance given no args" do
|
|
@@ -49,6 +51,18 @@ RSpec.describe RE2::Set do
|
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
|
|
54
|
+
describe "#dup" do
|
|
55
|
+
it "raises a TypeError" do
|
|
56
|
+
expect { described_class.new.dup }.to raise_error(TypeError, /cannot copy RE2::Set/)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe "#clone" do
|
|
61
|
+
it "raises a TypeError" do
|
|
62
|
+
expect { described_class.new.clone }.to raise_error(TypeError, /cannot copy RE2::Set/)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
52
66
|
describe "#add" do
|
|
53
67
|
it "allows multiple patterns to be added", :aggregate_failures do
|
|
54
68
|
set = RE2::Set.new
|
|
@@ -64,20 +78,18 @@ RSpec.describe RE2::Set do
|
|
|
64
78
|
expect { set.add("???") }.to raise_error(ArgumentError, /str rejected by RE2::Set->Add\(\)/)
|
|
65
79
|
end
|
|
66
80
|
|
|
67
|
-
it "
|
|
81
|
+
it "includes the full error message" do
|
|
68
82
|
set = RE2::Set.new(:unanchored, log_errors: false)
|
|
69
83
|
|
|
70
|
-
expect { set.add("(?P<#{'o' * 200}") }.to raise_error(ArgumentError, "str rejected by RE2::Set->Add(): invalid named capture group: (?P<
|
|
84
|
+
expect { set.add("(?P<#{'o' * 200}") }.to raise_error(ArgumentError, "str rejected by RE2::Set->Add(): invalid named capture group: (?P<oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")
|
|
71
85
|
end
|
|
72
86
|
|
|
73
|
-
it "raises
|
|
87
|
+
it "raises a FrozenError if called after #compile" do
|
|
74
88
|
set = RE2::Set.new(:unanchored, log_errors: false)
|
|
75
89
|
set.add("abc")
|
|
76
90
|
set.compile
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
expect { set.add("def") }.to raise_error(ArgumentError)
|
|
80
|
-
end
|
|
92
|
+
expect { set.add("def") }.to raise_error(FrozenError)
|
|
81
93
|
end
|
|
82
94
|
|
|
83
95
|
it "raises an error if given a pattern that can't be coerced to a String" do
|
|
@@ -91,6 +103,10 @@ RSpec.describe RE2::Set do
|
|
|
91
103
|
|
|
92
104
|
expect(set.add(StringLike.new("abc"))).to eq(0)
|
|
93
105
|
end
|
|
106
|
+
|
|
107
|
+
it "raises an error when called on an uninitialized object" do
|
|
108
|
+
expect { described_class.allocate.add("foo") }.to raise_error(TypeError, /uninitialized RE2::Set/)
|
|
109
|
+
end
|
|
94
110
|
end
|
|
95
111
|
|
|
96
112
|
describe "#compile" do
|
|
@@ -102,6 +118,33 @@ RSpec.describe RE2::Set do
|
|
|
102
118
|
|
|
103
119
|
expect(set.compile).to be_truthy
|
|
104
120
|
end
|
|
121
|
+
|
|
122
|
+
it "freezes the set on successful compilation" do
|
|
123
|
+
set = RE2::Set.new
|
|
124
|
+
set.add("abc")
|
|
125
|
+
set.compile
|
|
126
|
+
|
|
127
|
+
expect(set).to be_frozen
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "is not frozen before compilation" do
|
|
131
|
+
set = RE2::Set.new
|
|
132
|
+
set.add("abc")
|
|
133
|
+
|
|
134
|
+
expect(set).to_not be_frozen
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "cannot be re-initialized after compilation" do
|
|
138
|
+
set = RE2::Set.new
|
|
139
|
+
set.add("abc")
|
|
140
|
+
set.compile
|
|
141
|
+
|
|
142
|
+
expect { set.send(:initialize) }.to raise_error(FrozenError)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "raises an error when called on an uninitialized object" do
|
|
146
|
+
expect { described_class.allocate.compile }.to raise_error(TypeError, /uninitialized RE2::Set/)
|
|
147
|
+
end
|
|
105
148
|
end
|
|
106
149
|
|
|
107
150
|
describe "#match" do
|
|
@@ -200,6 +243,80 @@ RSpec.describe RE2::Set do
|
|
|
200
243
|
|
|
201
244
|
expect(set.match(StringLike.new("abcdef"), exception: false)).to contain_exactly(0)
|
|
202
245
|
end
|
|
246
|
+
|
|
247
|
+
it "raises an error when called on an uninitialized object" do
|
|
248
|
+
expect { described_class.allocate.match("foo") }.to raise_error(TypeError, /uninitialized RE2::Set/)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "can be run concurrently" do
|
|
252
|
+
set = RE2::Set.new
|
|
253
|
+
set.add("abc")
|
|
254
|
+
set.add("def")
|
|
255
|
+
set.add("ghi")
|
|
256
|
+
set.compile
|
|
257
|
+
|
|
258
|
+
threads = 10.times.map do
|
|
259
|
+
Thread.new { set.match("abcdefghi", exception: false) }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
expect(threads.map(&:value)).to all(eq([0, 1, 2]))
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
describe "#size" do
|
|
267
|
+
it "returns the number of patterns added to the set", :aggregate_failures do
|
|
268
|
+
skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
|
|
269
|
+
|
|
270
|
+
set = RE2::Set.new
|
|
271
|
+
|
|
272
|
+
expect(set.size).to eq(0)
|
|
273
|
+
|
|
274
|
+
set.add("abc")
|
|
275
|
+
|
|
276
|
+
expect(set.size).to eq(1)
|
|
277
|
+
|
|
278
|
+
set.add("def")
|
|
279
|
+
|
|
280
|
+
expect(set.size).to eq(2)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it "raises an error if RE2 does not support Set::Size" do
|
|
284
|
+
skip "Underlying RE2::Set has a Size method" if RE2::Set.size?
|
|
285
|
+
|
|
286
|
+
set = RE2::Set.new
|
|
287
|
+
|
|
288
|
+
expect { set.size }.to raise_error(RE2::Set::UnsupportedError)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it "raises an error when called on an uninitialized object" do
|
|
292
|
+
skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
|
|
293
|
+
|
|
294
|
+
expect { described_class.allocate.size }.to raise_error(TypeError, /uninitialized RE2::Set/)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
describe "#length" do
|
|
299
|
+
it "is an alias for size" do
|
|
300
|
+
skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
|
|
301
|
+
|
|
302
|
+
set = RE2::Set.new
|
|
303
|
+
|
|
304
|
+
expect(set.length).to eq(0)
|
|
305
|
+
|
|
306
|
+
set.add("abc")
|
|
307
|
+
|
|
308
|
+
expect(set.length).to eq(1)
|
|
309
|
+
|
|
310
|
+
set.add("def")
|
|
311
|
+
|
|
312
|
+
expect(set.length).to eq(2)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "raises an error when called on an uninitialized object" do
|
|
316
|
+
skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
|
|
317
|
+
|
|
318
|
+
expect { described_class.allocate.length }.to raise_error(TypeError, /uninitialized RE2::Set/)
|
|
319
|
+
end
|
|
203
320
|
end
|
|
204
321
|
|
|
205
322
|
def silence_stderr
|