expgen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: