re2 0.3.0 → 0.4.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/README.md +71 -27
- data/Rakefile +6 -14
- data/ext/re2/extconf.rb +1 -1
- data/ext/re2/re2.cc +69 -51
- data/lib/re2/string.rb +100 -0
- data/spec/kernel_spec.rb +15 -0
- data/spec/re2/match_data_spec.rb +141 -0
- data/spec/re2/regexp_spec.rb +394 -0
- data/spec/re2/string_spec.rb +47 -0
- data/spec/re2_spec.rb +84 -0
- data/spec/spec_helper.rb +3 -0
- metadata +28 -6
- data/test/re2_test.rb +0 -265
data/lib/re2/string.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# re2 (http://github.com/mudge/re2)
|
2
|
+
# Ruby bindings to re2, an "efficient, principled regular expression library"
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010-2012, Paul Mucur (http://mudge.name)
|
5
|
+
# Released under the BSD Licence, please see LICENSE.txt
|
6
|
+
|
7
|
+
require "re2"
|
8
|
+
|
9
|
+
module RE2
|
10
|
+
module String
|
11
|
+
|
12
|
+
# Replaces the first occurrence +pattern+ with +rewrite+ <i>in place</i>.
|
13
|
+
#
|
14
|
+
# @param [String, RE2::Regexp] pattern a regexp matching text to be replaced
|
15
|
+
# @param [String] rewrite the string to replace with
|
16
|
+
# @example
|
17
|
+
# "hello there".re2_sub("hello", "howdy") #=> "howdy there"
|
18
|
+
# re2 = RE2.new("hel+o")
|
19
|
+
# "hello there".re2_sub(re2, "yo") #=> "yo there"
|
20
|
+
# text = "Good morning"
|
21
|
+
# text.re2_sub("morn", "even") #=> "Good evening"
|
22
|
+
# text #=> "Good evening"
|
23
|
+
def re2_sub(*args)
|
24
|
+
RE2.Replace(self, *args)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Replaces every occurrence of +pattern+ with +rewrite+ <i>in place</i>.
|
28
|
+
#
|
29
|
+
# @param [String, RE2::Regexp] pattern a regexp matching text to be replaced
|
30
|
+
# @param [String] rewrite the string to replace with
|
31
|
+
# @example
|
32
|
+
# "hello there".re2_gsub("e", "i") #=> "hillo thiri"
|
33
|
+
# re2 = RE2.new("oo?")
|
34
|
+
# "whoops-doops".re2_gsub(re2, "e") #=> "wheps-deps"
|
35
|
+
# text = "Good morning"
|
36
|
+
# text.re2_gsub("o", "ee") #=> "Geeeed meerning"
|
37
|
+
# text #=> "Geeeed meerning"
|
38
|
+
def re2_gsub(*args)
|
39
|
+
RE2.GlobalReplace(self, *args)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Match the pattern and return either a boolean (if no submatches are required)
|
43
|
+
# or a {RE2::MatchData} instance.
|
44
|
+
#
|
45
|
+
# @return [Boolean, RE2::MatchData]
|
46
|
+
#
|
47
|
+
# @overload match(pattern)
|
48
|
+
# Returns an {RE2::MatchData} containing the matching
|
49
|
+
# pattern and all subpatterns resulting from looking for
|
50
|
+
# +pattern+.
|
51
|
+
#
|
52
|
+
# @param [String, RE2::Regexp] pattern the regular expression to match
|
53
|
+
# @return [RE2::MatchData] the matches
|
54
|
+
# @raise [NoMemoryError] if there was not enough memory to allocate the matches
|
55
|
+
# @example
|
56
|
+
# r = RE2::Regexp.new('w(o)(o)')
|
57
|
+
# "woo".re2_match(r) #=> #<RE2::MatchData "woo" 1:"o" 2:"o">
|
58
|
+
#
|
59
|
+
# @overload match(pattern, 0)
|
60
|
+
# Returns either true or false indicating whether a
|
61
|
+
# successful match was made.
|
62
|
+
#
|
63
|
+
# @param [String, RE2::Regexp] pattern the regular expression to match
|
64
|
+
# @return [Boolean] whether the match was successful
|
65
|
+
# @raise [NoMemoryError] if there was not enough memory to allocate the matches
|
66
|
+
# @example
|
67
|
+
# r = RE2::Regexp.new('w(o)(o)')
|
68
|
+
# "woo".re2_match(0) #=> true
|
69
|
+
# "bob".re2_match(0) #=> false
|
70
|
+
#
|
71
|
+
# @overload match(pattern, number_of_matches)
|
72
|
+
# See +match(pattern)+ but with a specific number of
|
73
|
+
# matches returned (padded with nils if necessary).
|
74
|
+
#
|
75
|
+
# @param [String, RE2::Regexp] pattern the regular expression to match
|
76
|
+
# @param [Fixnum] number_of_matches the number of matches to return
|
77
|
+
# @return [RE2::MatchData] the matches
|
78
|
+
# @raise [NoMemoryError] if there was not enough memory to allocate the matches
|
79
|
+
# @example
|
80
|
+
# r = RE2::Regexp.new('w(o)(o)')
|
81
|
+
# "woo".re2_match(r, 1) #=> #<RE2::MatchData "woo" 1:"o">
|
82
|
+
# "woo".re2_match(r, 3) #=> #<RE2::MatchData "woo" 1:"o" 2:"o" 3:nil>
|
83
|
+
def re2_match(pattern, *args)
|
84
|
+
RE2::Regexp.new(pattern).match(self, *args)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Escapes all potentially meaningful regexp characters.
|
88
|
+
# The returned string, used as a regular expression, will exactly match the
|
89
|
+
# original string.
|
90
|
+
#
|
91
|
+
# @return [String] the escaped string
|
92
|
+
# @example
|
93
|
+
# "1.5-2.0?".escape #=> "1\.5\-2\.0\?"
|
94
|
+
def re2_escape
|
95
|
+
RE2.QuoteMeta(self)
|
96
|
+
end
|
97
|
+
|
98
|
+
alias_method :re2_quote, :re2_escape
|
99
|
+
end
|
100
|
+
end
|
data/spec/kernel_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Kernel do
|
4
|
+
describe "#RE2" do
|
5
|
+
it "returns an RE2::Regexp instance given a pattern" do
|
6
|
+
RE2('w(o)(o)').must_be_instance_of(RE2::Regexp)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns an RE2::Regexp instance given a pattern and options" do
|
10
|
+
re = RE2('w(o)(o)', :case_sensitive => false)
|
11
|
+
re.must_be_instance_of(RE2::Regexp)
|
12
|
+
re.wont_be(:case_sensitive?)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RE2::MatchData do
|
4
|
+
|
5
|
+
describe "#to_a" do
|
6
|
+
it "is populated with the match and capturing groups" do
|
7
|
+
a = RE2::Regexp.new('w(o)(o)').match('woo').to_a
|
8
|
+
a.must_equal(["woo", "o", "o"])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "populates optional capturing groups with nil if they are missing" do
|
12
|
+
a = RE2::Regexp.new('(\d?)(a)(b)').match('ab').to_a
|
13
|
+
a.must_equal(["ab", nil, "a", "b"])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#[]" do
|
18
|
+
it "accesses capturing groups by numerical index" do
|
19
|
+
md = RE2::Regexp.new('(\d)(\d{2})').match("123")
|
20
|
+
md[1].must_equal("1")
|
21
|
+
md[2].must_equal("23")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "has the whole match as the 0th item" do
|
25
|
+
md = RE2::Regexp.new('(\d)(\d{2})').match("123")
|
26
|
+
md[0].must_equal("123")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "supports access by numerical ranges" do
|
30
|
+
md = RE2::Regexp.new('(\d+) (\d+) (\d+)').match("123 456 789")
|
31
|
+
md[1..3].must_equal(["123", "456", "789"])
|
32
|
+
md[1...3].must_equal(["123", "456"])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "supports slicing" do
|
36
|
+
md = RE2::Regexp.new('(\d+) (\d+) (\d+)').match("123 456 789")
|
37
|
+
md[1, 3].must_equal(["123", "456", "789"])
|
38
|
+
md[1, 2].must_equal(["123", "456"])
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil if attempting to access non-existent capturing groups by index" do
|
42
|
+
md = RE2::Regexp.new('(\d+)').match('bob 123')
|
43
|
+
md[2].must_be_nil
|
44
|
+
md[3].must_be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "allows access by string names when there are named groups" do
|
48
|
+
md = RE2::Regexp.new('(?P<numbers>\d+)').match('bob 123')
|
49
|
+
md["numbers"].must_equal("123")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "allows access by symbol names when there are named groups" do
|
53
|
+
md = RE2::Regexp.new('(?P<numbers>\d+)').match('bob 123')
|
54
|
+
md[:numbers].must_equal("123")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "allows access by names and indices with mixed groups" do
|
58
|
+
md = RE2::Regexp.new('(?P<name>\w+)(\s*)(?P<numbers>\d+)').match("bob 123")
|
59
|
+
md["name"].must_equal("bob")
|
60
|
+
md[:name].must_equal("bob")
|
61
|
+
md[2].must_equal(" ")
|
62
|
+
md["numbers"].must_equal("123")
|
63
|
+
md[:numbers].must_equal("123")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns nil if no such named group exists" do
|
67
|
+
md = RE2::Regexp.new('(\d+)').match("bob 123")
|
68
|
+
md["missing"].must_be_nil
|
69
|
+
md[:missing].must_be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#string" do
|
74
|
+
it "returns the original string to match against" do
|
75
|
+
re = RE2::Regexp.new('(\D+)').match("bob")
|
76
|
+
re.string.must_equal("bob")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns a copy, not the actual original" do
|
80
|
+
string = "bob"
|
81
|
+
re = RE2::Regexp.new('(\D+)').match(string)
|
82
|
+
re.string.wont_be_same_as(string)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns a frozen string" do
|
86
|
+
re = RE2::Regexp.new('(\D+)').match("bob")
|
87
|
+
re.string.must_be(:frozen?)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#size" do
|
92
|
+
it "returns the number of capturing groups plus the matching string" do
|
93
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("1234 56")
|
94
|
+
md.size.must_equal(3)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#length" do
|
99
|
+
it "returns the number of capturing groups plus the matching string" do
|
100
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("1234 56")
|
101
|
+
md.length.must_equal(3)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#regexp" do
|
106
|
+
it "returns the original RE2::Regexp used" do
|
107
|
+
re = RE2::Regexp.new('(\d+)')
|
108
|
+
md = re.match("123")
|
109
|
+
md.regexp.must_be_same_as(re)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#inspect" do
|
114
|
+
it "returns a text representation of the object and indices" do
|
115
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("1234 56")
|
116
|
+
md.inspect.must_equal('#<RE2::MatchData "1234 56" 1:"1234" 2:"56">')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "represents missing matches as nil" do
|
120
|
+
md = RE2::Regexp.new('(\d+) (\d+)?').match("1234 ")
|
121
|
+
md.inspect.must_equal('#<RE2::MatchData "1234 " 1:"1234" 2:nil>')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#to_s" do
|
126
|
+
it "returns the matching part of the original string" do
|
127
|
+
md = RE2::Regexp.new('(\d{2,5})').match("one two 23456")
|
128
|
+
md.to_s.must_equal("23456")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#to_ary" do
|
133
|
+
it "allows the object to be expanded with an asterisk" do
|
134
|
+
md = RE2::Regexp.new('(\d+) (\d+)').match("1234 56")
|
135
|
+
m1, m2, m3 = *md
|
136
|
+
m1.must_equal("1234 56")
|
137
|
+
m2.must_equal("1234")
|
138
|
+
m3.must_equal("56")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RE2::Regexp do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "returns an instance given only a pattern" do
|
6
|
+
re = RE2::Regexp.new('woo')
|
7
|
+
re.must_be_instance_of(RE2::Regexp)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns an instance given a pattern and options" do
|
11
|
+
re = RE2::Regexp.new('woo', :case_sensitive => false)
|
12
|
+
re.must_be_instance_of(RE2::Regexp)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#compile" do
|
17
|
+
it "returns an instance given only a pattern" do
|
18
|
+
re = RE2::Regexp.compile('woo')
|
19
|
+
re.must_be_instance_of(RE2::Regexp)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns an instance given a pattern and options" do
|
23
|
+
re = RE2::Regexp.compile('woo', :case_sensitive => false)
|
24
|
+
re.must_be_instance_of(RE2::Regexp)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#options" do
|
29
|
+
it "returns a hash of options" do
|
30
|
+
options = RE2::Regexp.new('woo').options
|
31
|
+
options.must_be_instance_of(Hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "is populated with default options when nothing has been set" do
|
35
|
+
options = RE2::Regexp.new('woo').options
|
36
|
+
assert options[:utf8]
|
37
|
+
refute options[:posix_syntax]
|
38
|
+
refute options[:longest_match]
|
39
|
+
assert [:log_errors]
|
40
|
+
refute options[:literal]
|
41
|
+
refute options[:never_nl]
|
42
|
+
assert options[:case_sensitive]
|
43
|
+
refute options[:perl_classes]
|
44
|
+
refute options[:word_boundary]
|
45
|
+
refute options[:one_line]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "is populated with overridden options when specified" do
|
49
|
+
options = RE2::Regexp.new('woo', :case_sensitive => false).options
|
50
|
+
refute options[:case_sensitive]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#error" do
|
55
|
+
it "returns nil if there is no error" do
|
56
|
+
error = RE2::Regexp.new('woo').error
|
57
|
+
error.must_be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# Use log_errors => false to suppress RE2's logging to STDERR.
|
61
|
+
it "contains the error string if there is an error" do
|
62
|
+
error = RE2::Regexp.new('wo(o', :log_errors => false).error
|
63
|
+
error.must_equal("missing ): wo(o")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#error_arg" do
|
68
|
+
it "returns nil if there is no error" do
|
69
|
+
error_arg = RE2::Regexp.new('woo').error_arg
|
70
|
+
error_arg.must_be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the offending portin of the regexp if there is an error" do
|
74
|
+
error_arg = RE2::Regexp.new('wo(o', :log_errors => false).error_arg
|
75
|
+
error_arg.must_equal("wo(o")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#program_size" do
|
80
|
+
it "returns a numeric value" do
|
81
|
+
program_size = RE2::Regexp.new('w(o)(o)').program_size
|
82
|
+
program_size.must_be_instance_of(Fixnum)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#to_str" do
|
87
|
+
it "returns the original pattern" do
|
88
|
+
string = RE2::Regexp.new('w(o)(o)').to_str
|
89
|
+
string.must_equal("w(o)(o)")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#pattern" do
|
94
|
+
it "returns the original pattern" do
|
95
|
+
pattern = RE2::Regexp.new('w(o)(o)').pattern
|
96
|
+
pattern.must_equal("w(o)(o)")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#inspect" do
|
101
|
+
it "shows the class name and original pattern" do
|
102
|
+
string = RE2::Regexp.new('w(o)(o)').inspect
|
103
|
+
string.must_equal("#<RE2::Regexp /w(o)(o)/>")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#utf8?" do
|
108
|
+
it "returns true by default" do
|
109
|
+
RE2::Regexp.new('woo').must_be(:utf8?)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "can be overridden on initialization" do
|
113
|
+
re = RE2::Regexp.new('woo', :utf8 => false)
|
114
|
+
re.wont_be(:utf8?)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#posix_syntax?" do
|
119
|
+
it "returns false by default" do
|
120
|
+
RE2::Regexp.new('woo').wont_be(:posix_syntax?)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "can be overridden on initialization" do
|
124
|
+
re = RE2::Regexp.new('woo', :posix_syntax => true)
|
125
|
+
re.must_be(:posix_syntax?)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#literal?" do
|
130
|
+
it "returns false by default" do
|
131
|
+
RE2::Regexp.new('woo').wont_be(:literal?)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "can be overridden on initialization" do
|
135
|
+
re = RE2::Regexp.new('woo', :literal => true)
|
136
|
+
re.must_be(:literal?)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#never_nl?" do
|
141
|
+
it "returns false by default" do
|
142
|
+
RE2::Regexp.new('woo').wont_be(:never_nl?)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "can be overridden on initialization" do
|
146
|
+
re = RE2::Regexp.new('woo', :never_nl => true)
|
147
|
+
re.must_be(:never_nl?)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "#case_sensitive?" do
|
152
|
+
it "returns true by default" do
|
153
|
+
RE2::Regexp.new('woo').must_be(:case_sensitive?)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "can be overridden on initialization" do
|
157
|
+
re = RE2::Regexp.new('woo', :case_sensitive => false)
|
158
|
+
re.wont_be(:case_sensitive?)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#case_insensitive?" do
|
163
|
+
it "returns false by default" do
|
164
|
+
RE2::Regexp.new('woo').wont_be(:case_insensitive?)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "can be overridden on initialization" do
|
168
|
+
re = RE2::Regexp.new('woo', :case_sensitive => false)
|
169
|
+
re.must_be(:case_insensitive?)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#casefold?" do
|
174
|
+
it "returns true by default" do
|
175
|
+
RE2::Regexp.new('woo').wont_be(:casefold?)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "can be overridden on initialization" do
|
179
|
+
re = RE2::Regexp.new('woo', :case_sensitive => false)
|
180
|
+
re.must_be(:casefold?)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#longest_match?" do
|
185
|
+
it "returns false by default" do
|
186
|
+
RE2::Regexp.new('woo').wont_be(:casefold?)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "can be overridden on initialization" do
|
190
|
+
re = RE2::Regexp.new('woo', :longest_match => true)
|
191
|
+
re.must_be(:longest_match?)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "#log_errors?" do
|
196
|
+
it "returns true by default" do
|
197
|
+
RE2::Regexp.new('woo').must_be(:log_errors?)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "can be overridden on initialization" do
|
201
|
+
re = RE2::Regexp.new('woo', :log_errors => false)
|
202
|
+
re.wont_be(:log_errors?)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "#perl_classes?" do
|
207
|
+
it "returns false by default" do
|
208
|
+
RE2::Regexp.new('woo').wont_be(:perl_classes?)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "can be overridden on initialization" do
|
212
|
+
re = RE2::Regexp.new('woo', :perl_classes => true)
|
213
|
+
re.must_be(:perl_classes?)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "#word_boundary?" do
|
218
|
+
it "returns false by default" do
|
219
|
+
RE2::Regexp.new('woo').wont_be(:word_boundary?)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "can be overridden on initialization" do
|
223
|
+
re = RE2::Regexp.new('woo', :word_boundary => true)
|
224
|
+
re.must_be(:word_boundary?)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#one_line?" do
|
229
|
+
it "returns false by default" do
|
230
|
+
RE2::Regexp.new('woo').wont_be(:one_line?)
|
231
|
+
end
|
232
|
+
|
233
|
+
it "can be overridden on initialization" do
|
234
|
+
re = RE2::Regexp.new('woo', :one_line => true)
|
235
|
+
re.must_be(:one_line?)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe "#max_mem" do
|
240
|
+
it "returns the default max memory" do
|
241
|
+
RE2::Regexp.new('woo').max_mem.must_equal(8388608)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "can be overridden on initialization" do
|
245
|
+
re = RE2::Regexp.new('woo', :max_mem => 1024)
|
246
|
+
re.max_mem.must_equal(1024)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "#match" do
|
251
|
+
let(:re) { RE2::Regexp.new('My name is (\S+) (\S+)') }
|
252
|
+
|
253
|
+
it "returns match data given only text" do
|
254
|
+
md = re.match("My name is Robert Paulson")
|
255
|
+
md.must_be_instance_of(RE2::MatchData)
|
256
|
+
end
|
257
|
+
|
258
|
+
it "returns nil if there is no match for the given text" do
|
259
|
+
re.match("My age is 99").must_be_nil
|
260
|
+
end
|
261
|
+
|
262
|
+
it "returns only true or false if no matches are requested" do
|
263
|
+
re.match("My name is Robert Paulson", 0).must_equal(true)
|
264
|
+
re.match("My age is 99", 0).must_equal(false)
|
265
|
+
end
|
266
|
+
|
267
|
+
describe "with a specific number of matches under the total in the pattern" do
|
268
|
+
subject { re.match("My name is Robert Paulson", 1) }
|
269
|
+
|
270
|
+
it "returns a match data object" do
|
271
|
+
subject.must_be_instance_of(RE2::MatchData)
|
272
|
+
end
|
273
|
+
|
274
|
+
it "has the whole match and only the specified number of matches" do
|
275
|
+
subject.size.must_equal(2)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "populates any specified matches" do
|
279
|
+
subject[1].must_equal("Robert")
|
280
|
+
end
|
281
|
+
|
282
|
+
it "does not populate any matches that weren't included" do
|
283
|
+
subject[2].must_be_nil
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe "with a number of matches over the total in the pattern" do
|
288
|
+
subject { re.match("My name is Robert Paulson", 5) }
|
289
|
+
|
290
|
+
it "returns a match data object" do
|
291
|
+
subject.must_be_instance_of(RE2::MatchData)
|
292
|
+
end
|
293
|
+
|
294
|
+
it "has the whole match the specified number of matches" do
|
295
|
+
subject.size.must_equal(6)
|
296
|
+
end
|
297
|
+
|
298
|
+
it "populates any specified matches" do
|
299
|
+
subject[1].must_equal("Robert")
|
300
|
+
subject[2].must_equal("Paulson")
|
301
|
+
end
|
302
|
+
|
303
|
+
it "pads the remaining matches with nil" do
|
304
|
+
subject[3].must_be_nil
|
305
|
+
subject[4].must_be_nil
|
306
|
+
subject[5].must_be_nil
|
307
|
+
subject[6].must_be_nil
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "#match?" do
|
313
|
+
it "returns only true or false if no matches are requested" do
|
314
|
+
re = RE2::Regexp.new('My name is (\S+) (\S+)')
|
315
|
+
re.match?("My name is Robert Paulson").must_equal(true)
|
316
|
+
re.match?("My age is 99").must_equal(false)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "#=~" do
|
321
|
+
it "returns only true or false if no matches are requested" do
|
322
|
+
re = RE2::Regexp.new('My name is (\S+) (\S+)')
|
323
|
+
(re =~ "My name is Robert Paulson").must_equal(true)
|
324
|
+
(re =~ "My age is 99").must_equal(false)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "#!~" do
|
329
|
+
it "returns only true or false if no matches are requested" do
|
330
|
+
re = RE2::Regexp.new('My name is (\S+) (\S+)')
|
331
|
+
(re !~ "My name is Robert Paulson").must_equal(false)
|
332
|
+
(re !~ "My age is 99").must_equal(true)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
describe "#===" do
|
337
|
+
it "returns only true or false if no matches are requested" do
|
338
|
+
re = RE2::Regexp.new('My name is (\S+) (\S+)')
|
339
|
+
(re === "My name is Robert Paulson").must_equal(true)
|
340
|
+
(re === "My age is 99").must_equal(false)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe "#ok?" do
|
345
|
+
it "returns true for valid regexps" do
|
346
|
+
RE2::Regexp.new('woo').must_be(:ok?)
|
347
|
+
RE2::Regexp.new('wo(o)').must_be(:ok?)
|
348
|
+
RE2::Regexp.new('((\d)\w+){3,}').must_be(:ok?)
|
349
|
+
end
|
350
|
+
|
351
|
+
it "returns false for invalid regexps" do
|
352
|
+
RE2::Regexp.new('wo(o', :log_errors => false).wont_be(:ok?)
|
353
|
+
RE2::Regexp.new('wo[o', :log_errors => false).wont_be(:ok?)
|
354
|
+
RE2::Regexp.new('*', :log_errors => false).wont_be(:ok?)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
describe "#escape" do
|
359
|
+
it "transforms a string into a regexp" do
|
360
|
+
RE2::Regexp.escape("1.5-2.0?").must_equal('1\.5\-2\.0\?')
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe "#quote" do
|
365
|
+
it "transforms a string into a regexp" do
|
366
|
+
RE2::Regexp.quote("1.5-2.0?").must_equal('1\.5\-2\.0\?')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
describe "#number_of_capturing_groups" do
|
371
|
+
it "returns the number of groups in a regexp" do
|
372
|
+
RE2::Regexp.new('(a)(b)(c)').number_of_capturing_groups.must_equal(3)
|
373
|
+
RE2::Regexp.new('abc').number_of_capturing_groups.must_equal(0)
|
374
|
+
RE2::Regexp.new('a((b)c)').number_of_capturing_groups.must_equal(2)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
describe "#named_capturing_groups" do
|
379
|
+
it "returns a hash of names to indices" do
|
380
|
+
RE2::Regexp.new('(?P<bob>a)').named_capturing_groups.must_be_instance_of(Hash)
|
381
|
+
end
|
382
|
+
|
383
|
+
it "maps names to indices with only one group" do
|
384
|
+
groups = RE2::Regexp.new('(?P<bob>a)').named_capturing_groups
|
385
|
+
groups["bob"].must_equal(1)
|
386
|
+
end
|
387
|
+
|
388
|
+
it "maps names to indices with several groups" do
|
389
|
+
groups = RE2::Regexp.new('(?P<bob>a)(o)(?P<rob>e)').named_capturing_groups
|
390
|
+
groups["bob"].must_equal(1)
|
391
|
+
groups["rob"].must_equal(3)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|