re2 2.6.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3a48d6f5934da3afa8da05d7ed2dc3aae1aa69cb9b7507c91053a8fec672b9e
4
- data.tar.gz: 9853896f0458f03ac39ea7a636211d423b16b33438b20c3eeae9780ce45f76d7
3
+ metadata.gz: a8d6ed54b0c51625b38158c82813c6b38f0151a637c224e6b6450ea2ebc9e00c
4
+ data.tar.gz: 9550936b7959af3654b58efdc07be5f5c38c3a41a4a657382878f06020f9081e
5
5
  SHA512:
6
- metadata.gz: 59c5a3a9b16992364c3f17c6a546d45546620cb81add16eaeb584b98068cdc2aac3959a88bc87c1aa00fa18b909716d32eda04d0727695ef486fe2bacee9a899
7
- data.tar.gz: 80f1f96454bb07d1495b02a378dfb04eacc64a9cd014386429bda129924d1043af800e31c26bc07710320aa786d7e51240640fc24bd232556649defeadc24a24
6
+ metadata.gz: f9b91c79e3efea56df671b887740c25e09e1d09e12383b6a3071c6bfcfccc01da3ea26431b34c6794fcf710bce17a71459f389911770ea06601048cc038c508f
7
+ data.tar.gz: a0f0d0971fa7074d5eccfca90bcdf058fcc02584f87c59531105cf04f1be872b97b213a4e17a5637e560b723f061ca95b2b7f4c782ce13a34234dfd134c3793e
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --require spec_helper
3
+ --format documentation
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.6.0
9
+ **Current version:** 2.7.0
10
10
  **Bundled RE2 version:** libre2.11 (2023-11-01)
11
11
 
12
12
  ```ruby
@@ -279,18 +279,18 @@ Where possible, a pre-compiled native gem will be provided for the following pla
279
279
  SHA256 checksums are included in the [release notes](https://github.com/mudge/re2/releases) for each version and can be checked with `sha256sum`, e.g.
280
280
 
281
281
  ```console
282
- $ gem fetch re2 -v 2.5.0
283
- Fetching re2-2.5.0-arm64-darwin.gem
284
- Downloaded re2-2.5.0-arm64-darwin
285
- $ sha256sum re2-2.5.0-arm64-darwin.gem
286
- 4b20c4539a12787102b22012e678968af23f87e35f88843744835bd13ac9f6bc re2-2.5.0-arm64-darwin.gem
282
+ $ gem fetch re2 -v 2.6.0
283
+ Fetching re2-2.6.0-arm64-darwin.gem
284
+ Downloaded re2-2.6.0-arm64-darwin
285
+ $ sha256sum re2-2.6.0-arm64-darwin.gem
286
+ ba6fda7a29cd16179d5401c1b4917ba204c92e5ca9d25df80d840ed76fca439f re2-2.6.0-arm64-darwin.gem
287
287
  ```
288
288
 
289
289
  [GPG](https://www.gnupg.org/) signatures are attached to each release (the assets ending in `.sig`) and can be verified if you import [our signing key `0x39AC3530070E0F75`](https://mudge.name/39AC3530070E0F75.asc) (or fetch it from a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key 0x39AC3530070E0F75`):
290
290
 
291
291
  ```console
292
- $ gpg --verify re2-2.5.0-arm64-darwin.gem.sig re2-2.5.0-arm64-darwin.gem
293
- gpg: Signature made Fri 15 Dec 2023 12:58:58 GMT
292
+ $ gpg --verify re2-2.6.0-arm64-darwin.gem.sig re2-2.6.0-arm64-darwin.gem
293
+ gpg: Signature made Wed 27 Dec 19:26:53 2023 GMT
294
294
  gpg: using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75
295
295
  gpg: Good signature from "Paul Mucur <mudge@mudge.name>" [unknown]
296
296
  gpg: aka "Paul Mucur <paul@ghostcassette.com>" [unknown]
@@ -373,6 +373,8 @@ Alternatively, you can set the `RE2_USE_SYSTEM_LIBRARIES` environment variable i
373
373
  * Thanks to [Jean Boussier](https://github.com/byroot) for contributing the
374
374
  switch to Ruby's `TypedData` API and the resulting garbage collection
375
375
  improvements in 2.4.0.
376
+ * Thanks to [Manuel Jacob](https://github.com/manueljacob) for reporting a bug
377
+ when passing strings with null bytes.
376
378
 
377
379
  ## Contact
378
380
 
data/ext/re2/re2.cc CHANGED
@@ -336,7 +336,8 @@ static VALUE re2_scanner_rewind(VALUE self) {
336
336
  TypedData_Get_Struct(self, re2_scanner, &re2_scanner_data_type, c);
337
337
 
338
338
  delete c->input;
339
- c->input = new(std::nothrow) re2::StringPiece(RSTRING_PTR(c->text));
339
+ c->input = new(std::nothrow) re2::StringPiece(
340
+ RSTRING_PTR(c->text), RSTRING_LEN(c->text));
340
341
  c->eof = false;
341
342
 
342
343
  return self;
@@ -425,10 +426,20 @@ static re2::StringPiece *re2_matchdata_find_match(VALUE idx, const VALUE self) {
425
426
 
426
427
  if (FIXNUM_P(idx)) {
427
428
  id = FIX2INT(idx);
429
+ } else if (SYMBOL_P(idx)) {
430
+ const std::map<std::string, int>& groups = p->pattern->NamedCapturingGroups();
431
+ std::map<std::string, int>::const_iterator search = groups.find(rb_id2name(SYM2ID(idx)));
432
+
433
+ if (search != groups.end()) {
434
+ id = search->second;
435
+ } else {
436
+ return NULL;
437
+ }
428
438
  } else {
429
- const char *name = SYMBOL_P(idx) ? rb_id2name(SYM2ID(idx)) : StringValuePtr(idx);
439
+ StringValue(idx);
440
+
430
441
  const std::map<std::string, int>& groups = p->pattern->NamedCapturingGroups();
431
- std::map<std::string, int>::const_iterator search = groups.find(name);
442
+ std::map<std::string, int>::const_iterator search = groups.find(std::string(RSTRING_PTR(idx), RSTRING_LEN(idx)));
432
443
 
433
444
  if (search != groups.end()) {
434
445
  id = search->second;
@@ -611,7 +622,7 @@ static VALUE re2_matchdata_nth_match(int nth, const VALUE self) {
611
622
  }
612
623
  }
613
624
 
614
- static VALUE re2_matchdata_named_match(const char* name, const VALUE self) {
625
+ static VALUE re2_matchdata_named_match(const std::string &name, const VALUE self) {
615
626
  re2_matchdata *m;
616
627
  re2_pattern *p;
617
628
 
@@ -678,7 +689,8 @@ static VALUE re2_matchdata_aref(int argc, VALUE *argv, const VALUE self) {
678
689
  rb_scan_args(argc, argv, "11", &idx, &rest);
679
690
 
680
691
  if (TYPE(idx) == T_STRING) {
681
- return re2_matchdata_named_match(RSTRING_PTR(idx), self);
692
+ return re2_matchdata_named_match(
693
+ std::string(RSTRING_PTR(idx), RSTRING_LEN(idx)), self);
682
694
  } else if (SYMBOL_P(idx)) {
683
695
  return re2_matchdata_named_match(rb_id2name(SYM2ID(idx)), self);
684
696
  } else if (!NIL_P(rest) || !FIXNUM_P(idx) || FIX2INT(idx) < 0) {
@@ -731,7 +743,8 @@ static VALUE re2_matchdata_inspect(const VALUE self) {
731
743
  if (match == Qnil) {
732
744
  output << "nil";
733
745
  } else {
734
- output << "\"" << RSTRING_PTR(match) << "\"";
746
+ output << "\"" << re2::StringPiece(RSTRING_PTR(match),
747
+ RSTRING_LEN(match)) << "\"";
735
748
  }
736
749
  }
737
750
 
@@ -910,9 +923,11 @@ static VALUE re2_regexp_initialize(int argc, VALUE *argv, VALUE self) {
910
923
  RE2::Options re2_options;
911
924
  parse_re2_options(&re2_options, options);
912
925
 
913
- p->pattern = new(std::nothrow) RE2(RSTRING_PTR(pattern), re2_options);
926
+ p->pattern = new(std::nothrow) RE2(
927
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)), re2_options);
914
928
  } else {
915
- p->pattern = new(std::nothrow) RE2(RSTRING_PTR(pattern));
929
+ p->pattern = new(std::nothrow) RE2(
930
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)));
916
931
  }
917
932
 
918
933
  if (p->pattern == 0) {
@@ -1501,11 +1516,13 @@ static VALUE re2_regexp_match(int argc, VALUE *argv, const VALUE self) {
1501
1516
 
1502
1517
  if (n == 0) {
1503
1518
  #ifdef HAVE_ENDPOS_ARGUMENT
1504
- bool matched = p->pattern->Match(RSTRING_PTR(text), startpos,
1505
- endpos, anchor, 0, 0);
1519
+ bool matched = p->pattern->Match(
1520
+ re2::StringPiece(RSTRING_PTR(text), RSTRING_LEN(text)),
1521
+ startpos, endpos, anchor, 0, 0);
1506
1522
  #else
1507
- bool matched = p->pattern->Match(RSTRING_PTR(text), startpos, anchor,
1508
- 0, 0);
1523
+ bool matched = p->pattern->Match(
1524
+ re2::StringPiece(RSTRING_PTR(text), RSTRING_LEN(text)),
1525
+ startpos, anchor, 0, 0);
1509
1526
  #endif
1510
1527
  return BOOL2RUBY(matched);
1511
1528
  } else {
@@ -1529,11 +1546,13 @@ static VALUE re2_regexp_match(int argc, VALUE *argv, const VALUE self) {
1529
1546
  m->number_of_matches = n;
1530
1547
 
1531
1548
  #ifdef HAVE_ENDPOS_ARGUMENT
1532
- bool matched = p->pattern->Match(RSTRING_PTR(m->text), startpos,
1533
- endpos, anchor, m->matches, n);
1549
+ bool matched = p->pattern->Match(
1550
+ re2::StringPiece(RSTRING_PTR(m->text), RSTRING_LEN(m->text)),
1551
+ startpos, endpos, anchor, m->matches, n);
1534
1552
  #else
1535
- bool matched = p->pattern->Match(RSTRING_PTR(m->text), startpos,
1536
- anchor, m->matches, n);
1553
+ bool matched = p->pattern->Match(
1554
+ re2::StringPiece(RSTRING_PTR(m->text), RSTRING_LEN(m->text)),
1555
+ startpos, anchor, m->matches, n);
1537
1556
  #endif
1538
1557
  if (matched) {
1539
1558
  return matchdata;
@@ -1559,7 +1578,8 @@ static VALUE re2_regexp_match_p(const VALUE self, VALUE text) {
1559
1578
 
1560
1579
  TypedData_Get_Struct(self, re2_pattern, &re2_regexp_data_type, p);
1561
1580
 
1562
- return BOOL2RUBY(RE2::PartialMatch(RSTRING_PTR(text), *p->pattern));
1581
+ return BOOL2RUBY(RE2::PartialMatch(
1582
+ re2::StringPiece(RSTRING_PTR(text), RSTRING_LEN(text)), *p->pattern));
1563
1583
  }
1564
1584
 
1565
1585
  /*
@@ -1578,7 +1598,8 @@ static VALUE re2_regexp_full_match_p(const VALUE self, VALUE text) {
1578
1598
 
1579
1599
  TypedData_Get_Struct(self, re2_pattern, &re2_regexp_data_type, p);
1580
1600
 
1581
- return BOOL2RUBY(RE2::FullMatch(RSTRING_PTR(text), *p->pattern));
1601
+ return BOOL2RUBY(RE2::FullMatch(
1602
+ re2::StringPiece(RSTRING_PTR(text), RSTRING_LEN(text)), *p->pattern));
1582
1603
  }
1583
1604
 
1584
1605
  /*
@@ -1604,7 +1625,8 @@ static VALUE re2_regexp_scan(const VALUE self, VALUE text) {
1604
1625
  VALUE scanner = rb_class_new_instance(0, 0, re2_cScanner);
1605
1626
  TypedData_Get_Struct(scanner, re2_scanner, &re2_scanner_data_type, c);
1606
1627
 
1607
- c->input = new(std::nothrow) re2::StringPiece(RSTRING_PTR(text));
1628
+ c->input = new(std::nothrow) re2::StringPiece(
1629
+ RSTRING_PTR(text), RSTRING_LEN(text));
1608
1630
  RB_OBJ_WRITE(scanner, &c->regexp, self);
1609
1631
  RB_OBJ_WRITE(scanner, &c->text, text);
1610
1632
 
@@ -1669,12 +1691,14 @@ static VALUE re2_Replace(VALUE, VALUE str, VALUE pattern,
1669
1691
  /* Take a copy of str so it can be modified in-place by
1670
1692
  * RE2::Replace.
1671
1693
  */
1672
- std::string str_as_string(StringValuePtr(str));
1694
+ StringValue(str);
1695
+ std::string str_as_string(RSTRING_PTR(str), RSTRING_LEN(str));
1673
1696
 
1674
1697
  /* Do the replacement. */
1675
1698
  if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
1676
1699
  TypedData_Get_Struct(pattern, re2_pattern, &re2_regexp_data_type, p);
1677
- RE2::Replace(&str_as_string, *p->pattern, RSTRING_PTR(rewrite));
1700
+ RE2::Replace(&str_as_string, *p->pattern,
1701
+ re2::StringPiece(RSTRING_PTR(rewrite), RSTRING_LEN(rewrite)));
1678
1702
 
1679
1703
  return encoded_str_new(str_as_string.data(), str_as_string.size(),
1680
1704
  p->pattern->options().encoding());
@@ -1682,7 +1706,9 @@ static VALUE re2_Replace(VALUE, VALUE str, VALUE pattern,
1682
1706
  /* Ensure pattern is a string. */
1683
1707
  StringValue(pattern);
1684
1708
 
1685
- RE2::Replace(&str_as_string, RSTRING_PTR(pattern), RSTRING_PTR(rewrite));
1709
+ RE2::Replace(&str_as_string,
1710
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)),
1711
+ re2::StringPiece(RSTRING_PTR(rewrite), RSTRING_LEN(rewrite)));
1686
1712
 
1687
1713
  return encoded_str_new(str_as_string.data(), str_as_string.size(), RE2::Options::EncodingUTF8);
1688
1714
  }
@@ -1717,12 +1743,14 @@ static VALUE re2_GlobalReplace(VALUE, VALUE str, VALUE pattern,
1717
1743
  * RE2::GlobalReplace.
1718
1744
  */
1719
1745
  re2_pattern *p;
1720
- std::string str_as_string(StringValuePtr(str));
1746
+ StringValue(str);
1747
+ std::string str_as_string(RSTRING_PTR(str), RSTRING_LEN(str));
1721
1748
 
1722
1749
  /* Do the replacement. */
1723
1750
  if (rb_obj_is_kind_of(pattern, re2_cRegexp)) {
1724
1751
  TypedData_Get_Struct(pattern, re2_pattern, &re2_regexp_data_type, p);
1725
- RE2::GlobalReplace(&str_as_string, *p->pattern, RSTRING_PTR(rewrite));
1752
+ RE2::GlobalReplace(&str_as_string, *p->pattern,
1753
+ re2::StringPiece(RSTRING_PTR(rewrite), RSTRING_LEN(rewrite)));
1726
1754
 
1727
1755
  return encoded_str_new(str_as_string.data(), str_as_string.size(),
1728
1756
  p->pattern->options().encoding());
@@ -1730,8 +1758,9 @@ static VALUE re2_GlobalReplace(VALUE, VALUE str, VALUE pattern,
1730
1758
  /* Ensure pattern is a string. */
1731
1759
  StringValue(pattern);
1732
1760
 
1733
- RE2::GlobalReplace(&str_as_string, RSTRING_PTR(pattern),
1734
- RSTRING_PTR(rewrite));
1761
+ RE2::GlobalReplace(&str_as_string,
1762
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)),
1763
+ re2::StringPiece(RSTRING_PTR(rewrite), RSTRING_LEN(rewrite)));
1735
1764
 
1736
1765
  return encoded_str_new(str_as_string.data(), str_as_string.size(), RE2::Options::EncodingUTF8);
1737
1766
  }
@@ -1753,7 +1782,8 @@ static VALUE re2_GlobalReplace(VALUE, VALUE str, VALUE pattern,
1753
1782
  static VALUE re2_QuoteMeta(VALUE, VALUE unquoted) {
1754
1783
  StringValue(unquoted);
1755
1784
 
1756
- std::string quoted_string = RE2::QuoteMeta(RSTRING_PTR(unquoted));
1785
+ std::string quoted_string = RE2::QuoteMeta(
1786
+ re2::StringPiece(RSTRING_PTR(unquoted), RSTRING_LEN(unquoted)));
1757
1787
 
1758
1788
  return rb_str_new(quoted_string.data(), quoted_string.size());
1759
1789
  }
@@ -1902,7 +1932,8 @@ static VALUE re2_set_add(VALUE self, VALUE pattern) {
1902
1932
 
1903
1933
  {
1904
1934
  std::string err;
1905
- index = s->set->Add(RSTRING_PTR(pattern), &err);
1935
+ index = s->set->Add(
1936
+ re2::StringPiece(RSTRING_PTR(pattern), RSTRING_LEN(pattern)), &err);
1906
1937
  strlcpy(msg, err.c_str(), sizeof(msg));
1907
1938
  }
1908
1939
 
@@ -2009,7 +2040,8 @@ static VALUE re2_set_match(int argc, VALUE *argv, const VALUE self) {
2009
2040
  if (raise_exception) {
2010
2041
  #ifdef HAVE_ERROR_INFO_ARGUMENT
2011
2042
  RE2::Set::ErrorInfo e;
2012
- bool match_failed = !s->set->Match(RSTRING_PTR(str), &v, &e);
2043
+ bool match_failed = !s->set->Match(
2044
+ re2::StringPiece(RSTRING_PTR(str), RSTRING_LEN(str)), &v, &e);
2013
2045
  VALUE result = rb_ary_new2(v.size());
2014
2046
 
2015
2047
  if (match_failed) {
@@ -2036,7 +2068,8 @@ static VALUE re2_set_match(int argc, VALUE *argv, const VALUE self) {
2036
2068
  rb_raise(re2_eSetUnsupportedError, "current version of RE2::Set::Match() does not output error information, :exception option can only be set to false");
2037
2069
  #endif
2038
2070
  } else {
2039
- bool matched = s->set->Match(RSTRING_PTR(str), &v);
2071
+ bool matched = s->set->Match(
2072
+ re2::StringPiece(RSTRING_PTR(str), RSTRING_LEN(str)), &v);
2040
2073
  VALUE result = rb_ary_new2(v.size());
2041
2074
 
2042
2075
  if (matched) {
data/lib/re2/version.rb CHANGED
@@ -10,5 +10,5 @@
10
10
 
11
11
 
12
12
  module RE2
13
- VERSION = "2.6.0"
13
+ VERSION = "2.7.0"
14
14
  end
data/spec/kernel_spec.rb CHANGED
@@ -10,6 +10,12 @@ RSpec.describe Kernel do
10
10
  expect(re).not_to be_case_sensitive
11
11
  end
12
12
 
13
+ it "accepts patterns containing null bytes" do
14
+ re = RE2("a\0b")
15
+
16
+ expect(re.pattern).to eq("a\0b")
17
+ end
18
+
13
19
  it "raises an error if given an inappropriate type" do
14
20
  expect { RE2(nil) }.to raise_error(TypeError)
15
21
  end
@@ -190,7 +190,7 @@ RSpec.describe RE2::MatchData do
190
190
  describe "#inspect" do
191
191
  it "returns a text representation of the object and indices" do
192
192
  md = RE2::Regexp.new('(\d+) (\d+)').match("1234 56")
193
-
193
+
194
194
  expect(md.inspect).to eq('#<RE2::MatchData "1234 56" 1:"1234" 2:"56">')
195
195
  end
196
196
 
@@ -199,6 +199,12 @@ RSpec.describe RE2::MatchData do
199
199
 
200
200
  expect(md.inspect).to eq('#<RE2::MatchData "1234 " 1:"1234" 2:nil>')
201
201
  end
202
+
203
+ it "supports matches with null bytes" do
204
+ md = RE2::Regexp.new("(\\w\0\\w) (\\w\0\\w)").match("a\0b c\0d")
205
+
206
+ expect(md.inspect).to eq("#<RE2::MatchData \"a\0b c\0d\" 1:\"a\0b\" 2:\"c\0d\">")
207
+ end
202
208
  end
203
209
 
204
210
  describe "#to_s" do
@@ -239,6 +245,12 @@ RSpec.describe RE2::MatchData do
239
245
  expect(md.string[md.begin(:foo)..-1]).to eq('foobar')
240
246
  end
241
247
 
248
+ it "returns the offset of the start of a match by something that can be coerced to a String" do
249
+ md = RE2::Regexp.new('(?P<foo>fo{2})').match('a foobar')
250
+
251
+ expect(md.string[md.begin(StringLike.new("foo"))..-1]).to eq('foobar')
252
+ end
253
+
242
254
  it "returns the offset despite multibyte characters" do
243
255
  md = RE2::Regexp.new('(Ruby)').match('I ♥ Ruby')
244
256
 
@@ -268,6 +280,12 @@ RSpec.describe RE2::MatchData do
268
280
 
269
281
  expect(md.begin(:foo)).to be_nil
270
282
  end
283
+
284
+ it "raises a type error if given an invalid name or number" do
285
+ md = RE2::Regexp.new('(\d)').match('123')
286
+
287
+ expect { md.begin(nil) }.to raise_error(TypeError)
288
+ end
271
289
  end
272
290
 
273
291
  describe "#end" do
@@ -289,6 +307,12 @@ RSpec.describe RE2::MatchData do
289
307
  expect(md.string[0...md.end(:foo)]).to eq('a foo')
290
308
  end
291
309
 
310
+ it "returns the offset of a match by something that can be coerced to a String" do
311
+ md = RE2::Regexp.new('(?P<foo>fo{2})').match('a foobar')
312
+
313
+ expect(md.string[0...md.end(StringLike.new("foo"))]).to eq('a foo')
314
+ end
315
+
292
316
  it "returns the offset despite multibyte characters" do
293
317
  md = RE2::Regexp.new('(Ruby)').match('I ♥ Ruby')
294
318
 
@@ -318,6 +342,12 @@ RSpec.describe RE2::MatchData do
318
342
 
319
343
  expect(md.end(:foo)).to be_nil
320
344
  end
345
+
346
+ it "raises a type error if given an invalid name or number" do
347
+ md = RE2::Regexp.new('(\d)').match('123')
348
+
349
+ expect { md.end(nil) }.to raise_error(TypeError)
350
+ end
321
351
  end
322
352
 
323
353
  describe "#deconstruct" do
@@ -12,6 +12,12 @@ RSpec.describe RE2::Regexp do
12
12
  expect(re).to be_a(RE2::Regexp)
13
13
  end
14
14
 
15
+ it "accepts patterns containing null bytes" do
16
+ re = RE2::Regexp.new("a\0b")
17
+
18
+ expect(re.pattern).to eq("a\0b")
19
+ end
20
+
15
21
  it "raises an error if given an inappropriate type" do
16
22
  expect { RE2::Regexp.new(nil) }.to raise_error(TypeError)
17
23
  end
@@ -41,6 +47,12 @@ RSpec.describe RE2::Regexp do
41
47
  expect(re).to be_a(RE2::Regexp)
42
48
  end
43
49
 
50
+ it "accepts patterns containing null bytes" do
51
+ re = RE2::Regexp.compile("a\0b")
52
+
53
+ expect(re.pattern).to eq("a\0b")
54
+ end
55
+
44
56
  it "raises an error if given an inappropriate type" do
45
57
  expect { RE2::Regexp.compile(nil) }.to raise_error(TypeError)
46
58
  end
@@ -339,6 +351,12 @@ RSpec.describe RE2::Regexp do
339
351
  expect(re.match("My name is Alice Bloggs")).to eq(true)
340
352
  end
341
353
 
354
+ it "supports matching against text containing null bytes" do
355
+ re = RE2::Regexp.new("a\0b")
356
+
357
+ expect(re.match("a\0b")).to eq(true)
358
+ end
359
+
342
360
  it "returns nil if the text does not match the pattern" do
343
361
  re = RE2::Regexp.new('My name is (\w+) (\w+)')
344
362
 
@@ -511,6 +529,13 @@ RSpec.describe RE2::Regexp do
511
529
  expect(md[3]).to eq("three")
512
530
  end
513
531
 
532
+ it "supports extracting submatches containing null bytes" do
533
+ re = RE2::Regexp.new("(a\0b)")
534
+ md = re.match("a\0bc")
535
+
536
+ expect(md[1]).to eq("a\0b")
537
+ end
538
+
514
539
  it "extracts a specific number of submatches", :aggregate_failures do
515
540
  re = RE2::Regexp.new('(\w+) (\w+) (\w+)')
516
541
  md = re.match("one two three", submatches: 2)
@@ -599,6 +624,13 @@ RSpec.describe RE2::Regexp do
599
624
  expect(re.partial_match?("My age is 99")).to eq(false)
600
625
  end
601
626
 
627
+ it "supports matching against text containing null bytes", :aggregate_failures do
628
+ re = RE2::Regexp.new("a\0b")
629
+
630
+ expect(re.partial_match?("a\0b")).to eq(true)
631
+ expect(re.partial_match?("ab")).to eq(false)
632
+ end
633
+
602
634
  it "returns false if the pattern is invalid" do
603
635
  re = RE2::Regexp.new('???', log_errors: false)
604
636
 
@@ -620,6 +652,13 @@ RSpec.describe RE2::Regexp do
620
652
  expect(re =~ "My age is 99").to eq(false)
621
653
  end
622
654
 
655
+ it "supports matching against text containing null bytes", :aggregate_failures do
656
+ re = RE2::Regexp.new("a\0b")
657
+
658
+ expect(re =~ "a\0b").to eq(true)
659
+ expect(re =~ "ab").to eq(false)
660
+ end
661
+
623
662
  it "returns false if the pattern is invalid" do
624
663
  re = RE2::Regexp.new('???', log_errors: false)
625
664
 
@@ -662,6 +701,13 @@ RSpec.describe RE2::Regexp do
662
701
  expect(re.full_match?("My name is Alice Bloggs and I am 99")).to eq(false)
663
702
  end
664
703
 
704
+ it "supports matching against text containing null bytes", :aggregate_failures do
705
+ re = RE2::Regexp.new("a\0b")
706
+
707
+ expect(re.full_match?("a\0b")).to eq(true)
708
+ expect(re.full_match?("a\0bc")).to eq(false)
709
+ end
710
+
665
711
  it "returns false if the pattern is invalid" do
666
712
  re = RE2::Regexp.new('???', log_errors: false)
667
713
 
@@ -742,6 +788,12 @@ RSpec.describe RE2::Regexp do
742
788
 
743
789
  expect(scanner).to be_a(RE2::Scanner)
744
790
  end
791
+
792
+ it "raises a type error if given invalid input" do
793
+ r = RE2::Regexp.new('(\w+)')
794
+
795
+ expect { r.scan(nil) }.to raise_error(TypeError)
796
+ end
745
797
  end
746
798
 
747
799
  describe "#partial_match" do
@@ -34,6 +34,16 @@ RSpec.describe RE2::Scanner do
34
34
  expect(scanner.scan).to be_nil
35
35
  end
36
36
 
37
+ it "supports scanning inputs with null bytes", :aggregate_failures do
38
+ r = RE2::Regexp.new("(\\w\0\\w)")
39
+ scanner = r.scan("a\0b c\0d e\0f")
40
+
41
+ expect(scanner.scan).to eq(["a\0b"])
42
+ expect(scanner.scan).to eq(["c\0d"])
43
+ expect(scanner.scan).to eq(["e\0f"])
44
+ expect(scanner.scan).to be_nil
45
+ end
46
+
37
47
  it "returns UTF-8 matches if the pattern is UTF-8" do
38
48
  r = RE2::Regexp.new('(\w+)')
39
49
  scanner = r.scan("It")
@@ -190,6 +200,18 @@ RSpec.describe RE2::Scanner do
190
200
  expect(scanner.to_enum.first).to eq(["1"])
191
201
  end
192
202
 
203
+ it "supports inputs with null bytes", :aggregate_failures do
204
+ r = RE2::Regexp.new("(\\w\0\\w)")
205
+ scanner = r.scan("a\0b c\0d")
206
+
207
+ expect(scanner.to_enum.first).to eq(["a\0b"])
208
+ expect(scanner.to_enum.first).to eq(["c\0d"])
209
+
210
+ scanner.rewind
211
+
212
+ expect(scanner.to_enum.first).to eq(["a\0b"])
213
+ end
214
+
193
215
  it "resets the eof? check", :aggregate_failures do
194
216
  r = RE2::Regexp.new('(\d)')
195
217
  scanner = r.scan("1")
data/spec/re2/set_spec.rb CHANGED
@@ -123,6 +123,14 @@ RSpec.describe RE2::Set do
123
123
  expect(set.match("def", exception: false)).to be_empty
124
124
  end
125
125
 
126
+ it "supports matching null bytes", :aggregate_failures do
127
+ set = RE2::Set.new
128
+ set.add("a\0b")
129
+ set.compile
130
+
131
+ expect(set.match("a\0b", exception: false)).to eq([0])
132
+ end
133
+
126
134
  it "returns an empty array if there is no match when :exception is true" do
127
135
  skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
128
136
 
data/spec/re2_spec.rb CHANGED
@@ -4,6 +4,18 @@ RSpec.describe RE2 do
4
4
  expect(RE2.Replace("woo", "o", "a")).to eq("wao")
5
5
  end
6
6
 
7
+ it "supports inputs with null bytes" do
8
+ expect(RE2.Replace("w\0oo", "o", "a")).to eq("w\0ao")
9
+ end
10
+
11
+ it "supports patterns with null bytes" do
12
+ expect(RE2.Replace("w\0oo", "\0", "o")).to eq("wooo")
13
+ end
14
+
15
+ it "supports replacements with null bytes" do
16
+ expect(RE2.Replace("woo", "o", "\0")).to eq("w\0o")
17
+ end
18
+
7
19
  it "performs replacement based on regular expressions" do
8
20
  expect(RE2.Replace("woo", "o+", "e")).to eq("we")
9
21
  end
@@ -82,6 +94,18 @@ RSpec.describe RE2 do
82
94
  expect(RE2.GlobalReplace("woo", "o", "a")).to eq("waa")
83
95
  end
84
96
 
97
+ it "supports inputs with null bytes" do
98
+ expect(RE2.GlobalReplace("w\0oo", "o", "a")).to eq("w\0aa")
99
+ end
100
+
101
+ it "supports patterns with null bytes" do
102
+ expect(RE2.GlobalReplace("w\0\0oo", "\0", "a")).to eq("waaoo")
103
+ end
104
+
105
+ it "supports replacements with null bytes" do
106
+ expect(RE2.GlobalReplace("woo", "o", "\0")).to eq("w\0\0")
107
+ end
108
+
85
109
  it "performs replacement based on regular expressions" do
86
110
  expect(RE2.GlobalReplace("woohoo", "o+", "e")).to eq("wehe")
87
111
  end
@@ -167,5 +191,9 @@ RSpec.describe RE2 do
167
191
  it "supports passing something that can be coerced to a String as input" do
168
192
  expect(RE2.QuoteMeta(StringLike.new("1.5"))).to eq('1\.5')
169
193
  end
194
+
195
+ it "supports strings containing null bytes" do
196
+ expect(RE2.QuoteMeta("abc\0def")).to eq('abc\x00def')
197
+ end
170
198
  end
171
199
  end
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.6.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Mucur
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-12-27 00:00:00.000000000 Z
12
+ date: 2024-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  - !ruby/object:Gem::Version
121
121
  version: '0'
122
122
  requirements: []
123
- rubygems_version: 3.4.10
123
+ rubygems_version: 3.4.19
124
124
  signing_key:
125
125
  specification_version: 4
126
126
  summary: Ruby bindings to RE2.