teebo 0.0.3 → 0.0.4
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 +4 -4
- data/lib/data/en-us.yml +38 -0
- data/lib/teebo.rb +8 -6
- data/lib/teebo/credit_card.rb +41 -0
- data/lib/teebo/database_handler.rb +49 -0
- data/lib/teebo/name.rb +19 -30
- data/lib/teebo/number.rb +28 -0
- metadata +19 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d25e0acff23d8791b96d50d72b36d326143a2c1
|
4
|
+
data.tar.gz: deb705f45ee7dfc04e34b6b6021a32640ff08c5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bed5a9899872dc9f634824f8614838af9b70c74e4c232041484bd40889376470e8aabadb992854d87343e632839a6c1db4b7773b21db628bfb50cab3a60fda66
|
7
|
+
data.tar.gz: c941cb7f2fc2f4cf7fc6c98b8a2d5a85a8c69aeeb26adf1d74787c914cf6ade5f6ac1e6e585798a394646837c4465ff8ac5f5776192635926517e6cf4cd4a442
|
data/lib/data/en-us.yml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
credit-card-issuers:
|
3
|
+
-
|
4
|
+
name: American Express
|
5
|
+
iin-prefixes:
|
6
|
+
- 34
|
7
|
+
- 37
|
8
|
+
lengths:
|
9
|
+
- 15
|
10
|
+
validation: yes
|
11
|
+
probability: .092
|
12
|
+
cvc-length: 4
|
13
|
+
-
|
14
|
+
name: Discover Card
|
15
|
+
iin-prefixes: [ 6011, 622126, 622127, 622128, 622129, 622130, 622131, 622132, 622133, 622134, 622135, 622136, 622137, 622138, 622139, 622140, 622141, 622142, 622143, 622144, 622145, 622146, 622147, 622148, 622149, 622150, 622151, 622152, 622153, 622154, 622155, 622156, 622157, 622158, 622159, 622160, 622161, 622162, 622163, 622164, 622165, 622166, 622167, 622168, 622169, 622170, 622171, 622172, 622173, 622174, 622175, 622176, 622177, 622178, 622179, 622180, 622181, 622182, 622183, 622184, 622185, 622186, 622187, 622188, 622189, 622190, 622191, 622192, 622193, 622194, 622195, 622196, 622197, 622198, 622199, 622200, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 622901, 622902, 622903, 622904, 622905, 622906, 622907, 622908, 622909, 622910, 622911, 622912, 622913, 622914, 622915, 622916, 622917, 622918, 622919, 622920, 622921, 622922, 622923, 622924, 622925, 644, 645, 646, 647, 648, 649, 65 ]
|
16
|
+
lengths:
|
17
|
+
- 16
|
18
|
+
validation: yes
|
19
|
+
probability: .107
|
20
|
+
cvc-length: 3
|
21
|
+
-
|
22
|
+
name: MasterCard
|
23
|
+
iin-prefixes: [ 51, 52, 53, 54, 55 ]
|
24
|
+
lengths:
|
25
|
+
- 16
|
26
|
+
validation: yes
|
27
|
+
probability: .313
|
28
|
+
cvc-length: 3
|
29
|
+
-
|
30
|
+
name: Visa
|
31
|
+
iin-prefixes:
|
32
|
+
- 4
|
33
|
+
lengths:
|
34
|
+
- 13
|
35
|
+
- 16
|
36
|
+
validation: yes
|
37
|
+
probability: .488
|
38
|
+
cvc-length: 3
|
data/lib/teebo.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'sqlite3'
|
2
|
+
require 'yaml'
|
3
|
+
require 'randexp'
|
2
4
|
|
3
5
|
module Teebo
|
4
6
|
|
5
|
-
class
|
6
|
-
|
7
|
+
class TeeboGenerator
|
7
8
|
def initialize
|
8
|
-
|
9
|
-
@
|
10
|
-
@database.results_as_hash = true
|
9
|
+
@db_connection = Teebo::DatabaseHandler.new
|
10
|
+
@yaml_mapping = YAML::load(File.open('lib/data/en-us.yml'))
|
11
11
|
end
|
12
|
-
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
15
|
+
require 'teebo/database_handler'
|
16
16
|
require 'teebo/name'
|
17
|
+
require 'teebo/number'
|
18
|
+
require 'teebo/credit_card'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Teebo
|
2
|
+
#
|
3
|
+
# Helper class for generating credit card numbers. Categorizes cards according to their card
|
4
|
+
# issuer, while attempting to maintain a realistic distribution between the issuers. Also ensures
|
5
|
+
# that the credit card numbers are actually valid.
|
6
|
+
#
|
7
|
+
class CreditCard < TeeboGenerator
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@cc_issuers = @yaml_mapping['credit-card-issuers']
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Returns a credit card issuer according to the likelihood that it would be seen in the wild.
|
16
|
+
#
|
17
|
+
def get_issuer
|
18
|
+
random_choice = Random.rand
|
19
|
+
full_weight = 0
|
20
|
+
@cc_issuers.each do |issuer|
|
21
|
+
full_weight += issuer['probability']
|
22
|
+
if random_choice < full_weight
|
23
|
+
return issuer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Generates a credit card number according to the pattern specified in the 'issuer' passed in.
|
30
|
+
#
|
31
|
+
def generate_number(issuer)
|
32
|
+
# TODO: Sample according to realistic distribution - numbers w/long prefixes are prioritized too highly right now.
|
33
|
+
prefix = issuer['iin-prefixes'].sample
|
34
|
+
length = issuer['lengths'].sample
|
35
|
+
puts prefix, length
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Teebo
|
2
|
+
# This class facilitates the use of the database that accompanies this gem. Its primary goal is to
|
3
|
+
# simplify querying the database for required data, without having to write raw SQL statements
|
4
|
+
# throughout the codebase.
|
5
|
+
#
|
6
|
+
# Author:: Russ Taylor (mailto:russ@russt.me)
|
7
|
+
class DatabaseHandler
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@database = SQLite3::Database.new 'lib/data/seed-data.db'
|
11
|
+
@database.results_as_hash = true
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Retrieves the sum of the specified column in the database. Optionally, a 'where' clause may
|
16
|
+
# be specified to restrict the sum to rows meeting a specified condition. Note that at present,
|
17
|
+
# only where clauses with one condition and an '=' comparison are supported.
|
18
|
+
#
|
19
|
+
def get_sum(table_name, column_name, where_clause=nil)
|
20
|
+
where_statement = ''
|
21
|
+
unless where_clause.nil?
|
22
|
+
where_statement = "where #{where_clause[:column]} = '#{where_clause[:condition]}'"
|
23
|
+
end
|
24
|
+
statement = <<-SQL
|
25
|
+
select sum(#{column_name}) from #{table_name} #{where_statement}
|
26
|
+
SQL
|
27
|
+
|
28
|
+
@database.execute(statement)[0][0]
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Retrieves the one row from the database where the specified number fits into this row's
|
33
|
+
# 'count_to' range.
|
34
|
+
#
|
35
|
+
def get_row_for_count(table_name, count_column, count_value, where_clause=nil)
|
36
|
+
where_statement = ''
|
37
|
+
unless where_clause.nil?
|
38
|
+
where_statement = "and #{where_clause[:column]} = '#{where_clause[:condition]}'"
|
39
|
+
end
|
40
|
+
statement = <<-SQL
|
41
|
+
select * from #{table_name} where (#{count_column} - #{count_value}) >= 0
|
42
|
+
#{where_statement}
|
43
|
+
order by id limit 1
|
44
|
+
SQL
|
45
|
+
|
46
|
+
@database.execute(statement)[0]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/teebo/name.rb
CHANGED
@@ -3,17 +3,20 @@ module Teebo
|
|
3
3
|
# Generates names in accordance with their frequency in the United States
|
4
4
|
# population.
|
5
5
|
#
|
6
|
-
class Name <
|
6
|
+
class Name < TeeboGenerator
|
7
|
+
|
8
|
+
GIVEN_NAMES_TABLE = 'given_names'
|
9
|
+
SURNAMES_TABLE = 'surnames'
|
7
10
|
|
8
11
|
#
|
9
12
|
# Picks a random first & last name, selecting a random gender if it's not
|
10
13
|
# specified.
|
11
14
|
#
|
12
|
-
def name sex=nil
|
15
|
+
def name (sex=nil)
|
13
16
|
if sex.nil?
|
14
|
-
sex =
|
17
|
+
sex = %w(M F).sample
|
15
18
|
end
|
16
|
-
given_name(sex) +
|
19
|
+
given_name(sex) + ' ' + surname
|
17
20
|
end
|
18
21
|
|
19
22
|
#
|
@@ -23,52 +26,38 @@ module Teebo
|
|
23
26
|
# simply be another given name of the same gender is almost certainly less
|
24
27
|
# than 100%.
|
25
28
|
#
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
def full_name sex=nil
|
29
|
+
def full_name(sex=nil)
|
30
|
+
# TODO: Take into account different probabilities of different types of middle names.
|
30
31
|
if sex.nil?
|
31
|
-
sex =
|
32
|
+
sex = %w(M F).sample
|
32
33
|
end
|
33
|
-
given_name(sex) +
|
34
|
+
given_name(sex) + ' ' + given_name(sex) + ' ' + surname
|
34
35
|
end
|
35
36
|
|
36
37
|
#
|
37
38
|
# Finds the total count for the number of names in the database.
|
38
39
|
#
|
39
|
-
def sum_count
|
40
|
-
|
41
|
-
select sum(count) from 'given_names' where sex = ?
|
42
|
-
SQL
|
43
|
-
@database.execute(find_count, sex)[0][0]
|
40
|
+
def sum_count(sex)
|
41
|
+
@db_connection.get_sum(GIVEN_NAMES_TABLE, 'count', {column: 'sex', condition: sex})
|
44
42
|
end
|
45
43
|
|
46
44
|
#
|
47
45
|
# Selects a random (weighted) given name from the database.
|
48
46
|
#
|
49
|
-
def given_name
|
50
|
-
|
51
|
-
select * from given_names where sex = ?
|
52
|
-
and (count_to - ?) >= 0
|
53
|
-
order by id limit 1
|
54
|
-
SQL
|
55
|
-
|
56
|
-
count = sum_count sex
|
47
|
+
def given_name(sex)
|
48
|
+
count = sum_count(sex)
|
57
49
|
selection = rand(count)
|
58
|
-
@
|
50
|
+
@db_connection.get_row_for_count(GIVEN_NAMES_TABLE, 'count_to', selection,
|
51
|
+
{column: 'sex', condition: sex})['name']
|
59
52
|
end
|
60
53
|
|
61
54
|
#
|
62
55
|
# Selects a random (weighted) surname from the database.
|
63
56
|
#
|
64
57
|
def surname
|
65
|
-
|
66
|
-
select * from surnames where (count_to - ?) >= 0 order by id limit 1
|
67
|
-
SQL
|
68
|
-
|
69
|
-
count = @database.execute('select sum(count) from surnames')[0][0]
|
58
|
+
count = @db_connection.get_sum(SURNAMES_TABLE, 'count')
|
70
59
|
selection = rand(count)
|
71
|
-
@
|
60
|
+
@db_connection.get_row_for_count(SURNAMES_TABLE, 'count_to', selection)['name']
|
72
61
|
end
|
73
62
|
end
|
74
63
|
end
|
data/lib/teebo/number.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Teebo
|
2
|
+
#
|
3
|
+
# Helper for generating numbers according to various distributions.
|
4
|
+
#
|
5
|
+
class Number
|
6
|
+
#
|
7
|
+
# Generates a number using a normal distribution.
|
8
|
+
#
|
9
|
+
# A basic implementation of the Box-Muller transform. Adapted from an answer by antonakos on
|
10
|
+
# Stack Overflow here: http://stackoverflow.com/questions/5825680
|
11
|
+
#
|
12
|
+
def normal_dist(mean, std_deviation, rand = lambda { Kernel.rand })
|
13
|
+
theta = 2 * Math::PI * rand.call
|
14
|
+
rho = Math.sqrt(-2 * Math.log(1 - rand.call))
|
15
|
+
scale = std_deviation * rho
|
16
|
+
mean + scale * Math.cos(theta)
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Generates a number according to Benford's law, meaning that it is more indicative of numbers
|
21
|
+
# encountered in real life.
|
22
|
+
#
|
23
|
+
def benford_dist(upper_bound, decimals=0)
|
24
|
+
(upper_bound**Random.rand).round(decimals)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teebo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Russ Taylor
|
@@ -30,15 +30,33 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.3.9
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: randexp
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.1.7
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.1.7
|
33
47
|
description: Contains basic functionality for data generation.
|
34
48
|
email: russ@russt.me
|
35
49
|
executables: []
|
36
50
|
extensions: []
|
37
51
|
extra_rdoc_files: []
|
38
52
|
files:
|
53
|
+
- lib/data/en-us.yml
|
39
54
|
- lib/data/seed-data.db
|
40
55
|
- lib/teebo.rb
|
56
|
+
- lib/teebo/credit_card.rb
|
57
|
+
- lib/teebo/database_handler.rb
|
41
58
|
- lib/teebo/name.rb
|
59
|
+
- lib/teebo/number.rb
|
42
60
|
homepage: http://github.com/russtaylor/teebo
|
43
61
|
licenses:
|
44
62
|
- MIT
|