re2 2.27.0-x86_64-linux-gnu → 2.29.0-x86_64-linux-gnu
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 +5 -0
- data/README.md +11 -1
- data/ext/re2/extconf.rb +2 -26
- data/ext/re2/re2.cc +175 -75
- 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/4.0/re2.so +0 -0
- data/lib/re2/match_data.rb +47 -0
- data/lib/re2/regexp.rb +43 -0
- data/lib/re2/version.rb +1 -1
- data/lib/re2.rb +1 -0
- data/re2.gemspec +2 -1
- data/spec/re2/match_data_spec.rb +283 -2
- data/spec/re2/regexp_spec.rb +175 -26
- data/spec/re2/scanner_spec.rb +9 -0
- data/spec/re2/set_spec.rb +31 -0
- metadata +5 -4
data/lib/re2/regexp.rb
CHANGED
|
@@ -68,5 +68,48 @@ module RE2
|
|
|
68
68
|
def full_match(text, options = {})
|
|
69
69
|
match(text, Hash(options).merge(anchor: :anchor_both))
|
|
70
70
|
end
|
|
71
|
+
|
|
72
|
+
# Match the pattern against any substring of the given `text`, returning
|
|
73
|
+
# `false` if it is not a `String`, `Symbol`, or object responding to
|
|
74
|
+
# `to_str` so that an {RE2::Regexp} can be used in a `case` statement like
|
|
75
|
+
# Ruby's own `Regexp#===`.
|
|
76
|
+
#
|
|
77
|
+
# @param [Object] text the text to search; anything other than a `String`,
|
|
78
|
+
# `Symbol`, or object responding to `to_str` returns `false`
|
|
79
|
+
# @return [Boolean] whether the match was successful
|
|
80
|
+
# @example
|
|
81
|
+
# case "bob 123"
|
|
82
|
+
# when RE2::Regexp.new('\d+')
|
|
83
|
+
# "numbers"
|
|
84
|
+
# end
|
|
85
|
+
def ===(text)
|
|
86
|
+
text = text.to_s if text.is_a?(Symbol)
|
|
87
|
+
text = ::String.try_convert(text)
|
|
88
|
+
return false unless text
|
|
89
|
+
|
|
90
|
+
match?(text)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Return whether this regular expression has the same pattern and options
|
|
94
|
+
# as another {RE2::Regexp}.
|
|
95
|
+
#
|
|
96
|
+
# @param [Object] other the object to compare against
|
|
97
|
+
# @return [Boolean] whether the two regular expressions are equal
|
|
98
|
+
# @example
|
|
99
|
+
# RE2::Regexp.new('abc') == RE2::Regexp.new('abc') #=> true
|
|
100
|
+
# RE2::Regexp.new('abc') == RE2::Regexp.new('abc', case_sensitive: false) #=> false
|
|
101
|
+
def ==(other)
|
|
102
|
+
other.is_a?(RE2::Regexp) && source == other.source && options == other.options
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
alias_method :eql?, :==
|
|
106
|
+
|
|
107
|
+
# Return a hash based on the pattern and options so that equal
|
|
108
|
+
# {RE2::Regexp}s can be used as Hash keys.
|
|
109
|
+
#
|
|
110
|
+
# @return [Integer] the hash of the regular expression
|
|
111
|
+
def hash
|
|
112
|
+
[source, options].hash
|
|
113
|
+
end
|
|
71
114
|
end
|
|
72
115
|
end
|
data/lib/re2/version.rb
CHANGED
data/lib/re2.rb
CHANGED
data/re2.gemspec
CHANGED
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
|
20
20
|
"Gemfile",
|
|
21
21
|
"lib/re2.rb",
|
|
22
22
|
"lib/re2/regexp.rb",
|
|
23
|
+
"lib/re2/match_data.rb",
|
|
23
24
|
"lib/re2/scanner.rb",
|
|
24
25
|
"lib/re2/string.rb",
|
|
25
26
|
"lib/re2/version.rb",
|
|
@@ -41,7 +42,7 @@ Gem::Specification.new do |s|
|
|
|
41
42
|
"spec/re2/scanner_spec.rb"
|
|
42
43
|
]
|
|
43
44
|
s.add_development_dependency("rake-compiler", "~> 1.3.1")
|
|
44
|
-
s.add_development_dependency("rake-compiler-dock", "~> 1.
|
|
45
|
+
s.add_development_dependency("rake-compiler-dock", "~> 1.12.0")
|
|
45
46
|
s.add_development_dependency("rspec", "~> 3.2")
|
|
46
47
|
s.add_runtime_dependency("mini_portile2", "~> 2.8.9") # keep version in sync with extconf.rb
|
|
47
48
|
end
|
data/spec/re2/match_data_spec.rb
CHANGED
|
@@ -59,6 +59,15 @@ RSpec.describe RE2::MatchData do
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
describe "#initialize_copy" do
|
|
63
|
+
it "is a no-op when the source is the same object" do
|
|
64
|
+
md = RE2::Regexp.new('(\d+)').match("123")
|
|
65
|
+
md.send(:initialize_copy, md)
|
|
66
|
+
|
|
67
|
+
expect(md.to_a).to eq(["123", "123"])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
62
71
|
describe "#to_a" do
|
|
63
72
|
it "is populated with the match and capturing groups" do
|
|
64
73
|
a = RE2::Regexp.new('w(o)(o)').match('woo').to_a
|
|
@@ -154,6 +163,24 @@ RSpec.describe RE2::MatchData do
|
|
|
154
163
|
expect(md[:numbers]).to eq("123")
|
|
155
164
|
end
|
|
156
165
|
|
|
166
|
+
it "allows access using a UTF-8 name and a UTF-8 pattern" do
|
|
167
|
+
re = RE2::Regexp.new('(?P<café>\d+)', log_errors: false)
|
|
168
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
169
|
+
|
|
170
|
+
md = re.match('bob 123')
|
|
171
|
+
|
|
172
|
+
expect(md[:café]).to eq("123")
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "allows access using a Latin-1 name and a Latin-1 pattern" do
|
|
176
|
+
re = RE2::Regexp.new('(?P<café>\d+)'.encode("ISO-8859-1"), utf8: false, log_errors: false)
|
|
177
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
178
|
+
|
|
179
|
+
md = re.match('bob 123')
|
|
180
|
+
|
|
181
|
+
expect(md["café".encode("ISO-8859-1")]).to eq("123")
|
|
182
|
+
end
|
|
183
|
+
|
|
157
184
|
it "allows access by names and indices with mixed groups", :aggregate_failures do
|
|
158
185
|
md = RE2::Regexp.new('(?P<name>\w+)(\s*)(?P<numbers>\d+)').match("bob 123")
|
|
159
186
|
|
|
@@ -199,6 +226,12 @@ RSpec.describe RE2::MatchData do
|
|
|
199
226
|
expect(md[:name].encoding.name).to eq("ISO-8859-1")
|
|
200
227
|
end
|
|
201
228
|
|
|
229
|
+
it "handles null bytes in symbol names" do
|
|
230
|
+
md = RE2::Regexp.new('(?P<name>\S+)').match("bob")
|
|
231
|
+
|
|
232
|
+
expect(md[:"name\0b"]).to be_nil
|
|
233
|
+
end
|
|
234
|
+
|
|
202
235
|
it "supports GC compaction" do
|
|
203
236
|
md = RE2::Regexp.new('(wo{2})').match('woohoo' * 5)
|
|
204
237
|
GC.compact
|
|
@@ -358,6 +391,24 @@ RSpec.describe RE2::MatchData do
|
|
|
358
391
|
expect(md.string[md.begin(:foo)..-1]).to eq('foobar')
|
|
359
392
|
end
|
|
360
393
|
|
|
394
|
+
it "returns the offset of the start of a match by non-ASCII symbol name" do
|
|
395
|
+
re = RE2::Regexp.new('(?P<café>fo{2})', log_errors: false)
|
|
396
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
397
|
+
|
|
398
|
+
md = re.match('a foobar')
|
|
399
|
+
|
|
400
|
+
expect(md.string[md.begin(:café)..-1]).to eq('foobar')
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
it "returns the offset of the start of a match by Latin-1 string name" do
|
|
404
|
+
re = RE2::Regexp.new('(?P<café>fo{2})'.encode("ISO-8859-1"), utf8: false, log_errors: false)
|
|
405
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
406
|
+
|
|
407
|
+
md = re.match('a foobar')
|
|
408
|
+
|
|
409
|
+
expect(md.string[md.begin("café".encode("ISO-8859-1"))..-1]).to eq('foobar')
|
|
410
|
+
end
|
|
411
|
+
|
|
361
412
|
it "returns the offset of the start of a match by something that can be coerced to a String" do
|
|
362
413
|
md = RE2::Regexp.new('(?P<foo>fo{2})').match('a foobar')
|
|
363
414
|
|
|
@@ -581,6 +632,108 @@ RSpec.describe RE2::MatchData do
|
|
|
581
632
|
end
|
|
582
633
|
end
|
|
583
634
|
|
|
635
|
+
describe "#bytebegin" do
|
|
636
|
+
it "returns the byte offset of the start of a match by index" do
|
|
637
|
+
md = RE2::Regexp.new('(Ruby)').match("I ♥ Ruby")
|
|
638
|
+
|
|
639
|
+
expect(md.bytebegin(0)).to eq(6)
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
it "returns the byte offset of the start of a submatch by string name" do
|
|
643
|
+
md = RE2::Regexp.new('(?P<word>Ruby)').match("I ♥ Ruby")
|
|
644
|
+
|
|
645
|
+
expect(md.bytebegin("word")).to eq(6)
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
it "returns the byte offset of the start of a submatch by symbol name" do
|
|
649
|
+
md = RE2::Regexp.new('(?P<word>Ruby)').match("I ♥ Ruby")
|
|
650
|
+
|
|
651
|
+
expect(md.bytebegin(:word)).to eq(6)
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
it "returns nil for an unmatched submatch" do
|
|
655
|
+
md = RE2::Regexp.new('a(b)?').match("ac")
|
|
656
|
+
|
|
657
|
+
expect(md.bytebegin(1)).to be_nil
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
it "returns nil for a nonexistent submatch" do
|
|
661
|
+
md = RE2::Regexp.new('(a)').match("a")
|
|
662
|
+
|
|
663
|
+
expect(md.bytebegin(5)).to be_nil
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
it "raises an error when called on an uninitialized object" do
|
|
667
|
+
expect { described_class.allocate.bytebegin(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
describe "#byteend" do
|
|
672
|
+
it "returns the byte offset after the end of a match by index" do
|
|
673
|
+
md = RE2::Regexp.new('(Ruby)').match("I ♥ Ruby")
|
|
674
|
+
|
|
675
|
+
expect(md.byteend(0)).to eq(10)
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
it "returns the byte offset after the end of a submatch by string name" do
|
|
679
|
+
md = RE2::Regexp.new('(?P<heart>♥)').match("I ♥ Ruby")
|
|
680
|
+
|
|
681
|
+
expect(md.byteend("heart")).to eq(5)
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
it "returns the byte offset after the end of a submatch by symbol name" do
|
|
685
|
+
md = RE2::Regexp.new('(?P<heart>♥)').match("I ♥ Ruby")
|
|
686
|
+
|
|
687
|
+
expect(md.byteend(:heart)).to eq(5)
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
it "returns nil for an unmatched submatch" do
|
|
691
|
+
md = RE2::Regexp.new('a(b)?').match("ac")
|
|
692
|
+
|
|
693
|
+
expect(md.byteend(1)).to be_nil
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
it "raises an error when called on an uninitialized object" do
|
|
697
|
+
expect { described_class.allocate.byteend(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
describe "#byteoffset" do
|
|
702
|
+
it "returns the byte offsets of a match by index" do
|
|
703
|
+
md = RE2::Regexp.new('(Ruby)').match("I ♥ Ruby")
|
|
704
|
+
|
|
705
|
+
expect(md.byteoffset(0)).to eq([6, 10])
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
it "returns the byte offsets of a submatch by string name" do
|
|
709
|
+
md = RE2::Regexp.new('(?P<heart>♥)').match("I ♥ Ruby")
|
|
710
|
+
|
|
711
|
+
expect(md.byteoffset("heart")).to eq([2, 5])
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
it "returns the byte offsets of a submatch by symbol name" do
|
|
715
|
+
md = RE2::Regexp.new('(?P<heart>♥)').match("I ♥ Ruby")
|
|
716
|
+
|
|
717
|
+
expect(md.byteoffset(:heart)).to eq([2, 5])
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
it "can be used to slice the original string by bytes" do
|
|
721
|
+
md = RE2::Regexp.new('(Ruby)').match("I ♥ Ruby")
|
|
722
|
+
|
|
723
|
+
expect(md.string.byteslice(*md.byteoffset(1))).to eq("Ruby")
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
it "returns nil for an unmatched submatch" do
|
|
727
|
+
md = RE2::Regexp.new('a(b)?').match("ac")
|
|
728
|
+
|
|
729
|
+
expect(md.byteoffset(1)).to be_nil
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
it "raises an error when called on an uninitialized object" do
|
|
733
|
+
expect { described_class.allocate.byteoffset(0) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
|
|
584
737
|
describe "#offset" do
|
|
585
738
|
it "returns the offset of a match by index" do
|
|
586
739
|
md = RE2::Regexp.new('ob (\d+)').match("bob 123")
|
|
@@ -822,12 +975,33 @@ RSpec.describe RE2::MatchData do
|
|
|
822
975
|
expect(md.named_captures).to eq("empty" => "", "word" => "bob")
|
|
823
976
|
end
|
|
824
977
|
|
|
978
|
+
it "returns UTF-8 names even for Latin-1 patterns" do
|
|
979
|
+
md = RE2::Regexp.new('(?P<numbers>\d+)', utf8: false).match('123')
|
|
980
|
+
key = md.named_captures.keys.first
|
|
981
|
+
|
|
982
|
+
expect(key.encoding).to eq(Encoding::UTF_8)
|
|
983
|
+
end
|
|
984
|
+
|
|
825
985
|
it "returns symbol keys when symbolize_names: true" do
|
|
826
986
|
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
827
987
|
|
|
828
988
|
expect(md.named_captures(symbolize_names: true)).to eq(numbers: "123", letters: "abc")
|
|
829
989
|
end
|
|
830
990
|
|
|
991
|
+
it "returns garbage-collectable symbol keys when symbolize_names: true" do
|
|
992
|
+
md = RE2::Regexp.new('(?P<collectable_named_capture>\d+)').match('123')
|
|
993
|
+
key = md.named_captures(symbolize_names: true).keys.first
|
|
994
|
+
|
|
995
|
+
expect(ObjectSpace.each_object(Symbol)).to include(key)
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
it "correctly encodes non-ASCII capturing group names as symbols" do
|
|
999
|
+
re = RE2::Regexp.new('(?P<café>\d+)', log_errors: false)
|
|
1000
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
1001
|
+
|
|
1002
|
+
expect(re.match('123').named_captures(symbolize_names: true)).to eq(café: "123")
|
|
1003
|
+
end
|
|
1004
|
+
|
|
831
1005
|
it "returns string keys when symbolize_names: false" do
|
|
832
1006
|
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
833
1007
|
|
|
@@ -858,10 +1032,10 @@ RSpec.describe RE2::MatchData do
|
|
|
858
1032
|
expect(md.names.first.encoding).to eq(Encoding::UTF_8)
|
|
859
1033
|
end
|
|
860
1034
|
|
|
861
|
-
it "returns
|
|
1035
|
+
it "returns UTF-8 strings if the pattern is not UTF-8" do
|
|
862
1036
|
md = RE2::Regexp.new('(?P<numbers>\d+)', utf8: false).match('123')
|
|
863
1037
|
|
|
864
|
-
expect(md.names.first.encoding).to eq(Encoding::
|
|
1038
|
+
expect(md.names.first.encoding).to eq(Encoding::UTF_8)
|
|
865
1039
|
end
|
|
866
1040
|
|
|
867
1041
|
it "raises an error when called on an uninitialized object" do
|
|
@@ -876,6 +1050,22 @@ RSpec.describe RE2::MatchData do
|
|
|
876
1050
|
expect(md.deconstruct_keys(nil)).to eq(numbers: '123', letters: 'abc')
|
|
877
1051
|
end
|
|
878
1052
|
|
|
1053
|
+
it "returns garbage-collectable symbol keys if given nil" do
|
|
1054
|
+
md = RE2::Regexp.new('(?P<collectable_deconstructed_key>\d+)').match('123')
|
|
1055
|
+
key = md.deconstruct_keys(nil).keys.first
|
|
1056
|
+
|
|
1057
|
+
expect(ObjectSpace.each_object(Symbol)).to include(key)
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
it "returns UTF-8 named captures for a Latin-1 pattern if given nil" do
|
|
1061
|
+
re = RE2::Regexp.new('(?P<café>\d+) (?P<letters>[a-zA-Z]+)'.encode("ISO-8859-1"), utf8: false, log_errors: false)
|
|
1062
|
+
skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
|
|
1063
|
+
|
|
1064
|
+
md = re.match('123 abc')
|
|
1065
|
+
|
|
1066
|
+
expect(md.deconstruct_keys(nil)).to eq(café: '123', letters: 'abc')
|
|
1067
|
+
end
|
|
1068
|
+
|
|
879
1069
|
it "returns only named captures if given names" do
|
|
880
1070
|
md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
|
|
881
1071
|
|
|
@@ -922,4 +1112,95 @@ RSpec.describe RE2::MatchData do
|
|
|
922
1112
|
expect { described_class.allocate.deconstruct_keys(nil) }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
923
1113
|
end
|
|
924
1114
|
end
|
|
1115
|
+
|
|
1116
|
+
describe "#==" do
|
|
1117
|
+
it "returns true for matches with the same regexp, text, and offsets" do
|
|
1118
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1119
|
+
|
|
1120
|
+
expect(re.match("abc 123")).to eq(re.match("abc 123"))
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
it "returns true for matches against equal but distinct regexps" do
|
|
1124
|
+
md = RE2::Regexp.new('(\d+)').match("abc 123")
|
|
1125
|
+
|
|
1126
|
+
expect(md).to eq(RE2::Regexp.new('(\d+)').match("abc 123"))
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
it "returns true for matches against a copy of the text" do
|
|
1130
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1131
|
+
|
|
1132
|
+
expect(re.match("abc 123")).to eq(re.match("abc 123".dup))
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
it "returns true for matches with unmatched optional groups" do
|
|
1136
|
+
re = RE2::Regexp.new('a(b)?')
|
|
1137
|
+
|
|
1138
|
+
expect(re.match("ac")).to eq(re.match("ac"))
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
it "returns false for matches against different text" do
|
|
1142
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1143
|
+
|
|
1144
|
+
expect(re.match("abc 123")).not_to eq(re.match("abc 456"))
|
|
1145
|
+
end
|
|
1146
|
+
|
|
1147
|
+
it "returns false for the same captures at different offsets" do
|
|
1148
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1149
|
+
|
|
1150
|
+
expect(re.match("123 abc")).not_to eq(re.match("abc 123"))
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
it "returns false for matches against regexps with different options" do
|
|
1154
|
+
md = RE2::Regexp.new('(abc)').match("abc")
|
|
1155
|
+
|
|
1156
|
+
expect(md).not_to eq(RE2::Regexp.new('(abc)', case_sensitive: false).match("abc"))
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
it "returns false for matches with a different number of submatches" do
|
|
1160
|
+
re = RE2::Regexp.new('(a)(b)')
|
|
1161
|
+
|
|
1162
|
+
expect(re.match("ab")).not_to eq(re.match("ab", submatches: 1))
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
it "returns false for a non-MatchData" do
|
|
1166
|
+
expect(RE2::Regexp.new('(a)').match("a")).not_to eq("a")
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
it "is aliased to eql?" do
|
|
1170
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1171
|
+
|
|
1172
|
+
expect(re.match("abc 123")).to eql(re.match("abc 123"))
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
it "raises an error when called on an uninitialized object" do
|
|
1176
|
+
expect { described_class.allocate == RE2::Regexp.new('(a)').match("a") }.to raise_error(TypeError, /uninitialized RE2::MatchData/)
|
|
1177
|
+
end
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
describe "#hash" do
|
|
1181
|
+
it "is the same for equal matches" do
|
|
1182
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1183
|
+
|
|
1184
|
+
expect(re.match("abc 123").hash).to eq(re.match("abc 123").hash)
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
it "differs for matches at different offsets" do
|
|
1188
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1189
|
+
|
|
1190
|
+
expect(re.match("123 abc").hash).not_to eq(re.match("abc 123").hash)
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
it "allows matches to be used as Hash keys" do
|
|
1194
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1195
|
+
hash = { re.match("abc 123") => :found }
|
|
1196
|
+
|
|
1197
|
+
expect(hash[re.match("abc 123")]).to eq(:found)
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
it "allows matches to be deduplicated" do
|
|
1201
|
+
re = RE2::Regexp.new('(\d+)')
|
|
1202
|
+
|
|
1203
|
+
expect([re.match("abc 123"), re.match("abc 123")].uniq.size).to eq(1)
|
|
1204
|
+
end
|
|
1205
|
+
end
|
|
925
1206
|
end
|