expgen 0.1.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in expgen.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jonas Nicklas
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.
@@ -0,0 +1,42 @@
1
+ # Expgen
2
+
3
+ Expgen solves a very simple problem: Given a regular expression, find a string
4
+ which matches that regular expression. Use it like this:
5
+
6
+ ``` ruby
7
+ Expgen.gen(/foo\w+b[a-z]{2,3}/) # => "fooxbdp"
8
+ ```
9
+
10
+ For a full list of supported syntax, see the spec file.
11
+
12
+ Some things are really difficult to generate accurate expressions for, it's
13
+ even quite easy to create a regexp which matches *no* strings. For example
14
+ `/a\bc/` will not match any string, since there can never be a word boundary
15
+ between characters.
16
+
17
+ When given a negative character class, Expgen takes the entire ASCII character
18
+ set (sans control characters) and removes from it any characters excluded by the
19
+ character class. In other words, if the character class excludes the *entire*
20
+ ASCII character set, Expgen will be unable to fill this space.
21
+
22
+ The following is a list of things Expgen does *not* support:
23
+
24
+ - Anchors (are ignored)
25
+ - Lookaheads and lookbehinds
26
+ - Subexpressions
27
+ - Backreferences
28
+
29
+ ## Doesn't this already exist?
30
+
31
+ There is a gem called Randexp which does much the same thing. Expgen differs
32
+ from Randexp in two important ways. (1) It actually works. (2) It supports a
33
+ *much* wider range of regexp syntax.
34
+
35
+ The idea behind Expgen is that you should be able to take any reasonable, real
36
+ world regular expression and be able to generate matching strings. The focus is
37
+ on finding Strings which match a particular expression, not necessarily using
38
+ it as a random generator.
39
+
40
+ # License
41
+
42
+ MIT, see separate LICENSE.txt file
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "expgen"
4
+ puts Expgen.gen(ARGV.first)
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'expgen/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "expgen"
8
+ gem.version = Expgen::VERSION
9
+ gem.authors = ["Jonas Nicklas"]
10
+ gem.email = ["jonas.nicklas@gmail.com"]
11
+ gem.description = %q{Generate random strings from regular expression}
12
+ gem.summary = %q{Generate random regular expression}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.add_dependency "parslet"
20
+ gem.add_development_dependency "pry"
21
+ gem.add_development_dependency "rspec"
22
+ end
@@ -0,0 +1,43 @@
1
+ require "parslet"
2
+ require "expgen/version"
3
+ require "expgen/parser"
4
+ require "expgen/transform"
5
+ require "expgen/randomizer"
6
+ require "expgen/nodes"
7
+
8
+ module Expgen
9
+ ASCII = (32..126).map(&:chr)
10
+ LOWER = ("a".."z").to_a
11
+ UPPER = ("A".."Z").to_a
12
+ DIGIT = (0..9).map(&:to_s)
13
+ ALPHA = LOWER + UPPER
14
+ WORD = ALPHA + DIGIT + ["_"]
15
+ NEGATIVE_WORD = ASCII - WORD
16
+ NON_DIGIT = ASCII - DIGIT
17
+ HEX_DIGIT = ("a".."f").to_a + ("A".."F").to_a + DIGIT
18
+ NON_HEX_DIGIT = ASCII - HEX_DIGIT
19
+ SPACE = [" "]
20
+ NON_SPACE = ASCII.drop(1)
21
+ CONTROL_CHARS = (0.chr..31.chr).to_a
22
+ PUNCT = (33..47).map(&:chr) + (58..64).map(&:chr) + (91..96).map(&:chr) + (123..126).map(&:chr)
23
+
24
+ ESCAPE_CHARS = { "n" => "\n", "s" => "\s", "r" => "\r", "t" => "\t", "v" => "\v", "f" => "\f", "a" => "\a", "e" => "\e" }
25
+
26
+ class ParseError < StandardError; end
27
+
28
+ def self.cache
29
+ @cache ||= {}
30
+ end
31
+
32
+ def self.clear_cache
33
+ @cache = nil
34
+ end
35
+
36
+ def self.gen(exp)
37
+ source = if exp.respond_to?(:source) then exp.source else exp.to_s end
38
+ cache[source] ||= Transform.new.apply((Parser::Expression.new.parse(source)))
39
+ Randomizer.randomize(cache[source])
40
+ rescue Parslet::ParseFailed => e
41
+ raise Expgen::ParseError, e.message
42
+ end
43
+ end
@@ -0,0 +1,128 @@
1
+ module Expgen
2
+ module Nodes
3
+ class Node
4
+ attr_reader :ast
5
+
6
+ def initialize(ast)
7
+ @ast = ast
8
+ end
9
+
10
+ def repeat
11
+ ast[:repeat]
12
+ end
13
+ end
14
+
15
+ class Group < Node
16
+ def elements
17
+ ast[:elements]
18
+ end
19
+ end
20
+
21
+ class Alternation < Node
22
+ def options
23
+ ast.map { |option| option[:alt] }
24
+ end
25
+ end
26
+
27
+ class Character < Node; end
28
+
29
+ class CharacterClass < Character
30
+ def groups
31
+ ast[:groups]
32
+ end
33
+
34
+ def chars
35
+ chars = groups.map(&:chars).flatten
36
+ val = if ast[:negative]
37
+ ASCII - chars
38
+ else
39
+ chars
40
+ end
41
+ end
42
+ end
43
+
44
+ class Literal < Character
45
+ def chars
46
+ [ast[:letter].to_s]
47
+ end
48
+ end
49
+
50
+ class Wildcard < Character
51
+ def chars
52
+ ASCII
53
+ end
54
+ end
55
+
56
+ class Shorthand < Character
57
+ def chars
58
+ case ast[:letter].to_s
59
+ when "w" then WORD
60
+ when "W" then NEGATIVE_WORD
61
+ when "d" then DIGIT
62
+ when "D" then NON_DIGIT
63
+ when "h" then HEX_DIGIT
64
+ when "H" then NON_HEX_DIGIT
65
+ when "s" then SPACE
66
+ when "S" then NON_SPACE
67
+ end
68
+ end
69
+ end
70
+
71
+ class BracketExpression < Character
72
+ def chars
73
+ case ast[:name].to_s
74
+ when "alnum" then ALPHA + DIGIT
75
+ when "alpha" then ALPHA
76
+ when "blank" then " "
77
+ when "cntrl" then CONTROL_CHARS
78
+ when "digit" then DIGIT
79
+ when "graph" then NON_SPACE
80
+ when "lower" then LOWER
81
+ when "print" then ASCII
82
+ when "punct" then PUNCT
83
+ when "space" then SPACE
84
+ when "upper" then UPPER
85
+ when "xdigit" then HEX_DIGIT
86
+ when "word" then WORD + ["_"]
87
+ when "ascii" then ASCII
88
+ end
89
+ end
90
+ end
91
+
92
+ class Range < Character
93
+ def chars
94
+ (ast[:from].to_s..ast[:to].to_s).to_a
95
+ end
96
+ end
97
+
98
+ class EscapeCharControl < Character
99
+ def chars
100
+ [ESCAPE_CHARS[ast[:letter].to_s]]
101
+ end
102
+ end
103
+
104
+ class EscapeCharLiteral < Character
105
+ def chars
106
+ [ast[:letter].to_s]
107
+ end
108
+ end
109
+
110
+ class CodePointOctal < Character
111
+ def chars
112
+ [ast[:code].to_s.to_i(8).chr]
113
+ end
114
+ end
115
+
116
+ class CodePointHex < Character
117
+ def chars
118
+ [ast[:code].to_s.to_i(16).chr]
119
+ end
120
+ end
121
+
122
+ class CodePointUnicode < Character
123
+ def chars
124
+ [ast[:code].to_s.to_i(16).chr("UTF-8")]
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,85 @@
1
+ module Expgen
2
+ NON_LITERALS = "[]\^$.|?*+()".split("").map { |l| "\\" + l }.join
3
+
4
+ module Parser
5
+ class Repeat < Parslet::Parser
6
+ rule(:lcurly) { str('{') }
7
+ rule(:rcurly) { str('}') }
8
+ rule(:multiply) { str('*') }
9
+ rule(:plus) { str('+') }
10
+ rule(:comma) { str(',') }
11
+ rule(:questionmark) { str('?') }
12
+
13
+ rule(:integer) { match('[0-9]').repeat(1).as(:int) }
14
+
15
+ rule(:amount) { lcurly >> integer.as(:repeat) >> (comma >> integer.as(:max).maybe).maybe >> rcurly }
16
+ rule(:repeat) { plus.as(:repeat) | multiply.as(:repeat) | questionmark.as(:optional) | amount }
17
+
18
+ root(:repeat)
19
+ end
20
+
21
+ class EscapeChar < Parslet::Parser
22
+ rule(:backslash) { str('\\') }
23
+
24
+ rule(:code_point_octal) { backslash >> match["0-7"].repeat(3,3).as(:code) >> Repeat.new.maybe }
25
+ rule(:code_point_hex) { backslash >> str("x") >> match["0-9a-fA-F"].repeat(2,2).as(:code) >> Repeat.new.maybe }
26
+ rule(:code_point_unicode) { backslash >> str("u") >> match["0-9a-fA-F"].repeat(4,4).as(:code) >> Repeat.new.maybe }
27
+ rule(:escape_char_control) { backslash >> match["nsrtvfae"].as(:letter) >> Repeat.new.maybe }
28
+ rule(:escape_char_literal) { backslash >> any.as(:letter) >> Repeat.new.maybe }
29
+
30
+ rule(:escape_char) { escape_char_control.as(:escape_char_control) | code_point_octal.as(:code_point_octal) | code_point_hex.as(:code_point_hex) | code_point_unicode.as(:code_point_unicode) | escape_char_literal.as(:escape_char_literal) }
31
+ root(:escape_char)
32
+ end
33
+
34
+ class ShorthandCharacterClass < Parslet::Parser
35
+ rule(:backslash) { str('\\') }
36
+
37
+ rule(:char_class_shorthand) { (backslash >> match["wWdDhHsS"].as(:letter) >> Repeat.new.maybe).as(:char_class_shorthand) }
38
+
39
+ root(:char_class_shorthand)
40
+ end
41
+
42
+ class CharacterClass < Parslet::Parser
43
+ rule(:dash) { str('-') }
44
+ rule(:lbracket) { str('[') }
45
+ rule(:rbracket) { str(']') }
46
+
47
+ rule(:alpha) { match["a-z"] }
48
+ rule(:number) { match["0-9"] }
49
+ rule(:char) { match["^\\[\\]"].as(:letter) }
50
+ rule(:wildcard) { str('.').as(:wildcard) }
51
+ rule(:range) { (alpha.as(:from) >> dash >> alpha.as(:to)) | (number.as(:from) >> dash >> number.as(:to)) }
52
+ rule(:bracket_expression) { str("[:") >> alpha.repeat(1).as(:name) >> str(":]") }
53
+
54
+ rule(:contents) { ShorthandCharacterClass.new | EscapeChar.new | range.as(:char_class_range) | char.as(:char_class_literal) | bracket_expression.as(:bracket_expression) }
55
+ rule(:negative) { match["\\^"] }
56
+
57
+ rule(:char_class) { (lbracket >> negative.maybe.as(:negative) >> contents.repeat.as(:groups) >> rbracket >> Repeat.new.maybe).as(:char_class) }
58
+ root(:char_class)
59
+ end
60
+
61
+ class Expression < Parslet::Parser
62
+ rule(:lparen) { str('(') }
63
+ rule(:rparen) { str(')') }
64
+ rule(:pipe) { str('|') }
65
+ rule(:backslash) { str('\\') }
66
+
67
+ rule(:literal) { match["^#{NON_LITERALS}"].as(:letter) >> Repeat.new.maybe }
68
+
69
+ rule(:wildcard) { str('.').as(:wildcard) >> Repeat.new.maybe }
70
+
71
+ rule(:non_capturing) { str('?:') | str("?-mix:") }
72
+ rule(:group) { lparen >> non_capturing.maybe >> expression.as(:elements) >> rparen >> Repeat.new.maybe }
73
+
74
+ rule(:thing) { anchor | ShorthandCharacterClass.new | EscapeChar.new | wildcard.as(:wildcard) | literal.as(:literal) | group.as(:group) | CharacterClass.new }
75
+ rule(:things) { thing.repeat(1) }
76
+
77
+ rule(:anchor) { str("^") | str("$") | backslash >> match["bBAzZ"] }
78
+
79
+ rule(:alternation) { things.as(:alt) >> (pipe >> things.as(:alt)).repeat(1) }
80
+
81
+ rule(:expression) { alternation.as(:alternation) | things }
82
+ root(:expression)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,32 @@
1
+ module Expgen
2
+ module Randomizer
3
+ extend self
4
+
5
+ def range(number)
6
+ if number == "*"
7
+ [0,5]
8
+ elsif number == "+"
9
+ [1,5]
10
+ elsif number
11
+ [number[:int].to_i, number[:int].to_i]
12
+ else
13
+ [1,1]
14
+ end
15
+ end
16
+
17
+ def repeat(number)
18
+ first, last = range(number)
19
+ number = rand(last - first + 1) + first
20
+ number.times.map { yield }.join
21
+ end
22
+
23
+ def randomize(tree)
24
+ case tree
25
+ when Array then tree.map { |el| randomize(el) }.join
26
+ when Nodes::Alternation then randomize(tree.options.sample)
27
+ when Nodes::Group then repeat(tree.repeat) { randomize(tree.elements) }
28
+ when Nodes::Character then repeat(tree.repeat) { tree.chars.sample }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
1
+ module Expgen
2
+ class Transform < Parslet::Transform
3
+ rule(:literal => subtree(:x)) { Nodes::Literal.new(x) }
4
+ rule(:wildcard => subtree(:x)) { Nodes::Wildcard.new(x) }
5
+ rule(:char_class_range => subtree(:x)) { Nodes::Range.new(x) }
6
+ rule(:char_class_literal => subtree(:x)) { Nodes::Literal.new(x) }
7
+ rule(:char_class_shorthand => subtree(:x)) { Nodes::Shorthand.new(x) }
8
+ rule(:char_class => subtree(:x)) { Nodes::CharacterClass.new(x) }
9
+ rule(:escape_char_control => subtree(:x)) { Nodes::EscapeCharControl.new(x) }
10
+ rule(:escape_char_literal => subtree(:x)) { Nodes::EscapeCharLiteral.new(x) }
11
+ rule(:code_point_octal => subtree(:x)) { Nodes::CodePointOctal.new(x) }
12
+ rule(:code_point_hex => subtree(:x)) { Nodes::CodePointHex.new(x) }
13
+ rule(:code_point_unicode => subtree(:x)) { Nodes::CodePointUnicode.new(x) }
14
+ rule(:bracket_expression => subtree(:x)) { Nodes::BracketExpression.new(x) }
15
+ rule(:group => subtree(:x)) { Nodes::Group.new(x) }
16
+ rule(:alternation => subtree(:x)) { Nodes::Alternation.new(x) }
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module Expgen
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,243 @@
1
+ require "spec_helper"
2
+
3
+ describe Expgen do
4
+ def self.test(exp)
5
+ it "can generate expressions which match #{exp.inspect}", :caller => caller do
6
+ 20.times { Expgen.gen(exp).should =~ exp }
7
+ end
8
+ end
9
+
10
+ it "raises an exception if the regexp can't be parsed" do
11
+ expect { Expgen.gen(/(?!foo)/) } .to raise_error(Expgen::ParseError)
12
+ end
13
+
14
+ it "can generate from a string" do
15
+ Expgen.gen("f\wo").should =~ /f\wo/
16
+ end
17
+
18
+ test(/foo|bar/)
19
+
20
+ describe "groups" do
21
+ test(/(foo)/)
22
+ test(/(foo|bar)/)
23
+ test(/f(oo|ba)r/)
24
+ test(/f(oo|ba){3}r/)
25
+ test(/f(oo|ba){3,6}r/)
26
+ test(/f(oo|ba){3,}r/)
27
+ test(/f(oo|ba)+r/)
28
+ test(/f(oo|ba)*r/)
29
+ test(/f(oo|ba)?r/)
30
+ test(/f(oo|ba|qx|foo)+r/)
31
+ test(/(oo)|(ba)/)
32
+ test(/(o(blah|baz)(o|b))|(ba)/)
33
+ end
34
+
35
+ describe "character classes" do
36
+ test(/[abcd]/)
37
+ test(/f[abcd]b/)
38
+ test(/f[a-z]b/)
39
+ test(/f[0-9]b/)
40
+ test(/f[&a-z%]b/)
41
+ test(/f[abcd]b/)
42
+ test(/f[abcd]*b/)
43
+ test(/f[abcd]+b/)
44
+ test(/f[abcd]{2}b/)
45
+ test(/f[abcd]{2,}b/)
46
+ test(/f[abcd]{2,4}b/)
47
+ test(/f[abcd]?b/)
48
+ end
49
+
50
+ describe "anchors (are simply ignored)" do
51
+ test(/^foo$/)
52
+ test(/\bfoo\b/)
53
+ test(/f\Bfo/)
54
+ test(/\Afoo\z/)
55
+ test(/\Afoo\Z/)
56
+ end
57
+
58
+ describe "shorthand character classes" do
59
+ test(/f\wo/)
60
+ test(/f\w+o/)
61
+ test(/f\w*o/)
62
+ test(/f\w{2}o/)
63
+ test(/f\w{3,}o/)
64
+ test(/f\w{2,4}o/)
65
+ test(/f\w?o/)
66
+ test(/f\Wo/)
67
+ test(/f\do/)
68
+ test(/f\Do/)
69
+ test(/f\ho/)
70
+ test(/f\Ho/)
71
+ test(/f\so/)
72
+ test(/f\So/)
73
+ end
74
+
75
+ describe "shorthand character classes inside regular character classes" do
76
+ test(/f[\w]o/)
77
+ test(/f[\w%&]o/)
78
+ test(/f[\w]o/)
79
+ end
80
+
81
+ describe "negated character classes" do
82
+ test(/[^abcd]/)
83
+ test(/f[^abcd]b/)
84
+ test(/f[^a-z]b/)
85
+ test(/f[^0-9]b/)
86
+ test(/f[^&a-z%]b/)
87
+ test(/f[^abcd]b/)
88
+ test(/f[^abcd]*b/)
89
+ test(/f[^abcd]+b/)
90
+ test(/f[^abcd]{2}b/)
91
+ test(/f[^abcd]{2,}b/)
92
+ test(/f[^abcd]{2,4}b/)
93
+ test(/f[^\w]o/)
94
+ test(/f[^\w%&]o/)
95
+ test(/f[^\w]o/)
96
+ end
97
+
98
+ describe "control characters" do
99
+ test(/f\no/)
100
+ test(/f\so/)
101
+ test(/f\ro/)
102
+ test(/f\to/)
103
+ test(/f\vo/)
104
+ test(/f\fo/)
105
+ test(/f\ao/)
106
+ test(/f\eo/)
107
+ test(/f\345o/)
108
+ test(/f\345123o/)
109
+ test(/f\xAFo/)
110
+ test(/f\xAF12o/)
111
+ test(/f\u04AFo/u)
112
+ test(/f\u04AF00o/u)
113
+ test(/f\qo/)
114
+ end
115
+
116
+ describe "control characters in character classes" do
117
+ test(/f[\n]o/)
118
+ test(/f[\s]o/)
119
+ test(/f[\r]o/)
120
+ test(/f[\t]o/)
121
+ test(/f[\v]o/)
122
+ test(/f[\f]o/)
123
+ test(/f[\a]o/)
124
+ test(/f[\e]o/)
125
+ test(/f[\345]o/)
126
+ test(/f[\xAF]o/)
127
+ test(/f[\u04AF]o/u)
128
+ test(/f[\q]o/)
129
+ end
130
+
131
+ describe "repeated letters" do
132
+ test(/fo*o/)
133
+ test(/fo+o/)
134
+ test(/fo{2}o/)
135
+ test(/fo{2,}o/)
136
+ test(/fo{2,4}o/)
137
+ test(/fo?o/)
138
+ end
139
+
140
+ describe "repeated escape characters" do
141
+ test(/f\n*o/)
142
+ test(/f\n+o/)
143
+ test(/f\n{2}o/)
144
+ test(/f\n{2,5}o/)
145
+ test(/f\n?o/)
146
+ test(/f\345*o/)
147
+ test(/f\345+o/)
148
+ test(/f\345{2}o/)
149
+ test(/f\345{2,}o/)
150
+ test(/f\345{2,4}o/)
151
+ test(/f\345?o/)
152
+ test(/f\xAF*o/)
153
+ test(/f\xAF+o/)
154
+ test(/f\xAF{2}o/)
155
+ test(/f\xAF{2,}o/)
156
+ test(/f\xAF{2,4}o/)
157
+ test(/f\xAF?o/)
158
+ test(/f\u04AF*o/u)
159
+ test(/f\u04AF+o/u)
160
+ test(/f\u04AF{2}o/u)
161
+ test(/f\u04AF{2,}o/u)
162
+ test(/f\u04AF{2,4}o/u)
163
+ test(/f\u04AF?o/u)
164
+ test(/f\q+o/)
165
+ test(/f\q*o/)
166
+ test(/f\q{2}o/)
167
+ test(/f\q{2,}o/)
168
+ test(/f\q{2,4}o/)
169
+ test(/f\q?o/)
170
+ end
171
+
172
+ describe "escaped special characters" do
173
+ test(/\//)
174
+ test(/#{Expgen::NON_LITERALS}/)
175
+ test(/}{/)
176
+ test(/\{\}/)
177
+ end
178
+
179
+ describe "the wildcard character" do
180
+ test(/f.*o/)
181
+ test(/f.+o/)
182
+ test(/f.{2}o/)
183
+ test(/f.{2,}o/)
184
+ test(/f.{2,4}o/)
185
+ test(/f.?o/)
186
+ end
187
+
188
+ describe "special char inside character class" do
189
+ test(/f[.]o/)
190
+ test(/f[\\]o/)
191
+ test(/f[a^]o/)
192
+ test(/f[$]o/)
193
+ test(/f[|]o/)
194
+ test(/f[?]o/)
195
+ test(/f[*]o/)
196
+ test(/f[+]o/)
197
+ test(/f[(]o/)
198
+ test(/f[)]o/)
199
+ test(/f[{]o/)
200
+ test(/f[}]o/)
201
+ end
202
+
203
+ describe "optional capture groups" do
204
+ test(/f(?:foo)o/)
205
+ test(/f(?:foo|bar)+o/)
206
+ end
207
+
208
+ describe "weird interpolation thing" do
209
+ test(/f#{/oo/}o/)
210
+ end
211
+
212
+ describe "bracket expressions" do
213
+ test(/f[[:alnum:]]o/)
214
+ test(/f[[:alpha:]]o/)
215
+ test(/f[[:blank:]]o/)
216
+ test(/f[[:cntrl:]]o/)
217
+ test(/f[[:digit:]]o/)
218
+ test(/f[[:graph:]]o/)
219
+ test(/f[[:lower:]]o/)
220
+ test(/f[[:print:]]o/)
221
+ test(/f[[:punct:]]o/)
222
+ test(/f[[:space:]]o/)
223
+ test(/f[[:upper:]]o/)
224
+ test(/f[[:xdigit:]]o/)
225
+ test(/f[[:word:]]o/)
226
+ test(/f[[:ascii:]]o/)
227
+ end
228
+
229
+ describe "negated bracket expressions" do
230
+ test(/f[^[:alnum:]]o/)
231
+ test(/f[^[:alpha:]]o/)
232
+ test(/f[^[:blank:]]o/)
233
+ test(/f[^[:cntrl:]]o/)
234
+ test(/f[^[:digit:]]o/)
235
+ test(/f[^[:graph:]]o/)
236
+ test(/f[^[:lower:]]o/)
237
+ test(/f[^[:punct:]]o/)
238
+ test(/f[^[:space:]]o/)
239
+ test(/f[^[:upper:]]o/)
240
+ test(/f[^[:xdigit:]]o/)
241
+ test(/f[^[:word:]]o/)
242
+ end
243
+ end
@@ -0,0 +1,6 @@
1
+ require "expgen"
2
+ require "pry"
3
+
4
+ RSpec.configure do |c|
5
+ c.treat_symbols_as_metadata_keys_with_true_values = true
6
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: expgen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonas Nicklas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: parslet
16
+ prerelease: false
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ none: false
23
+ type: :runtime
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ name: pry
32
+ prerelease: false
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ none: false
39
+ type: :development
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ none: false
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ prerelease: false
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ none: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ none: false
62
+ description: Generate random strings from regular expression
63
+ email:
64
+ - jonas.nicklas@gmail.com
65
+ executables:
66
+ - expgen
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - Gemfile
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - bin/expgen
76
+ - expgen.gemspec
77
+ - lib/expgen.rb
78
+ - lib/expgen/nodes.rb
79
+ - lib/expgen/parser.rb
80
+ - lib/expgen/randomizer.rb
81
+ - lib/expgen/transform.rb
82
+ - lib/expgen/version.rb
83
+ - spec/expgen_spec.rb
84
+ - spec/spec_helper.rb
85
+ homepage: ''
86
+ licenses: []
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ none: false
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ none: false
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 1.8.24
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Generate random regular expression
109
+ test_files:
110
+ - spec/expgen_spec.rb
111
+ - spec/spec_helper.rb
112
+ has_rdoc: