randomexp 0.1.7
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 +7 -0
- data/.gitignore +9 -0
- data/CHANGELOG +20 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README +82 -0
- data/Rakefile +76 -0
- data/TODO +4 -0
- data/lib/randomexp/core_ext/array.rb +5 -0
- data/lib/randomexp/core_ext/integer.rb +5 -0
- data/lib/randomexp/core_ext/range.rb +9 -0
- data/lib/randomexp/core_ext/regexp.rb +7 -0
- data/lib/randomexp/core_ext.rb +6 -0
- data/lib/randomexp/dictionary.rb +32 -0
- data/lib/randomexp/parser.rb +97 -0
- data/lib/randomexp/randgen.rb +78 -0
- data/lib/randomexp/reducer.rb +102 -0
- data/lib/randomexp/version.rb +3 -0
- data/lib/randomexp/wordlists/female_names.rb +25 -0
- data/lib/randomexp/wordlists/male_names.rb +25 -0
- data/lib/randomexp/wordlists/real_name.rb +35 -0
- data/lib/randomexp.rb +22 -0
- data/randomexp.gemspec +25 -0
- data/spec/fixtures/osx_dictionary +235886 -0
- data/spec/regression/regexp_spec.rb +191 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/core_ext/regexp_spec.rb +9 -0
- data/spec/unit/randgen_spec.rb +244 -0
- data/spec/unit/randomexp/parser_spec.rb +77 -0
- data/spec/unit/randomexp/reducer_spec.rb +224 -0
- data/spec/unit/randomexp_spec.rb +158 -0
- data/wordlists/female_names +4275 -0
- data/wordlists/male_names +1219 -0
- data/wordlists/surnames +475 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f4ed76ede990b9650d5c9331fe59588474d2cde7e0db2c6d2498419141addcb6
|
4
|
+
data.tar.gz: 68521de0cdd541576301d925caa1f96d5cd880ec5450ee36d2ae1a6bd39a3f47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '081fcebdacd959ddefc4efa2f4cef6bb33bc90bc7d1ce9fc0eced2125ca2d8452936ee3ec46af276d3b44a8c2e88e4be68479c17c2e7d1b56b8af5ae3ed8f469'
|
7
|
+
data.tar.gz: 3ee83fbb22614b931d84efbbad75330543dd5392f9823f55bd1bd0767aafaf0979e2d79320ab8cbd636a16c9a5c210309599396111a0edbf2e17709baa3b71c7
|
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
== 0.1.4 "Wally Wisoky" 2008-10-08
|
2
|
+
* Added realistic name generation (Matt Aimonetti)
|
3
|
+
* Fixed loadpath issues (Gerrit Kaiser)
|
4
|
+
|
5
|
+
== 0.1.3 "Oological" 2008-07-08
|
6
|
+
* Randgen.word should not return a string that does not match /^\w+$/
|
7
|
+
|
8
|
+
== 0.1.2 "I'm Not Saying It's Not Beta"
|
9
|
+
* Changed rand to Kernel#rand to avoid conflicting with rails (thanks agile!)
|
10
|
+
|
11
|
+
== 0.1.1 "Still Quite Beta" 2008-07-20
|
12
|
+
* Added Range#of method.
|
13
|
+
* Heavy refactoring of the Parser.parse method.
|
14
|
+
* Fixed the /\./ bug.
|
15
|
+
|
16
|
+
== 0.1.0 "Very Beta" 2008-07-08
|
17
|
+
* Initial version of randomexp!
|
18
|
+
* Has support for very simple regular expressions.
|
19
|
+
* Randgen has limited methods.
|
20
|
+
* Dictionary is reading from the local words file.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2021-2022 Naresh Sekar
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Randomexp
|
2
|
+
by Naresh Sekar
|
3
|
+
http://github.com/nareshnavinash/randomexp
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
andexp makes it easy to generate random string from most regular expressions.
|
8
|
+
|
9
|
+
== REQUIREMENTS:
|
10
|
+
|
11
|
+
* none!
|
12
|
+
|
13
|
+
== INSTALL:
|
14
|
+
|
15
|
+
$ sudo gem install randomexp
|
16
|
+
|
17
|
+
== USAGE:
|
18
|
+
|
19
|
+
Randomexp adds the #generate (or #gen, for short) method to the Regexp class,
|
20
|
+
which generates a 'random' string that will match your regular expression.
|
21
|
+
|
22
|
+
/abc|def/.gen
|
23
|
+
# => "def"
|
24
|
+
|
25
|
+
== Valid Regexp's
|
26
|
+
|
27
|
+
Randomexp can only generate matching string from simple regular expression.
|
28
|
+
Except for a few circumstances, wildcards are generally not allowed in the
|
29
|
+
regular expression. is pretty domain specific, so trying to guess when to
|
30
|
+
terminate a random pattern would produce unhelpful data:
|
31
|
+
|
32
|
+
>> /Aa{3}h*!/.gen
|
33
|
+
# => RuntimeError: Sorry, "h*" is too vague, try setting a range: "h{0,3}"
|
34
|
+
>> /Aa{3}h{3,15}!/.gen
|
35
|
+
=> "Aaaahhhhh!"
|
36
|
+
|
37
|
+
>> /(never gonna (give you up|let you down), )*/.gen
|
38
|
+
=> RuntimeError: Sorry, "(...)*" is too vague, try setting a range: "(...){0, 3}"
|
39
|
+
>> /(never gonna (give you up|let you down), ){3,5}/.gen
|
40
|
+
=> "never gonna give you up, never gonna let you down, never gonna give you up, never gonna give you up, "
|
41
|
+
|
42
|
+
The exception being word characters (\w), which generate a random word from the Dictionary class.
|
43
|
+
|
44
|
+
>> /\w+/.gen
|
45
|
+
=> "groveling"
|
46
|
+
|
47
|
+
= Primitives & Complex matches
|
48
|
+
|
49
|
+
The single character matchers supported are words(\w), whitespace(\s), and digits(\d).
|
50
|
+
|
51
|
+
>> /\d{50}/.gen
|
52
|
+
=> "50315410741096763188525493528315906035878741451037"
|
53
|
+
|
54
|
+
When a multiplicity constraint is placed on a word character, a word with the valid length is generated.
|
55
|
+
|
56
|
+
>> /\w{10}/.gen # a word with 10 letters
|
57
|
+
=> "Chaucerism"
|
58
|
+
|
59
|
+
>> /\w{5,15}/.gen
|
60
|
+
=> "cabalistic"
|
61
|
+
|
62
|
+
Complex matchers use the [:...:] syntax within the regular expression.
|
63
|
+
|
64
|
+
>> /[:sentence:]/.gen
|
65
|
+
=> "Nonhearer demetricize toppiece filicic possessedness rhodizite zoomagnetism earwigginess steady"
|
66
|
+
|
67
|
+
Complex matchers can also be added by extending the Randgen class.
|
68
|
+
|
69
|
+
class Randgen
|
70
|
+
def self.serial_number(options = {})
|
71
|
+
/XX\d{4}-\w-\d{5}/.gen
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
>> /[:serial_number:]/.gen
|
76
|
+
=> "XX3770-M-33114"
|
77
|
+
|
78
|
+
= Dictionary
|
79
|
+
|
80
|
+
The Dictionary loads the local users' words file, allowing randomly generated words to be chosen from
|
81
|
+
thousands of entries to the words file. Words are mapped by their length to allow words to be randomly
|
82
|
+
chosen based on size.
|
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems/package_task'
|
2
|
+
require 'rubygems/specification'
|
3
|
+
require 'date'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
PROJECT_NAME = "randomexp"
|
7
|
+
GEM = "randomexp"
|
8
|
+
GEM_VERSION = "0.1.6"
|
9
|
+
AUTHOR = "Naresh Sekar"
|
10
|
+
EMAIL = "nareshnavinash@gmail.com"
|
11
|
+
HOMEPAGE = "http://github.com/nareshnavinash/randomexp"
|
12
|
+
TITLE = "Randomexp Gem"
|
13
|
+
SUMMARY = "Library for generating random strings."
|
14
|
+
FILES = %w(LICENSE README Rakefile TODO CHANGELOG) + Dir.glob("{lib,spec}/**/*") + Dir.glob("wordlists/**/*")
|
15
|
+
RDOC_FILES = %w(LICENSE README Rakefile TODO CHANGELOG) + Dir.glob("lib/**/*")
|
16
|
+
|
17
|
+
task :default => :specs
|
18
|
+
|
19
|
+
spec = Gem::Specification.new do |s|
|
20
|
+
s.name = GEM
|
21
|
+
s.version = GEM_VERSION
|
22
|
+
s.platform = Gem::Platform::RUBY
|
23
|
+
s.has_rdoc = true
|
24
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
25
|
+
s.summary = SUMMARY
|
26
|
+
s.description = s.summary
|
27
|
+
s.author = AUTHOR
|
28
|
+
s.email = EMAIL
|
29
|
+
s.homepage = HOMEPAGE
|
30
|
+
|
31
|
+
s.require_path = 'lib'
|
32
|
+
s.autorequire = GEM
|
33
|
+
s.files = FILES
|
34
|
+
end
|
35
|
+
|
36
|
+
Gem::PackageTask.new(spec) do |package|
|
37
|
+
package.gem_spec = spec
|
38
|
+
package.need_zip = true
|
39
|
+
package.need_tar = true
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "install the gem locally"
|
43
|
+
task :install => [:package] do
|
44
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "create a gemspec file"
|
48
|
+
task :make_spec do
|
49
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
50
|
+
file.puts spec.to_ruby
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##############################################################################
|
55
|
+
# rSpec & rcov
|
56
|
+
##############################################################################
|
57
|
+
desc "Run all unit specs"
|
58
|
+
RSpec::Core::RakeTask.new("specs:unit") do |t|
|
59
|
+
t.rspec_opts = ["--format", "documentation", "--colour"]
|
60
|
+
t.pattern = "spec/unit/**/*_spec.rb"
|
61
|
+
t.rcov_opts = %w[--sort coverage --sort-reverse]
|
62
|
+
t.rcov_opts << '--only-uncovered'
|
63
|
+
t.rcov_opts << '--output coverage/unit'
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Run all regression specs"
|
68
|
+
RSpec::Core::RakeTask.new("specs:regression") do |t|
|
69
|
+
t.rspec_opts = ["--format", "documentation", "--colour"]
|
70
|
+
t.pattern = "spec/regression/**/*_spec.rb"
|
71
|
+
t.rcov_opts = %w[--sort coverage --sort-reverse]
|
72
|
+
t.rcov_opts << '--only-uncovered'
|
73
|
+
t.rcov_opts << '--output coverage/integration'
|
74
|
+
end
|
75
|
+
|
76
|
+
task :specs => ['specs:unit', 'specs:regression']
|
data/TODO
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class Randomexp::Dictionary
|
2
|
+
def self.file_paths
|
3
|
+
@dictionary_path ||= %w[/usr/share/dict/words /usr/dict/words ~/.dict/words]
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.register(path)
|
7
|
+
file_paths.unshift(path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.load_dictionary
|
11
|
+
if path = file_paths.detect {|path| File.exists?(File.expand_path(path)) }
|
12
|
+
File.read(path).split
|
13
|
+
else
|
14
|
+
raise "Words file not found. Check if it is installed in (/usr/share/dict/words or /usr/dict/words) "
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.words(options = {})
|
19
|
+
if options.has_key?(:length)
|
20
|
+
words_by_length[options[:length]]
|
21
|
+
else
|
22
|
+
@@words ||= load_dictionary
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.words_by_length
|
27
|
+
@@words_by_length ||= begin
|
28
|
+
hash = Hash.new {|h,k| h[k] = [] }
|
29
|
+
words.inject(hash) {|h, w| h[w.size] << w; h }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class Randomexp
|
2
|
+
class Parser
|
3
|
+
def self.parse(source)
|
4
|
+
case
|
5
|
+
when source =~ /^(.*)(\*|\*\?|\+|\+\?|\?)$/ && balanced?($1, $2)
|
6
|
+
parse_quantified($1, $2.to_sym) # ends with *, +, or ?: /(..)?/
|
7
|
+
when source =~ /^(.*)\{(\d+)\,(\d+)\}$/ && balanced?($1, $2)
|
8
|
+
parse_quantified($1, ($2.to_i)..($3.to_i)) #ends with a range: /(..){..,..}/
|
9
|
+
when source =~ /^(.*)\{(\d+)\}$/ && balanced?($1, $2)
|
10
|
+
parse_quantified($1, $2.to_i) #ends with a range: /..(..){..}/
|
11
|
+
when source =~ /^\((.*)\)\((.*)\)$/ && balanced?($1, $2)
|
12
|
+
union(parse($1), parse($2)) #balanced union: /(..)(..)/
|
13
|
+
when source =~ /^(\(.*\))\|(\(.*\))$/ && balanced?($1, $2)
|
14
|
+
intersection(parse($1), parse($2)) #balanced intersection: /(..)|(..)/
|
15
|
+
when source =~ /^(.*)\|(.*)$/ && balanced?($1, $2)
|
16
|
+
intersection(parse($1), parse($2)) #implied intersection: /..|../
|
17
|
+
when source =~ /^(.*)\|\((\(.*\))\)$/ && balanced?($1, $2)
|
18
|
+
intersection(parse($1), parse($2)) #unbalanced intersection: /(..)|((...))/
|
19
|
+
when source =~ /^(.+)(\(.*\))$/ && balanced?($1, $2)
|
20
|
+
union(parse($1), parse($2)) #unbalanced union: /...(...)/
|
21
|
+
when source =~ /^\((.*)\)$/ && balanced?($1)
|
22
|
+
union(parse($1)) #explicit group: /(..)/
|
23
|
+
when source =~ /^([^()]*)(\(.*\))$/ && balanced?($1, $2)
|
24
|
+
union(parse($1), parse($2)) #implied group: /..(..)/
|
25
|
+
when source =~ /^(.*)\[\:(.*)\:\]$/
|
26
|
+
union(parse($1), random($2)) #custom random: /[:word:]/
|
27
|
+
when source =~ /^(.*)\\([wsdc])$/
|
28
|
+
union(parse($1), random($2)) #reserved random: /..\w/
|
29
|
+
when source =~ /^(.*)\\(.)$/ || source =~ /(.*)(.|\s)$/
|
30
|
+
union(parse($1), literal($2)) #end with literal or space: /... /
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.parse_quantified(source, multiplicity)
|
37
|
+
case source
|
38
|
+
when /^[^()]*$/ then quantify_rhs(parse(source), multiplicity) #implied union: /...+/
|
39
|
+
when /^(\(.*\))$/ then quantify(parse(source), multiplicity) #group: /(...)?/
|
40
|
+
when /^(.*\))$/ then quantify_rhs(parse(source), multiplicity) #implied union: /...(...)?/
|
41
|
+
when /^(.*[^)]+)$/ then quantify_rhs(parse(source), multiplicity) #implied union: /...(...)...?/
|
42
|
+
else quantify(parse(source), multiplicity)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
alias_method :[], :parse
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.balanced?(*args)
|
51
|
+
args.all? {|s| s.count('(') == s.count(')')}
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.quantify_rhs(sexp, multiplicity)
|
55
|
+
case sexp.first
|
56
|
+
when :union
|
57
|
+
rhs = sexp.pop
|
58
|
+
sexp << quantify(rhs, multiplicity)
|
59
|
+
else
|
60
|
+
quantify(sexp, multiplicity)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.quantify(lhs, sym)
|
65
|
+
[:quantify, lhs, sym]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.union(lhs, *rhs)
|
69
|
+
if lhs.nil?
|
70
|
+
union(*rhs)
|
71
|
+
elsif rhs.empty?
|
72
|
+
lhs
|
73
|
+
elsif lhs.first == :union
|
74
|
+
rhs.each {|s| lhs << s}
|
75
|
+
lhs
|
76
|
+
else
|
77
|
+
[:union, lhs, *rhs]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.intersection(lhs, rhs)
|
82
|
+
if rhs.first == :intersection
|
83
|
+
[:intersection, lhs] + rhs[1..-1]
|
84
|
+
else
|
85
|
+
[:intersection, lhs, rhs]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.random(char)
|
90
|
+
[:random, char.to_sym]
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.literal(word)
|
94
|
+
[:literal, word]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Randgen
|
2
|
+
WORDS_PER_SENTENCE = 3..20
|
3
|
+
SENTENCES_PER_PARAGRAPH = 3..8
|
4
|
+
|
5
|
+
def self.bool(options = {})
|
6
|
+
['true', 'false'].pick_rand_value
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.lchar(options = {})
|
10
|
+
('a'..'z').to_a.pick_rand_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.uchar(options = {})
|
14
|
+
('A'..'Z').to_a.pick_rand_value
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.char(options = {})
|
18
|
+
[lchar, uchar].pick_rand_value
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.whitespace(options = {})
|
22
|
+
["\t", "\n", "\r", "\f"].pick_rand_value
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.digit(options = {})
|
26
|
+
('0'..'9').to_a.pick_rand_value
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.alpha_numeric(options = {})
|
30
|
+
[char, digit].pick_rand_value
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.word(options = {})
|
34
|
+
begin
|
35
|
+
word = Randomexp::Dictionary.words(options).pick_rand_value
|
36
|
+
word ||= options[:length].of { alpha_numeric }.join
|
37
|
+
end until word =~ /^\w+$/
|
38
|
+
|
39
|
+
word
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.first_name(options = {})
|
43
|
+
RealName.first_names(options).pick_rand_value
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.surname(options = {})
|
47
|
+
RealName.surnames(options).pick_rand_value
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
alias_method :last_name, :surname
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.name(options = {})
|
55
|
+
"#{first_name(options)} #{surname(options)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.email(options = {})
|
59
|
+
domain = options.fetch(:domain, "#{word(options)}.example.org")
|
60
|
+
"#{word(options)}@#{domain}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.sentence(options = {})
|
64
|
+
((options[:length] || WORDS_PER_SENTENCE.pick_rand_value).of { word } * " ").capitalize
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.paragraph(options = {})
|
68
|
+
((options[:length] || SENTENCES_PER_PARAGRAPH.pick_rand_value).of { sentence } * ". ") + "."
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.phone_number(options = {})
|
72
|
+
case options[:length]
|
73
|
+
when 7 then /\d{3}-\d{4}/.gen
|
74
|
+
when 10 then /\d{3}-\d{3}-\d{4}/.gen
|
75
|
+
else /(\d{3}-)?\d{3}-\d{4}/.gen
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
class Randomexp
|
2
|
+
class Reducer
|
3
|
+
def self.reduce(sexp, quantity = nil)
|
4
|
+
send(sexp.first, sexp[1..-1], quantity)
|
5
|
+
end
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias_method :[], :reduce
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.quantify(sexp, old_quantity)
|
12
|
+
reduce(*sexp)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.random(sexpish, quantity)
|
16
|
+
case s = sexpish.first
|
17
|
+
when :w then char(quantity)
|
18
|
+
when :s then whitespace(quantity)
|
19
|
+
when :d then digit(quantity)
|
20
|
+
else randgen(s, quantity)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.literal(cell, quantity = nil)
|
25
|
+
case quantity
|
26
|
+
when :'?' then ([''] + cell).pick_rand_value
|
27
|
+
when :+, :'+?' then raise "Sorry, \"#{cell * ''}+\" is too vague, try setting a range: \"#{cell * ''}{1,3}\""
|
28
|
+
when :*, :'*?' then raise "Sorry, \"#{cell * ''}*\" is too vague, try setting a range: \"#{cell * ''}{0,3}\""
|
29
|
+
when Range then quantity.pick_rand_value.of { cell * '' } * ''
|
30
|
+
when Integer then quantity.of { cell * '' } * ''
|
31
|
+
when nil then cell * ''
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.intersection(cell, quantity)
|
36
|
+
case quantity
|
37
|
+
when :'?' then ['', cell.map {|s| reduce(s)}.pick_rand_value].pick_rand_value
|
38
|
+
when :+, :'+?' then raise "Sorry, \"((...)|(...))+\" is too vague, try setting a range: \"((...)|(...)){1, 3}\""
|
39
|
+
when :*, :'*?' then raise "Sorry, \"((...)|(...))*\" is too vague, try setting a range: \"((...)|(...)){0, 3}\""
|
40
|
+
when Range then quantity.pick_rand_value.of { cell.map {|s| reduce(s)}.pick_rand_value } * ''
|
41
|
+
when Integer then quantity.of { cell.map {|s| reduce(s)}.pick_rand_value } * ''
|
42
|
+
when nil then cell.map {|s| reduce(s)}.pick_rand_value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.union(cell, quantity)
|
47
|
+
case quantity
|
48
|
+
when :'?' then ['', cell.map {|s| reduce(s)} * ''].pick_rand_value
|
49
|
+
when :+, :'+?' then raise "Sorry, \"(...)+\" is too vague, try setting a range: \"(...){1, 3}\""
|
50
|
+
when :*, :'*?' then raise "Sorry, \"(...)*\" is too vague, try setting a range: \"(...){0, 3}\""
|
51
|
+
when Range then quantity.pick_rand_value.of { cell.map {|s| reduce(s)} * '' } * ''
|
52
|
+
when Integer then quantity.of { cell.map {|s| reduce(s)} * '' } * ''
|
53
|
+
when nil then cell.map {|s| reduce(s)} * ''
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.char(quantity)
|
58
|
+
case quantity
|
59
|
+
when :'?' then ['', Randgen.char].pick_rand_value
|
60
|
+
when :+, :'+?' then Randgen.word
|
61
|
+
when :*, :'*?' then ['', Randgen.word].pick_rand_value
|
62
|
+
when Range then Randgen.word(:length => quantity.pick_rand_value)
|
63
|
+
when 1, nil then Randgen.char
|
64
|
+
when Integer then Randgen.word(:length => quantity)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.whitespace(quantity)
|
69
|
+
case quantity
|
70
|
+
when :'?' then ['', Randgen.whitespace].pick_rand_value
|
71
|
+
when :+, :'+?' then raise "Sorry, \"\\s+\" is too vague, try setting a range: \"\\s{1, 5}\""
|
72
|
+
when :*, :'*?' then raise "Sorry, \"\\s*\" is too vague, try setting a range: \"\\s{0, 5}\""
|
73
|
+
when Range then quantity.pick_rand_value.of { Randgen.whitespace } * ''
|
74
|
+
when Integer then quantity.of { Randgen.whitespace } * ''
|
75
|
+
when nil then Randgen.whitespace
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.digit(quantity)
|
80
|
+
case quantity
|
81
|
+
when :'?' then ['', Randgen.digit].pick_rand_value
|
82
|
+
when :+, :'+?' then raise "Sorry, \"\\d+\" is too vague, try setting a range: \"\\d{1, 5}\""
|
83
|
+
when :*, :'*?' then raise "Sorry, \"\\d*\" is too vague, try setting a range: \"\\d{0, 5}\""
|
84
|
+
when Range then quantity.pick_rand_value.of { Randgen.digit } * ''
|
85
|
+
when Integer then quantity.of { Randgen.digit } * ''
|
86
|
+
when nil then Randgen.digit
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.randgen(args, quantity)
|
91
|
+
method_name, _ = *args
|
92
|
+
case quantity
|
93
|
+
when :'?' then ['', Randgen.send(method_name, :length => 1)].pick_rand_value
|
94
|
+
when :+, :'+?' then Randgen.send(method_name)
|
95
|
+
when :*, :'*?' then ['', Randgen.send(method_name)].pick_rand_value
|
96
|
+
when Range then Randgen.send(method_name, :length => quantity.pick_rand_value)
|
97
|
+
when 1, nil then Randgen.send(method_name)
|
98
|
+
when Integer then Randgen.send(method_name, :length => quantity)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class RealName
|
2
|
+
|
3
|
+
def self.load_female_first_names
|
4
|
+
dir = File.dirname(__FILE__)
|
5
|
+
if File.exists?("#{dir}/../../../wordlists/female_names")
|
6
|
+
File.read("#{dir}/../../../wordlists/female_names").split
|
7
|
+
else
|
8
|
+
raise "words file not found"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.female_first_names(options = {})
|
13
|
+
if options.has_key?(:length)
|
14
|
+
female_first_names_by_length[options[:length]]
|
15
|
+
else
|
16
|
+
@@female_first_names ||= load_female_first_names
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.female_first_names_by_length
|
21
|
+
@@female_first_names_by_length ||= begin
|
22
|
+
female_first_names.inject(Hash.new {|h,k| h[k] = [] }) {|h, w| (h[w.size] ||= []) << w; h }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class RealName
|
2
|
+
|
3
|
+
def self.load_male_first_names
|
4
|
+
dir = File.dirname(__FILE__)
|
5
|
+
if File.exists?("#{dir}/../../../wordlists/male_names")
|
6
|
+
File.read("#{dir}/../../../wordlists/male_names").split
|
7
|
+
else
|
8
|
+
raise "words file not found"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.male_first_names(options = {})
|
13
|
+
if options.has_key?(:length)
|
14
|
+
male_first_names_by_length[options[:length]]
|
15
|
+
else
|
16
|
+
@@male_first_names ||= load_male_first_names
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.male_first_names_by_length
|
21
|
+
@@male_first_names_by_length ||= begin
|
22
|
+
male_first_names.inject(Hash.new {|h,k| h[k] = [] }) {|h, w| (h[w.size] ||= []) << w; h }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class RealName
|
2
|
+
def self.load_surnames
|
3
|
+
dir = File.dirname(__FILE__)
|
4
|
+
if File.exists?("#{dir}/../../../wordlists/surnames")
|
5
|
+
File.read("#{dir}/../../../wordlists/surnames").split
|
6
|
+
else
|
7
|
+
raise "words file not found"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.surnames(options = {})
|
12
|
+
if options.has_key?(:length)
|
13
|
+
surnames_by_length[options[:length]]
|
14
|
+
else
|
15
|
+
@@surnames ||= load_surnames
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.surnames_by_length
|
20
|
+
@@surnames_by_length ||= begin
|
21
|
+
surnames.inject(Hash.new {|h,k| h[k] = [] }) {|h, w| (h[w.size] ||= []) << w; h }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.first_names(options)
|
26
|
+
case options[:gender].to_s
|
27
|
+
when /^male/i
|
28
|
+
male_first_names(options)
|
29
|
+
when /^female/i
|
30
|
+
female_first_names(options)
|
31
|
+
else
|
32
|
+
[male_first_names(options), female_first_names(options)].pick_rand_value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|