identitycode 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -4
- data/identitycode.gemspec +2 -2
- data/lib/identity_code/ee.rb +106 -0
- data/lib/identity_code/lv.rb +83 -0
- data/lib/identity_code/version.rb +1 -1
- data/lib/identity_code.rb +41 -120
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cfc172aeb2d5abd52ea44ebbadc44025ef8010c
|
4
|
+
data.tar.gz: ba6ef782a21f0173f63558d42d402a51e5ebcbe4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 278c2f861d6a222a31d5f3f9b3bea27600fc587a804a27c46916270ef033e13edde802839657eee38484c18453b9095d09f75983c86b1eac2f208ca14a8676f7
|
7
|
+
data.tar.gz: 354d693d5f86494c4c1f94bcba338bbea1a3f4b12296c04c0332b5f3c258560e3c26ebf30c9b146212e34eb5de1bb96a44333257c8ab3633343947cf20d7e860
|
data/README.md
CHANGED
@@ -18,12 +18,18 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
This gem supports Estonian and Latvian identity codes. Just specify `EE` or `LV` class accordingly (`IdentityCode::EE` or `IdentityCode::LV`)
|
22
|
+
|
23
|
+
*NB*: Latvian identity codes don't have sex support
|
24
|
+
|
21
25
|
```ruby
|
22
26
|
> require 'identity_code'
|
23
|
-
> code = IdentityCode::
|
27
|
+
> code = IdentityCode::EE.new('38312203720')
|
24
28
|
> code.valid?
|
25
29
|
# or
|
26
|
-
> IdentityCode::
|
30
|
+
> IdentityCode::EE.valid?('38312203720')
|
31
|
+
=> true
|
32
|
+
> IdentityCode::LV.valid?('20128315289')
|
27
33
|
=> true
|
28
34
|
> code.sex
|
29
35
|
=> 'M'
|
@@ -32,10 +38,12 @@ Or install it yourself as:
|
|
32
38
|
> code.age
|
33
39
|
=> 31
|
34
40
|
# Generate random valid identity code
|
35
|
-
> IdentityCode::
|
41
|
+
> IdentityCode::EE.generate
|
36
42
|
=> '37504163700'
|
37
|
-
> IdentityCode::
|
43
|
+
> IdentityCode::EE.generate(sex: 'M', year: 1983, month: 12, day: 20)
|
38
44
|
=> '38312209528'
|
45
|
+
> IdentityCode::LV.generate(year: 1983, month: 12, day: 20, separator: true)
|
46
|
+
=> '201283-15289'
|
39
47
|
```
|
40
48
|
|
41
49
|
## Development
|
data/identitycode.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Artem Pakk']
|
10
10
|
spec.email = ['apakk@me.com']
|
11
11
|
|
12
|
-
spec.summary = %q{Ruby gem to generate and validate Estonian identity codes}
|
13
|
-
spec.description = %q{Ruby gem to generate and validate Estonian identity codes}
|
12
|
+
spec.summary = %q{Ruby gem to generate and validate Estonian and Latvian identity codes}
|
13
|
+
spec.description = %q{Ruby gem to generate and validate Estonian and Latvian identity codes}
|
14
14
|
spec.homepage = 'https://github.com/defeed/identitycode'
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module IdentityCode
|
4
|
+
class EE
|
5
|
+
HOSPITALS = [
|
6
|
+
'00', # Kuressaare Haigla (järjekorranumbrid 001 kuni 020)
|
7
|
+
'01', # Tartu Ülikooli Naistekliinik, Tartumaa, Tartu (011...019)
|
8
|
+
'02', # Ida-Tallinna Keskhaigla, Hiiumaa, Keila, Rapla haigla (021...220)
|
9
|
+
'22', # Ida-Viru Keskhaigla (Kohtla-Järve, endine Jõhvi) (221...270)
|
10
|
+
'27', # Maarjamõisa Kliinikum (Tartu), Jõgeva Haigla (271...370)
|
11
|
+
'37', # Narva Haigla (371...420)
|
12
|
+
'42', # Pärnu Haigla (421...470)
|
13
|
+
'47', # Pelgulinna Sünnitusmaja (Tallinn), Haapsalu haigla (471...490)
|
14
|
+
'49', # Järvamaa Haigla (Paide) (491...520)
|
15
|
+
'52', # Rakvere, Tapa haigla (521...570)
|
16
|
+
'57', # Valga Haigla (571...600)
|
17
|
+
'60', # Viljandi Haigla (601...650)
|
18
|
+
'65', # Lõuna-Eesti Haigla (Võru), Pälva Haigla (651...710?)
|
19
|
+
'70', # All other hospitals
|
20
|
+
'95' # Foreigners who are born in Estonia
|
21
|
+
]
|
22
|
+
|
23
|
+
def self.generate(opts = {})
|
24
|
+
first_digit = 0
|
25
|
+
|
26
|
+
sex = opts[:sex] || (rand.round == 0 ? :M : :F)
|
27
|
+
year = opts[:year] || rand(Date.today.year - 90..Date.today.year - 1)
|
28
|
+
year = rand(Date.today.year - 50..Date.today.year - 19) if opts[:safe_age]
|
29
|
+
month = opts[:month] || rand(1..12)
|
30
|
+
day = opts[:day] || rand(1..NUM_DAYS[month])
|
31
|
+
|
32
|
+
first_digit += 1 if (1800..1899).include?(year)
|
33
|
+
first_digit += 3 if (1900..1999).include?(year)
|
34
|
+
first_digit += 5 if year >= 2000
|
35
|
+
first_digit += 1 if sex.upcase.to_sym == :F
|
36
|
+
|
37
|
+
result = first_digit.to_s
|
38
|
+
result += "%02d" % year.to_s[2..3].to_i
|
39
|
+
result += "%02d" % month
|
40
|
+
result += "%02d" % day
|
41
|
+
result += HOSPITALS[(rand * HOSPITALS.size - 1).round]
|
42
|
+
result += rand(0..9).to_s
|
43
|
+
result += new(result).control_code.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.valid?(code)
|
47
|
+
new(code).valid?
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(code)
|
51
|
+
@code = code.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?
|
55
|
+
@code.length == 11 &&
|
56
|
+
@code[10].chr.to_i == control_code
|
57
|
+
end
|
58
|
+
|
59
|
+
def birth_date
|
60
|
+
return unless valid?
|
61
|
+
year = century + @code[1..2].to_i
|
62
|
+
month = @code[3..4].to_i
|
63
|
+
day = @code[5..6].to_i
|
64
|
+
return unless Date.valid_date?(year, month, day)
|
65
|
+
Date.new(year, month, day)
|
66
|
+
end
|
67
|
+
|
68
|
+
def age
|
69
|
+
return unless valid?
|
70
|
+
now = Time.now.utc.to_date
|
71
|
+
now.year - (birth_date.year + IdentityCode::age_correction(birth_date))
|
72
|
+
end
|
73
|
+
|
74
|
+
def sex
|
75
|
+
return unless valid?
|
76
|
+
@code[0].to_i.odd? ? :M : :F
|
77
|
+
end
|
78
|
+
|
79
|
+
def control_code
|
80
|
+
scales1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]
|
81
|
+
checknum = scales1.each_with_index.map do |scale, i|
|
82
|
+
@code[i].chr.to_i * scale
|
83
|
+
end.inject(0, :+) % 11
|
84
|
+
return checknum unless checknum == 10
|
85
|
+
|
86
|
+
scales2 = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
|
87
|
+
checknum = scales2.each_with_index.map do |scale, i|
|
88
|
+
@code[i].chr.to_i * scale
|
89
|
+
end.inject(0, :+) % 11
|
90
|
+
|
91
|
+
checknum == 10 ? 0 : checknum
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def century
|
97
|
+
case @code[0].chr.to_i
|
98
|
+
when 1..2 then 1800
|
99
|
+
when 3..4 then 1900
|
100
|
+
when 5..6 then 2000
|
101
|
+
else
|
102
|
+
2100
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module IdentityCode
|
4
|
+
class LV
|
5
|
+
def initialize(code)
|
6
|
+
@code = code.to_s.gsub('-', '')
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.generate(opts = {})
|
10
|
+
year = opts[:year] || rand(Date.today.year - 90..Date.today.year - 1)
|
11
|
+
year = rand(Date.today.year - 50..Date.today.year - 19) if opts[:safe_age]
|
12
|
+
month = opts[:month] || rand(1..12)
|
13
|
+
day = opts[:day] || rand(1..NUM_DAYS[month])
|
14
|
+
|
15
|
+
century_code = begin
|
16
|
+
case year
|
17
|
+
when 1800..1899 then 0
|
18
|
+
when 1900..1999 then 1
|
19
|
+
when 2000..2099 then 2
|
20
|
+
else
|
21
|
+
9
|
22
|
+
end
|
23
|
+
end.to_s
|
24
|
+
|
25
|
+
result = "%02d" % day
|
26
|
+
result += "%02d" % month
|
27
|
+
result += "%02d" % year.to_s[2..3].to_i
|
28
|
+
result += '-' if opts[:separator]
|
29
|
+
result += century_code
|
30
|
+
result += "%03d" % rand(0..999).to_s
|
31
|
+
result += new(result).control_code.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.valid?(code)
|
35
|
+
new(code).valid?
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?
|
39
|
+
@code.length == 11 &&
|
40
|
+
@code[10].chr.to_i == control_code
|
41
|
+
end
|
42
|
+
|
43
|
+
def birth_date
|
44
|
+
return unless valid?
|
45
|
+
year = century + @code[4..5].to_i
|
46
|
+
month = @code[2..3].to_i
|
47
|
+
day = @code[0..1].to_i
|
48
|
+
return unless Date.valid_date?(year, month, day)
|
49
|
+
Date.new(year, month, day)
|
50
|
+
end
|
51
|
+
|
52
|
+
def age
|
53
|
+
return unless valid?
|
54
|
+
now = Time.now.utc.to_date
|
55
|
+
now.year - (birth_date.year + IdentityCode.age_correction(birth_date))
|
56
|
+
end
|
57
|
+
|
58
|
+
def control_code
|
59
|
+
array = @code.split('').map(&:to_i)
|
60
|
+
multipliers = [1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
|
61
|
+
hash = Hash[multipliers.zip(array)]
|
62
|
+
|
63
|
+
check = 0
|
64
|
+
hash.map do |k, v|
|
65
|
+
check += k * v
|
66
|
+
end
|
67
|
+
|
68
|
+
((1 - check) % 11) % 10
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def century
|
74
|
+
case @code[6].chr.to_i
|
75
|
+
when 0 then 1800
|
76
|
+
when 1 then 1900
|
77
|
+
when 2 then 2000
|
78
|
+
else
|
79
|
+
2100
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/identity_code.rb
CHANGED
@@ -1,129 +1,50 @@
|
|
1
1
|
require 'identity_code/version'
|
2
|
-
require '
|
2
|
+
require 'identity_code/ee'
|
3
|
+
require 'identity_code/lv'
|
3
4
|
|
4
5
|
module IdentityCode
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
7 => 31,
|
32
|
-
8 => 31,
|
33
|
-
9 => 30,
|
34
|
-
10 => 31,
|
35
|
-
11 => 30,
|
36
|
-
12 => 31
|
37
|
-
}
|
38
|
-
|
39
|
-
def self.generate(opts = {})
|
40
|
-
first_digit = 0
|
41
|
-
|
42
|
-
sex = opts[:sex] || (rand.round == 0 ? 'M' : 'F')
|
43
|
-
year = opts[:year] || rand(Date.today.year - 90..Date.today.year - 1)
|
44
|
-
year = rand(Date.today.year - 50..Date.today.year - 19) if opts[:safe_age]
|
45
|
-
month = opts[:month] || rand(1..12)
|
46
|
-
day = opts[:day] || rand(1..NUM_DAYS[month])
|
47
|
-
|
48
|
-
first_digit += 1 if (1800..1899).include?(year)
|
49
|
-
first_digit += 3 if (1900..1999).include?(year)
|
50
|
-
first_digit += 5 if year >= 2000
|
51
|
-
first_digit += 1 if sex == 'F'
|
52
|
-
|
53
|
-
result = first_digit.to_s
|
54
|
-
result += "%02d" % year.to_s[2..3].to_i
|
55
|
-
result += "%02d" % month
|
56
|
-
result += "%02d" % day
|
57
|
-
result += HOSPITALS[(rand * HOSPITALS.size - 1).round]
|
58
|
-
result += rand(0..9).to_s
|
59
|
-
result += new(result).control_code.to_s
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.valid?(code)
|
63
|
-
new(code).valid?
|
64
|
-
end
|
65
|
-
|
66
|
-
def initialize(code)
|
67
|
-
@code = code.to_s
|
68
|
-
end
|
69
|
-
|
70
|
-
def valid?
|
71
|
-
@code.length == 11 &&
|
72
|
-
@code[10].chr.to_i == control_code
|
73
|
-
end
|
74
|
-
|
75
|
-
def birth_date
|
76
|
-
return unless valid?
|
77
|
-
year = century + @code[1..2].to_i
|
78
|
-
month = @code[3..4].to_i
|
79
|
-
day = @code[5..6].to_i
|
80
|
-
return unless Date.valid_date?(year, month, day)
|
81
|
-
Date.new(year, month, day)
|
82
|
-
end
|
83
|
-
|
84
|
-
def age
|
85
|
-
return unless valid?
|
86
|
-
now = Time.now.utc.to_date
|
87
|
-
now.year - (birth_date.year + age_correction)
|
88
|
-
end
|
89
|
-
|
90
|
-
def sex
|
91
|
-
return unless valid?
|
92
|
-
@code[0].to_i.odd? ? 'M' : 'F'
|
93
|
-
end
|
94
|
-
|
95
|
-
def control_code
|
96
|
-
scales1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]
|
97
|
-
checknum = scales1.each_with_index.map do |scale, i|
|
98
|
-
@code[i].chr.to_i * scale
|
99
|
-
end.inject(0, :+) % 11
|
100
|
-
return checknum unless checknum == 10
|
101
|
-
|
102
|
-
scales2 = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
|
103
|
-
checknum = scales2.each_with_index.map do |scale, i|
|
104
|
-
@code[i].chr.to_i * scale
|
105
|
-
end.inject(0, :+) % 11
|
6
|
+
NUM_DAYS = {
|
7
|
+
1 => 31,
|
8
|
+
2 => 28,
|
9
|
+
3 => 31,
|
10
|
+
4 => 30,
|
11
|
+
5 => 31,
|
12
|
+
6 => 30,
|
13
|
+
7 => 31,
|
14
|
+
8 => 31,
|
15
|
+
9 => 30,
|
16
|
+
10 => 31,
|
17
|
+
11 => 30,
|
18
|
+
12 => 31
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
SUPPORTED_COUNTRY_CODES = %i(ee lv).freeze
|
22
|
+
|
23
|
+
def self.generate(opts = {})
|
24
|
+
country_code = opts.delete(:country)
|
25
|
+
raise 'Country param is missing or invalid (ee or lv)' unless begin
|
26
|
+
country_code &&
|
27
|
+
SUPPORTED_COUNTRY_CODES.include?(country_code.downcase.to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
Object.const_get("IdentityCode::#{country_code.upcase}").generate(opts)
|
31
|
+
end
|
106
32
|
|
107
|
-
|
33
|
+
def self.valid?(opts = {})
|
34
|
+
country_code = opts.delete(:country)
|
35
|
+
raise 'Country param is missing or invalid (ee or lv)' unless begin
|
36
|
+
country_code &&
|
37
|
+
SUPPORTED_COUNTRY_CODES.include?(country_code.downcase.to_sym)
|
108
38
|
end
|
109
39
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
now = Time.now.utc.to_date
|
114
|
-
return 0 if now.month > birth_date.month
|
115
|
-
return 0 if now.month == birth_date.month && now.day >= birth_date.day
|
116
|
-
1
|
117
|
-
end
|
40
|
+
code = opts.delete(:code)
|
41
|
+
Object.const_get("IdentityCode::#{country_code.upcase}").valid?(code)
|
42
|
+
end
|
118
43
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
else
|
125
|
-
2100
|
126
|
-
end
|
127
|
-
end
|
44
|
+
def self.age_correction(birth_date)
|
45
|
+
now = Time.now.utc.to_date
|
46
|
+
return 0 if now.month > birth_date.month
|
47
|
+
return 0 if now.month == birth_date.month && now.day >= birth_date.day
|
48
|
+
1
|
128
49
|
end
|
129
50
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: identitycode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artem Pakk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
-
description: Ruby gem to generate and validate Estonian identity codes
|
41
|
+
description: Ruby gem to generate and validate Estonian and Latvian identity codes
|
42
42
|
email:
|
43
43
|
- apakk@me.com
|
44
44
|
executables: []
|
@@ -55,6 +55,8 @@ files:
|
|
55
55
|
- bin/setup
|
56
56
|
- identitycode.gemspec
|
57
57
|
- lib/identity_code.rb
|
58
|
+
- lib/identity_code/ee.rb
|
59
|
+
- lib/identity_code/lv.rb
|
58
60
|
- lib/identity_code/version.rb
|
59
61
|
homepage: https://github.com/defeed/identitycode
|
60
62
|
licenses:
|
@@ -76,8 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
78
|
version: '0'
|
77
79
|
requirements: []
|
78
80
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.4.
|
81
|
+
rubygems_version: 2.4.5.1
|
80
82
|
signing_key:
|
81
83
|
specification_version: 4
|
82
|
-
summary: Ruby gem to generate and validate Estonian identity codes
|
84
|
+
summary: Ruby gem to generate and validate Estonian and Latvian identity codes
|
83
85
|
test_files: []
|