re2 2.23.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/README.md +107 -4
- data/Rakefile +0 -4
- data/dependencies.yml +2 -2
- data/ext/re2/extconf.rb +4 -5
- data/ext/re2/re2.cc +962 -275
- data/lib/re2/string.rb +6 -6
- data/lib/re2/version.rb +1 -1
- data/ports/archives/20260107.1.tar.gz +0 -0
- data/spec/re2/match_data_spec.rb +495 -2
- data/spec/re2/regexp_spec.rb +324 -1
- data/spec/re2/scanner_spec.rb +134 -13
- data/spec/re2/set_spec.rb +75 -4
- data/spec/re2_spec.rb +217 -43
- metadata +3 -3
- data/ports/archives/20250814.1.tar.gz +0 -0
data/lib/re2/string.rb
CHANGED
|
@@ -13,14 +13,14 @@ require "re2"
|
|
|
13
13
|
module RE2
|
|
14
14
|
# @deprecated Use methods on {RE2} and {RE2::Regexp} instead.
|
|
15
15
|
module String
|
|
16
|
-
# @deprecated Use {RE2.
|
|
16
|
+
# @deprecated Use {RE2.replace} instead.
|
|
17
17
|
def re2_sub(*args)
|
|
18
|
-
RE2.
|
|
18
|
+
RE2.replace(self, *args)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# @deprecated Use {RE2.
|
|
21
|
+
# @deprecated Use {RE2.global_replace} instead.
|
|
22
22
|
def re2_gsub(*args)
|
|
23
|
-
RE2.
|
|
23
|
+
RE2.global_replace(self, *args)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# @deprecated Use {RE2::Regexp#match} instead.
|
|
@@ -28,9 +28,9 @@ module RE2
|
|
|
28
28
|
RE2::Regexp.new(pattern).match(self, *args)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
# @deprecated Use {RE2.
|
|
31
|
+
# @deprecated Use {RE2.escape} instead.
|
|
32
32
|
def re2_escape
|
|
33
|
-
RE2.
|
|
33
|
+
RE2.escape(self)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
alias_method :re2_quote, :re2_escape
|
data/lib/re2/version.rb
CHANGED
|
Binary file
|
data/spec/re2/match_data_spec.rb
CHANGED
|
@@ -10,6 +10,55 @@ RSpec.describe RE2::MatchData do
|
|
|
10
10
|
expect(ObjectSpace.memsize_of(matches1)).to be < ObjectSpace.memsize_of(matches2)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
describe "#dup" do
|
|
14
|
+
it "returns a copy of the match data" do
|
|
15
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("123 456")
|
|
16
|
+
copy = md.dup
|
|
17
|
+
|
|
18
|
+
expect(copy.to_a).to eq(["123 456", "123", "456"])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "returns a different object" do
|
|
22
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("123 456")
|
|
23
|
+
copy = md.dup
|
|
24
|
+
|
|
25
|
+
expect(copy).to_not equal(md)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "preserves the original string" do
|
|
29
|
+
str = "bob 123"
|
|
30
|
+
md = RE2::Regexp.new('(\d+)').match(str)
|
|
31
|
+
copy = md.dup
|
|
32
|
+
|
|
33
|
+
expect(copy.string).to equal(str)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "preserves the original regexp" do
|
|
37
|
+
re = RE2::Regexp.new('(\d+)')
|
|
38
|
+
md = re.match("123")
|
|
39
|
+
copy = md.dup
|
|
40
|
+
|
|
41
|
+
expect(copy.regexp).to equal(re)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "raises an error when called on an uninitialized object" do
|
|
45
|
+
expect { described_class.allocate.dup }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "#clone" do
|
|
50
|
+
it "returns a copy of the match data" do
|
|
51
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("123 456")
|
|
52
|
+
copy = md.clone
|
|
53
|
+
|
|
54
|
+
expect(copy.to_a).to eq(["123 456", "123", "456"])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "raises an error when called on an uninitialized object" do
|
|
58
|
+
expect { described_class.allocate.clone }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
13
62
|
describe "#to_a" do
|
|
14
63
|
it "is populated with the match and capturing groups" do
|
|
15
64
|
a = RE2::Regexp.new('w(o)(o)').match('woo').to_a
|
|
@@ -17,10 +66,16 @@ RSpec.describe RE2::MatchData do
|
|
|
17
66
|
expect(a).to eq(["woo", "o", "o"])
|
|
18
67
|
end
|
|
19
68
|
|
|
20
|
-
it "populates optional capturing groups with
|
|
69
|
+
it "populates optional capturing groups with empty strings if they match zero characters" do
|
|
21
70
|
a = RE2::Regexp.new('(\d?)(a)(b)').match('ab').to_a
|
|
22
71
|
|
|
23
|
-
expect(a).to eq(["ab",
|
|
72
|
+
expect(a).to eq(["ab", "", "a", "b"])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "distinguishes between zero-length matches and unmatched groups" do
|
|
76
|
+
a = RE2::Regexp.new('()(a)?').match('b').to_a
|
|
77
|
+
|
|
78
|
+
expect(a).to eq(["", "", nil])
|
|
24
79
|
end
|
|
25
80
|
|
|
26
81
|
it "returns UTF-8 strings if the pattern is UTF-8" do
|
|
@@ -34,6 +89,10 @@ RSpec.describe RE2::MatchData do
|
|
|
34
89
|
|
|
35
90
|
expect(a.map(&:encoding)).to all eq(Encoding::ISO_8859_1)
|
|
36
91
|
end
|
|
92
|
+
|
|
93
|
+
it "raises an error when called on an uninitialized object" do
|
|
94
|
+
expect { described_class.allocate.to_a }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
95
|
+
end
|
|
37
96
|
end
|
|
38
97
|
|
|
39
98
|
describe "#[]" do
|
|
@@ -105,6 +164,12 @@ RSpec.describe RE2::MatchData do
|
|
|
105
164
|
expect(md[:numbers]).to eq("123")
|
|
106
165
|
end
|
|
107
166
|
|
|
167
|
+
it "returns an empty string for a zero-length capturing group" do
|
|
168
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
169
|
+
|
|
170
|
+
expect(md[1]).to eq("")
|
|
171
|
+
end
|
|
172
|
+
|
|
108
173
|
it "returns nil if no such named group exists", :aggregate_failures do
|
|
109
174
|
md = RE2::Regexp.new('(\d+)').match("bob 123")
|
|
110
175
|
|
|
@@ -140,6 +205,10 @@ RSpec.describe RE2::MatchData do
|
|
|
140
205
|
|
|
141
206
|
expect(md[1]).to eq("woo")
|
|
142
207
|
end
|
|
208
|
+
|
|
209
|
+
it "raises an error when called on an uninitialized object" do
|
|
210
|
+
expect { described_class.allocate[0] }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
211
|
+
end
|
|
143
212
|
end
|
|
144
213
|
|
|
145
214
|
describe "#string" do
|
|
@@ -168,6 +237,10 @@ RSpec.describe RE2::MatchData do
|
|
|
168
237
|
|
|
169
238
|
expect(re.string).to equal(string)
|
|
170
239
|
end
|
|
240
|
+
|
|
241
|
+
it "raises an error when called on an uninitialized object" do
|
|
242
|
+
expect { described_class.allocate.string }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
243
|
+
end
|
|
171
244
|
end
|
|
172
245
|
|
|
173
246
|
describe "#size" do
|
|
@@ -176,6 +249,10 @@ RSpec.describe RE2::MatchData do
|
|
|
176
249
|
|
|
177
250
|
expect(md.size).to eq(3)
|
|
178
251
|
end
|
|
252
|
+
|
|
253
|
+
it "raises an error when called on an uninitialized object" do
|
|
254
|
+
expect { described_class.allocate.size }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
255
|
+
end
|
|
179
256
|
end
|
|
180
257
|
|
|
181
258
|
describe "#length" do
|
|
@@ -184,6 +261,10 @@ RSpec.describe RE2::MatchData do
|
|
|
184
261
|
|
|
185
262
|
expect(md.length).to eq(3)
|
|
186
263
|
end
|
|
264
|
+
|
|
265
|
+
it "raises an error when called on an uninitialized object" do
|
|
266
|
+
expect { described_class.allocate.length }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
267
|
+
end
|
|
187
268
|
end
|
|
188
269
|
|
|
189
270
|
describe "#regexp" do
|
|
@@ -193,6 +274,10 @@ RSpec.describe RE2::MatchData do
|
|
|
193
274
|
|
|
194
275
|
expect(md.regexp).to equal(re)
|
|
195
276
|
end
|
|
277
|
+
|
|
278
|
+
it "raises an error when called on an uninitialized object" do
|
|
279
|
+
expect { described_class.allocate.regexp }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
280
|
+
end
|
|
196
281
|
end
|
|
197
282
|
|
|
198
283
|
describe "#inspect" do
|
|
@@ -208,11 +293,21 @@ RSpec.describe RE2::MatchData do
|
|
|
208
293
|
expect(md.inspect).to eq('#<RE2::MatchData "1234 " 1:"1234" 2:nil>')
|
|
209
294
|
end
|
|
210
295
|
|
|
296
|
+
it "represents zero-length capturing groups as empty strings" do
|
|
297
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
298
|
+
|
|
299
|
+
expect(md.inspect).to eq('#<RE2::MatchData "" 1:"">')
|
|
300
|
+
end
|
|
301
|
+
|
|
211
302
|
it "supports matches with null bytes" do
|
|
212
303
|
md = RE2::Regexp.new("(\\w\0\\w) (\\w\0\\w)").match("a\0b c\0d")
|
|
213
304
|
|
|
214
305
|
expect(md.inspect).to eq("#<RE2::MatchData \"a\0b c\0d\" 1:\"a\0b\" 2:\"c\0d\">")
|
|
215
306
|
end
|
|
307
|
+
|
|
308
|
+
it "raises an error when called on an uninitialized object" do
|
|
309
|
+
expect { described_class.allocate.inspect }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
310
|
+
end
|
|
216
311
|
end
|
|
217
312
|
|
|
218
313
|
describe "#to_s" do
|
|
@@ -221,6 +316,16 @@ RSpec.describe RE2::MatchData do
|
|
|
221
316
|
|
|
222
317
|
expect(md.to_s).to eq("23456")
|
|
223
318
|
end
|
|
319
|
+
|
|
320
|
+
it "returns an empty string for a zero-length match" do
|
|
321
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
322
|
+
|
|
323
|
+
expect(md.to_s).to eq("")
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it "raises an error when called on an uninitialized object" do
|
|
327
|
+
expect { described_class.allocate.to_s }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
328
|
+
end
|
|
224
329
|
end
|
|
225
330
|
|
|
226
331
|
describe "#to_ary" do
|
|
@@ -265,6 +370,12 @@ RSpec.describe RE2::MatchData do
|
|
|
265
370
|
expect(md.string[md.begin(0)..-1]).to eq('Ruby')
|
|
266
371
|
end
|
|
267
372
|
|
|
373
|
+
it "returns the offset for a zero-length capturing group" do
|
|
374
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
375
|
+
|
|
376
|
+
expect(md.begin(1)).to eq(0)
|
|
377
|
+
end
|
|
378
|
+
|
|
268
379
|
it "returns nil for non-existent numerical matches" do
|
|
269
380
|
md = RE2::Regexp.new('(\d)').match('123')
|
|
270
381
|
|
|
@@ -301,6 +412,10 @@ RSpec.describe RE2::MatchData do
|
|
|
301
412
|
|
|
302
413
|
expect(md.string[md.begin(0)..-1]).to eq('woohoo' * 5)
|
|
303
414
|
end
|
|
415
|
+
|
|
416
|
+
it "raises an error when called on an uninitialized object" do
|
|
417
|
+
expect { described_class.allocate.begin(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
418
|
+
end
|
|
304
419
|
end
|
|
305
420
|
|
|
306
421
|
describe "#end" do
|
|
@@ -334,6 +449,12 @@ RSpec.describe RE2::MatchData do
|
|
|
334
449
|
expect(md.string[0...md.end(0)]).to eq('I ♥ Ruby')
|
|
335
450
|
end
|
|
336
451
|
|
|
452
|
+
it "returns the offset for a zero-length capturing group" do
|
|
453
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
454
|
+
|
|
455
|
+
expect(md.end(1)).to eq(0)
|
|
456
|
+
end
|
|
457
|
+
|
|
337
458
|
it "returns nil for non-existent numerical matches" do
|
|
338
459
|
md = RE2::Regexp.new('(\d)').match('123')
|
|
339
460
|
|
|
@@ -370,6 +491,268 @@ RSpec.describe RE2::MatchData do
|
|
|
370
491
|
|
|
371
492
|
expect(md.string[0...md.end(0)]).to eq('woo')
|
|
372
493
|
end
|
|
494
|
+
|
|
495
|
+
it "raises an error when called on an uninitialized object" do
|
|
496
|
+
expect { described_class.allocate.end(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
describe "#pre_match" do
|
|
501
|
+
it "returns the portion of the string before the match" do
|
|
502
|
+
md = RE2::Regexp.new('(\d+)').match("bob 123 456")
|
|
503
|
+
|
|
504
|
+
expect(md.pre_match).to eq("bob ")
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
it "returns an empty string when the match starts at the beginning" do
|
|
508
|
+
md = RE2::Regexp.new('(\w+)').match("bob 123")
|
|
509
|
+
|
|
510
|
+
expect(md.pre_match).to eq("")
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
it "supports multibyte characters" do
|
|
514
|
+
md = RE2::Regexp.new('(\d+)').match("I ♥ 123")
|
|
515
|
+
|
|
516
|
+
expect(md.pre_match).to eq("I ♥ ")
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
it "returns UTF-8 strings by default" do
|
|
520
|
+
md = RE2::Regexp.new('(\d+)').match("abc 123")
|
|
521
|
+
|
|
522
|
+
expect(md.pre_match.encoding).to eq(Encoding::UTF_8)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it "returns ISO-8859-1 strings if the pattern is not UTF-8" do
|
|
526
|
+
md = RE2::Regexp.new('(\d+)', utf8: false).match("abc 123")
|
|
527
|
+
|
|
528
|
+
expect(md.pre_match.encoding).to eq(Encoding::ISO_8859_1)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
it "returns the text before a zero-length match" do
|
|
532
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
533
|
+
|
|
534
|
+
expect(md.pre_match).to eq("")
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
it "raises an error when called on an uninitialized object" do
|
|
538
|
+
expect { described_class.allocate.pre_match }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
describe "#post_match" do
|
|
543
|
+
it "returns the portion of the string after the match" do
|
|
544
|
+
md = RE2::Regexp.new('(\d+)').match("bob 123 456")
|
|
545
|
+
|
|
546
|
+
expect(md.post_match).to eq(" 456")
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it "returns an empty string when the match ends at the end" do
|
|
550
|
+
md = RE2::Regexp.new('(\d+)$').match("bob 123")
|
|
551
|
+
|
|
552
|
+
expect(md.post_match).to eq("")
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it "supports multibyte characters" do
|
|
556
|
+
md = RE2::Regexp.new('(\d+)').match("123 ♥ world")
|
|
557
|
+
|
|
558
|
+
expect(md.post_match).to eq(" ♥ world")
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
it "returns UTF-8 strings by default" do
|
|
562
|
+
md = RE2::Regexp.new('(\d+)').match("abc 123 def")
|
|
563
|
+
|
|
564
|
+
expect(md.post_match.encoding).to eq(Encoding::UTF_8)
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
it "returns ISO-8859-1 strings if the pattern is not UTF-8" do
|
|
568
|
+
md = RE2::Regexp.new('(\d+)', utf8: false).match("abc 123 def")
|
|
569
|
+
|
|
570
|
+
expect(md.post_match.encoding).to eq(Encoding::ISO_8859_1)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
it "returns the text after a zero-length match" do
|
|
574
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
575
|
+
|
|
576
|
+
expect(md.post_match).to eq("bob")
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
it "raises an error when called on an uninitialized object" do
|
|
580
|
+
expect { described_class.allocate.post_match }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
describe "#offset" do
|
|
585
|
+
it "returns the offset of a match by index" do
|
|
586
|
+
md = RE2::Regexp.new('ob (\d+)').match("bob 123")
|
|
587
|
+
|
|
588
|
+
expect(md.offset(0)).to eq([1, 7])
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
it "returns the offset of a submatch by index" do
|
|
592
|
+
md = RE2::Regexp.new('ob (\d+)').match("bob 123")
|
|
593
|
+
|
|
594
|
+
expect(md.offset(1)).to eq([4, 7])
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
it "returns the offset of a match by string name" do
|
|
598
|
+
md = RE2::Regexp.new('(?P<number>\d+)').match("bob 123")
|
|
599
|
+
|
|
600
|
+
expect(md.offset("number")).to eq([4, 7])
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
it "returns the offset of a match by symbol name" do
|
|
604
|
+
md = RE2::Regexp.new('(?P<number>\d+)').match("bob 123")
|
|
605
|
+
|
|
606
|
+
expect(md.offset(:number)).to eq([4, 7])
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
it "returns character offsets despite multibyte characters" do
|
|
610
|
+
md = RE2::Regexp.new('(Ruby)').match("I ♥ Ruby")
|
|
611
|
+
|
|
612
|
+
expect(md.offset(0)).to eq([4, 8])
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
it "returns identical offsets for a zero-length capturing group" do
|
|
616
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
617
|
+
|
|
618
|
+
expect(md.offset(1)).to eq([0, 0])
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
it "returns nil for non-existent numerical matches" do
|
|
622
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
623
|
+
|
|
624
|
+
expect(md.offset(10)).to be_nil
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
it "returns nil for non-existent named matches" do
|
|
628
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
629
|
+
|
|
630
|
+
expect(md.offset("foo")).to be_nil
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
it "raises a type error if given an invalid name or number" do
|
|
634
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
635
|
+
|
|
636
|
+
expect { md.offset(nil) }.to raise_error(TypeError)
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
it "raises an error when called on an uninitialized object" do
|
|
640
|
+
expect { described_class.allocate.offset(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
describe "#match_length" do
|
|
645
|
+
it "returns the length of the overall match" do
|
|
646
|
+
md = RE2::Regexp.new('ob (\d+)').match("bob 123")
|
|
647
|
+
|
|
648
|
+
expect(md.match_length(0)).to eq(6)
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
it "returns the length of a submatch by index" do
|
|
652
|
+
md = RE2::Regexp.new('ob (\d+)').match("bob 123")
|
|
653
|
+
|
|
654
|
+
expect(md.match_length(1)).to eq(3)
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
it "returns the length of a match by string name" do
|
|
658
|
+
md = RE2::Regexp.new('(?P<number>\d+)').match("bob 123")
|
|
659
|
+
|
|
660
|
+
expect(md.match_length("number")).to eq(3)
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
it "returns the length of a match by symbol name" do
|
|
664
|
+
md = RE2::Regexp.new('(?P<number>\d+)').match("bob 123")
|
|
665
|
+
|
|
666
|
+
expect(md.match_length(:number)).to eq(3)
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
it "returns character length despite multibyte characters" do
|
|
670
|
+
md = RE2::Regexp.new('(♥ Ruby)').match("I ♥ Ruby!")
|
|
671
|
+
|
|
672
|
+
expect(md.match_length(0)).to eq(6)
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
it "returns zero for a zero-length capturing group" do
|
|
676
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
677
|
+
|
|
678
|
+
expect(md.match_length(1)).to eq(0)
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
it "returns nil for non-existent numerical matches" do
|
|
682
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
683
|
+
|
|
684
|
+
expect(md.match_length(10)).to be_nil
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
it "returns nil for non-existent named matches" do
|
|
688
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
689
|
+
|
|
690
|
+
expect(md.match_length("foo")).to be_nil
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
it "raises a type error if given an invalid name or number" do
|
|
694
|
+
md = RE2::Regexp.new('(\d)').match("123")
|
|
695
|
+
|
|
696
|
+
expect { md.match_length(nil) }.to raise_error(TypeError)
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
it "raises an error when called on an uninitialized object" do
|
|
700
|
+
expect { described_class.allocate.match_length(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
describe "#values_at" do
|
|
705
|
+
it "returns match values at the given indices" do
|
|
706
|
+
md = RE2::Regexp.new('(\d+) (\d+) (\d+)').match("123 456 789")
|
|
707
|
+
|
|
708
|
+
expect(md.values_at(1, 3)).to eq(["123", "789"])
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
it "returns match values by named groups" do
|
|
712
|
+
md = RE2::Regexp.new('(?P<a>\d+) (?P<b>\d+)').match("123 456")
|
|
713
|
+
|
|
714
|
+
expect(md.values_at(:a, :b)).to eq(["123", "456"])
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
it "supports a mix of indices and names" do
|
|
718
|
+
md = RE2::Regexp.new('(?P<a>\d+) (\d+)').match("123 456")
|
|
719
|
+
|
|
720
|
+
expect(md.values_at(2, :a)).to eq(["456", "123"])
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
it "returns nil for non-existent indices" do
|
|
724
|
+
md = RE2::Regexp.new('(\d+)').match("123")
|
|
725
|
+
|
|
726
|
+
expect(md.values_at(1, 5)).to eq(["123", nil])
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
it "returns nil for non-existent names" do
|
|
730
|
+
md = RE2::Regexp.new('(?P<a>\d+)').match("123")
|
|
731
|
+
|
|
732
|
+
expect(md.values_at(:a, :z)).to eq(["123", nil])
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
it "returns an empty string for a zero-length capturing group" do
|
|
736
|
+
md = RE2::Regexp.new('()(b)').match("bob")
|
|
737
|
+
|
|
738
|
+
expect(md.values_at(1, 2)).to eq(["", "b"])
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
it "returns the full match when given index 0" do
|
|
742
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("123 456")
|
|
743
|
+
|
|
744
|
+
expect(md.values_at(0, 1)).to eq(["123 456", "123"])
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
it "returns an empty array if given no arguments" do
|
|
748
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("123 456")
|
|
749
|
+
|
|
750
|
+
expect(md.values_at).to be_empty
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
it "raises an error when called on an uninitialized object" do
|
|
754
|
+
expect { described_class.allocate.values_at(1) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
755
|
+
end
|
|
373
756
|
end
|
|
374
757
|
|
|
375
758
|
describe "#deconstruct" do
|
|
@@ -384,6 +767,106 @@ RSpec.describe RE2::MatchData do
|
|
|
384
767
|
|
|
385
768
|
expect(md.deconstruct).to eq(['o', 'o', nil])
|
|
386
769
|
end
|
|
770
|
+
|
|
771
|
+
it "includes zero-length capturing groups as empty strings" do
|
|
772
|
+
md = RE2::Regexp.new('()').match("bob")
|
|
773
|
+
|
|
774
|
+
expect(md.deconstruct).to eq([""])
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
it "raises an error when called on an uninitialized object" do
|
|
778
|
+
expect { described_class.allocate.deconstruct }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
describe "#captures" do
|
|
783
|
+
it "returns all capturing groups" do
|
|
784
|
+
md = RE2::Regexp.new('w(o)(o)').match('woo')
|
|
785
|
+
|
|
786
|
+
expect(md.captures).to eq(['o', 'o'])
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
it "includes optional capturing groups as nil" do
|
|
790
|
+
md = RE2::Regexp.new('w(.)(.)(.)?').match('woo')
|
|
791
|
+
|
|
792
|
+
expect(md.captures).to eq(['o', 'o', nil])
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
it "raises an error when called on an uninitialized object" do
|
|
796
|
+
expect { described_class.allocate.captures }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
describe "#named_captures" do
|
|
801
|
+
it "returns a hash of capturing group names to matched strings" do
|
|
802
|
+
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
803
|
+
|
|
804
|
+
expect(md.named_captures).to eq("numbers" => "123", "letters" => "abc")
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
it "returns an empty hash if there are no named capturing groups" do
|
|
808
|
+
md = RE2::Regexp.new('(\d+)').match('123')
|
|
809
|
+
|
|
810
|
+
expect(md.named_captures).to be_empty
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
it "returns unmatched optional groups as nil" do
|
|
814
|
+
md = RE2::Regexp.new('(?P<a>\d+) (?P<b>\w+)?').match('123 ')
|
|
815
|
+
|
|
816
|
+
expect(md.named_captures).to eq("a" => "123", "b" => nil)
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
it "returns an empty string for a zero-length named capturing group" do
|
|
820
|
+
md = RE2::Regexp.new('(?P<empty>)(?P<word>\w+)').match("bob")
|
|
821
|
+
|
|
822
|
+
expect(md.named_captures).to eq("empty" => "", "word" => "bob")
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
it "returns symbol keys when symbolize_names: true" do
|
|
826
|
+
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
827
|
+
|
|
828
|
+
expect(md.named_captures(symbolize_names: true)).to eq(numbers: "123", letters: "abc")
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
it "returns string keys when symbolize_names: false" do
|
|
832
|
+
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
833
|
+
|
|
834
|
+
expect(md.named_captures(symbolize_names: false)).to eq("numbers" => "123", "letters" => "abc")
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
it "raises an error when called on an uninitialized object" do
|
|
838
|
+
expect { described_class.allocate.named_captures }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
describe "#names" do
|
|
843
|
+
it "returns an array of names of named capturing groups" do
|
|
844
|
+
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
845
|
+
|
|
846
|
+
expect(md.names).to eq(["letters", "numbers"])
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
it "returns an empty array if there are no named capturing groups" do
|
|
850
|
+
md = RE2::Regexp.new('(\d+)').match('123')
|
|
851
|
+
|
|
852
|
+
expect(md.names).to be_empty
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
it "returns UTF-8 strings if the pattern is UTF-8" do
|
|
856
|
+
md = RE2::Regexp.new('(?P<numbers>\d+)').match('123')
|
|
857
|
+
|
|
858
|
+
expect(md.names.first.encoding).to eq(Encoding::UTF_8)
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
it "returns ISO-8859-1 strings if the pattern is not UTF-8" do
|
|
862
|
+
md = RE2::Regexp.new('(?P<numbers>\d+)', utf8: false).match('123')
|
|
863
|
+
|
|
864
|
+
expect(md.names.first.encoding).to eq(Encoding::ISO_8859_1)
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
it "raises an error when called on an uninitialized object" do
|
|
868
|
+
expect { described_class.allocate.names }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
869
|
+
end
|
|
387
870
|
end
|
|
388
871
|
|
|
389
872
|
describe "#deconstruct_keys" do
|
|
@@ -417,6 +900,12 @@ RSpec.describe RE2::MatchData do
|
|
|
417
900
|
expect(md.deconstruct_keys(nil)).to eq({})
|
|
418
901
|
end
|
|
419
902
|
|
|
903
|
+
it "returns an empty string for a zero-length named capturing group" do
|
|
904
|
+
md = RE2::Regexp.new('(?P<empty>)(?P<word>\w+)').match("bob")
|
|
905
|
+
|
|
906
|
+
expect(md.deconstruct_keys(nil)).to eq(empty: "", word: "bob")
|
|
907
|
+
end
|
|
908
|
+
|
|
420
909
|
it "raises an error if given a non-array of keys" do
|
|
421
910
|
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
422
911
|
|
|
@@ -428,5 +917,9 @@ RSpec.describe RE2::MatchData do
|
|
|
428
917
|
|
|
429
918
|
expect { md.deconstruct_keys([0]) }.to raise_error(TypeError)
|
|
430
919
|
end
|
|
920
|
+
|
|
921
|
+
it "raises an error when called on an uninitialized object" do
|
|
922
|
+
expect { described_class.allocate.deconstruct_keys(nil) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
923
|
+
end
|
|
431
924
|
end
|
|
432
925
|
end
|