re2 2.27.0-arm-linux-gnu → 2.28.0-arm-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 645eab3b4e65e9324ce7c21fb194003d47e49218bc14ea9a33a971d128b8426d
4
- data.tar.gz: f1459959f76efa60581508fd0b1f8360afb4ccfaf8a651d076a4b67cbd334659
3
+ metadata.gz: 140f6962d695db89ed1410372669691144d1c71e31c49873504bcb68291ce986
4
+ data.tar.gz: 91120b25899a2db5f6b5e31c65a940710a9614123e9fac4c029f5ee42ed6863e
5
5
  SHA512:
6
- metadata.gz: 55cc7f7cf8a3ac43c7dfc64040a1f9f137bf04d040b99bcbc4039be358c6b6d6176239164747d8b8ad7be1a1af2a38ba82870bf00965caf2a76af7609a78aefb
7
- data.tar.gz: 753a84156ac0cea64cf30e579baf613d691dd04bfd1f092ecbc5e5ad5308ecba601c360c97c4f42b5ddf0f5983b9555d09393f46564dc2e1cb5a0b81f2d401fa
6
+ metadata.gz: 31498cbb945d8595590a63d93d3031f67de273e95fc976dfcd227e43fc619c93a6c8403d5e1eafded51559f7e985282836dab6072cc6056249a7d830c515565a
7
+ data.tar.gz: 53981ca65527f73169d63361022736afd5d301b6b7e1e3a4cd90463f176481a57efdab1e00428449e4296a67bde72f11c4b50fd77abf6990a21731144ff4b342
data/Gemfile CHANGED
@@ -9,3 +9,8 @@ gem "rake", "> 12.3.2"
9
9
  group :memcheck, optional: true do
10
10
  gem "ruby_memcheck"
11
11
  end
12
+
13
+ group :docs, optional: true do
14
+ gem "redcarpet"
15
+ gem "yard"
16
+ end
data/README.md CHANGED
@@ -6,7 +6,7 @@ Python".
6
6
 
7
7
  [![Build Status](https://github.com/mudge/re2/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/mudge/re2/actions)
8
8
 
9
- **Current version:** 2.27.0
9
+ **Current version:** 2.28.0
10
10
  **Bundled RE2 version:** libre2.11 (2025-11-05)
11
11
 
12
12
  ```ruby
data/ext/re2/extconf.rb CHANGED
@@ -132,38 +132,14 @@ module RE2
132
132
 
133
133
  def build_extension
134
134
  $CFLAGS << " -Wall -Wextra -funroll-loops"
135
- $CXXFLAGS << " -Wall -Wextra -funroll-loops"
135
+ $CXXFLAGS << " -Wall -Wextra -funroll-loops -std=c++17"
136
136
 
137
137
  # Pass -x c++ to force gcc to compile the test program
138
138
  # as C++ (as it will end in .c by default).
139
- compile_options = +"-x c++"
139
+ compile_options = +"-x c++ -std=c++17"
140
140
 
141
141
  have_library("stdc++")
142
142
 
143
- minimal_program = <<~SRC
144
- #include <re2/re2.h>
145
- int main() { return 0; }
146
- SRC
147
-
148
- re2_requires_version_flag = checking_for("re2 that requires explicit C++ version flag") do
149
- !try_compile(minimal_program, compile_options)
150
- end
151
-
152
- if re2_requires_version_flag
153
- # Recent versions of RE2 depend directly on Abseil, which requires a
154
- # compiler with C++17 support.
155
- abort "Cannot compile re2 with your compiler: recent versions require C++17 support." unless %w[c++20 c++17 c++11].any? do |std|
156
- checking_for("re2 that compiles with #{std} standard") do
157
- if try_compile(minimal_program, compile_options + " -std=#{std}")
158
- compile_options << " -std=#{std}"
159
- $CPPFLAGS << " -std=#{std}"
160
-
161
- true
162
- end
163
- end
164
- end
165
- end
166
-
167
143
  # Determine which version of re2 the user has installed.
168
144
  # Revision d9f8806c004d added an `endpos` argument to the
169
145
  # generic Match() function.
data/ext/re2/re2.cc CHANGED
@@ -42,6 +42,7 @@ typedef struct {
42
42
 
43
43
  typedef struct {
44
44
  RE2::Set *set;
45
+ bool compiled;
45
46
  } re2_set;
46
47
 
47
48
  struct nogvl_match_arg {
@@ -170,6 +171,13 @@ static void *nogvl_extract(void *ptr) {
170
171
  return nullptr;
171
172
  }
172
173
 
174
+ static std::string group_name(VALUE key) {
175
+ VALUE str = SYMBOL_P(key) ? rb_sym2str(key) : key;
176
+ str = rb_str_conv_enc(str, rb_enc_get(str), rb_utf8_encoding());
177
+
178
+ return std::string(RSTRING_PTR(str), RSTRING_LEN(str));
179
+ }
180
+
173
181
  VALUE re2_mRE2, re2_cRegexp, re2_cMatchData, re2_cScanner, re2_cSet,
174
182
  re2_eSetMatchError, re2_eSetUnsupportedError, re2_eRegexpUnsupportedError;
175
183
 
@@ -412,9 +420,9 @@ static re2_scanner *unwrap_re2_scanner(VALUE self) {
412
420
  * in alphabetical order rather than definition order, as RE2 stores named
413
421
  * groups internally in a sorted map.
414
422
  *
415
- * Note RE2 only supports UTF-8 and ISO-8859-1 encoding so strings will be
416
- * returned in UTF-8 by default or ISO-8859-1 if the `:utf8` option for the
417
- * {RE2::Regexp} is set to `false` (any other encoding's behaviour is undefined).
423
+ * Note RE2 stores capturing group names as UTF-8, even if the {RE2::Regexp}
424
+ * sets the `:utf8` option to false so strings will always be returned in
425
+ * UTF-8.
418
426
  *
419
427
  * @return [Array<String>] an array of names of named capturing groups
420
428
  * @example
@@ -427,9 +435,7 @@ static VALUE re2_regexp_names(const VALUE self) {
427
435
  VALUE names = rb_ary_new2(groups.size());
428
436
 
429
437
  for (const auto& group : groups) {
430
- rb_ary_push(names,
431
- encoded_str_new(group.first.data(), group.first.size(),
432
- p->pattern->options().encoding()));
438
+ rb_ary_push(names, rb_utf8_str_new(group.first.data(), group.first.size()));
433
439
  }
434
440
 
435
441
  return names;
@@ -523,6 +529,8 @@ static VALUE re2_scanner_rewind(VALUE self) {
523
529
  }
524
530
 
525
531
  static VALUE re2_scanner_initialize_copy(VALUE self, VALUE other) {
532
+ if (self == other) return self;
533
+
526
534
  re2_scanner *self_c;
527
535
  re2_scanner *other_c = unwrap_re2_scanner(other);
528
536
 
@@ -646,20 +654,13 @@ static re2::StringPiece *re2_matchdata_find_match(VALUE idx, const VALUE self) {
646
654
 
647
655
  if (RB_INTEGER_TYPE_P(idx)) {
648
656
  id = NUM2INT(idx);
649
- } else if (SYMBOL_P(idx)) {
650
- const auto& groups = p->pattern->NamedCapturingGroups();
651
- auto search = groups.find(rb_id2name(SYM2ID(idx)));
652
-
653
- if (search != groups.end()) {
654
- id = search->second;
655
- } else {
656
- return nullptr;
657
- }
658
657
  } else {
659
- StringValue(idx);
658
+ if (!SYMBOL_P(idx)) {
659
+ StringValue(idx);
660
+ }
660
661
 
661
662
  const auto& groups = p->pattern->NamedCapturingGroups();
662
- auto search = groups.find(std::string(RSTRING_PTR(idx), RSTRING_LEN(idx)));
663
+ auto search = groups.find(group_name(idx));
663
664
 
664
665
  if (search != groups.end()) {
665
666
  id = search->second;
@@ -1004,11 +1005,8 @@ static VALUE re2_matchdata_aref(int argc, VALUE *argv, const VALUE self) {
1004
1005
  VALUE idx, rest;
1005
1006
  rb_scan_args(argc, argv, "11", &idx, &rest);
1006
1007
 
1007
- if (TYPE(idx) == T_STRING) {
1008
- return re2_matchdata_named_match(
1009
- std::string(RSTRING_PTR(idx), RSTRING_LEN(idx)), self);
1010
- } else if (SYMBOL_P(idx)) {
1011
- return re2_matchdata_named_match(rb_id2name(SYM2ID(idx)), self);
1008
+ if (TYPE(idx) == T_STRING || SYMBOL_P(idx)) {
1009
+ return re2_matchdata_named_match(group_name(idx), self);
1012
1010
  } else if (!NIL_P(rest) || !RB_INTEGER_TYPE_P(idx) || NUM2INT(idx) < 0) {
1013
1011
  return rb_ary_aref(argc, argv, re2_matchdata_to_a(self));
1014
1012
  } else {
@@ -1122,6 +1120,7 @@ static VALUE re2_matchdata_deconstruct(const VALUE self) {
1122
1120
  * Note RE2 only supports UTF-8 and ISO-8859-1 encoding so strings will be
1123
1121
  * returned in UTF-8 by default or ISO-8859-1 if the `:utf8` option for the
1124
1122
  * {RE2::Regexp} is set to `false` (any other encoding's behaviour is undefined).
1123
+ * Capturing group names will always be returned in UTF-8.
1125
1124
  *
1126
1125
  * @return [Hash] a hash of capturing group names to submatches
1127
1126
  * @param [Array<Symbol>, nil] keys an array of `Symbol` capturing group names
@@ -1151,7 +1150,7 @@ static VALUE re2_matchdata_deconstruct_keys(const VALUE self, const VALUE keys)
1151
1150
  if (NIL_P(keys)) {
1152
1151
  for (const auto& group : groups) {
1153
1152
  rb_hash_aset(capturing_groups,
1154
- ID2SYM(rb_intern2(group.first.data(), group.first.size())),
1153
+ rb_str_intern(rb_utf8_str_new(group.first.data(), group.first.size())),
1155
1154
  re2_matchdata_nth_match(group.second, self));
1156
1155
  }
1157
1156
  } else {
@@ -1161,8 +1160,7 @@ static VALUE re2_matchdata_deconstruct_keys(const VALUE self, const VALUE keys)
1161
1160
  for (int i = 0; i < RARRAY_LEN(keys); ++i) {
1162
1161
  VALUE key = rb_ary_entry(keys, i);
1163
1162
  Check_Type(key, T_SYMBOL);
1164
- const char *name = rb_id2name(SYM2ID(key));
1165
- auto search = groups.find(name);
1163
+ auto search = groups.find(group_name(key));
1166
1164
 
1167
1165
  if (search != groups.end()) {
1168
1166
  rb_hash_aset(capturing_groups, key, re2_matchdata_nth_match(search->second, self));
@@ -1182,6 +1180,7 @@ static VALUE re2_matchdata_deconstruct_keys(const VALUE self, const VALUE keys)
1182
1180
  * Note RE2 only supports UTF-8 and ISO-8859-1 encoding so strings will be
1183
1181
  * returned in UTF-8 by default or ISO-8859-1 if the `:utf8` option for the
1184
1182
  * {RE2::Regexp} is set to `false` (any other encoding's behaviour is undefined).
1183
+ * Capturing group names will always be returned in UTF-8.
1185
1184
  *
1186
1185
  * @overload named_captures
1187
1186
  * Returns a hash with string keys.
@@ -1219,12 +1218,9 @@ static VALUE re2_matchdata_named_captures(int argc, VALUE *argv, const VALUE sel
1219
1218
  VALUE result = rb_hash_new();
1220
1219
 
1221
1220
  for (const auto& group : groups) {
1222
- VALUE key;
1221
+ VALUE key = rb_utf8_str_new(group.first.data(), group.first.size());
1223
1222
  if (symbolize) {
1224
- key = ID2SYM(rb_intern2(group.first.data(), group.first.size()));
1225
- } else {
1226
- key = encoded_str_new(group.first.data(), group.first.size(),
1227
- p->pattern->options().encoding());
1223
+ key = rb_str_intern(key);
1228
1224
  }
1229
1225
  rb_hash_aset(result, key, re2_matchdata_nth_match(group.second, self));
1230
1226
  }
@@ -1237,9 +1233,9 @@ static VALUE re2_matchdata_named_captures(int argc, VALUE *argv, const VALUE sel
1237
1233
  * alphabetical order rather than definition order, as RE2 stores named groups
1238
1234
  * internally in a sorted map.
1239
1235
  *
1240
- * Note RE2 only supports UTF-8 and ISO-8859-1 encoding so strings will be
1241
- * returned in UTF-8 by default or ISO-8859-1 if the `:utf8` option for the
1242
- * {RE2::Regexp} is set to `false` (any other encoding's behaviour is undefined).
1236
+ * Note RE2 stores capturing group names as UTF-8, even if the {RE2::Regexp}
1237
+ * sets the `:utf8` option to false so strings will always be returned in
1238
+ * UTF-8.
1243
1239
  *
1244
1240
  * @return [Array<String>] an array of names of named capturing groups
1245
1241
  * @example
@@ -1276,12 +1272,8 @@ static VALUE re2_matchdata_values_at(int argc, VALUE *argv, const VALUE self) {
1276
1272
  for (int i = 0; i < argc; ++i) {
1277
1273
  VALUE idx = argv[i];
1278
1274
 
1279
- if (TYPE(idx) == T_STRING) {
1280
- rb_ary_push(result, re2_matchdata_named_match(
1281
- std::string(RSTRING_PTR(idx), RSTRING_LEN(idx)), self));
1282
- } else if (SYMBOL_P(idx)) {
1283
- rb_ary_push(result, re2_matchdata_named_match(
1284
- rb_id2name(SYM2ID(idx)), self));
1275
+ if (TYPE(idx) == T_STRING || SYMBOL_P(idx)) {
1276
+ rb_ary_push(result, re2_matchdata_named_match(group_name(idx), self));
1285
1277
  } else {
1286
1278
  rb_ary_push(result, re2_matchdata_nth_match(NUM2INT(idx), self));
1287
1279
  }
@@ -1291,6 +1283,8 @@ static VALUE re2_matchdata_values_at(int argc, VALUE *argv, const VALUE self) {
1291
1283
  }
1292
1284
 
1293
1285
  static VALUE re2_matchdata_initialize_copy(VALUE self, VALUE other) {
1286
+ if (self == other) return self;
1287
+
1294
1288
  re2_matchdata *self_m;
1295
1289
  re2_matchdata *other_m = unwrap_re2_matchdata(other);
1296
1290
 
@@ -1376,24 +1370,17 @@ static VALUE re2_regexp_initialize(int argc, VALUE *argv, VALUE self) {
1376
1370
 
1377
1371
  TypedData_Get_Struct(self, re2_pattern, &re2_regexp_data_type, p);
1378
1372
 
1379
- rb_check_frozen(self);
1380
-
1381
- if (p->pattern) {
1382
- delete p->pattern;
1383
- p->pattern = nullptr;
1384
- }
1373
+ RE2::Options re2_options;
1385
1374
 
1386
1375
  if (RTEST(options)) {
1387
- RE2::Options re2_options;
1388
1376
  parse_re2_options(&re2_options, options);
1389
-
1390
- p->pattern = new(std::nothrow) RE2(
1391
- re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)), re2_options);
1392
- } else {
1393
- p->pattern = new(std::nothrow) RE2(
1394
- re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)));
1395
1377
  }
1396
1378
 
1379
+ rb_check_frozen(self);
1380
+
1381
+ p->pattern = new(std::nothrow) RE2(
1382
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)), re2_options);
1383
+
1397
1384
  if (p->pattern == nullptr) {
1398
1385
  rb_raise(rb_eNoMemError, "not enough memory to allocate RE2 object");
1399
1386
  }
@@ -1778,9 +1765,9 @@ static VALUE re2_regexp_number_of_capturing_groups(const VALUE self) {
1778
1765
  /*
1779
1766
  * Returns a hash of names to capturing indices of groups.
1780
1767
  *
1781
- * Note RE2 only supports UTF-8 and ISO-8859-1 encoding so strings will be
1782
- * returned in UTF-8 by default or ISO-8859-1 if the `:utf8` option for the
1783
- * {RE2::Regexp} is set to `false` (any other encoding's behaviour is undefined).
1768
+ * Note RE2 stores capturing group names as UTF-8, even if the {RE2::Regexp}
1769
+ * sets the `:utf8` option to false so strings will always be returned in
1770
+ * UTF-8.
1784
1771
  *
1785
1772
  * @return [Hash] a hash of names to capturing indices
1786
1773
  */
@@ -1791,8 +1778,7 @@ static VALUE re2_regexp_named_capturing_groups(const VALUE self) {
1791
1778
 
1792
1779
  for (const auto& group : groups) {
1793
1780
  rb_hash_aset(capturing_groups,
1794
- encoded_str_new(group.first.data(), group.first.size(),
1795
- p->pattern->options().encoding()),
1781
+ rb_utf8_str_new(group.first.data(), group.first.size()),
1796
1782
  INT2FIX(group.second));
1797
1783
  }
1798
1784
 
@@ -2503,9 +2489,12 @@ static VALUE re2_set_initialize(int argc, VALUE *argv, VALUE self) {
2503
2489
 
2504
2490
  rb_check_frozen(self);
2505
2491
 
2492
+ /* Prevent re-initialisation: #match releases the GVL while holding a
2493
+ * pointer to s->set, so replacing s->set from another thread would free
2494
+ * the object out from under a concurrent match.
2495
+ */
2506
2496
  if (s->set) {
2507
- delete s->set;
2508
- s->set = nullptr;
2497
+ rb_raise(rb_eTypeError, "already initialized RE2::Set");
2509
2498
  }
2510
2499
 
2511
2500
  s->set = new(std::nothrow) RE2::Set(re2_options, re2_anchor);
@@ -2570,6 +2559,7 @@ static VALUE re2_set_compile(VALUE self) {
2570
2559
  bool compiled = s->set->Compile();
2571
2560
 
2572
2561
  if (compiled) {
2562
+ s->compiled = true;
2573
2563
  rb_obj_freeze(self);
2574
2564
  }
2575
2565
 
@@ -2687,6 +2677,11 @@ static VALUE re2_set_match(int argc, VALUE *argv, const VALUE self) {
2687
2677
 
2688
2678
  if (raise_exception) {
2689
2679
  #ifdef HAVE_ERROR_INFO_ARGUMENT
2680
+ /* RE2::Set::Match dereferences a null program after a failed Compile. */
2681
+ if (!s->compiled) {
2682
+ rb_raise(re2_eSetMatchError, "#match must not be called before #compile");
2683
+ }
2684
+
2690
2685
  RE2::Set::ErrorInfo e;
2691
2686
  nogvl_set_match_arg arg;
2692
2687
  arg.set = s->set;
@@ -2729,6 +2724,10 @@ static VALUE re2_set_match(int argc, VALUE *argv, const VALUE self) {
2729
2724
  rb_raise(re2_eSetUnsupportedError, "current version of RE2::Set::Match() does not output error information, :exception option can only be set to false");
2730
2725
  #endif
2731
2726
  } else {
2727
+ if (!s->compiled) {
2728
+ return rb_ary_new();
2729
+ }
2730
+
2732
2731
  nogvl_set_match_arg arg;
2733
2732
  arg.set = s->set;
2734
2733
  arg.text = re2::StringPiece(RSTRING_PTR(str), RSTRING_LEN(str));
data/lib/3.1/re2.so CHANGED
Binary file
data/lib/3.2/re2.so CHANGED
Binary file
data/lib/3.3/re2.so CHANGED
Binary file
data/lib/3.4/re2.so CHANGED
Binary file
data/lib/4.0/re2.so CHANGED
Binary file
data/lib/re2/version.rb CHANGED
@@ -10,5 +10,5 @@
10
10
 
11
11
 
12
12
  module RE2
13
- VERSION = "2.27.0"
13
+ VERSION = "2.28.0"
14
14
  end
data/re2.gemspec CHANGED
@@ -41,7 +41,7 @@ Gem::Specification.new do |s|
41
41
  "spec/re2/scanner_spec.rb"
42
42
  ]
43
43
  s.add_development_dependency("rake-compiler", "~> 1.3.1")
44
- s.add_development_dependency("rake-compiler-dock", "~> 1.11.0")
44
+ s.add_development_dependency("rake-compiler-dock", "~> 1.12.0")
45
45
  s.add_development_dependency("rspec", "~> 3.2")
46
46
  s.add_runtime_dependency("mini_portile2", "~> 2.8.9") # keep version in sync with extconf.rb
47
47
  end
@@ -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
 
@@ -822,12 +873,33 @@ RSpec.describe RE2::MatchData do
822
873
  expect(md.named_captures).to eq("empty" => "", "word" => "bob")
823
874
  end
824
875
 
876
+ it "returns UTF-8 names even for Latin-1 patterns" do
877
+ md = RE2::Regexp.new('(?P<numbers>\d+)', utf8: false).match('123')
878
+ key = md.named_captures.keys.first
879
+
880
+ expect(key.encoding).to eq(Encoding::UTF_8)
881
+ end
882
+
825
883
  it "returns symbol keys when symbolize_names: true" do
826
884
  md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
827
885
 
828
886
  expect(md.named_captures(symbolize_names: true)).to eq(numbers: "123", letters: "abc")
829
887
  end
830
888
 
889
+ it "returns garbage-collectable symbol keys when symbolize_names: true" do
890
+ md = RE2::Regexp.new('(?P<collectable_named_capture>\d+)').match('123')
891
+ key = md.named_captures(symbolize_names: true).keys.first
892
+
893
+ expect(ObjectSpace.each_object(Symbol)).to include(key)
894
+ end
895
+
896
+ it "correctly encodes non-ASCII capturing group names as symbols" do
897
+ re = RE2::Regexp.new('(?P<café>\d+)', log_errors: false)
898
+ skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
899
+
900
+ expect(re.match('123').named_captures(symbolize_names: true)).to eq(café: "123")
901
+ end
902
+
831
903
  it "returns string keys when symbolize_names: false" do
832
904
  md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
833
905
 
@@ -858,10 +930,10 @@ RSpec.describe RE2::MatchData do
858
930
  expect(md.names.first.encoding).to eq(Encoding::UTF_8)
859
931
  end
860
932
 
861
- it "returns ISO-8859-1 strings if the pattern is not UTF-8" do
933
+ it "returns UTF-8 strings if the pattern is not UTF-8" do
862
934
  md = RE2::Regexp.new('(?P<numbers>\d+)', utf8: false).match('123')
863
935
 
864
- expect(md.names.first.encoding).to eq(Encoding::ISO_8859_1)
936
+ expect(md.names.first.encoding).to eq(Encoding::UTF_8)
865
937
  end
866
938
 
867
939
  it "raises an error when called on an uninitialized object" do
@@ -876,6 +948,22 @@ RSpec.describe RE2::MatchData do
876
948
  expect(md.deconstruct_keys(nil)).to eq(numbers: '123', letters: 'abc')
877
949
  end
878
950
 
951
+ it "returns garbage-collectable symbol keys if given nil" do
952
+ md = RE2::Regexp.new('(?P<collectable_deconstructed_key>\d+)').match('123')
953
+ key = md.deconstruct_keys(nil).keys.first
954
+
955
+ expect(ObjectSpace.each_object(Symbol)).to include(key)
956
+ end
957
+
958
+ it "returns UTF-8 named captures for a Latin-1 pattern if given nil" do
959
+ re = RE2::Regexp.new('(?P<café>\d+) (?P<letters>[a-zA-Z]+)'.encode("ISO-8859-1"), utf8: false, log_errors: false)
960
+ skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
961
+
962
+ md = re.match('123 abc')
963
+
964
+ expect(md.deconstruct_keys(nil)).to eq(café: '123', letters: 'abc')
965
+ end
966
+
879
967
  it "returns only named captures if given names" do
880
968
  md = RE2::Regexp.new('(?P<numbers>\d+) (?P<letters>[a-zA-Z]+)').match('123 abc')
881
969
 
@@ -49,6 +49,13 @@ RSpec.describe RE2::Regexp do
49
49
 
50
50
  expect { re.send(:initialize, 'bar') }.to raise_error(FrozenError)
51
51
  end
52
+
53
+ it "cannot be re-initialized while parsing options" do
54
+ re = described_class.allocate
55
+ options = Hash.new { |_, key| re.send(:initialize, 'bar') if key == :utf8 }
56
+
57
+ expect { re.send(:initialize, 'woo', options) }.to raise_error(FrozenError)
58
+ end
52
59
  end
53
60
 
54
61
  describe "#dup" do
@@ -1048,6 +1055,13 @@ RSpec.describe RE2::Regexp do
1048
1055
  expect(RE2::Regexp.new('???', log_errors: false).named_capturing_groups).to be_empty
1049
1056
  end
1050
1057
 
1058
+ it "returns names as UTF-8 even if the pattern is Latin-1" do
1059
+ groups = RE2::Regexp.new('(?P<bob>a)', utf8: false).named_capturing_groups
1060
+ key = groups.keys.first
1061
+
1062
+ expect(key.encoding).to eq(Encoding::UTF_8)
1063
+ end
1064
+
1051
1065
  it "raises an error when called on an uninitialized object" do
1052
1066
  expect { described_class.allocate.named_capturing_groups }.to raise_error(TypeError, /uninitialized RE2::Regexp/)
1053
1067
  end
@@ -1071,15 +1085,17 @@ RSpec.describe RE2::Regexp do
1071
1085
  end
1072
1086
 
1073
1087
  it "returns UTF-8 strings if the pattern is UTF-8" do
1074
- names = RE2::Regexp.new('(?P<bob>a)').names
1088
+ re = RE2::Regexp.new('(?P<café>\d+)', log_errors: false)
1089
+ skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
1075
1090
 
1076
- expect(names.first.encoding).to eq(Encoding::UTF_8)
1091
+ expect(re.names.first.encoding).to eq(Encoding::UTF_8)
1077
1092
  end
1078
1093
 
1079
- it "returns ISO-8859-1 strings if the pattern is not UTF-8" do
1080
- names = RE2::Regexp.new('(?P<bob>a)', utf8: false).names
1094
+ it "returns UTF-8 strings if the pattern is not UTF-8" do
1095
+ re = RE2::Regexp.new('(?P<café>a)'.encode("ISO-8859-1"), utf8: false, log_errors: false)
1096
+ skip "Underlying RE2 does not support non-ASCII capturing group names" unless re.ok?
1081
1097
 
1082
- expect(names.first.encoding).to eq(Encoding::ISO_8859_1)
1098
+ expect(re.names).to contain_exactly("café")
1083
1099
  end
1084
1100
 
1085
1101
  it "raises an error when called on an uninitialized object" do
@@ -106,6 +106,15 @@ RSpec.describe RE2::Scanner do
106
106
  end
107
107
  end
108
108
 
109
+ describe "#initialize_copy" do
110
+ it "is a no-op when the source is the same object" do
111
+ scanner = RE2::Regexp.new('(\w+)').scan("foo bar")
112
+ scanner.send(:initialize_copy, scanner)
113
+
114
+ expect(scanner.scan).to eq(["foo"])
115
+ end
116
+ end
117
+
109
118
  describe "#scan" do
110
119
  it "returns the next array of matches", :aggregate_failures do
111
120
  r = RE2::Regexp.new('(\w+)')
data/spec/re2/set_spec.rb CHANGED
@@ -49,6 +49,13 @@ RSpec.describe RE2::Set do
49
49
  "anchor should be one of: :unanchored, :anchor_start, :anchor_both"
50
50
  )
51
51
  end
52
+
53
+ it "cannot be re-initialized before compilation" do
54
+ set = RE2::Set.new
55
+ set.add("abc")
56
+
57
+ expect { set.send(:initialize) }.to raise_error(TypeError, /already initialized RE2::Set/)
58
+ end
52
59
  end
53
60
 
54
61
  describe "#dup" do
@@ -212,6 +219,30 @@ RSpec.describe RE2::Set do
212
219
  end
213
220
  end
214
221
 
222
+ it "raises an error if called after a failed #compile" do
223
+ skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
224
+
225
+ set = RE2::Set.new(:unanchored, max_mem: 1, log_errors: false)
226
+ set.add("a{1000}b{1000}c{1000}")
227
+
228
+ silence_stderr do
229
+ set.compile
230
+
231
+ expect { set.match("abc") }.to raise_error(RE2::Set::MatchError, "#match must not be called before #compile")
232
+ end
233
+ end
234
+
235
+ it "returns an empty array if called after a failed #compile when :exception is false" do
236
+ set = RE2::Set.new(:unanchored, max_mem: 1, log_errors: false)
237
+ set.add("a{1000}b{1000}c{1000}")
238
+
239
+ silence_stderr do
240
+ set.compile
241
+
242
+ expect(set.match("abc", exception: false)).to be_empty
243
+ end
244
+ end
245
+
215
246
  it "raises an error if :exception is true and RE2 does not support it" do
216
247
  skip "Underlying RE2::Set::Match outputs error information" if RE2::Set.match_raises_errors?
217
248
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: re2
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.27.0
4
+ version: 2.28.0
5
5
  platform: arm-linux-gnu
6
6
  authors:
7
7
  - Paul Mucur
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.11.0
33
+ version: 1.12.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.11.0
40
+ version: 1.12.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: 3.3.22
110
110
  requirements: []
111
- rubygems_version: 4.0.3
111
+ rubygems_version: 4.0.6
112
112
  specification_version: 4
113
113
  summary: Ruby bindings to RE2.
114
114
  test_files: