randomperson 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -21,3 +21,4 @@ vendor/
21
21
  bin/
22
22
  docs/
23
23
  .yardoc/
24
+ .rbx/
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ v1.3.0 Tuesday the 11th of September 2012
2
+
3
+ * Quicker to get data out if you're not bothered about the demographic make up.
4
+ * Better error handling.
5
+ * Much easier to find out which name classes have been loaded.
6
+
7
+ ----
8
+
1
9
  v1.2.0 Wednesday the 22nd of August 2012
2
10
 
3
11
  * Removed the evil evals.
data/README.markdown CHANGED
@@ -14,7 +14,7 @@ Development branch:
14
14
 
15
15
  ## QUICK NOTE!
16
16
 
17
- This was the first Ruby library I wrote. I'm adding specs and improving the code now I've half an idea of what I should be doing, but I'd really, *really* appreciate it that if you do see something is wrong or doesn't work for you or you've an idea for improvement **let me know**. Wow, Github makes this so easy, just go for it! I'll be happy to help and happy for the help.
17
+ I'd really, *really* appreciate it that if you see something is wrong or doesn't work for you or you've an idea for improvement **let me know**. Wow, Github makes this so easy, just go for it! I'll be happy to help and happy for the help. Bonus points for a topic branch too!
18
18
 
19
19
 
20
20
  ## Why did I write this?
@@ -29,8 +29,21 @@ It also has unicode characters, so it'll give your database a real test. At leas
29
29
  ## Installation:
30
30
 
31
31
  gem install randomperson
32
+
33
+ ## Super quick start! ##
32
34
 
33
- ## USAGE:
35
+ For those with a short attention span:
36
+
37
+ require 'randomperson'
38
+
39
+ r = RandomPerson() # don't forget the brackets!
40
+ r.generate # => each time this will generate a new person.
41
+
42
+ The demographics will be randomly selected.
43
+
44
+ ## USAGE: ##
45
+
46
+ For those with more willpower:
34
47
 
35
48
  The original API (if you can call it that) was very clunky so I've endeavoured to improve it by adding a nice facade over the top. I'll start off using that but as the examples move along I might do some things "the old fashioned way" by using some of the classes underlying everything directly, just so you know what's going on under there. If you see several ways of doing the same thing don't freak out! You're probably best using the stuff just below here.
36
49
 
@@ -49,7 +62,7 @@ So, to generate 1000 random people with Spanish names, between the ages of 16 an
49
62
 
50
63
  Output:
51
64
 
52
- Bartolomé Andrés de Elixaeberna age: 20 born: 28-Apr-1990
65
+ > Bartolomé Andrés de Elixaeberna age: 20 born: 28-Apr-1990
53
66
  Fabiana Cordero Balmaceda age: 21 born: 14-Jun-1989
54
67
  Jorge Alas Albarracin age: 29 born: 16-Apr-1981
55
68
  Eufemia Berlanga de Sergi age: 33 born: 25-Jan-1977
@@ -69,7 +82,7 @@ Here's an example using the Thai Romanised data:
69
82
 
70
83
  Output:
71
84
 
72
- Yongchaiyuth Sripituksakul Puntasrima age: 39 born: 29-Mar-1971
85
+ > Yongchaiyuth Sripituksakul Puntasrima age: 39 born: 29-Mar-1971
73
86
  Sri-Patana Wattanasin age: 77 born: 04-Feb-1933
74
87
  Wattana Rojjanasukchai age: 7 born: 27-Jun-2003
75
88
  Ban Sukbunsung age: 85 born: 07-Sep-1925
@@ -219,7 +232,8 @@ etc etc
219
232
  or you can do things the old fashioned way (but why? anyway...)
220
233
 
221
234
  require 'namefiles/spanish-female-first'
222
- #obviously you need to use the path from where you are or where the script will run from
235
+ # obviously you need to use the path from where you are
236
+ # or where the script will run from
223
237
 
224
238
  r.demographic["My fancy demo"].femalefirst = RandomPerson::Names::SpanishFemaleFirst.new
225
239
 
@@ -246,24 +260,21 @@ English males:
246
260
  r.demographic.add_English_Male
247
261
 
248
262
 
249
- If you need to check what's loaded, have a look in the instance variables of the demographic:
263
+ If you need to check what's loaded, use `loaded_classes`
250
264
 
251
- r.demographics["Mix n match"].malefirst.class.name
252
- > => "RandomPerson::Names::SpanishMaleFirst"
265
+ r.demographics["French"].loaded_classes
253
266
 
254
- r.demographics["Mix n match"].femalefirst.class.name
255
- > => "RandomPerson::Names::SpanishFemaleFirst"
267
+ > # => {:femalefirst=>"French_Female_First", :last=>"French_Last", :malefirst=>"French_Male_First"}
256
268
 
257
- r.demographics["Mix n match"].last.class.name
258
- > => "RandomPerson::Names::SpanishLast"
269
+ Or, see all the demographics' loaded classes:
259
270
 
260
- r.demographics["Mix n match"].prefix.class.name
261
- > => "RandomPerson::Names::SpanishPrefix"
271
+ r.demographics.loaded_classes
262
272
 
263
- r.demographics["Mix n match"].suffix.class.name
264
- > => "NilClass"
265
-
266
-
273
+ And (because I'm really lazy and like convenience), this does the same:
274
+
275
+ r.loaded_classes
276
+
277
+
267
278
  ## NEGATIONS
268
279
 
269
280
  Sometimes you'll want to load something but not another, you can do this by prepending _not_ to the things you don't want. For example, to get the Thai names that are in Thai script and not romanised:
@@ -357,62 +368,91 @@ If you do make your own name file then fork this project and send me a pull requ
357
368
 
358
369
  These are current name files in the library:
359
370
 
360
- AmericanFemaleFirst
361
- AmericanLast
362
- AmericanMaleFirst
363
- AmericanPrefix
364
- AmericanSuffix
365
- AncientGreekFemaleFirst
366
- AncientGreekLast
367
- AncientGreekMaleFirst
368
- AnyLast
369
- BasqueFemaleFirst
370
- BasqueLast
371
- BasqueMaleFirst
372
- BritishPrefix
373
- BritishSuffix
374
- EnglishFemaleFirst
375
- EnglishLast
376
- EnglishMaleFirst
377
- EnglishPrefix
378
- FinnishFemaleFirst
379
- FinnishLast
380
- FinnishMaleFirst
381
- FinnishPrefix
382
- FrenchFemaleFirst
383
- FrenchLast
384
- FrenchMaleFirst
385
- GermanFemaleFirst
386
- GermanLast
387
- GermanMaleFirst
388
- ScottishFemaleFirst
389
- ScottishLast
390
- ScottishMaleFirst
391
- ScottishPrefix
392
- SpanishFemaleFirst
393
- SpanishLast
394
- SpanishMaleFirst
395
- SpanishPrefix
396
- SwedishFemaleFirst
397
- SwedishLast
398
- SwedishMaleFirst
399
- ThaiFemaleFirst
400
- ThaiFirst
401
- ThaiLast
402
- ThaiMaleFirst
403
- ThaiRomanisedFemaleFirst
404
- ThaiRomanisedLast
405
- ThaiRomanisedMaleFirst
406
- WelshFemaleFirst
407
- WelshLast
408
- WelshMaleFirst
409
- WelshPrefix
371
+ American\_Female\_First
372
+ American\_Last
373
+ American\_Male\_First
374
+ American\_Prefix
375
+ American\_Suffix
376
+ Ancient\_Greek\_Female\_First
377
+ Ancient\_Greek\_Last
378
+ Ancient\_Greek\_Male\_First
379
+ Any\_Last
380
+ Basque\_Female\_First
381
+ Basque\_Last
382
+ Basque\_Male\_First
383
+ British\_Prefix
384
+ British\_Suffix
385
+ English\_Female\_First
386
+ English\_Last
387
+ English\_Male\_First
388
+ English\_Prefix
389
+ Finnish\_Female\_First
390
+ Finnish\_Last
391
+ Finnish\_Male\_First
392
+ Finnish\_Prefix
393
+ French\_Female\_First
394
+ French\_Last
395
+ French\_Male\_First
396
+ German\_Female\_First
397
+ German\_Last
398
+ German\_Male\_First
399
+ Scottish\_Female\_First
400
+ Scottish\_Last
401
+ Scottish\_Male\_First
402
+ Scottish\_Prefix
403
+ Spanish\_Female\_First
404
+ Spanish\_Last
405
+ Spanish\_Male\_First
406
+ Spanish\_Prefix
407
+ Swedish\_Female\_First
408
+ Swedish\_Last
409
+ Swedish\_Male\_First
410
+ Thai\_Female\_First
411
+ Thai\_First
412
+ Thai\_Last
413
+ Thai\_Male\_First
414
+ Thai\_Romanised\_Female\_First
415
+ Thai\_Romanised\_Last
416
+ Thai\_Romanised\_Male\_First
417
+ Welsh\_Female\_First
418
+ Welsh\_Last
419
+ Welsh\_Male\_First
420
+ Welsh\_Prefix
410
421
 
411
422
 
412
423
  ## ACCURACY OF NAMES AND RATIOS
413
424
 
414
425
  I've taken bits and pieces from wherever I could get them, so if you see something is wrong then either let me know or produce a patch, just have a look at the help links on Github for how to do it. I'll also add you name to this readme, and worldly fame will be yours.
415
426
 
427
+ ## PASS A BLOCK TO HANDLE ERRORS ##
428
+
429
+ If you try calling a demographic that doesn't exist yet, an error will be raised. There is a default handler for this, and it will output a warning, and the result returned will be nil. If you wish, you may supply a block to handle the error.
430
+
431
+ e.g.
432
+
433
+ r.person # => this will produce a person, with a randomised demographic
434
+ r.demographic("French").add_French
435
+ r.person # => this will produce a person too, with a French demographic
436
+ r.person "French" # => French again
437
+
438
+ # This raises an error, caught by the default block
439
+ # which prints a warning to stdout
440
+ r.person "British" # => That demographic does not exist!
441
+
442
+ r.person "British" do |error|
443
+ warn "There are no British people here, this is Scotland!"
444
+ end
445
+ # => "There are no British people here, this is Scotland!"
446
+
447
+ The default block can be set via:
448
+
449
+ RandomPerson::Facade.default_error_block= #... put your block here, e.g
450
+ RandomPerson::Facade.default_error_block= ->(error){ warn "-> #{error}" }
451
+
452
+ Or if you're lazy like me and have an instance floating around:
453
+
454
+ r.class.default_error_block= ->(error){ warn "-> #{error}" }
455
+
416
456
  ## TODO:
417
457
 
418
458
  There's lots to do. Lot of repetition and ugly bits here and there, but it works so I'll get round to it when I can.
@@ -421,7 +461,7 @@ There's lots to do. Lot of repetition and ugly bits here and there, but it works
421
461
 
422
462
  Peter Hickman for writing the original library in Perl that inspired this on in Ruby.
423
463
 
424
- My good friends:
464
+ My good friends:
425
465
  Johan Bergsten for helping me out with the Swedish names.
426
466
  HALLOJULIA (hayl yeah!) for helping me with the German names.
427
467
  Aino Rissanen for helping me with the Finnish names.
data/lib/randomperson.rb CHANGED
@@ -5,6 +5,9 @@ module RandomPerson
5
5
 
6
6
  #require all the scaffolding
7
7
 
8
+ require 'set'
9
+ require 'date'
10
+
8
11
  require_relative './randomperson/version.rb'
9
12
  require_relative './randomperson/ext/array.rb'
10
13
  require_relative './randomperson/ext/date.rb'
@@ -19,11 +22,37 @@ module RandomPerson
19
22
  require_relative './randomperson/person.rb'
20
23
  #require_relative './randomperson/ratio.rb'
21
24
 
25
+ class DemoHash < Hash
26
+ def loaded_classes
27
+ if @loaded_classes.nil?
28
+ @loaded_classes = Hash.new
29
+ self.each do |key,demographic|
30
+ @loaded_classes[key] = demographic.loaded_classes
31
+ end
32
+ end
33
+ @loaded_classes
34
+ end
35
+
36
+ alias :old_store :store
37
+ alias :"[]=" :store
38
+
39
+ def store( key, value )
40
+ @loaded_classes ||= Hash.new
41
+ @loaded_classes[key] = value
42
+ old_store key, value
43
+ end
44
+ end
22
45
 
23
46
  class Facade
24
47
 
48
+ # @return [Hash{String => RandomPerson::Demographic}]
25
49
  def demographics
26
- @demos ||= {}
50
+ @demos ||= DemoHash.new
51
+ end
52
+
53
+ # @return [Hash]
54
+ def loaded_classes
55
+ demographics.loaded_classes
27
56
  end
28
57
 
29
58
  #class instance variable to keep track of generators
@@ -32,7 +61,10 @@ module RandomPerson
32
61
  end
33
62
 
34
63
 
35
- # little factory
64
+ # A little factory
65
+ # @param [String,Symbol,Integer] name The key for retrieving the demographic.
66
+ # @param [Hash] opts Option hash to pass to Demographic.new
67
+ # @see Demographic#initialize
36
68
  def demographic( name=nil, opts={} )
37
69
  if name.kind_of? Hash
38
70
  opts = name
@@ -60,40 +92,28 @@ module RandomPerson
60
92
 
61
93
  # The last person generated.
62
94
  # If a demographic name is given that is different to the last then a new person is generated. If no name is given then the last is used.
63
- # @param [String] demo_name The key of the demographic to use, e.g "American Ladies".
64
- def person( demo_name=nil )
95
+ # @param [String,Symbol,Integer] name The key for retrieving the demographic.
96
+ # @param [#call] block Error handler for when a key is given that does not exist.
97
+ # @return [RandomPerson::Person]
98
+ def person( demo_name=nil, &block )
65
99
  person, last_demo_name =
66
100
  if demo_name.nil?
67
-
68
101
  if @person.nil?
69
-
70
102
  # either generate a new one
71
- gen_new( demo_name ) # gen a new person and get back demo name
72
- else
73
-
103
+ gen_new( demo_name, &block ) # gen a new person and get back demo name
104
+ else
74
105
  # get last one
75
106
  [@person, @last_demo_name]
76
107
  end
77
108
  else # demo name given
78
-
79
109
  if demographics.has_key? demo_name
80
-
81
110
  if demo_name == @last_demo_name
82
-
83
111
  [@person, @last_demo_name]
84
112
  else
85
-
86
- gen_new( demo_name )
87
- end
88
- else
89
-
90
- if demographics.nil? || demographics.empty?
91
-
92
- raise "No demographics have been selected yet! Try something like r.demographic.add_Spanish..."
93
- else # that demo name doesn't exist...
94
-
95
- [nil, @last_demo_name] # so preserve the last good demo name
113
+ gen_new( demo_name, &block )
96
114
  end
115
+ else
116
+ gen_new( demo_name, &block )
97
117
  end
98
118
  end
99
119
  return nil if person.nil?
@@ -103,37 +123,68 @@ module RandomPerson
103
123
  end
104
124
 
105
125
 
106
- # generate a new person
107
- # either with the last demographic loaded, or a specific one by passing the name.
108
- def generate( demo_name=nil )
109
- ds = gen_new( demo_name )
126
+
127
+ def generate( demo_name=nil, &block )
128
+ ds = gen_new( demo_name, &block )
110
129
  ds.nil? ? nil : ds.first
111
130
  end
112
131
 
113
132
 
114
- # If not given a demographic's name then the *last demographic defined* will be used.
115
- def gen_new( demo_name=nil )
116
- if demographics.nil? || demographics.empty?
117
- raise "No demographics have been selected yet! Try something like r.demographic.add_Spanish..."
118
- end
133
+ # For when a demo isn't given but you still need one.
134
+ # @return [String, RandomPerson::Demographic]
135
+ def generate_demo
136
+ Demographic.load
137
+ yesses = %w{prefix suffix female -male last}.map {|word|
138
+ Demographic.available_name_files.classify_true(word).to_a.sample
139
+ }
140
+ demo = self.demographic
141
+ demo.require_and_add yesses
142
+ [demo.name, demo]
143
+ end
144
+
145
+ DEFAULT_gen_new_BLOCK = ->(error) {
146
+ warn error.message
147
+ }
148
+
149
+
150
+ def self.default_error_block
151
+ @default_gen_new_error_block ||= DEFAULT_gen_new_BLOCK
152
+ end
153
+
154
+ def self.default_error_block=( block )
155
+ @default_gen_new_error_block = block
156
+ end
157
+
158
+
159
+ # If not given a demographic's name then the *last demographic defined* will be used. If there is no demographic already defined a new one will be created. If a key is given but does not exist then the supplied block will be called. If no block is given an exception will be raised.
160
+ # @param [String,Symbol,Integer] name The key for retrieving the demographic.
161
+ # @param [#call] block Default for when a key is given that does not exist.
162
+ def gen_new( demo_name=nil, &block )
163
+ block = self.class.default_error_block if block.nil?
119
164
  demo_name, demo = if demo_name.nil?
120
- demographics.to_a.last # this produces a 2 dimensional array
121
- else
122
- demographics.assoc(demo_name)
123
- end
124
-
125
- if demo_name
126
- @last_demo_name = demo_name
127
- unless generators.has_key? demo.name
128
- generators[demo.name] = Generator.make_generator( demo )
165
+ if demographics.nil? || demographics.empty?
166
+ generate_demo
167
+ else
168
+ demographics.to_a.last # this produces a 2 dimensional array
129
169
  end
130
-
131
- @person = generators[@last_demo_name].call
132
-
133
- [@person, @last_demo_name]
134
170
  else
135
- nil
171
+ if ds = demographics.assoc(demo_name)
172
+ ds
173
+ else
174
+ fail "That demographic does not exist!"
175
+ end
176
+ end
177
+
178
+ @last_demo_name = demo_name
179
+ unless generators.has_key? demo_name
180
+ generators[demo_name] = Generator.make_generator( demo )
136
181
  end
182
+
183
+ @person = generators[demo_name].call
184
+
185
+ [@person, demo_name]
186
+ rescue => error
187
+ block.call(error)
137
188
  end
138
189
 
139
190
  end # class
@@ -28,12 +28,24 @@ module RandomPerson
28
28
  # the name of this demographic
29
29
  attr_accessor :name
30
30
 
31
+
32
+ def loaded_classes
33
+ @loaded_classes ||= {}
34
+ end
35
+
36
+
31
37
  attr_accessor :malefirst, :femalefirst, :last, :gender_ratio, :age_lower, :age_upper, :prefix, :suffix #,:age_ratio
32
-
38
+
39
+
40
+ alias :lastname :last
41
+ alias :male_first :malefirst
42
+ alias :female_first :femalefirst
43
+
44
+
33
45
  def self.available_name_files
34
46
  @available_name_files ||= Set.new
35
47
  end
36
-
48
+
37
49
 
38
50
  # Initialize the class with the parameters for the population you want.
39
51
  # @example
@@ -47,9 +59,14 @@ module RandomPerson
47
59
  @gender_ratio = opts[:gender_ratio] || [1,1] #default
48
60
  @age_lower = opts[:age_lower] || 0
49
61
  @age_upper = opts[:age_upper] || 115
50
-
62
+ @loaded_classes ||= {}
63
+
64
+ self.class.load
65
+ end
51
66
 
52
- Demographic.available_name_files.merge Demographic.load_names
67
+ # puts the demo files into the class instance var
68
+ def self.load
69
+ self.available_name_files.merge self.load_names if self.available_name_files.empty?
53
70
  end
54
71
 
55
72
 
@@ -44,6 +44,7 @@ module RandomPerson
44
44
  patterns.each do |ps|
45
45
  if ps.all?{|p| klass =~ /#{p}/ }
46
46
  instance_variable_set( "@#{ps.join.downcase}", klass.to_constant.new)
47
+ instance_variable_get( :@loaded_classes ).store ps.join.downcase.to_sym, klass.to_s.split("::").last.scan( /([A-Z][a-z]+)/ ).flatten.join("_")
47
48
  end # if
48
49
  end
49
50
  klass
@@ -24,7 +24,8 @@ module RandomPerson
24
24
 
25
25
  @possibles.each_pair{|k,v| break v if k === r }
26
26
  end #
27
-
27
+
28
+ super
28
29
  end # initialize
29
30
 
30
31
  end # class
@@ -14,8 +14,8 @@ module RandomPerson
14
14
  @names = Names
15
15
  @formats_ratiod = [ 0..47, 48..49, 50..70, 71..87, 88..99]
16
16
  @possibles = Hash[ @formats_ratiod.zip @names ]
17
-
18
17
  @on_execute = for_prefixes( 'Miss', 'Mr' )
18
+ super
19
19
  end
20
20
 
21
21
  end
@@ -15,7 +15,7 @@ module RandomPerson
15
15
  @formats_ratiod = [ 0..47, 48..49, 50..70, 71..87, 88..99]
16
16
  @possibles = Hash[ @formats_ratiod.zip @names ]
17
17
  @on_execute = for_prefixes( 'Miss', 'Mr' )
18
-
18
+ super
19
19
  end
20
20
 
21
21
  end
@@ -17,7 +17,7 @@ module RandomPerson
17
17
  @possibles = Hash[ @formats_ratiod.zip @names ]
18
18
 
19
19
  @on_execute = for_prefixes( @names[3], @names.first )
20
-
20
+ super
21
21
  end # initialize
22
22
 
23
23
 
@@ -1,3 +1,3 @@
1
1
  module RandomPerson
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -63,9 +63,6 @@ shared_examples "clear or reset" do
63
63
  specify { r.should be_a_kind_of RandomPerson::Facade }
64
64
  specify { r.generators.should be_empty }
65
65
  specify { r.demographics.should be_empty }
66
- specify { expect { r.person }.to raise_error }
67
- specify { expect { r.generate }.to raise_error }
68
- specify { expect { r.gen_new }.to raise_error }
69
66
  end
70
67
 
71
68
 
@@ -148,21 +145,32 @@ describe RandomPerson do
148
145
  end
149
146
  end
150
147
  end
148
+
151
149
  context "With no demographic" do
152
150
  context "Already loaded" do
151
+ before { r.demographics.clear }
153
152
  subject { r.person }
154
- specify { expect { subject }.to raise_error }
155
- context "and given a demo name" do
153
+ it { should be_a_kind_of RandomPerson::Person }
154
+ context "and given a demo name (that does not exist)" do
156
155
  subject { r.person "Not loaded" }
157
- specify { expect { subject }.to raise_error }
156
+ it { should be_nil }
158
157
  end
159
158
  end
160
159
  context "Because they've been cleared" do
160
+ before { r.demographics.clear }
161
161
  subject { r.person }
162
- specify { expect { subject }.to raise_error }
163
- context "and given a demo name" do
162
+ it { should be_a_kind_of RandomPerson::Person }
163
+ context "and given a demo name (that does not exist)" do
164
164
  subject { r.person "Been cleared" }
165
- specify { expect { subject }.to raise_error }
165
+ it { should be_nil }
166
+ context "and given a block with a raise" do
167
+ subject {
168
+ r.person "Does not exist" do
169
+ fail "This demo name does not exist!"
170
+ end
171
+ }
172
+ specify { expect { subject }.to raise_error }
173
+ end
166
174
  end
167
175
  end
168
176
  end
@@ -205,7 +213,8 @@ describe RandomPerson do
205
213
  let(:r) { RandomPerson() }
206
214
  context "Before a demographic has been loaded" do
207
215
  subject { r.generate }
208
- specify { expect { subject }.to raise_error }
216
+ it { should_not be_nil }
217
+ it { should be_a_kind_of RandomPerson::Person }
209
218
  end
210
219
  context "When there is a demographic loaded" do
211
220
  before(:all) {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: randomperson
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-22 00:00:00.000000000 Z
12
+ date: 2012-09-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: wirble