regexp-examples 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,18 +2,24 @@ module RegexpExamples
2
2
  class BackReferenceReplacer
3
3
  def substitute_backreferences(full_examples)
4
4
  full_examples.map do |full_example|
5
- while full_example.match(/__(\w+?)__/)
6
- full_example.sub!(/__(\w+?)__/, find_backref_for(full_example, $1))
5
+ begin
6
+ while full_example.match(/__(\w+?)__/)
7
+ full_example.sub!(/__(\w+?)__/, find_backref_for(full_example, $1))
8
+ end
9
+ full_example
10
+ rescue RegexpExamples::BackrefNotFound
11
+ # For instance, one "full example" from /(a|(b)) \2/: "a __2__"
12
+ # should be rejected because the backref (\2) does not exist
13
+ nil
7
14
  end
8
- full_example
9
- end
15
+ end.compact
10
16
  end
11
17
 
12
18
  private
13
19
  def find_backref_for(full_example, group_id)
14
20
  full_example.all_subgroups.detect do |subgroup|
15
21
  subgroup.group_id == group_id
16
- end
22
+ end || raise(RegexpExamples::BackrefNotFound)
17
23
  end
18
24
 
19
25
  end
@@ -1,18 +1,35 @@
1
1
  module RegexpExamples
2
- # The maximum variance for any given repeater, to prevent a huge/infinite number of
3
- # examples from being listed. For example, if MaxRepeaterVariance = 2 then:
4
- # .* is equivalent to .{0,2}
5
- # .+ is equivalent to .{1,3}
6
- # .{2,} is equivalent to .{2,4}
7
- # .{,3} is equivalent to .{0,2}
8
- # .{3,8} is equivalent to .{3,5}
9
- MaxRepeaterVariance = 2
2
+ class ResultCountLimiters
3
+ # The maximum variance for any given repeater, to prevent a huge/infinite number of
4
+ # examples from being listed. For example, if @@max_repeater_variance = 2 then:
5
+ # .* is equivalent to .{0,2}
6
+ # .+ is equivalent to .{1,3}
7
+ # .{2,} is equivalent to .{2,4}
8
+ # .{,3} is equivalent to .{0,2}
9
+ # .{3,8} is equivalent to .{3,5}
10
+ MaxRepeaterVarianceDefault = 2
10
11
 
11
- # Maximum number of characters returned from a char set, to reduce output spam
12
- # For example:
13
- # If MaxGroupResults = 5, then
14
- # \d = [0, 1, 2, 3, 4]
15
- MaxGroupResults = 5
12
+ # Maximum number of characters returned from a char set, to reduce output spam
13
+ # For example, if @@max_group_results = 5 then:
14
+ # \d = ["0", "1", "2", "3", "4"]
15
+ # \w = ["a", "b", "c", "d", "e"]
16
+ MaxGroupResultsDefault = 5
17
+
18
+ class << self
19
+ attr_reader :max_repeater_variance, :max_group_results
20
+ def configure!(max_repeater_variance, max_group_results)
21
+ @max_repeater_variance = (max_repeater_variance || MaxRepeaterVarianceDefault)
22
+ @max_group_results = (max_group_results || MaxGroupResultsDefault)
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.MaxRepeaterVariance
28
+ ResultCountLimiters.max_repeater_variance
29
+ end
30
+ def self.MaxGroupResults
31
+ ResultCountLimiters.max_group_results
32
+ end
16
33
 
17
34
  module CharSets
18
35
  Lower = Array('a'..'z')
@@ -2,4 +2,5 @@ module RegexpExamples
2
2
  class Error < StandardError; end
3
3
  class UnsupportedSyntaxError < Error; end
4
4
  class IllegalSyntaxError < Error; end
5
+ class BackrefNotFound < Error; end
5
6
  end
@@ -16,12 +16,6 @@ module RegexpExamples
16
16
  def all_subgroups
17
17
  [self, subgroups].flatten.reject { |subgroup| subgroup.group_id.nil? }
18
18
  end
19
-
20
- # Overridden in order to preserve the @group_id and @subgroups
21
- # Used by BaseGroup (which, in turn, is used by all Group objects)
22
- def *(int)
23
- self.class.new(super.to_s, group_id, subgroups)
24
- end
25
19
  end
26
20
 
27
21
  class SingleCharGroup
@@ -120,7 +114,7 @@ module RegexpExamples
120
114
  # itself
121
115
  def result
122
116
  strings = @groups.map {|repeater| repeater.result}
123
- RegexpExamples::permutations_of_strings(strings).map do |result|
117
+ RegexpExamples.permutations_of_strings(strings).map do |result|
124
118
  GroupResult.new(result, group_id)
125
119
  end
126
120
  end
@@ -137,8 +131,8 @@ module RegexpExamples
137
131
 
138
132
 
139
133
  def result
140
- left_result = RegexpExamples::map_results(@left_repeaters)
141
- right_result = RegexpExamples::map_results(@right_repeaters)
134
+ left_result = RegexpExamples.map_results(@left_repeaters)
135
+ right_result = RegexpExamples.map_results(@right_repeaters)
142
136
  left_result.concat(right_result).flatten.uniq.map do |result|
143
137
  GroupResult.new(result)
144
138
  end
@@ -27,7 +27,7 @@ module RegexpExamples
27
27
  repeaters
28
28
  .map {|repeater| repeater.result}
29
29
  .instance_eval do |partial_results|
30
- RegexpExamples::permutations_of_strings(partial_results)
30
+ RegexpExamples.permutations_of_strings(partial_results)
31
31
  end
32
32
  end
33
33
  end
@@ -1,10 +1,14 @@
1
1
  module RegexpExamples
2
2
  class Parser
3
3
  attr_reader :regexp_string
4
- def initialize(regexp_string)
4
+ def initialize(regexp_string, options={})
5
5
  @regexp_string = regexp_string
6
6
  @num_groups = 0
7
7
  @current_position = 0
8
+ RegexpExamples::ResultCountLimiters.configure!(
9
+ options[:max_repeater_variance],
10
+ options[:max_group_results]
11
+ )
8
12
  end
9
13
 
10
14
  def parse
@@ -1,8 +1,8 @@
1
1
  class Regexp
2
2
  module Examples
3
- def examples
4
- full_examples = RegexpExamples::map_results(
5
- RegexpExamples::Parser.new(source).parse
3
+ def examples(options={})
4
+ full_examples = RegexpExamples.map_results(
5
+ RegexpExamples::Parser.new(source, options).parse
6
6
  )
7
7
  RegexpExamples::BackReferenceReplacer.new.substitute_backreferences(full_examples)
8
8
  end
@@ -6,14 +6,18 @@ module RegexpExamples
6
6
  end
7
7
 
8
8
  def result(min_repeats, max_repeats)
9
- group_results = @group.result[0 .. MaxGroupResults-1]
9
+ group_results = @group.result[0 .. RegexpExamples.MaxGroupResults-1]
10
10
  results = []
11
11
  min_repeats.upto(max_repeats) do |repeats|
12
- group_results.each do |group_result|
13
- results << group_result * repeats
12
+ if repeats.zero?
13
+ results << [ GroupResult.new('') ]
14
+ else
15
+ results << RegexpExamples.permutations_of_strings(
16
+ [group_results] * repeats
17
+ )
14
18
  end
15
19
  end
16
- results.uniq
20
+ results.flatten.uniq
17
21
  end
18
22
  end
19
23
 
@@ -33,7 +37,7 @@ module RegexpExamples
33
37
  end
34
38
 
35
39
  def result
36
- super(0, MaxRepeaterVariance)
40
+ super(0, RegexpExamples.MaxRepeaterVariance)
37
41
  end
38
42
  end
39
43
 
@@ -43,7 +47,7 @@ module RegexpExamples
43
47
  end
44
48
 
45
49
  def result
46
- super(1, MaxRepeaterVariance + 1)
50
+ super(1, RegexpExamples.MaxRepeaterVariance + 1)
47
51
  end
48
52
  end
49
53
 
@@ -63,9 +67,9 @@ module RegexpExamples
63
67
  @min = min || 0
64
68
  if max
65
69
  # Prevent huge number of results in case of e.g. /.{1,100}/.examples
66
- @max = smallest(max, @min + MaxRepeaterVariance)
70
+ @max = smallest(max, @min + RegexpExamples.MaxRepeaterVariance)
67
71
  elsif has_comma
68
- @max = @min + MaxRepeaterVariance
72
+ @max = @min + RegexpExamples.MaxRepeaterVariance
69
73
  else
70
74
  @max = @min
71
75
  end
@@ -1,3 +1,3 @@
1
1
  module RegexpExamples
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -115,7 +115,9 @@ RSpec.describe Regexp, "#examples" do
115
115
  /((ref2)ref1) \1 \2/,
116
116
  /((ref1and2)) \1 \2/,
117
117
  /(one)(two)(three)(four)(five)(six)(seven)(eight)(nine)(ten) \10\9\8\7\6\5\4\3\2\1/,
118
- /(a?(b?(c?(d?(e?)))))/
118
+ /(a?(b?(c?(d?(e?)))))/,
119
+ /(a)? \1/,
120
+ /(a|(b)) \2/
119
121
  )
120
122
  end
121
123
 
@@ -208,12 +210,36 @@ RSpec.describe Regexp, "#examples" do
208
210
  /[^\h\H]/,
209
211
  /[^\D0-9]/,
210
212
  /[^\Wa-zA-Z0-9_]/,
211
- /[^\d\D]*/,
212
213
  /[^\d\D]+/,
213
214
  /[^\d\D]{2}/,
214
215
  /[^\d\D]word/
215
216
  )
216
217
  end
217
218
 
219
+ context "exact examples match" do
220
+ # More rigorous tests to assert that ALL examples are being listed
221
+ context "default options" do
222
+ it { expect(/[ab]{2}/.examples).to eq ["aa", "ab", "ba", "bb"] }
223
+ it { expect(/(a|b){2}/.examples).to eq ["aa", "ab", "ba", "bb"] }
224
+ it { expect(/a+|b?/.examples).to eq ["a", "aa", "aaa", "", "b"] }
225
+ end
226
+ context "max_repeater_variance option" do
227
+ it do
228
+ expect(/a+/.examples(max_repeater_variance: 5))
229
+ .to eq %w(a aa aaa aaaa aaaaa aaaaaa)
230
+ end
231
+ it do
232
+ expect(/a{4,8}/.examples(max_repeater_variance: 0))
233
+ .to eq %w(aaaa)
234
+ end
235
+ end
236
+ context "max_group_results option" do
237
+ it do
238
+ expect(/\d/.examples(max_group_results: 10))
239
+ .to eq %w(0 1 2 3 4 5 6 7 8 9)
240
+ end
241
+ end
242
+ end
243
+
218
244
  end
219
245
  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: 0.3.2
4
+ version: 0.4.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-01-24 00:00:00.000000000 Z
11
+ date: 2015-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler