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.
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.Replace} instead.
16
+ # @deprecated Use {RE2.replace} instead.
17
17
  def re2_sub(*args)
18
- RE2.Replace(self, *args)
18
+ RE2.replace(self, *args)
19
19
  end
20
20
 
21
- # @deprecated Use {RE2.GlobalReplace} instead.
21
+ # @deprecated Use {RE2.global_replace} instead.
22
22
  def re2_gsub(*args)
23
- RE2.GlobalReplace(self, *args)
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.QuoteMeta} instead.
31
+ # @deprecated Use {RE2.escape} instead.
32
32
  def re2_escape
33
- RE2.QuoteMeta(self)
33
+ RE2.escape(self)
34
34
  end
35
35
 
36
36
  alias_method :re2_quote, :re2_escape
data/lib/re2/version.rb CHANGED
@@ -10,5 +10,5 @@
10
10
 
11
11
 
12
12
  module RE2
13
- VERSION = "2.23.0"
13
+ VERSION = "2.27.0"
14
14
  end
Binary file
@@ -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 nil if they are missing" do
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", nil, "a", "b"])
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