re2 0.2.0 → 0.3.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 +32 -8
- data/ext/re2/extconf.rb +27 -0
- data/ext/re2/re2.cc +103 -29
- data/test/re2_test.rb +34 -0
- metadata +31 -50
- data/test/leak.rb +0 -32
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
re2
|
1
|
+
re2 [](http://travis-ci.org/mudge/re2)
|
2
2
|
===
|
3
3
|
|
4
4
|
A Ruby binding to [re2][], an "efficient, principled regular expression library".
|
@@ -6,7 +6,13 @@ A Ruby binding to [re2][], an "efficient, principled regular expression library"
|
|
6
6
|
Installation
|
7
7
|
------------
|
8
8
|
|
9
|
-
You will need [re2][] installed as well as a C++ compiler such as [gcc][] (on Debian and Ubuntu, this is provided by the [build-essential][] package).
|
9
|
+
You will need [re2][] installed as well as a C++ compiler such as [gcc][] (on Debian and Ubuntu, this is provided by the [build-essential][] package). If you are using Mac OS X, I recommend installing re2 with [Homebrew][] by running the following:
|
10
|
+
|
11
|
+
$ brew install --HEAD re2
|
12
|
+
|
13
|
+
If you are using Debian, you can install the [libre2-dev][] package like so:
|
14
|
+
|
15
|
+
$ sudo apt-get install libre2-dev
|
10
16
|
|
11
17
|
If you are using a packaged Ruby distribution, make sure you also have the Ruby header files installed such as those provided by the [ruby-dev][] package on Debian and Ubuntu.
|
12
18
|
|
@@ -15,7 +21,9 @@ You can then install the library via RubyGems with `gem install re2` or `gem ins
|
|
15
21
|
Documentation
|
16
22
|
-------------
|
17
23
|
|
18
|
-
Full documentation automatically generated from the latest version is available at <http://
|
24
|
+
Full documentation automatically generated from the latest version is available at <http://rubydoc.info/github/mudge/re2>.
|
25
|
+
|
26
|
+
Bear in mind that re2's regular expression syntax differs from PCRE, see the [official syntax page][] for more details.
|
19
27
|
|
20
28
|
Usage
|
21
29
|
-----
|
@@ -39,20 +47,33 @@ You can use re2 as a mostly drop-in replacement for Ruby's own [Regexp][] and [M
|
|
39
47
|
> r.match("bob")
|
40
48
|
=> nil
|
41
49
|
|
50
|
+
As of 0.3.0, you can use named groups:
|
51
|
+
|
52
|
+
> r = RE2::Regexp.compile('(?P<name>\w+) (?P<age>\d+)')
|
53
|
+
=> #<RE2::Regexp /(?P<name>\w+) (?P<age>\d+)/>
|
54
|
+
> m = r.match("Bob 40")
|
55
|
+
=> #<RE2::MatchData "Bob 40" 1:"Bob" 2:"40">
|
56
|
+
> m[:name]
|
57
|
+
=> "Bob"
|
58
|
+
> m["age"]
|
59
|
+
=> "40"
|
60
|
+
|
42
61
|
Features
|
43
62
|
--------
|
44
63
|
|
45
64
|
* Pre-compiling regular expressions with [`RE2::Regexp.new(re)`](http://code.google.com/p/re2/source/browse/re2/re2.h#96), `RE2::Regexp.compile(re)` or `RE2(re)` (including specifying options, e.g. `RE2::Regexp.new("pattern", :case_sensitive => false)`
|
46
65
|
|
47
|
-
|
66
|
+
* Extracting matches with `re2.match(text)` (and an exact number of matches with `re2.match(text, number_of_matches)` such as `re2.match("123-234", 2)`)
|
67
|
+
|
68
|
+
* Extracting matches by name (both with strings and symbols)
|
48
69
|
|
49
|
-
|
70
|
+
* Checking for matches with `re2 =~ text`, `re2 === text` (for use in `case` statements) and `re2 !~ text`
|
50
71
|
|
51
|
-
|
72
|
+
* Checking regular expression compilation with `re2.ok?`, `re2.error` and `re2.error_arg`
|
52
73
|
|
53
|
-
|
74
|
+
* Checking regular expression "cost" with `re2.program_size`
|
54
75
|
|
55
|
-
|
76
|
+
* Checking the options for an expression with `re2.options` or individually with `re2.case_sensitive?`
|
56
77
|
|
57
78
|
* Performing in-place replacement with [`RE2::Replace(str, pattern, replace)`](http://code.google.com/p/re2/source/browse/re2/re2.h#335)
|
58
79
|
|
@@ -71,3 +92,6 @@ All feedback should go to the mailing list: <mailto:ruby.re2@librelist.com>
|
|
71
92
|
[build-essential]: http://packages.debian.org/build-essential
|
72
93
|
[Regexp]: http://ruby-doc.org/core/classes/Regexp.html
|
73
94
|
[MatchData]: http://ruby-doc.org/core/classes/MatchData.html
|
95
|
+
[Homebrew]: http://mxcl.github.com/homebrew
|
96
|
+
[libre2-dev]: http://packages.debian.org/search?keywords=libre2-dev
|
97
|
+
[official syntax page]: http://code.google.com/p/re2/wiki/Syntax
|
data/ext/re2/extconf.rb
CHANGED
@@ -12,6 +12,33 @@ $CFLAGS << " -Wall -Wextra -funroll-loops"
|
|
12
12
|
|
13
13
|
have_library("stdc++")
|
14
14
|
if have_library("re2")
|
15
|
+
|
16
|
+
# Determine which version of re2 the user has installed.
|
17
|
+
# Revision d9f8806c004d added an `endpos` argument to the
|
18
|
+
# generic Match() function.
|
19
|
+
#
|
20
|
+
# To test for this, try to compile a simple program that uses
|
21
|
+
# the newer form of Match() and set a flag if it is successful.
|
22
|
+
checking_for("RE2::Match() with endpos argument") do
|
23
|
+
test_re2_match_signature = <<SRC
|
24
|
+
#include <re2/re2.h>
|
25
|
+
|
26
|
+
int main() {
|
27
|
+
RE2 pattern("test");
|
28
|
+
re2::StringPiece *match;
|
29
|
+
pattern.Match("test", 0, 0, RE2::UNANCHORED, match, 0);
|
30
|
+
|
31
|
+
return 0;
|
32
|
+
}
|
33
|
+
SRC
|
34
|
+
|
35
|
+
# Pass -x c++ to force gcc to compile the test program
|
36
|
+
# as C++ (as it will end in .c by default).
|
37
|
+
if try_compile(test_re2_match_signature, "-x c++")
|
38
|
+
$defs.push("-DHAVE_ENDPOS_ARGUMENT")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
15
42
|
create_makefile("re2")
|
16
43
|
else
|
17
44
|
abort "You must have re2 installed and specified with --with-re2-dir, please see http://code.google.com/p/re2/wiki/Install"
|
data/ext/re2/re2.cc
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
*/
|
8
8
|
|
9
9
|
#include <re2/re2.h>
|
10
|
+
#include <string>
|
11
|
+
using namespace std;
|
10
12
|
|
11
13
|
extern "C" {
|
12
14
|
|
@@ -30,7 +32,7 @@ extern "C" {
|
|
30
32
|
typedef struct {
|
31
33
|
re2::StringPiece *matches;
|
32
34
|
int number_of_matches;
|
33
|
-
VALUE regexp,
|
35
|
+
VALUE regexp, text;
|
34
36
|
} re2_matchdata;
|
35
37
|
|
36
38
|
VALUE re2_mRE2, re2_cRegexp, re2_cMatchData;
|
@@ -43,7 +45,7 @@ extern "C" {
|
|
43
45
|
void re2_matchdata_mark(re2_matchdata* self)
|
44
46
|
{
|
45
47
|
rb_gc_mark(self->regexp);
|
46
|
-
rb_gc_mark(self->
|
48
|
+
rb_gc_mark(self->text);
|
47
49
|
}
|
48
50
|
|
49
51
|
void re2_matchdata_free(re2_matchdata* self)
|
@@ -84,7 +86,7 @@ extern "C" {
|
|
84
86
|
re2_matchdata *m;
|
85
87
|
Data_Get_Struct(self, re2_matchdata, m);
|
86
88
|
|
87
|
-
return m->
|
89
|
+
return m->text;
|
88
90
|
}
|
89
91
|
|
90
92
|
/*
|
@@ -141,13 +143,16 @@ extern "C" {
|
|
141
143
|
{
|
142
144
|
int i;
|
143
145
|
re2_matchdata *m;
|
146
|
+
re2::StringPiece match;
|
147
|
+
|
144
148
|
Data_Get_Struct(self, re2_matchdata, m);
|
145
149
|
VALUE array = rb_ary_new2(m->number_of_matches);
|
146
150
|
for (i = 0; i < m->number_of_matches; i++) {
|
147
151
|
if (m->matches[i].empty()) {
|
148
152
|
rb_ary_push(array, Qnil);
|
149
153
|
} else {
|
150
|
-
|
154
|
+
match = m->matches[i];
|
155
|
+
rb_ary_push(array, rb_str_new(match.data(), match.size()));
|
151
156
|
}
|
152
157
|
}
|
153
158
|
return array;
|
@@ -157,17 +162,42 @@ extern "C" {
|
|
157
162
|
re2_matchdata_nth_match(int nth, VALUE self)
|
158
163
|
{
|
159
164
|
re2_matchdata *m;
|
165
|
+
re2::StringPiece match;
|
166
|
+
|
160
167
|
Data_Get_Struct(self, re2_matchdata, m);
|
168
|
+
match = m->matches[nth];
|
161
169
|
|
162
|
-
if (nth >= m->number_of_matches ||
|
170
|
+
if (nth >= m->number_of_matches || match.empty()) {
|
163
171
|
return Qnil;
|
164
172
|
} else {
|
165
|
-
return rb_str_new(
|
173
|
+
return rb_str_new(match.data(), match.size());
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
static VALUE
|
178
|
+
re2_matchdata_named_match(const char* name, VALUE self)
|
179
|
+
{
|
180
|
+
int idx;
|
181
|
+
re2_matchdata *m;
|
182
|
+
re2_pattern *p;
|
183
|
+
map<string, int> groups;
|
184
|
+
string name_as_string(name);
|
185
|
+
|
186
|
+
Data_Get_Struct(self, re2_matchdata, m);
|
187
|
+
Data_Get_Struct(m->regexp, re2_pattern, p);
|
188
|
+
|
189
|
+
groups = p->pattern->NamedCapturingGroups();
|
190
|
+
|
191
|
+
if (groups.count(name_as_string) == 1) {
|
192
|
+
idx = groups[name_as_string];
|
193
|
+
return re2_matchdata_nth_match(idx, self);
|
194
|
+
} else {
|
195
|
+
return Qnil;
|
166
196
|
}
|
167
197
|
}
|
168
198
|
|
169
199
|
/*
|
170
|
-
* Retrieve zero, one or more matches by index.
|
200
|
+
* Retrieve zero, one or more matches by index or name.
|
171
201
|
*
|
172
202
|
* @return [Array<String, nil>, String, Boolean]
|
173
203
|
*
|
@@ -198,6 +228,16 @@ extern "C" {
|
|
198
228
|
* @example
|
199
229
|
* m = RE2('(\d+)').match("bob 123")
|
200
230
|
* m[0..1] #=> "[123", "123"]
|
231
|
+
*
|
232
|
+
* @overload [](name)
|
233
|
+
* Access a particular match by name.
|
234
|
+
*
|
235
|
+
* @param [String, Symbol] name the name of the match to fetch
|
236
|
+
* @return [String, nil] the specific match
|
237
|
+
* @example
|
238
|
+
* m = RE2('(?P<number>\d+)').match("bob 123")
|
239
|
+
* m["number"] #=> "123"
|
240
|
+
* m[:number] #=> "123"
|
201
241
|
*/
|
202
242
|
static VALUE
|
203
243
|
re2_matchdata_aref(int argc, VALUE *argv, VALUE self)
|
@@ -205,7 +245,11 @@ extern "C" {
|
|
205
245
|
VALUE idx, rest;
|
206
246
|
rb_scan_args(argc, argv, "11", &idx, &rest);
|
207
247
|
|
208
|
-
if (
|
248
|
+
if (TYPE(idx) == T_STRING) {
|
249
|
+
return re2_matchdata_named_match(StringValuePtr(idx), self);
|
250
|
+
} else if (TYPE(idx) == T_SYMBOL) {
|
251
|
+
return re2_matchdata_named_match(rb_id2name(SYM2ID(idx)), self);
|
252
|
+
} else if (!NIL_P(rest) || !FIXNUM_P(idx) || FIX2INT(idx) < 0) {
|
209
253
|
return rb_ary_aref(argc, argv, re2_matchdata_to_a(self));
|
210
254
|
} else {
|
211
255
|
return re2_matchdata_nth_match(FIX2INT(idx), self);
|
@@ -391,9 +435,9 @@ extern "C" {
|
|
391
435
|
re2_options.set_one_line(RTEST(one_line));
|
392
436
|
}
|
393
437
|
|
394
|
-
p->pattern = new (
|
438
|
+
p->pattern = new (nothrow) RE2(StringValuePtr(pattern), re2_options);
|
395
439
|
} else {
|
396
|
-
p->pattern = new (
|
440
|
+
p->pattern = new (nothrow) RE2(StringValuePtr(pattern));
|
397
441
|
}
|
398
442
|
|
399
443
|
if (p->pattern == 0) {
|
@@ -773,6 +817,32 @@ extern "C" {
|
|
773
817
|
return INT2FIX(p->pattern->NumberOfCapturingGroups());
|
774
818
|
}
|
775
819
|
|
820
|
+
/*
|
821
|
+
* Returns a hash of names to capturing indices of groups.
|
822
|
+
*
|
823
|
+
* @return [Hash] a hash of names to capturing indices
|
824
|
+
*/
|
825
|
+
static VALUE
|
826
|
+
re2_regexp_named_capturing_groups(VALUE self)
|
827
|
+
{
|
828
|
+
VALUE capturing_groups;
|
829
|
+
re2_pattern *p;
|
830
|
+
map<string, int> groups;
|
831
|
+
map<string, int>::iterator iterator;
|
832
|
+
|
833
|
+
Data_Get_Struct(self, re2_pattern, p);
|
834
|
+
groups = p->pattern->NamedCapturingGroups();
|
835
|
+
capturing_groups = rb_hash_new();
|
836
|
+
|
837
|
+
for (iterator = groups.begin(); iterator != groups.end(); iterator++) {
|
838
|
+
rb_hash_aset(capturing_groups,
|
839
|
+
rb_str_new(iterator->first.data(), iterator->first.size()),
|
840
|
+
INT2FIX(iterator->second));
|
841
|
+
}
|
842
|
+
|
843
|
+
return capturing_groups;
|
844
|
+
}
|
845
|
+
|
776
846
|
/*
|
777
847
|
* Match the pattern against the given +text+ and return either
|
778
848
|
* a boolean (if no submatches are required) or a {RE2::MatchData}
|
@@ -836,10 +906,12 @@ extern "C" {
|
|
836
906
|
n = p->pattern->NumberOfCapturingGroups();
|
837
907
|
}
|
838
908
|
|
839
|
-
re2::StringPiece text_as_string_piece(StringValuePtr(text));
|
840
|
-
|
841
909
|
if (n == 0) {
|
842
|
-
|
910
|
+
#if defined(HAVE_ENDPOS_ARGUMENT)
|
911
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
|
912
|
+
#else
|
913
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, RE2::UNANCHORED, 0, 0);
|
914
|
+
#endif
|
843
915
|
return BOOL2RUBY(matched);
|
844
916
|
} else {
|
845
917
|
|
@@ -848,10 +920,10 @@ extern "C" {
|
|
848
920
|
|
849
921
|
matchdata = rb_class_new_instance(0, 0, re2_cMatchData);
|
850
922
|
Data_Get_Struct(matchdata, re2_matchdata, m);
|
851
|
-
m->matches = new (
|
923
|
+
m->matches = new (nothrow) re2::StringPiece[n];
|
852
924
|
m->regexp = self;
|
853
|
-
m->
|
854
|
-
rb_str_freeze(m->
|
925
|
+
m->text = rb_str_dup(text);
|
926
|
+
rb_str_freeze(m->text);
|
855
927
|
|
856
928
|
if (m->matches == 0) {
|
857
929
|
rb_raise(rb_eNoMemError, "not enough memory to allocate StringPieces for matches");
|
@@ -859,7 +931,11 @@ extern "C" {
|
|
859
931
|
|
860
932
|
m->number_of_matches = n;
|
861
933
|
|
862
|
-
|
934
|
+
#if defined(HAVE_ENDPOS_ARGUMENT)
|
935
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, m->matches, n);
|
936
|
+
#else
|
937
|
+
matched = p->pattern->Match(StringValuePtr(text), 0, RE2::UNANCHORED, m->matches, n);
|
938
|
+
#endif
|
863
939
|
|
864
940
|
if (matched) {
|
865
941
|
return matchdata;
|
@@ -912,19 +988,18 @@ extern "C" {
|
|
912
988
|
re2_pattern *p;
|
913
989
|
|
914
990
|
/* Convert all the inputs to be pumped into RE2::Replace. */
|
915
|
-
|
916
|
-
re2::StringPiece rewrite_as_string_piece(StringValuePtr(rewrite));
|
991
|
+
string str_as_string(StringValuePtr(str));
|
917
992
|
|
918
993
|
/* Do the replacement. */
|
919
994
|
if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
|
920
995
|
Data_Get_Struct(pattern, re2_pattern, p);
|
921
|
-
RE2::Replace(&str_as_string, *p->pattern,
|
996
|
+
RE2::Replace(&str_as_string, *p->pattern, StringValuePtr(rewrite));
|
922
997
|
} else {
|
923
|
-
RE2::Replace(&str_as_string, StringValuePtr(pattern),
|
998
|
+
RE2::Replace(&str_as_string, StringValuePtr(pattern), StringValuePtr(rewrite));
|
924
999
|
}
|
925
1000
|
|
926
1001
|
/* Save the replacement as a VALUE. */
|
927
|
-
repl = rb_str_new(str_as_string.
|
1002
|
+
repl = rb_str_new(str_as_string.data(), str_as_string.size());
|
928
1003
|
|
929
1004
|
/* Replace the original string with the replacement. */
|
930
1005
|
if (RSTRING_LEN(str) != RSTRING_LEN(repl)) {
|
@@ -961,20 +1036,19 @@ extern "C" {
|
|
961
1036
|
|
962
1037
|
/* Convert all the inputs to be pumped into RE2::GlobalReplace. */
|
963
1038
|
re2_pattern *p;
|
964
|
-
|
965
|
-
re2::StringPiece rewrite_as_string_piece(StringValuePtr(rewrite));
|
1039
|
+
string str_as_string(StringValuePtr(str));
|
966
1040
|
VALUE repl;
|
967
1041
|
|
968
1042
|
/* Do the replacement. */
|
969
1043
|
if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
|
970
1044
|
Data_Get_Struct(pattern, re2_pattern, p);
|
971
|
-
RE2::GlobalReplace(&str_as_string, *p->pattern,
|
1045
|
+
RE2::GlobalReplace(&str_as_string, *p->pattern, StringValuePtr(rewrite));
|
972
1046
|
} else {
|
973
|
-
RE2::GlobalReplace(&str_as_string, StringValuePtr(pattern),
|
1047
|
+
RE2::GlobalReplace(&str_as_string, StringValuePtr(pattern), StringValuePtr(rewrite));
|
974
1048
|
}
|
975
1049
|
|
976
1050
|
/* Save the replacement as a VALUE. */
|
977
|
-
repl = rb_str_new(str_as_string.
|
1051
|
+
repl = rb_str_new(str_as_string.data(), str_as_string.size());
|
978
1052
|
|
979
1053
|
/* Replace the original string with the replacement. */
|
980
1054
|
if (RSTRING_LEN(str) != RSTRING_LEN(repl)) {
|
@@ -999,8 +1073,7 @@ extern "C" {
|
|
999
1073
|
re2_QuoteMeta(VALUE self, VALUE unquoted)
|
1000
1074
|
{
|
1001
1075
|
UNUSED(self);
|
1002
|
-
|
1003
|
-
std::string quoted_string = RE2::QuoteMeta(unquoted_as_string_piece);
|
1076
|
+
string quoted_string = RE2::QuoteMeta(StringValuePtr(unquoted));
|
1004
1077
|
return rb_str_new(quoted_string.data(), quoted_string.size());
|
1005
1078
|
}
|
1006
1079
|
|
@@ -1030,6 +1103,7 @@ extern "C" {
|
|
1030
1103
|
rb_define_method(re2_cRegexp, "program_size", RUBY_METHOD_FUNC(re2_regexp_program_size), 0);
|
1031
1104
|
rb_define_method(re2_cRegexp, "options", RUBY_METHOD_FUNC(re2_regexp_options), 0);
|
1032
1105
|
rb_define_method(re2_cRegexp, "number_of_capturing_groups", RUBY_METHOD_FUNC(re2_regexp_number_of_capturing_groups), 0);
|
1106
|
+
rb_define_method(re2_cRegexp, "named_capturing_groups", RUBY_METHOD_FUNC(re2_regexp_named_capturing_groups), 0);
|
1033
1107
|
rb_define_method(re2_cRegexp, "match", RUBY_METHOD_FUNC(re2_regexp_match), -1);
|
1034
1108
|
rb_define_method(re2_cRegexp, "match?", RUBY_METHOD_FUNC(re2_regexp_match_query), 1);
|
1035
1109
|
rb_define_method(re2_cRegexp, "=~", RUBY_METHOD_FUNC(re2_regexp_match_query), 1);
|
data/test/re2_test.rb
CHANGED
@@ -121,11 +121,44 @@ class RE2Test < Test::Unit::TestCase
|
|
121
121
|
assert_equal 2, RE2('a((b)c)').number_of_capturing_groups
|
122
122
|
end
|
123
123
|
|
124
|
+
def test_named_capturing_groups
|
125
|
+
assert_equal(1, RE2('(?P<bob>a)').named_capturing_groups["bob"])
|
126
|
+
assert_equal(1, RE2('(?P<bob>a)(o)(?P<rob>e)').named_capturing_groups["bob"])
|
127
|
+
assert_equal(3, RE2('(?P<bob>a)(o)(?P<rob>e)').named_capturing_groups["rob"])
|
128
|
+
end
|
129
|
+
|
124
130
|
def test_matching_all_subpatterns
|
125
131
|
assert_equal ["woo", "o", "o"], RE2('w(o)(o)').match('woo').to_a
|
126
132
|
assert_equal ["ab", nil, "a", "b"], RE2('(\d?)(a)(b)').match('ab').to_a
|
127
133
|
end
|
128
134
|
|
135
|
+
def test_fetching_matchdata_out_of_range
|
136
|
+
matchdata = RE2('(\d+)').match('bob 123')
|
137
|
+
assert_nil matchdata[2]
|
138
|
+
assert_nil matchdata[3]
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_accessing_matches_by_name
|
142
|
+
matchdata = RE2('(?P<numbers>\d+)').match("bob 123")
|
143
|
+
assert_equal "123", matchdata["numbers"]
|
144
|
+
assert_equal "123", matchdata[:numbers]
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_accessing_matches_by_name_with_multiple_groups
|
148
|
+
matchdata = RE2('(?P<name>\w+)(\s*)(?P<numbers>\d+)').match("bob 123")
|
149
|
+
assert_equal "bob", matchdata["name"]
|
150
|
+
assert_equal "bob", matchdata[:name]
|
151
|
+
assert_equal " ", matchdata[2]
|
152
|
+
assert_equal "123", matchdata["numbers"]
|
153
|
+
assert_equal "123", matchdata[:numbers]
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_accessing_matches_by_incorrect_names
|
157
|
+
matchdata = RE2('(?P<numbers>\d+)').match("bob 123")
|
158
|
+
assert_nil matchdata["missing"]
|
159
|
+
assert_nil matchdata[:missing]
|
160
|
+
end
|
161
|
+
|
129
162
|
def test_matchdata
|
130
163
|
r = RE2('(\d+)')
|
131
164
|
text = "bob 123"
|
@@ -146,6 +179,7 @@ class RE2Test < Test::Unit::TestCase
|
|
146
179
|
assert_equal "123", m.to_s
|
147
180
|
assert_equal "123", m[0]
|
148
181
|
assert_equal "123", m[1]
|
182
|
+
assert_nil m[4]
|
149
183
|
assert_equal ["123"], m[0, 1]
|
150
184
|
assert_equal ["123", "123"], m[0, 2]
|
151
185
|
assert_equal ["123"], m[0...1]
|
metadata
CHANGED
@@ -1,83 +1,64 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: re2
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Paul Mucur
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2012-02-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rake-compiler
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70320711075760 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
- 0
|
30
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
31
22
|
type: :development
|
32
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70320711075760
|
33
25
|
description: Ruby bindings to re2, "an efficient, principled regular expression library".
|
34
26
|
email: ruby.re2@librelist.com
|
35
27
|
executables: []
|
36
|
-
|
37
|
-
extensions:
|
28
|
+
extensions:
|
38
29
|
- ext/re2/extconf.rb
|
39
30
|
extra_rdoc_files: []
|
40
|
-
|
41
|
-
files:
|
31
|
+
files:
|
42
32
|
- ext/re2/extconf.rb
|
43
33
|
- ext/re2/re2.cc
|
44
34
|
- LICENSE.txt
|
45
35
|
- README.md
|
46
36
|
- Rakefile
|
47
37
|
- test/re2_test.rb
|
48
|
-
- test/leak.rb
|
49
|
-
has_rdoc: true
|
50
38
|
homepage: http://github.com/mudge/re2
|
51
39
|
licenses: []
|
52
|
-
|
53
40
|
post_install_message:
|
54
41
|
rdoc_options: []
|
55
|
-
|
56
|
-
require_paths:
|
42
|
+
require_paths:
|
57
43
|
- lib
|
58
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
45
|
none: false
|
60
|
-
requirements:
|
61
|
-
- -
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
|
64
|
-
|
65
|
-
version: "0"
|
66
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
51
|
none: false
|
68
|
-
requirements:
|
69
|
-
- -
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
- 0
|
73
|
-
version: "0"
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
74
56
|
requirements: []
|
75
|
-
|
76
57
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.8.11
|
78
59
|
signing_key:
|
79
60
|
specification_version: 3
|
80
61
|
summary: Ruby bindings to re2.
|
81
|
-
test_files:
|
62
|
+
test_files:
|
82
63
|
- test/re2_test.rb
|
83
|
-
|
64
|
+
has_rdoc:
|
data/test/leak.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
require 're2'
|
3
|
-
|
4
|
-
loops = if ENV["LOOPS"]
|
5
|
-
ENV["LOOPS"].to_i
|
6
|
-
else
|
7
|
-
150
|
8
|
-
end
|
9
|
-
|
10
|
-
puts "Looping #{loops} times..."
|
11
|
-
|
12
|
-
loops.times do
|
13
|
-
r = RE2::Regexp.new('woo(oo)(o+)(\d*)')
|
14
|
-
r.ok?
|
15
|
-
r.match('wooo')
|
16
|
-
r.match('wooo', 0)
|
17
|
-
r.match('wooo', 1)
|
18
|
-
r.match('wooo', 2)
|
19
|
-
r =~ 'woooo'
|
20
|
-
r =~ 'bob'
|
21
|
-
RE2::Replace("woo", "woo", "bob")
|
22
|
-
RE2::GlobalReplace("woo", "woo", "bob")
|
23
|
-
m = r.match('woooooo1234')
|
24
|
-
m[0]
|
25
|
-
m[1]
|
26
|
-
m[0,2]
|
27
|
-
m[1..-1]
|
28
|
-
m.string
|
29
|
-
m.regexp
|
30
|
-
m.inspect
|
31
|
-
sleep 0.1
|
32
|
-
end
|