regexp-examples 0.3.2 → 0.4.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.
@@ -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