forgery 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +99 -0
- data/VERSION.yml +4 -0
- data/generators/forgery/USAGE +6 -0
- data/generators/forgery/forgery_generator.rb +12 -0
- data/lib/dictionaries.rb +24 -0
- data/lib/dictionaries/cities +478 -0
- data/lib/dictionaries/colors +19 -0
- data/lib/dictionaries/company_names +400 -0
- data/lib/dictionaries/countries +249 -0
- data/lib/dictionaries/female_first_names +100 -0
- data/lib/dictionaries/frequencies +8 -0
- data/lib/dictionaries/genders +2 -0
- data/lib/dictionaries/languages +97 -0
- data/lib/dictionaries/last_names +250 -0
- data/lib/dictionaries/lorem_ipsum +151 -0
- data/lib/dictionaries/male_first_names +100 -0
- data/lib/dictionaries/name_suffixes +5 -0
- data/lib/dictionaries/name_titles +6 -0
- data/lib/dictionaries/province_abbrevs +13 -0
- data/lib/dictionaries/provinces +13 -0
- data/lib/dictionaries/races +93 -0
- data/lib/dictionaries/shirt_sizes +7 -0
- data/lib/dictionaries/state_abbrevs +50 -0
- data/lib/dictionaries/states +50 -0
- data/lib/dictionaries/street_suffixes +21 -0
- data/lib/dictionaries/streets +500 -0
- data/lib/dictionaries/top_level_domains +9 -0
- data/lib/extensions/array.rb +11 -0
- data/lib/extensions/hash.rb +12 -0
- data/lib/extensions/range.rb +9 -0
- data/lib/extensions/string.rb +48 -0
- data/lib/file_reader.rb +53 -0
- data/lib/forgeries/address_forgery.rb +136 -0
- data/lib/forgeries/basic_forgery.rb +71 -0
- data/lib/forgeries/internet_forgery.rb +17 -0
- data/lib/forgeries/lorem_ipsum_forgery.rb +112 -0
- data/lib/forgeries/monetary_forgery.rb +13 -0
- data/lib/forgeries/name_forgery.rb +34 -0
- data/lib/forgeries/personal_forgery.rb +22 -0
- data/lib/forgery.rb +47 -0
- data/lib/formats.rb +24 -0
- data/lib/formats/phone +1 -0
- data/lib/formats/street_number +5 -0
- data/lib/formats/zip +2 -0
- data/spec/dictionaries_spec.rb +35 -0
- data/spec/extensions/array_spec.rb +25 -0
- data/spec/extensions/range_spec.rb +26 -0
- data/spec/extensions/string_spec.rb +29 -0
- data/spec/file_reader_spec.rb +11 -0
- data/spec/forgeries/address_forgery_spec.rb +79 -0
- data/spec/forgeries/basic_forgery_spec.rb +175 -0
- data/spec/forgeries/internet_forgery_spec.rb +30 -0
- data/spec/forgeries/lorem_ipsum_forgery_spec.rb +128 -0
- data/spec/forgeries/monetary_forgery_spec.rb +4 -0
- data/spec/forgeries/name_forgery_spec.rb +4 -0
- data/spec/forgeries/personal_forgery_spec.rb +15 -0
- data/spec/forgery_spec.rb +42 -0
- data/spec/formats_spec.rb +35 -0
- data/spec/spec_helper.rb +32 -0
- metadata +114 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
class Hash
|
2
|
+
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
3
|
+
def reverse_merge(other_hash)
|
4
|
+
other_hash.merge(self)
|
5
|
+
end
|
6
|
+
|
7
|
+
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
8
|
+
# Modifies the receiver in place.
|
9
|
+
def reverse_merge!(other_hash)
|
10
|
+
replace(reverse_merge(other_hash))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class String
|
2
|
+
def to_numbers(replace='#')
|
3
|
+
self.gsub(/#{replace}/){ Kernel.rand(10) }
|
4
|
+
end
|
5
|
+
|
6
|
+
if !defined?(RAILS_ROOT)
|
7
|
+
def camelize(first_letter = :upper)
|
8
|
+
case first_letter
|
9
|
+
when :upper
|
10
|
+
to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
11
|
+
when :lower
|
12
|
+
first.downcase + camelize(self)[1..-1]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def underscore
|
17
|
+
to_s.gsub(/::/, '/').
|
18
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
19
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
20
|
+
tr("-", "_").
|
21
|
+
downcase
|
22
|
+
end
|
23
|
+
|
24
|
+
if Module.method(:const_get).arity == 1
|
25
|
+
def constantize
|
26
|
+
names = self.split('::')
|
27
|
+
names.shift if names.empty? || names.first.empty?
|
28
|
+
|
29
|
+
constant = Object
|
30
|
+
names.each do |name|
|
31
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
32
|
+
end
|
33
|
+
constant
|
34
|
+
end
|
35
|
+
else
|
36
|
+
def constantize
|
37
|
+
names = self.split('::')
|
38
|
+
names.shift if names.empty? || names.first.empty?
|
39
|
+
|
40
|
+
constant = Object
|
41
|
+
names.each do |name|
|
42
|
+
constant = constant.const_get(name, false) || constant.const_missing(name)
|
43
|
+
end
|
44
|
+
constant
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/file_reader.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
class FileReader
|
2
|
+
|
3
|
+
def self.read_dictionary(dictionary)
|
4
|
+
read_file(path_to_dictionary(dictionary))
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.read_format(format)
|
8
|
+
read_file(path_to_format(format))
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def self.read_file(file)
|
14
|
+
lines = []
|
15
|
+
IO.foreach(file) do |line|
|
16
|
+
lines << line.chomp unless line.chomp == ''
|
17
|
+
end
|
18
|
+
lines
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.path_to_format(format)
|
22
|
+
if external_path_to_format(format) && File.exists?(external_path_to_format(format))
|
23
|
+
external_path_to_format(format)
|
24
|
+
else
|
25
|
+
internal_path_to_format(format)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.external_path_to_format(format)
|
30
|
+
RAILS_ROOT + '/lib/forgery/formats/' + format.to_s if defined?(RAILS_ROOT)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.internal_path_to_format(format)
|
34
|
+
File.dirname(__FILE__) + '/formats/' + format.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.path_to_dictionary(dictionary)
|
38
|
+
if external_path_to_dictionary(dictionary) && File.exists?(external_path_to_dictionary(dictionary))
|
39
|
+
external_path_to_dictionary(dictionary)
|
40
|
+
else
|
41
|
+
internal_path_to_dictionary(dictionary)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.external_path_to_dictionary(dictionary)
|
46
|
+
RAILS_ROOT + '/lib/forgery/dictionaries/' + dictionary.to_s if defined?(RAILS_ROOT)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.internal_path_to_dictionary(dictionary)
|
50
|
+
File.dirname(__FILE__) + '/dictionaries/' + dictionary.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Generates random address information.
|
2
|
+
class AddressForgery < Forgery
|
3
|
+
# Gets a random street name out of the 'streets' dictionary.
|
4
|
+
#
|
5
|
+
# AddressForgery.street_name
|
6
|
+
# # => "Atwood"
|
7
|
+
#
|
8
|
+
# AddressForgery.street_name
|
9
|
+
# # => "Fordem"
|
10
|
+
def self.street_name
|
11
|
+
dictionaries[:streets].random
|
12
|
+
end
|
13
|
+
|
14
|
+
# Gets one of the formats from 'street_number_formats' and converts it to
|
15
|
+
# numbers.
|
16
|
+
#
|
17
|
+
# AddressForgery.street_number
|
18
|
+
# # => 1
|
19
|
+
#
|
20
|
+
# AddressForgery.street_number
|
21
|
+
# # => 1234
|
22
|
+
def self.street_number
|
23
|
+
formats[:street_number].random.to_numbers
|
24
|
+
end
|
25
|
+
|
26
|
+
# Gets a random street suffix out of the 'street_suffixes' dictionary.
|
27
|
+
#
|
28
|
+
# AddressForgery.street_suffix
|
29
|
+
# # => "Street"
|
30
|
+
#
|
31
|
+
# AddressForgery.street_suffix
|
32
|
+
# # => "Parkway"
|
33
|
+
def self.street_suffix
|
34
|
+
dictionaries[:street_suffixes].random
|
35
|
+
end
|
36
|
+
|
37
|
+
# Gets a full street address, including street number, street name, and
|
38
|
+
# street suffix.
|
39
|
+
#
|
40
|
+
# AddressForgery.street_address
|
41
|
+
# # => "92 West Circle"
|
42
|
+
#
|
43
|
+
# AddressForgery.street_address
|
44
|
+
# # => "93265 Harper Lane"
|
45
|
+
def self.street_address
|
46
|
+
"#{street_number} #{street_name} #{street_suffix}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Gets a random city out of the 'cities' dictionary.
|
50
|
+
#
|
51
|
+
# AddressForgery.city
|
52
|
+
# # => "Anaheim"
|
53
|
+
#
|
54
|
+
# AddressForgery.city
|
55
|
+
# # => "Sacramento"
|
56
|
+
def self.city
|
57
|
+
dictionaries[:cities].random
|
58
|
+
end
|
59
|
+
|
60
|
+
# Gets a random state out of the 'states' dictionary.
|
61
|
+
#
|
62
|
+
# AddressForgery.state
|
63
|
+
# # => "Mississippi"
|
64
|
+
#
|
65
|
+
# AddressForgery.state
|
66
|
+
# # => "Minnesota"
|
67
|
+
def self.state
|
68
|
+
dictionaries[:states].random
|
69
|
+
end
|
70
|
+
|
71
|
+
# Gets a random state abbreviation out of the 'state_abbrev' dictionary.
|
72
|
+
#
|
73
|
+
# AddressForgery.state_abbrev
|
74
|
+
# # => "GA"
|
75
|
+
#
|
76
|
+
# AddressForgery.state_abbrev
|
77
|
+
# # => "TX"
|
78
|
+
def self.state_abbrev
|
79
|
+
dictionaries[:state_abbrevs].random
|
80
|
+
end
|
81
|
+
|
82
|
+
# Gets a random Canadian province or territory out of the 'provinces' dictionary.
|
83
|
+
#
|
84
|
+
# AddressForgery.province
|
85
|
+
# # => "Ontario"
|
86
|
+
#
|
87
|
+
# AddressForgery.province
|
88
|
+
# # => "Northwest Territories"
|
89
|
+
def self.province
|
90
|
+
dictionaries[:provinces].random
|
91
|
+
end
|
92
|
+
|
93
|
+
# Gets a random Canadian province or territory abbreviation out of the 'province_abbrev' dictionary.
|
94
|
+
#
|
95
|
+
# AddressForgery.province_abbrev
|
96
|
+
# # => "ON"
|
97
|
+
#
|
98
|
+
# AddressForgery.province_abbrev
|
99
|
+
# # => "NT"
|
100
|
+
def self.province_abbrev
|
101
|
+
dictionaries[:province_abbrevs].random
|
102
|
+
end
|
103
|
+
|
104
|
+
# Gets one of the formats from 'zip_formats' and converts it to numbers.
|
105
|
+
#
|
106
|
+
# AddressForgery.zip
|
107
|
+
# # => "52474"
|
108
|
+
#
|
109
|
+
# AddressForgery.zip
|
110
|
+
# # => "66702-4349"
|
111
|
+
def self.zip
|
112
|
+
formats[:zip].random.to_numbers
|
113
|
+
end
|
114
|
+
|
115
|
+
# Gets one of the formats from 'phone_formats' and converts it to numbers.
|
116
|
+
#
|
117
|
+
# AddressForgery.phone
|
118
|
+
# # => "1-(416)185-8799"
|
119
|
+
#
|
120
|
+
# AddressForgery.phone
|
121
|
+
# # => "1-(589)248-0418"
|
122
|
+
def self.phone
|
123
|
+
formats[:phone].random.to_numbers
|
124
|
+
end
|
125
|
+
|
126
|
+
# Gets a random country out of the 'countries' dictionary.
|
127
|
+
#
|
128
|
+
# AddressForgery.country
|
129
|
+
# # => "Uruguay"
|
130
|
+
#
|
131
|
+
# AddressForgery.country
|
132
|
+
# # => "Romania"
|
133
|
+
def self.country
|
134
|
+
dictionaries[:countries].random
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
class BasicForgery < Forgery
|
4
|
+
HEX_DIGITS = %w{0 1 2 3 4 5 6 7 8 9 a b c d e f}
|
5
|
+
UPPER_ALPHA = ('A'..'Z').to_a
|
6
|
+
LOWER_ALPHA = ('a'..'z').to_a
|
7
|
+
NUMERIC = ('0'..'9').to_a
|
8
|
+
SPECIAL_CHARACTERS = %w{! ' @ # $ % ^ & * ( ) _ + - = [ ] { } ; : " , . / ?}
|
9
|
+
BOOLEAN = [true, false]
|
10
|
+
|
11
|
+
def self.password(options={})
|
12
|
+
options = {:at_least => 6,
|
13
|
+
:at_most => 12,
|
14
|
+
:allow_lower => true,
|
15
|
+
:allow_upper => true,
|
16
|
+
:allow_numeric => true,
|
17
|
+
:allow_special => false}.merge!(options)
|
18
|
+
self.text(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.encrypt(password="password", salt=Time.now.to_s)
|
22
|
+
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.boolean
|
26
|
+
BOOLEAN.random
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.color
|
30
|
+
dictionaries[:colors].random
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.hex_color
|
34
|
+
hex_digits = (1..6).collect { HEX_DIGITS.random}
|
35
|
+
"##{hex_digits.join}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.short_hex_color
|
39
|
+
hex_color[0,4]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.number(options={})
|
43
|
+
options = {:at_least => 1,
|
44
|
+
:at_most => 10}.merge(options)
|
45
|
+
|
46
|
+
(options[:at_least]..options[:at_most]).random
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.text(options={})
|
50
|
+
options = {:at_least => 10,
|
51
|
+
:at_most => 15,
|
52
|
+
:allow_lower => true,
|
53
|
+
:allow_upper => true,
|
54
|
+
:allow_numeric => true,
|
55
|
+
:allow_special => false}.merge!(options)
|
56
|
+
|
57
|
+
allowed_characters = []
|
58
|
+
allowed_characters += LOWER_ALPHA if options[:allow_lower]
|
59
|
+
allowed_characters += UPPER_ALPHA if options[:allow_upper]
|
60
|
+
allowed_characters += NUMERIC if options[:allow_numeric]
|
61
|
+
allowed_characters += SPECIAL_CHARACTERS if options[:allow_special]
|
62
|
+
|
63
|
+
length = (options[:at_least]..options[:at_most]).random
|
64
|
+
|
65
|
+
allowed_characters.random_subset(length).join
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.frequency
|
69
|
+
dictionaries[:frequencies].random
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class InternetForgery < Forgery
|
2
|
+
def self.user_name
|
3
|
+
(dictionaries[:male_first_names].random[0,1] + dictionaries[:last_names].random).downcase
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.top_level_domain
|
7
|
+
dictionaries[:top_level_domains].random
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.domain_name
|
11
|
+
dictionaries[:company_names].random.downcase + '.' + self.top_level_domain
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.email_address
|
15
|
+
self.user_name + '@' + self.domain_name
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class LoremIpsumForgery < Forgery
|
2
|
+
|
3
|
+
def self.text(what=:sentence, quantity=2, options={})
|
4
|
+
case what
|
5
|
+
when :character
|
6
|
+
self.character(options)
|
7
|
+
when :characters
|
8
|
+
self.characters(quantity, options)
|
9
|
+
when :word
|
10
|
+
self.word(options)
|
11
|
+
when :words
|
12
|
+
self.words(quantity, options)
|
13
|
+
when :sentence
|
14
|
+
self.sentence(options)
|
15
|
+
when :sentences
|
16
|
+
self.sentences(quantity, options)
|
17
|
+
when :paragraph
|
18
|
+
self.paragraph(options)
|
19
|
+
when :paragraphs
|
20
|
+
self.paragraphs(quantity, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.character(options={})
|
26
|
+
self.characters(1, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.characters(quantity=10, options={})
|
30
|
+
options.merge!(:random_limit => lorem_ipsum_characters.length-quantity) if quantity.is_a?(Fixnum)
|
31
|
+
|
32
|
+
lorem_ipsum_characters[range_from_quantity(quantity, options)]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.word(options={})
|
36
|
+
self.words(1, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.words(quantity=10, options={})
|
40
|
+
options.merge!(:random_limit => lorem_ipsum_words.length-quantity) if quantity.is_a?(Fixnum)
|
41
|
+
|
42
|
+
lorem_ipsum_words[range_from_quantity(quantity, options)].join(" ")
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.sentence(options={})
|
46
|
+
self.sentences(1, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.sentences(quantity=2, options={})
|
50
|
+
options.merge!(:random_limit => (dictionaries[:lorem_ipsum].length-quantity)) if quantity.is_a?(Fixnum)
|
51
|
+
|
52
|
+
dictionaries[:lorem_ipsum][range_from_quantity(quantity, options)].join(" ")
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.paragraph(options={})
|
56
|
+
self.paragraphs(1, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.paragraphs(quantity=2, options={})
|
60
|
+
options.reverse_merge!(:separator => "\n\n",
|
61
|
+
:wrap => {
|
62
|
+
:start => "",
|
63
|
+
:end => "" },
|
64
|
+
:html => false,
|
65
|
+
:sentences => 3)
|
66
|
+
options.merge!(:random_limit => (dictionaries[:lorem_ipsum].length/options[:sentences])-quantity) if quantity.is_a?(Fixnum)
|
67
|
+
|
68
|
+
if options[:html]
|
69
|
+
options[:wrap] = { :start => "<p>",
|
70
|
+
:end => "</p>" }
|
71
|
+
end
|
72
|
+
|
73
|
+
range = range_from_quantity(quantity, options)
|
74
|
+
start = range.first * options[:sentences]
|
75
|
+
|
76
|
+
paragraphs = []
|
77
|
+
|
78
|
+
range.to_a.length.times do |i|
|
79
|
+
paragraphs << (
|
80
|
+
options[:wrap][:start] +
|
81
|
+
dictionaries[:lorem_ipsum][start..(start+options[:sentences]-1)].join(" ") +
|
82
|
+
options[:wrap][:end]
|
83
|
+
)
|
84
|
+
start += options[:sentences]
|
85
|
+
end
|
86
|
+
|
87
|
+
paragraphs.join(options[:separator])
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def self.range_from_quantity(quantity, options={})
|
94
|
+
return quantity if quantity.is_a?(Range)
|
95
|
+
|
96
|
+
if options[:random]
|
97
|
+
start = (0..options[:random_limit]).random
|
98
|
+
start..(start+quantity-1)
|
99
|
+
else
|
100
|
+
0..(quantity-1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.lorem_ipsum_words
|
105
|
+
@@lorem_ipsum_words ||= dictionaries[:lorem_ipsum].join(" ").downcase.gsub(/\.|,|;/, '').split(" ")
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.lorem_ipsum_characters
|
109
|
+
@@lorem_ipsum_characters ||= dictionaries[:lorem_ipsum].join("").downcase.gsub(/[^a-z\s]/,'')
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|