regexp-examples 1.1.4 → 1.2.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
  SHA1:
3
- metadata.gz: 43bddf0ebdc30ee2ae0e7ed35722165921d25c93
4
- data.tar.gz: 3e52ef064a6dd7c484f06814c15135997f7fb19d
3
+ metadata.gz: 47da78b8a954d0a3cc88910fffd716e34675d953
4
+ data.tar.gz: 69705d5fa7a10b0e4980fd6036b8aa8b29486947
5
5
  SHA512:
6
- metadata.gz: 9e53baeb48bce1a0e5d00e610b0ea933bc5a014d1fe0ea5b9678875c63b5507aaa32baab9f339e60610ce1b9c97e4173729a89340b8b75530912a6560352ca19
7
- data.tar.gz: e63cf93bfb1ec76e4aa710bb15da91bd61e27f259c30d6011e0805c64f3b219420b20cbe2343cf6736ba2e7e40c7cc413b6b8a04779eb4cf7438cad3e4aa04cf
6
+ metadata.gz: 224d21492ee5097eac3700ea168866f04f32e62e0bb8a2e2fd955a2398df27e5ff97daf9907ed0e27e3523238b020ef676243ecc9bc888dc24aad49565d4fae0
7
+ data.tar.gz: 91c0d6413d6f7ef35e8cb3a20dda797eb33b26ec4e6da88e23afad5c02e0f61fea3fceeb8afd2727980efbbe7667051e6c0df92e8f2e576cbc99354113d7f18b
@@ -2,6 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 2.0.0-p598
4
4
  - 2.1.6
5
- - 2.2.0
6
- - 2.2.2
5
+ - 2.2.4
6
+ - 2.3.0
7
7
  - ruby-head
data/README.md CHANGED
@@ -15,7 +15,7 @@ or a huge number of possible matches, such as `/.\w/`, then only a subset of the
15
15
 
16
16
  For more detail on this, see [configuration options](#configuration-options).
17
17
 
18
- If you'd like to understand how/why this gem works, please check out my [blog post](http://tom-lord.weebly.com/blog/reverse-engineering-regular-expressions) about it!
18
+ If you'd like to understand how/why this gem works, please check out my [blog post](http://tom-lord.weebly.com/blog/reverse-engineering-regular-expressions) about it.
19
19
 
20
20
  ## Usage
21
21
 
@@ -46,6 +46,24 @@ If you'd like to understand how/why this gem works, please check out my [blog po
46
46
  /written by tom lord/i.random_example #=> "WrITtEN bY tOM LORD"
47
47
  ```
48
48
 
49
+ ## Supported ruby versions
50
+ * MRI 2.0.x
51
+ * MRI 2.1.x
52
+ * MRI 2.2.x
53
+ * MRI 2.3.x
54
+ * MRI 2.4.0-dev
55
+
56
+ MRI ≤ 1.9.3 are not supported. This is primarily because MRI 2.0.0 introduced a new
57
+ regexp engine (`Oniguruma` was replaced by `Onigmo`). Whilst *most* of this gem could
58
+ be made to work with MRI 1.9.x (or even 1.8.x), I feel the changes are too significant
59
+ to implement backwards compatability (especially since [long-term support for MRI
60
+ 1.9.3 has now ended](https://www.ruby-lang.org/en/news/2014/01/10/ruby-1-9-3-will-end-on-2015/)).
61
+
62
+ For example, named properties (e.g. `/\p{Alpha}/`) are illegal syntax on MRI 1.9.3.
63
+
64
+ Other implementations, such as JRuby, could probably work fine -
65
+ but I haven't fully tried/tested it. Pull requests are welcome.
66
+
49
67
  ## Installation
50
68
 
51
69
  Add this line to your application's Gemfile:
@@ -86,12 +104,12 @@ Long answer:
86
104
  * Non-capture groups, e.g. `/(?:foo)/`
87
105
  * Comment groups, e.g. `/foo(?#comment)bar/`
88
106
  * Control characters, e.g. `/\ca/`, `/\cZ/`, `/\C-9/`
89
- * Escape sequences, e.g. `/\x42/`, `/\x5word/`, `/#{"\x80".force_encoding("ASCII-8BIT")}/`
107
+ * Escape sequences, e.g. `/\x42/`, `/\x5word/`, `/#{"\x80".force\_encoding("ASCII-8BIT")}/`
90
108
  * Unicode characters, e.g. `/\u0123/`, `/\uabcd/`, `/\u{789}/`
91
109
  * Octal characters, e.g. `/\10/`, `/\177/`
92
110
  * Named properties, e.g. `/\p{L}/` ("Letter"), `/\p{Arabic}/` ("Arabic character")
93
- , `/\p{^Ll}/` ("Not a lowercase letter"), `/\P{^Canadian_Aboriginal}/` ("Not not a Canadian aboriginal character")
94
- * ...Even between different ruby versions!! (e.g. `/\p{Arabic}/.examples(max_group_results: 999)` will give you a different answer in ruby v2.1.x and v2.2.x)
111
+ , `/\p{^Ll}/` ("Not a lowercase letter"), `/\P{^Canadian\_Aboriginal}/` ("Not not a Canadian aboriginal character")
112
+ * ...Even between different ruby versions!! (e.g. `/\p{Arabic}/.examples(max\_group\_results: 999)` will give you a different answer in ruby v2.1.x and v2.2.x)
95
113
  * **Arbitrarily complex combinations of all the above!**
96
114
 
97
115
  * Regexp options can also be used:
@@ -102,12 +120,12 @@ Long answer:
102
120
 
103
121
  ## Bugs and Not-Yet-Supported syntax
104
122
 
105
- * There are some (rare) edge cases where backreferences do not work properly, e.g. `/(a*)a* \1/.examples` - which includes "aaaa aa". This is because each repeater is not context-aware, so the "greediness" logic is flawed. (E.g. in this case, the second `a*` should always evaluate to an empty string, because the previous `a*` was greedy!) However, patterns like this are highly unusual...
123
+ * There are some (rare) edge cases where backreferences do not work properly, e.g. `/(a\*)a\* \1/.examples` - which includes "aaaa aa". This is because each repeater is not context-aware, so the "greediness" logic is flawed. (E.g. in this case, the second `a\*` should always evaluate to an empty string, because the previous `a\*` was greedy!) However, patterns like this are highly unusual...
106
124
 
107
125
  Since the Regexp language is so vast, it's quite likely I've missed something (please raise an issue if you find something)! The only missing feature that I'm currently aware of is:
108
126
  * Conditional capture groups, e.g. `/(group1)? (?(1)yes|no)/.examples` (which *should* return: `["group1 yes", " no"]`)
109
127
 
110
- Some of the most obscure regexp features are not even mentioned in the ruby docs! However, full documentation on all the intricate obscurities in the ruby (version 2.x) regexp parser can be found [here](https://raw.githubusercontent.com/k-takata/Onigmo/master/doc/RE).
128
+ Some of the most obscure regexp features are not even mentioned in the ruby docs. However, full documentation on all the intricate obscurities in the ruby (version 2.x) regexp parser can be found [here](https://raw.githubusercontent.com/k-takata/Onigmo/master/doc/RE).
111
129
 
112
130
  ## Impossible features ("illegal syntax")
113
131
 
@@ -116,61 +134,65 @@ If you'd like to understand this in more detail, check out what I had to say in
116
134
 
117
135
  Using any of the following will raise a RegexpExamples::IllegalSyntax exception:
118
136
 
119
- * Lookarounds, e.g. `/foo(?=bar)/`, `/foo(?!bar)/`, `/(?<=foo)bar/`, `/(?<!foo)bar/`
137
+ * Lookarounds, e.g. `/foo(?=bar)/`, `/foo(?!bar)/`, `/(?<=foo)bar/`, `/(?<\!foo)bar/`
120
138
  * [Anchors](http://ruby-doc.org/core-2.2.0/Regexp.html#class-Regexp-label-Anchors) (`\b`, `\B`, `\G`, `^`, `\A`, `$`, `\z`, `\Z`), e.g. `/\bword\b/`, `/line1\n^line2/`
121
139
  * However, a special case has been made to allow `^`, `\A` and `\G` at the start of a pattern; and to allow `$`, `\z` and `\Z` at the end of pattern. In such cases, the characters are effectively just ignored.
122
- * Subexpression calls (`\g`), e.g. `/(?<name> ... \g<name>* )/`
140
+ * Subexpression calls (`\g`), e.g. `/(?<name> ... \g<name>\* )/`
123
141
 
124
- (Note: Backreferences are not really "regular" either, but I got these to work with a bit of hackery!)
142
+ (Note: Backreferences are not really "regular" either, but I got these to work with a bit of hackery.)
125
143
 
126
144
  ##Configuration Options
127
145
 
128
- When generating examples, the gem uses 2 configurable values to limit how many examples are listed:
146
+ When generating examples, the gem uses 3 configurable values to limit how many examples are listed:
129
147
 
130
- * `max_repeater_variance` (default = `2`) restricts how many examples to return for each repeater. For example:
131
- * `.*` is equivalent to `.{0,2}`
148
+ * `max\_repeater\_variance` (default = `2`) restricts how many examples to return for each repeater. For example:
149
+ * `.\*` is equivalent to `.{0,2}`
132
150
  * `.+` is equivalent to `.{1,3}`
133
151
  * `.{2,}` is equivalent to `.{2,4}`
134
152
  * `.{,3}` is equivalent to `.{0,2}`
135
153
  * `.{3,8}` is equivalent to `.{3,5}`
136
154
 
137
- * `max_group_results` (default = `5`) restricts how many characters to return for each "set". For example:
155
+ * `max\_group\_results` (default = `5`) restricts how many characters to return for each "set". For example:
138
156
  * `\d` is equivalent to `[01234]`
139
157
  * `\w` is equivalent to `[abcde]`
140
158
  * `[h-s]` is equivalent to `[hijkl]`
141
159
  * `(1|2|3|4|5|6|7|8)` is equivalent to `[12345]`
142
160
 
143
- `Rexexp#examples` makes use of *both* these options; `Rexexp#random_example` only uses `max_repeater_variance`, since the other option is redundant!
161
+ * `max\_results\_limit` (default = `10000`) restricts the maximum number of results that can possibly be generated. For example:
162
+ * `/(crazy){1,999} B\*I\*G\* regex/.examples.length <= 10000` -- Attempting this will NOT freeze your system
163
+
164
+ `Rexexp#examples` makes use of *all* these options; `Rexexp#random\_example` only uses `max\_repeater\_variance`, since the other options are redundant.
144
165
 
145
166
  To use an alternative value, simply pass the configuration option as follows:
146
167
 
147
168
  ```ruby
148
- /a*/.examples(max_repeater_variance: 5)
169
+ /a*/.examples(max\_repeater\_variance: 5)
149
170
  #=> [''. 'a', 'aa', 'aaa', 'aaaa' 'aaaaa']
150
- /[F-X]/.examples(max_group_results: 10)
171
+ /[F-X]/.examples(max\_group\_results: 10)
151
172
  #=> ['F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O']
152
- /.*/.random_example(max_repeater_variance: 50)
173
+ /[ab]{10}/.examples(max\_results\_limit: 64).length == 64 # NOT 1024
174
+ /[slow]{9}/.examples(max\_results\_limit: 9999999).length == 4 \*\* 9 == 262144 # Warning - this will take a while!
175
+ /.\*/.random\_example(max\_repeater\_variance: 50)
153
176
  #=> "A very unlikely result!"
154
177
  ```
155
178
 
156
- _**WARNING**: Choosing huge numbers for `Regexp#examples` and/or a sufficiently "complex" regex, could easily cause your system to freeze!_
179
+ A sensible use case might be, for example, to generate all 1-5 digit strings:
157
180
 
158
- For example, if you try to generate a list of _all_ 5-letter words: `/\w{5}/.examples(max_group_results: 999)`, then since there are actually `63` "word" characters (upper/lower case letters, numbers and "\_"), this will try to generate `63**5 #=> 992436543` (almost 1 _billion_) examples!
159
-
160
- In other words, think twice before playing around with this config!
161
-
162
- A more sensible use case might be, for example, to generate all 1-4 digit strings:
163
-
164
- `/\d{1,4}/.examples(max_repeater_variance: 3, max_group_results: 10)`
181
+ ```ruby
182
+ /\d{1,5}/.examples(max\_repeater\_variance: 4, max\_group\_results: 10, max\_results\_limit: 100000)
183
+ #=> ['0', '1', '2', ..., '99998', '99999']
184
+ ```
165
185
 
166
- Due to code optimisation, this is not something you need to worry about (much) for `Regexp#random_example`. For instance, the following takes no more than ~ 1 second on my machine:
186
+ Due to code optimisation, `Regexp#random\_example` runs pretty fast even on very complex patterns.
187
+ (I.e. It's a _lot_ faster than using `/pattern/.exammples.sample(1)`.)
188
+ For instance, the following takes no more than ~ 1 second on my machine:
167
189
 
168
- `/.*\w+\d{100}/.random_example(max_repeater_variance: 1000)`
190
+ `/.\*\w+\d{100}/.random\_example(max\_repeater\_variance: 1000)`
169
191
 
170
192
  ## TODO
171
193
 
172
- * Performance improvements:
173
- * (Maybe?) add a `max_examples` configuration option and use lazy evaluation, to ensure the method never "freezes".
194
+ * Make regexp#examples always return up to `max\_results\_limit` - currenty, it usually "aborts" before this limit is reached.
195
+ * `\z` should be interpreted like `\n?\z`, not just `\z` like it is currently.
174
196
 
175
197
  ## Contributing
176
198
 
@@ -1,30 +1,31 @@
1
1
  module CoreExtensions
2
2
  module Regexp
3
- # A wrapper module to namespace/isolate the Regexp#examples and Regexp#random_exanple
3
+ # A wrapper module to namespace/isolate the Regexp#examples and Regexp#random_example
4
4
  # monkey patches.
5
5
  # No core classes are extended in any way, other than the above two methods.
6
6
  module Examples
7
7
  def examples(**config_options)
8
8
  RegexpExamples::ResultCountLimiters.configure!(
9
- config_options[:max_repeater_variance],
10
- config_options[:max_group_results]
9
+ max_repeater_variance: config_options[:max_repeater_variance],
10
+ max_group_results: config_options[:max_group_results],
11
+ max_results_limit: config_options[:max_results_limit]
11
12
  )
12
- examples_by_method(:map_results)
13
+ examples_by_method(:result)
13
14
  end
14
15
 
15
16
  def random_example(**config_options)
16
17
  RegexpExamples::ResultCountLimiters.configure!(
17
- config_options[:max_repeater_variance]
18
+ max_repeater_variance: config_options[:max_repeater_variance]
18
19
  )
19
- examples_by_method(:map_random_result).first
20
+ examples_by_method(:random_result).first
20
21
  end
21
22
 
22
23
  private
23
24
 
24
25
  def examples_by_method(method)
25
- full_examples = RegexpExamples.public_send(
26
- method,
27
- RegexpExamples::Parser.new(source, options).parse
26
+ full_examples = RegexpExamples.generic_map_result(
27
+ RegexpExamples::Parser.new(source, options).parse,
28
+ method
28
29
  )
29
30
  RegexpExamples::BackReferenceReplacer.new.substitute_backreferences(full_examples)
30
31
  end
@@ -3,6 +3,7 @@ require_relative 'regexp-examples/chargroup_parser'
3
3
  require_relative 'regexp-examples/constants'
4
4
  require_relative 'regexp-examples/groups'
5
5
  require_relative 'regexp-examples/backreferences'
6
+ require_relative 'regexp-examples/max_results_limiter'
6
7
  require_relative 'regexp-examples/helpers'
7
8
  require_relative 'regexp-examples/parser'
8
9
  require_relative 'regexp-examples/repeaters'
@@ -17,11 +17,17 @@ module RegexpExamples
17
17
  # \w is equivalent to [abcde]
18
18
  MAX_GROUP_RESULTS_DEFAULT = 5
19
19
 
20
+ # Maximum number of results to be generated, for Regexp#examples
21
+ # This is to prevent the system "freezing" when given instructions like:
22
+ # /[ab]{30}/.examples
23
+ # (Which would attempt to generate 2**30 == 1073741824 examples!!!)
24
+ MAX_RESULTS_LIMIT_DEFAULT = 10000
20
25
  class << self
21
- attr_reader :max_repeater_variance, :max_group_results
22
- def configure!(max_repeater_variance, max_group_results = nil)
26
+ attr_reader :max_repeater_variance, :max_group_results, :max_results_limit
27
+ def configure!(max_repeater_variance: nil, max_group_results: nil, max_results_limit: nil)
23
28
  @max_repeater_variance = (max_repeater_variance || MAX_REPEATER_VARIANCE_DEFAULT)
24
29
  @max_group_results = (max_group_results || MAX_GROUP_RESULTS_DEFAULT)
30
+ @max_results_limit = (max_results_limit || MAX_RESULTS_LIMIT_DEFAULT)
25
31
  end
26
32
  end
27
33
  end
@@ -32,6 +38,9 @@ module RegexpExamples
32
38
  def self.max_group_results
33
39
  ResultCountLimiters.max_group_results
34
40
  end
41
+ def self.max_results_limit
42
+ ResultCountLimiters.max_results_limit
43
+ end
35
44
 
36
45
  # Definitions of various special characters, used in regular expressions.
37
46
  # For example, `/\h/.examples` will return the value of `Hex` in this module
@@ -158,18 +158,20 @@ module RegexpExamples
158
158
  end
159
159
 
160
160
  def result
161
- result_by_method(:map_results)
161
+ result_by_method(:result)
162
162
  end
163
163
 
164
164
  def random_result
165
- result_by_method(:map_random_result).sample(1)
165
+ result_by_method(:random_result).sample(1)
166
166
  end
167
167
 
168
168
  private
169
169
 
170
170
  def result_by_method(method)
171
+ max_results_limiter = MaxResultsLimiterBySum.new
171
172
  repeaters_list
172
- .map { |repeaters| RegexpExamples.public_send(method, repeaters) }
173
+ .map { |repeaters| RegexpExamples.generic_map_result(repeaters, method) }
174
+ .map { |result| max_results_limiter.limit_results(result)}
173
175
  .inject(:concat)
174
176
  .map { |result| GroupResult.new(result) }
175
177
  .uniq
@@ -6,10 +6,14 @@ module RegexpExamples
6
6
  # For example:
7
7
  # permutations_of_strings [ ['a'], ['b'], ['c', 'd', 'e'] ] #=> ['abc', 'abd', 'abe']
8
8
  # permutations_of_strings [ ['a', 'b'], ['c', 'd'] ] #=> [ 'ac', 'ad', 'bc', 'bd' ]
9
- def self.permutations_of_strings(arrays_of_strings)
10
- first = arrays_of_strings.shift
11
- return first if arrays_of_strings.empty?
12
- first.product(permutations_of_strings(arrays_of_strings)).map do |result|
9
+ #
10
+ # Edge case:
11
+ # permutations_of_strings [ [] ] #=> nil
12
+ # (For example, ths occurs during /[^\d\D]/.examples #=> [])
13
+ def self.permutations_of_strings(arrays_of_strings, max_results_limiter = MaxResultsLimiterByProduct.new)
14
+ partial_result = max_results_limiter.limit_results(arrays_of_strings.shift)
15
+ return partial_result if arrays_of_strings.empty?
16
+ partial_result.product(permutations_of_strings(arrays_of_strings, max_results_limiter)).map do |result|
13
17
  join_preserving_capture_groups(result)
14
18
  end
15
19
  end
@@ -25,21 +29,9 @@ module RegexpExamples
25
29
  GroupResult.new(result.join, nil, subgroups)
26
30
  end
27
31
 
28
- def self.map_results(repeaters)
29
- generic_map_result(repeaters, :result)
30
- end
31
-
32
- def self.map_random_result(repeaters)
33
- generic_map_result(repeaters, :random_result)
34
- end
35
-
36
- private
37
-
38
32
  def self.generic_map_result(repeaters, method)
39
- repeaters
40
- .map { |repeater| repeater.public_send(method) }
41
- .instance_eval do |partial_results|
42
- RegexpExamples.permutations_of_strings(partial_results)
43
- end
33
+ permutations_of_strings(
34
+ repeaters.map { |repeater| repeater.public_send(method) }
35
+ )
44
36
  end
45
37
  end
@@ -0,0 +1,58 @@
1
+ module RegexpExamples
2
+ class MaxResultsLimiter # Base class
3
+ def initialize(initial_results_count)
4
+ @results_count = initial_results_count
5
+ end
6
+
7
+ private
8
+
9
+ # limiter_method and cumulator_method must be inverses
10
+ # i.e. :- and :+, or :/ and :*
11
+ def limit_results(partial_results, limiter_method, cumulator_method)
12
+ return [] if partial_results.empty? # guard clause
13
+ results_allowed = results_allowed_from(partial_results, limiter_method)
14
+ cumulate_total(results_allowed.length, cumulator_method)
15
+ results_allowed
16
+ end
17
+
18
+ def cumulate_total(new_results_count, cumulator_method)
19
+ if @results_count.zero?
20
+ @results_count = new_results_count
21
+ else
22
+ @results_count = @results_count.public_send(cumulator_method, new_results_count)
23
+ end
24
+ end
25
+
26
+ def results_allowed_from(partial_results, limiter_method)
27
+ partial_results.first(
28
+ RegexpExamples.max_results_limit.public_send(limiter_method, @results_count)
29
+ )
30
+ end
31
+ end
32
+
33
+ # For example:
34
+ # Needed when generating examples for /[ab]{10}/
35
+ # (here, results_count will reach 2**10 == 1024)
36
+ class MaxResultsLimiterByProduct < MaxResultsLimiter
37
+ def initialize
38
+ super(1)
39
+ end
40
+
41
+ def limit_results(partial_results)
42
+ super(partial_results, :/, :*)
43
+ end
44
+ end
45
+
46
+ # For example:
47
+ # Needed when generating examples for /[ab]{10}|{cd}{11}/
48
+ # (here, results_count will reach 1024 + 2048 == 3072)
49
+ class MaxResultsLimiterBySum < MaxResultsLimiter
50
+ def initialize
51
+ super(0)
52
+ end
53
+
54
+ def limit_results(partial_results)
55
+ super(partial_results, :-, :+)
56
+ end
57
+ end
58
+ end
@@ -12,14 +12,16 @@ module RegexpExamples
12
12
  def result
13
13
  group_results = group.result.first(RegexpExamples.max_group_results)
14
14
  results = []
15
+ max_results_limiter = MaxResultsLimiterBySum.new
15
16
  min_repeats.upto(max_repeats) do |repeats|
16
- if repeats.zero?
17
- results << [GroupResult.new('')]
18
- else
19
- results << RegexpExamples.permutations_of_strings(
20
- [group_results] * repeats
21
- )
22
- end
17
+ result = if repeats.zero?
18
+ [GroupResult.new('')]
19
+ else
20
+ RegexpExamples.permutations_of_strings(
21
+ [group_results] * repeats
22
+ )
23
+ end
24
+ results << max_results_limiter.limit_results(result)
23
25
  end
24
26
  results.flatten.uniq
25
27
  end
@@ -1,4 +1,4 @@
1
1
  # Gem version
2
2
  module RegexpExamples
3
- VERSION = '1.1.4'
3
+ VERSION = '1.2.0'
4
4
  end
@@ -369,6 +369,41 @@ RSpec.describe Regexp, '#examples' do
369
369
  it { expect(/a(?-i:b)c/i.examples).to match_array %w(abc abC Abc AbC) }
370
370
  end
371
371
  end
372
+ end # context 'exact examples match'
373
+ end # context 'returns matching strings'
374
+
375
+ context 'max_results_limit config option' do
376
+ it 'with low limit' do
377
+ expect(/[A-Z]/.examples(max_results_limit: 5))
378
+ .to match_array %w(A B C D E)
379
+ end
380
+ it 'with (default) high limit' do
381
+ expect(/[ab]{14}/.examples.length)
382
+ .to be <= 10000 # NOT 2**14 == 16384, because it's been limited
383
+ end
384
+ it 'with (custom) high limit' do
385
+ expect(/[ab]{14}/.examples(max_results_limit: 20000).length)
386
+ .to eq 16384 # NOT 10000, because it's below the limit
387
+ end
388
+ it 'for boolean or groups' do
389
+ expect(/[ab]{3}|[cd]{3}/.examples(max_results_limit: 10).length)
390
+ .to eq 10
391
+ end
392
+ it 'for case insensitive examples' do
393
+ expect(/[ab]{3}/i.examples(max_results_limit: 10).length)
394
+ .to be <= 10
395
+ end
396
+ it 'for range repeaters' do
397
+ expect(/[ab]{2,3}/.examples(max_results_limit: 10).length)
398
+ .to be <= 10 # NOT 4 + 8 = 12
399
+ end
400
+ it 'for backreferences' do
401
+ expect(/([ab]{3})\1?/.examples(max_results_limit: 10).length)
402
+ .to be <= 10 # NOT 8 * 2 = 16
403
+ end
404
+ it 'for a complex pattern' do
405
+ expect(/(a|[bc]{2})\1{1,3}/.examples(max_results_limit: 14).length)
406
+ .to be <= 14 # NOT (1 + 4) * 3 = 15
372
407
  end
373
408
  end
374
409
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regexp-examples
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Lord
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-31 00:00:00.000000000 Z
11
+ date: 2016-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -65,6 +65,7 @@ files:
65
65
  - lib/regexp-examples/constants.rb
66
66
  - lib/regexp-examples/groups.rb
67
67
  - lib/regexp-examples/helpers.rb
68
+ - lib/regexp-examples/max_results_limiter.rb
68
69
  - lib/regexp-examples/parser.rb
69
70
  - lib/regexp-examples/parser_helpers/charset_negation_helper.rb
70
71
  - lib/regexp-examples/parser_helpers/parse_after_backslash_group_helper.rb
@@ -100,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
101
  version: '0'
101
102
  requirements: []
102
103
  rubyforge_project:
103
- rubygems_version: 2.5.1
104
+ rubygems_version: 2.4.6
104
105
  signing_key:
105
106
  specification_version: 4
106
107
  summary: Extends the Regexp class with '#examples' and '#random_example'
@@ -1 +0,0 @@
1
- unicode_ranges_2.0.pstore