forgery 0.2.2
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.
- 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
|