regexp-examples 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f72e32a8b9c2934cb90f1d32d3e50c8f735b0dac
4
+ data.tar.gz: fa76e5281143d5d14a9b7b3207ea2ea28915ea47
5
+ SHA512:
6
+ metadata.gz: 72348eafa1f3257eca9761c088293057eef0018825541f773993c04f1d579279431b06389a3185f4f8e5bb98e7ce0f331ae89aa53750f20b6fccee0cac3b6187
7
+ data.tar.gz: d4e3ac8e6951a3707eed765ed2373d25949bc7ea32281a75c173da11df03db4962d71e0a2ca339f5fc74370b97b596331bd93d65632557c82081a2d2728db933
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in regexp-examples.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Regexp::Examples
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'regexp-examples'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install regexp-examples
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/regexp-examples/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,15 @@
1
+ Dir[File.dirname(__FILE__) + '/regexp-examples/*.rb'].each {|file| require file }
2
+
3
+ # TODO: DEBUG. DELETE THIS.
4
+ #require 'pry'
5
+ #RegexpExamples::show(/a*/)
6
+ #RegexpExamples::show(/a+/)
7
+ #RegexpExamples::show(/a?/)
8
+ #RegexpExamples::show(/a{1,2}/)
9
+ #RegexpExamples::show(/a{1,}/)
10
+ #RegexpExamples::show(/https?:\/\/(www\.)?google\.com/) # AWWW YEEEAHH!
11
+ #RegexpExamples::show(/a|b/)
12
+ #RegexpExamples::show(/(a)/)
13
+ #RegexpExamples::show(/((a))\1\2/)
14
+ #
15
+ #binding.pry
@@ -0,0 +1,22 @@
1
+ module RegexpExamples
2
+ class BackReferenceTracker
3
+ @filled_groups = {}
4
+ class << self
5
+ attr_accessor :filled_groups
6
+
7
+ def add_filled_group(num, group)
8
+ @filled_groups[num] = group
9
+ end
10
+ end
11
+ end
12
+
13
+ class BackReferenceReplacer
14
+ def substitute_backreferences(full_example)
15
+ # TODO: Update this for named capture groups
16
+ # TODO: Define this magic __X__ pattern as a constant? Maybe?
17
+ full_example.gsub!(/__(\d+)__/) do |_|
18
+ BackReferenceTracker.filled_groups[$1.to_i]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module RegexpExamples
2
+ # Number of times to repeat for Star and Plus repeaters
3
+ TIMES = 2
4
+
5
+ # Set of chars for Dot and negated [^] char groups
6
+ #CHARS = [("a".."z").to_a, ("A".."Z").to_a, ".", ",", ";"].flatten
7
+ #TODO: Make these character sets more complete
8
+ #e.g. Sets for \d, \w, \h, \s
9
+ CHARS = %w{a b c d e}
10
+ end
11
+
@@ -0,0 +1,98 @@
1
+ module RegexpExamples
2
+ class SingleCharGroup
3
+ def initialize(char)
4
+ @char = char
5
+ end
6
+ def result
7
+ [@char]
8
+ end
9
+ end
10
+
11
+ class CharGroup
12
+ def initialize(chars)
13
+ @chars = chars
14
+ if chars[0] == "^"
15
+ @negative = true
16
+ @chars = @chars[1..-1]
17
+ else
18
+ @negative = false
19
+ end
20
+
21
+ # TODO: Can I make this more legible?
22
+ # Ranges a-b
23
+ # save first and last "-" if present
24
+ first = nil
25
+ last = nil
26
+ first = @chars.shift if @chars.first == "-"
27
+ last = @chars.pop if @chars.last == "-"
28
+ while i = @chars.index("-")
29
+ @chars[i-1..i+1] = (@chars[i-1]..@chars[i+1]).to_a
30
+ end
31
+ # restore them back
32
+ @chars.unshift(first) if first
33
+ @chars.push(last) if last
34
+ end
35
+ def result
36
+ if @negative
37
+ CHARS - @chars
38
+ else
39
+ @chars
40
+ end
41
+ end
42
+ end
43
+
44
+ class DotGroup
45
+ def result
46
+ CHARS
47
+ end
48
+ end
49
+
50
+ class MultiGroup
51
+ attr_reader :group_num
52
+ def initialize(groups, group_num)
53
+ @groups = groups
54
+ @group_num = group_num
55
+ end
56
+
57
+ # Generates the result of each contained group
58
+ # and adds the filled group of each result to
59
+ # itself
60
+ def result
61
+ strings = @groups.map {|x| x.result}
62
+ result = RegexpExamples::permutations_of_strings(strings)
63
+ result.each {|x| BackReferenceTracker.add_filled_group(@group_num, x)}
64
+ result
65
+ end
66
+ end
67
+
68
+ class MultiGroupEnd
69
+ def result
70
+ ['']
71
+ end
72
+ end
73
+
74
+ class OrGroup
75
+ def initialize(repeaters)
76
+ @repeaters = repeaters
77
+ end
78
+
79
+ def result
80
+ repeaters_results = @repeaters.map do |repeater|
81
+ repeater.result
82
+ end
83
+ RegexpExamples::permutations_of_strings(repeaters_results)
84
+ end
85
+ end
86
+
87
+ class BackReferenceGroup
88
+ attr_reader :num
89
+ def initialize(num)
90
+ @num = num
91
+ end
92
+
93
+ def result
94
+ ["__#{@num}__"]
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,29 @@
1
+ module RegexpExamples
2
+ # Given an array of arrays of strings,
3
+ # returns all possible perutations,
4
+ # for strings created by joining one
5
+ # element from each array
6
+ #
7
+ # For example:
8
+ # permutations_of_strings [ ['a'], ['b'], ['c', 'd', 'e'] ] #=> ['acb', 'abd', 'abe']
9
+ # permutations_of_strings [ ['a', 'b'], ['c', 'd'] ] #=> [ 'ac', 'ad', 'bc', 'bd' ]
10
+ def self.permutations_of_strings(arrays_of_strings)
11
+ return arrays_of_strings[0] if arrays_of_strings.size == 1
12
+ first = arrays_of_strings.shift
13
+ first.product( permutations_of_strings(arrays_of_strings) ).map {|x| x.flatten.join}
14
+ end
15
+
16
+ # TODO: For debugging only!! Delete this before v1.0
17
+ def self.show(regexp)
18
+ s = regexp.examples
19
+ puts "#{regexp.inspect} --> #{s.inspect}"
20
+ puts "Checking..."
21
+ errors = s.reject {|string| string =~ regexp}
22
+ if errors.size == 0
23
+ puts "All strings match"
24
+ else
25
+ puts "These don't match: #{errors.inspect}"
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,147 @@
1
+ module RegexpExamples
2
+ class Parser
3
+ attr_reader :regexp_string
4
+ def initialize(regexp_string)
5
+ @regexp_string = regexp_string
6
+ @num_groups = 0
7
+ @current_position = 0
8
+ end
9
+
10
+ def parse
11
+ repeaters = []
12
+ while @current_position < regexp_string.length
13
+ group = parse_group
14
+ break if group.is_a? MultiGroupEnd
15
+ @current_position += 1
16
+ repeaters << parse_repeater(group)
17
+ end
18
+ repeaters
19
+ end
20
+
21
+ private
22
+
23
+ def parse_group
24
+ char = regexp_string[@current_position]
25
+ case char
26
+ when '('
27
+ group = parse_multi_group
28
+ when ')'
29
+ group = parse_multi_end_group
30
+ when '['
31
+ group = parse_char_group
32
+ when '.'
33
+ group = parse_dot_group
34
+ when '|'
35
+ group = parse_or_group
36
+ when '\\'
37
+ group = parse_after_backslash_group
38
+ else
39
+ group = parse_single_char_group(char)
40
+ end
41
+ group
42
+ end
43
+
44
+ def parse_after_backslash_group
45
+ @current_position += 1
46
+ case regexp_string[@current_position..-1]
47
+ when /^(\d+)/
48
+ group = parse_backreference_group($&)
49
+ else
50
+ group = parse_single_char_group( regexp_string[@current_position] )
51
+ # TODO: What about cases like \n, \(, \^, etc?
52
+ # SpecialCharsAfterBackslash ?
53
+ end
54
+ group
55
+ end
56
+
57
+ def parse_repeater(group)
58
+ char = regexp_string[@current_position]
59
+ case char
60
+ when '*'
61
+ repeater = parse_star_repeater(group)
62
+ when '+'
63
+ repeater = parse_plus_repeater(group)
64
+ when '?'
65
+ repeater = parse_question_mark_repeater(group)
66
+ when '{'
67
+ repeater = parse_range_repeater(group)
68
+ else
69
+ repeater = parse_one_time_repeater(group)
70
+ end
71
+ repeater
72
+ end
73
+
74
+ def parse_multi_group
75
+ @current_position += 1
76
+ @num_groups += 1
77
+ this_group_num = @num_groups
78
+ groups = parse
79
+ # TODO: Non-capture groups, i.e. /...(?:foo).../
80
+ # TODO: Named capture groups, i.e. /...(?<name>foo).../
81
+ MultiGroup.new(groups, this_group_num)
82
+ end
83
+
84
+ def parse_multi_end_group
85
+ MultiGroupEnd.new
86
+ end
87
+
88
+ def parse_char_group
89
+ chars = []
90
+ @current_position += 1
91
+ # TODO: What about the sneaky edge case of /...[]a-z].../ ?
92
+ until regexp_string[@current_position].chr == ']'
93
+ chars << regexp_string[@current_position].chr
94
+ @current_position += 1
95
+ end
96
+ CharGroup.new(chars)
97
+ end
98
+
99
+ def parse_dot_group
100
+ DotGroup.new
101
+ end
102
+
103
+ def parse_or_group
104
+ @current_position += 1
105
+ repeaters = parse
106
+ OrGroup.new(repeaters)
107
+ end
108
+
109
+
110
+ def parse_single_char_group(char)
111
+ SingleCharGroup.new(char)
112
+ end
113
+
114
+ def parse_backreference_group(match)
115
+ BackReferenceGroup.new(match.to_i)
116
+ end
117
+
118
+ def parse_star_repeater(group)
119
+ @current_position += 1
120
+ StarRepeater.new(group)
121
+ end
122
+
123
+ def parse_plus_repeater(group)
124
+ @current_position += 1
125
+ PlusRepeater.new(group)
126
+ end
127
+
128
+ def parse_question_mark_repeater(group)
129
+ @current_position += 1
130
+ QuestionMarkRepeater.new(group)
131
+ end
132
+
133
+ def parse_range_repeater(group)
134
+ match = regexp_string[@current_position..-1].match(/^\{(\d+)(,)?(\d+)?\}/)
135
+ @current_position += match[0].size
136
+ min = match[1].to_i if match[1]
137
+ has_comma = !match[2].nil?
138
+ max = match[3].to_i if match[3]
139
+ RangeRepeater.new(group, min, has_comma, max)
140
+ end
141
+
142
+ def parse_one_time_repeater(group)
143
+ OneTimeRepeater.new(group)
144
+ end
145
+ end
146
+ end
147
+
@@ -0,0 +1,16 @@
1
+ class Regexp
2
+ module Examples
3
+ def examples
4
+ regexp_string = self.inspect[1..-2]
5
+ partial_examples =
6
+ RegexpExamples::Parser.new(regexp_string)
7
+ .parse
8
+ .map {|repeater| repeater.result}
9
+ full_examples = RegexpExamples::permutations_of_strings(partial_examples)
10
+ full_examples.map{ |full_example| RegexpExamples::BackReferenceReplacer.new.substitute_backreferences(full_example)}
11
+ full_examples
12
+ end
13
+ end
14
+ include Examples
15
+ end
16
+
@@ -0,0 +1,77 @@
1
+ module RegexpExamples
2
+ class BaseRepeater
3
+ def initialize(group)
4
+ @group = group
5
+ end
6
+
7
+ def result(min_repeats, max_repeats)
8
+ group_result = @group.result
9
+ results = []
10
+ min_repeats.upto(max_repeats) do |repeats|
11
+ group_result.each do |result|
12
+ results << result * repeats
13
+ end
14
+ end
15
+ results.uniq
16
+ end
17
+ end
18
+
19
+ class OneTimeRepeater < BaseRepeater
20
+ def initialize(group)
21
+ super
22
+ end
23
+
24
+ def result
25
+ super(1, 1)
26
+ end
27
+ end
28
+
29
+ class StarRepeater < BaseRepeater
30
+ def initialize(group)
31
+ super
32
+ end
33
+
34
+ def result
35
+ super(0, TIMES)
36
+ end
37
+ end
38
+
39
+ class PlusRepeater < BaseRepeater
40
+ def initialize(group)
41
+ super
42
+ end
43
+
44
+ def result
45
+ super(1, TIMES)
46
+ end
47
+ end
48
+
49
+ class QuestionMarkRepeater < BaseRepeater
50
+ def initialize(group)
51
+ super
52
+ end
53
+
54
+ def result
55
+ super(0, 1)
56
+ end
57
+ end
58
+
59
+ class RangeRepeater < BaseRepeater
60
+ def initialize(group, min, has_comma, max)
61
+ super(group)
62
+ @min = min
63
+ if max
64
+ @max = max
65
+ elsif has_comma
66
+ @max = min + TIMES
67
+ else
68
+ @max = min
69
+ end
70
+ end
71
+
72
+ def result
73
+ super(@min, @max)
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,3 @@
1
+ module RegexpExamples
2
+ VERSION = '0.0.0'
3
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path("../lib/regexp-examples/version", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'regexp-examples'
5
+ s.version = RegexpExamples::VERSION
6
+ s.date = '2014-11-04'
7
+ s.summary = "Extends the Regexp class with '#examples'"
8
+ s.description =
9
+ 'Regexp#examples returns a list of strings what are matched by the regex'
10
+ s.authors = ['Tom Lord']
11
+ s.email = 'lord.thom@gmail.com'
12
+ s.files = `git ls-files -z`.split("\x0")
13
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
15
+ s.require_paths = ["lib"]
16
+ s.homepage =
17
+ 'http://rubygems.org/gems/regexp-examples'
18
+ s.add_development_dependency "bundler", "~> 1.7"
19
+ s.add_development_dependency "rake", "~> 10.0"
20
+ s.license = 'MIT'
21
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: regexp-examples
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lord
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Regexp#examples returns a list of strings what are matched by the regex
42
+ email: lord.thom@gmail.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - ".gitignore"
48
+ - Gemfile
49
+ - LICENSE.txt
50
+ - README.md
51
+ - Rakefile
52
+ - lib/regexp-examples.rb
53
+ - lib/regexp-examples/backreferences.rb
54
+ - lib/regexp-examples/constants.rb
55
+ - lib/regexp-examples/groups.rb
56
+ - lib/regexp-examples/helpers.rb
57
+ - lib/regexp-examples/parser.rb
58
+ - lib/regexp-examples/regexp_extensions.rb
59
+ - lib/regexp-examples/repeaters.rb
60
+ - lib/regexp-examples/version.rb
61
+ - regexp-examples.gemspec
62
+ homepage: http://rubygems.org/gems/regexp-examples
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.2.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Extends the Regexp class with '#examples'
86
+ test_files: []