forgery 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/README.markdown +99 -0
  2. data/VERSION.yml +4 -0
  3. data/generators/forgery/USAGE +6 -0
  4. data/generators/forgery/forgery_generator.rb +12 -0
  5. data/lib/dictionaries.rb +24 -0
  6. data/lib/dictionaries/cities +478 -0
  7. data/lib/dictionaries/colors +19 -0
  8. data/lib/dictionaries/company_names +400 -0
  9. data/lib/dictionaries/countries +249 -0
  10. data/lib/dictionaries/female_first_names +100 -0
  11. data/lib/dictionaries/frequencies +8 -0
  12. data/lib/dictionaries/genders +2 -0
  13. data/lib/dictionaries/languages +97 -0
  14. data/lib/dictionaries/last_names +250 -0
  15. data/lib/dictionaries/lorem_ipsum +151 -0
  16. data/lib/dictionaries/male_first_names +100 -0
  17. data/lib/dictionaries/name_suffixes +5 -0
  18. data/lib/dictionaries/name_titles +6 -0
  19. data/lib/dictionaries/province_abbrevs +13 -0
  20. data/lib/dictionaries/provinces +13 -0
  21. data/lib/dictionaries/races +93 -0
  22. data/lib/dictionaries/shirt_sizes +7 -0
  23. data/lib/dictionaries/state_abbrevs +50 -0
  24. data/lib/dictionaries/states +50 -0
  25. data/lib/dictionaries/street_suffixes +21 -0
  26. data/lib/dictionaries/streets +500 -0
  27. data/lib/dictionaries/top_level_domains +9 -0
  28. data/lib/extensions/array.rb +11 -0
  29. data/lib/extensions/hash.rb +12 -0
  30. data/lib/extensions/range.rb +9 -0
  31. data/lib/extensions/string.rb +48 -0
  32. data/lib/file_reader.rb +53 -0
  33. data/lib/forgeries/address_forgery.rb +136 -0
  34. data/lib/forgeries/basic_forgery.rb +71 -0
  35. data/lib/forgeries/internet_forgery.rb +17 -0
  36. data/lib/forgeries/lorem_ipsum_forgery.rb +112 -0
  37. data/lib/forgeries/monetary_forgery.rb +13 -0
  38. data/lib/forgeries/name_forgery.rb +34 -0
  39. data/lib/forgeries/personal_forgery.rb +22 -0
  40. data/lib/forgery.rb +47 -0
  41. data/lib/formats.rb +24 -0
  42. data/lib/formats/phone +1 -0
  43. data/lib/formats/street_number +5 -0
  44. data/lib/formats/zip +2 -0
  45. data/spec/dictionaries_spec.rb +35 -0
  46. data/spec/extensions/array_spec.rb +25 -0
  47. data/spec/extensions/range_spec.rb +26 -0
  48. data/spec/extensions/string_spec.rb +29 -0
  49. data/spec/file_reader_spec.rb +11 -0
  50. data/spec/forgeries/address_forgery_spec.rb +79 -0
  51. data/spec/forgeries/basic_forgery_spec.rb +175 -0
  52. data/spec/forgeries/internet_forgery_spec.rb +30 -0
  53. data/spec/forgeries/lorem_ipsum_forgery_spec.rb +128 -0
  54. data/spec/forgeries/monetary_forgery_spec.rb +4 -0
  55. data/spec/forgeries/name_forgery_spec.rb +4 -0
  56. data/spec/forgeries/personal_forgery_spec.rb +15 -0
  57. data/spec/forgery_spec.rb +42 -0
  58. data/spec/formats_spec.rb +35 -0
  59. data/spec/spec_helper.rb +32 -0
  60. metadata +114 -0
@@ -0,0 +1,9 @@
1
+ biz
2
+ com
3
+ info
4
+ name
5
+ net
6
+ org
7
+ gov
8
+ edu
9
+ mil
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def random
3
+ self[Kernel.rand(size)]
4
+ end
5
+
6
+ def random_subset(len=2)
7
+ rs = []
8
+ len.times { rs << random }
9
+ rs
10
+ end
11
+ end
@@ -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,9 @@
1
+ class Range
2
+ def random
3
+ Integer(first) && Integer(last)
4
+ raise ArgumentError if first > last
5
+ Kernel.rand(last - first + 1) + first
6
+ rescue ArgumentError
7
+ self.to_a.random
8
+ end
9
+ 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
@@ -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