regexp-examples 0.0.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.
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: []