resident 0.0.9 → 0.0.12
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 +7 -0
- data/{README.rdoc → README.md} +17 -11
- data/lib/national_identification_number/base.rb +15 -1
- data/lib/national_identification_number/danish.rb +43 -0
- data/lib/national_identification_number/finnish.rb +6 -4
- data/lib/national_identification_number/norwegian.rb +60 -0
- data/lib/national_identification_number/swedish.rb +22 -12
- data/lib/national_identification_number.rb +2 -0
- data/spec/national_identification_number/base_spec.rb +44 -41
- data/spec/national_identification_number/danish_spec.rb +81 -0
- data/spec/national_identification_number/finnish_spec.rb +113 -45
- data/spec/national_identification_number/norwegian_spec.rb +97 -0
- data/spec/national_identification_number/swedish_spec.rb +197 -126
- data/spec/spec_helper.rb +14 -0
- metadata +54 -66
- data/.gemtest +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f46bb28b43ee9e5b885a50fdad775f2730dfaf059d238bf78f2e4f687f015440
|
4
|
+
data.tar.gz: 3daabe1d914221094e18cc29032ffd365c3ce497150a3c92c2f9293255772214
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7156a5215a04bf80888f46a88b9d84979dc45097c8480184e58aed0c1b2d6548dbe31dd3e4e018be71e3a0f73e65b30c4601ae2791e96c7e1456c64fd2ba24c
|
7
|
+
data.tar.gz: 5e3b40279eabe8e69113a8767985e281adc2f7d8d30ffd48e887d8c3d7e4f80072c3fc66ed96825c325e1720b64ed3c47de9af3548cea14dbe37414b62e8cde4
|
data/{README.rdoc → README.md}
RENAMED
@@ -1,25 +1,31 @@
|
|
1
|
-
|
1
|
+
# Resident
|
2
2
|
|
3
3
|
Validates a National Identification Number (See http://en.wikipedia.org/wiki/National_identification_number).
|
4
4
|
There are some 62 countries that have this type of number.
|
5
|
-
This gem currently only supports Swedish (Personnummer) and Finnish (Henkilöasiakkaat) ones.
|
6
5
|
|
7
|
-
|
6
|
+
This gem currently only supports Swedish (Personnummer), Finnish
|
7
|
+
(Henkilöasiakkaat), Norwegian (Fødelsenummer) and Danish (CPR).
|
8
8
|
|
9
|
-
|
9
|
+
There is a special focus on identifying these numbers robustly
|
10
|
+
(i.e. you can safely validate a param[:number] directly, or cleanup
|
11
|
+
your database by running every non-normalized value through this gem).
|
12
|
+
|
13
|
+
## Installation
|
10
14
|
|
11
15
|
gem install resident
|
12
16
|
|
13
|
-
|
17
|
+
## Usage
|
14
18
|
|
15
|
-
Really, you can just use <tt>valid?</tt> and <tt>
|
19
|
+
Really, you can just use <tt>valid?</tt>, <tt>sanitize</tt>, <tt>to_s</tt>, and <tt>age</tt> like so:
|
16
20
|
|
17
21
|
require 'resident'
|
18
22
|
|
19
23
|
number = NationalIdentificationNumber::Swedish.new('0501261853')
|
20
24
|
|
21
|
-
number.valid?
|
22
|
-
number.to_s
|
25
|
+
number.valid? #=> true
|
26
|
+
number.to_s #=> "050126-1853"
|
27
|
+
number.sanitize #=> "050126-1853" (Would have been nil if invalid)
|
28
|
+
number.age #=> 9
|
23
29
|
|
24
30
|
Please have a look at the specs to see how the national identification numbers of various countries are handled.
|
25
31
|
|
@@ -27,7 +33,7 @@ An example of robustness:
|
|
27
33
|
|
28
34
|
NationalIdentificationNumber::Swedish.new("19050126-185d3\n").to_s => "050126-1853"
|
29
35
|
|
30
|
-
|
36
|
+
## License
|
31
37
|
|
32
38
|
Some marked parts of the code are inspired or taken from MIT licensed code of
|
33
39
|
|
@@ -36,7 +42,7 @@ Some marked parts of the code are inspired or taken from MIT licensed code of
|
|
36
42
|
|
37
43
|
Other than that you got:
|
38
44
|
|
39
|
-
Copyright (c) 2011 Bukowskis.
|
45
|
+
Copyright (c) 2011-2022 Bukowskis.
|
40
46
|
|
41
47
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
42
48
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -54,4 +60,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
54
60
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
55
61
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
56
62
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
57
|
-
THE SOFTWARE.
|
63
|
+
THE SOFTWARE.
|
@@ -17,8 +17,23 @@ module NationalIdentificationNumber
|
|
17
17
|
@number
|
18
18
|
end
|
19
19
|
|
20
|
+
def sanitize
|
21
|
+
to_s if valid?
|
22
|
+
end
|
23
|
+
|
24
|
+
def age
|
25
|
+
age_for_dob date
|
26
|
+
end
|
27
|
+
|
20
28
|
protected
|
21
29
|
|
30
|
+
# stackoverflow.com/questions/819263
|
31
|
+
def age_for_dob(dob)
|
32
|
+
today = Time.now.utc.to_date
|
33
|
+
return nil unless dob && today >= dob
|
34
|
+
today.year - dob.year - ((today.month > dob.month || (today.month == dob.month && today.day >= dob.day)) ? 0 : 1)
|
35
|
+
end
|
36
|
+
|
22
37
|
def repair
|
23
38
|
@number = @number.to_s.upcase.gsub(/\s/, '')
|
24
39
|
end
|
@@ -26,6 +41,5 @@ module NationalIdentificationNumber
|
|
26
41
|
def validate
|
27
42
|
raise 'You need to implement at least this method in subclasses.'
|
28
43
|
end
|
29
|
-
|
30
44
|
end
|
31
45
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'national_identification_number/base'
|
2
|
+
|
3
|
+
module NationalIdentificationNumber
|
4
|
+
class Danish < Base
|
5
|
+
attr_reader :date
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def repair
|
10
|
+
super
|
11
|
+
@number.gsub!(/[^0-9]/, '')
|
12
|
+
if (matches = @number.match(/\A(?<birthday>[0-9]{6})(?<checksum>[0-9]{4})\z/))
|
13
|
+
birthday, checksum = matches.values_at(:birthday, :checksum)
|
14
|
+
@number = "#{birthday}-#{checksum}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate
|
19
|
+
if (matches = @number.match(/\A(?<day>\d{2})(?<month>\d{2})(?<year>\d{2})-(?<serial>\d{3})(?<checksum>\d{1})\z/))
|
20
|
+
day, month, year, serial, checksum = matches.values_at(:day, :month, :year, :serial, :checksum)
|
21
|
+
begin
|
22
|
+
@date = Date.parse("#{full_year(serial, year)}-#{month}-#{day}")
|
23
|
+
@valid = true
|
24
|
+
@number = "#{day}#{month}#{year}-#{serial}#{checksum}"
|
25
|
+
rescue ArgumentError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def full_year(serial, year)
|
33
|
+
century(serial, year.to_i) + year.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def century(serial, year)
|
37
|
+
first_digit = serial[0].to_i
|
38
|
+
return 1800 if (5..8).include?(first_digit) && year > 57
|
39
|
+
return 2000 if (4..9).include?(first_digit) && year < 37
|
40
|
+
1900
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -3,21 +3,23 @@ require 'national_identification_number/base'
|
|
3
3
|
module NationalIdentificationNumber
|
4
4
|
class Finnish < Base
|
5
5
|
|
6
|
+
attr_reader :date
|
7
|
+
|
6
8
|
CHECKSUMS = %w{ 0 1 2 3 4 5 6 7 8 9 A B C D E F H J K L M N P R S T U V W X Y }
|
7
9
|
|
8
10
|
protected
|
9
11
|
|
10
12
|
def repair
|
11
13
|
super
|
12
|
-
if @number.match(/(\d{6})(\-{0,1})(\d{3})([#{CHECKSUMS}]{1})/)
|
14
|
+
if @number.match(/(\d{6})(\-{0,1})(\d{3})([#{CHECKSUMS.join('')}]{1})/)
|
13
15
|
@number = "#{$1}-#{$3}#{$4}"
|
14
16
|
else
|
15
|
-
@number.gsub!(/[^#{CHECKSUMS}\-\+]/, '')
|
17
|
+
@number.gsub!(/[^#{CHECKSUMS.join('')}\-\+]/, '')
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
21
|
def validate
|
20
|
-
if @number.match(/(\d{2})(\d{2})(\d{2})([\-\+A]{0,1})(\d{3})([#{CHECKSUMS}]{1})/)
|
22
|
+
if @number.match(/(\d{2})(\d{2})(\d{2})([\-\+A]{0,1})(\d{3})([#{CHECKSUMS.join('')}]{1})/)
|
21
23
|
checksum = self.class.calculate_checksum("#{$1}#{$2}#{$3}#{$5}")
|
22
24
|
if checksum == $6
|
23
25
|
|
@@ -34,7 +36,7 @@ module NationalIdentificationNumber
|
|
34
36
|
end
|
35
37
|
|
36
38
|
begin
|
37
|
-
Date.parse("#{century+year}-#{month}-#{day}")
|
39
|
+
@date = Date.parse("#{century+year}-#{month}-#{day}")
|
38
40
|
@valid = true
|
39
41
|
@number = ("#{$1}#{$2}#{$3}#{divider}#{$5}#{checksum}")
|
40
42
|
rescue ArgumentError
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'national_identification_number/base'
|
2
|
+
|
3
|
+
module NationalIdentificationNumber
|
4
|
+
class Norwegian < Base
|
5
|
+
attr_reader :date
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def repair
|
10
|
+
super
|
11
|
+
@number.gsub!(/[^0-9]/, '')
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate
|
15
|
+
if (matches = @number.match(/\A(?<day>\d{2})(?<month>\d{2})(?<year>\d{2})(?<serial>\d{3})(?<checksum>\d{2})\z/))
|
16
|
+
day, month, year, serial, checksum = matches.values_at(:day, :month, :year, :serial, :checksum)
|
17
|
+
sans_checksum = "#{day}#{month}#{year}#{serial}"
|
18
|
+
|
19
|
+
if checksum == calculate_checksum(sans_checksum)
|
20
|
+
begin
|
21
|
+
@date = Date.parse("#{full_year(serial, year)}-#{month}-#{day}")
|
22
|
+
@valid = true
|
23
|
+
@number = "#{sans_checksum}#{checksum}"
|
24
|
+
rescue ArgumentError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def full_year(serial, year)
|
33
|
+
century(serial) + year.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def century(serial)
|
37
|
+
case serial.to_i
|
38
|
+
when 0..499 then 1900
|
39
|
+
else 2000 # or 1800, not possible to tell.
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def calculate_checksum(number)
|
44
|
+
digits = number.split('').map(&:to_i)
|
45
|
+
w1 = [3, 7, 6, 1, 8, 9, 4, 5, 2]
|
46
|
+
w2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
|
47
|
+
|
48
|
+
k1 = weighted_modulo_11(digits.zip(w1))
|
49
|
+
k2 = weighted_modulo_11([*digits, k1].zip(w2))
|
50
|
+
"#{k1}#{k2}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def weighted_modulo_11(digits_and_weights)
|
54
|
+
result = 11 - (digits_and_weights.map do |terms|
|
55
|
+
terms.reduce(:*)
|
56
|
+
end.sum % 11)
|
57
|
+
result > 9 ? 0 : result
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -4,7 +4,6 @@ module NationalIdentificationNumber
|
|
4
4
|
# Inspired by https://github.com/c7/personnummer/blob/master/lib/personnummer.rb
|
5
5
|
# Copyright (c) 2008 Peter Hellberg MIT
|
6
6
|
class Swedish < Base
|
7
|
-
|
8
7
|
attr_reader :date # used for testing
|
9
8
|
|
10
9
|
# Generator for valid Swedish personnummer: http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)
|
@@ -31,7 +30,12 @@ module NationalIdentificationNumber
|
|
31
30
|
if @number.match(/\A(\d{0}|\d{2})(\d{6})(\-{0,1})(\d{4})\Z/)
|
32
31
|
@number = "#{$2}-#{$4}"
|
33
32
|
else
|
34
|
-
@number.gsub
|
33
|
+
candidate = @number.gsub(/[^\d\-\+]/, '')
|
34
|
+
if candidate.match(/\A(\d{0}|\d{2})(\d{6})(\-{0,1})(\d{4})\Z/)
|
35
|
+
@number = "#{$2}-#{$4}"
|
36
|
+
else
|
37
|
+
@number = candidate
|
38
|
+
end
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
@@ -54,7 +58,14 @@ module NationalIdentificationNumber
|
|
54
58
|
elsif divider == '+'
|
55
59
|
century = 1800
|
56
60
|
else
|
57
|
-
|
61
|
+
preliminary_age = age_for_dob(Date.parse("#{1900 + year}-#{month}-#{day}")) rescue 0
|
62
|
+
#raise preliminary_age.inspect
|
63
|
+
if preliminary_age > 99
|
64
|
+
# It's unlikely that the person is older than 99, so assume a child when no divider was provided.
|
65
|
+
century = 2000
|
66
|
+
else
|
67
|
+
century = 1900
|
68
|
+
end
|
58
69
|
end
|
59
70
|
|
60
71
|
begin
|
@@ -91,15 +102,14 @@ module NationalIdentificationNumber
|
|
91
102
|
end
|
92
103
|
control_digit
|
93
104
|
end
|
94
|
-
|
95
105
|
end
|
96
106
|
end
|
97
107
|
|
98
|
-
if $0 == __FILE__
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
108
|
+
# if $0 == __FILE__
|
109
|
+
# # Randomize every part
|
110
|
+
# puts Bukowskis::NationalIdentificationNumber::Swedish.generate
|
111
|
+
# # Use given date, randomize serial
|
112
|
+
# puts Bukowskis::NationalIdentificationNumber::Swedish.generate(Date.new(1975,1,1))
|
113
|
+
# # Use given date and serial, calculate checksum
|
114
|
+
# puts Bukowskis::NationalIdentificationNumber::Swedish.generate(Date.new(1975,1,1), 123)
|
115
|
+
# end
|
@@ -1,74 +1,77 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require '
|
3
|
-
|
4
|
-
include NationalIdentificationNumber
|
2
|
+
require 'national_identification_number/base'
|
5
3
|
|
6
4
|
class TestBaseChild < NationalIdentificationNumber::Base
|
7
5
|
def set_valid_to_nil
|
8
6
|
@valid = nil
|
9
7
|
end
|
8
|
+
|
10
9
|
protected
|
10
|
+
|
11
11
|
def validate
|
12
12
|
@valid = 'validates_to_true'
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe Base
|
16
|
+
describe NationalIdentificationNumber::Base do
|
17
17
|
|
18
|
-
|
19
|
-
TestBaseChild.new('12345').should be_an_instance_of TestBaseChild
|
20
|
-
end
|
18
|
+
describe '#initialize' do
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
it "instantiates correctly" do
|
21
|
+
expect( TestBaseChild.new('12345') ).to be_an_instance_of TestBaseChild
|
22
|
+
end
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
it "repairs on initialization" do
|
25
|
+
expect( TestBaseChild.new(' 12345abc ').to_s ).to eq '12345ABC'
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
it "validates on initialization" do
|
29
|
+
expect { NationalIdentificationNumber::Base.new('12345') }.to raise_error(RuntimeError, 'You need to implement at least this method in subclasses.')
|
30
|
+
end
|
33
31
|
|
34
|
-
it "should return true if it is valid" do
|
35
|
-
TestBaseChild.new('12345abc').should be_valid
|
36
32
|
end
|
37
33
|
|
38
|
-
|
39
|
-
base = TestBaseChild.new('12345abc')
|
40
|
-
base.set_valid_to_nil
|
41
|
-
base.should_not be_valid
|
42
|
-
end
|
34
|
+
describe '#valid?' do
|
43
35
|
|
44
|
-
|
36
|
+
it "should return true if it is valid" do
|
37
|
+
expect( TestBaseChild.new('12345abc') ).to be_valid
|
38
|
+
end
|
45
39
|
|
46
|
-
|
40
|
+
it "should return true if it is valid" do
|
41
|
+
base = TestBaseChild.new('12345abc')
|
42
|
+
base.set_valid_to_nil
|
43
|
+
expect( base ).to_not be_valid
|
44
|
+
end
|
47
45
|
|
48
|
-
it "should return the number" do
|
49
|
-
TestBaseChild.new('12345ABC').to_s.should == '12345ABC'
|
50
46
|
end
|
51
47
|
|
52
|
-
|
48
|
+
describe '#to_s' do
|
53
49
|
|
54
|
-
|
50
|
+
it "should return the number" do
|
51
|
+
expect( TestBaseChild.new('12345ABC').to_s ).to eq '12345ABC'
|
52
|
+
end
|
55
53
|
|
56
|
-
it "should be a protected method" do
|
57
|
-
lambda { TestBaseChild.new('12345').repair }.should raise_error NoMethodError
|
58
54
|
end
|
59
55
|
|
60
|
-
|
61
|
-
TestBaseChild.new(' 123 45 abc %&/ ').to_s.should == '12345ABC%&/'
|
62
|
-
end
|
56
|
+
describe '#repair' do
|
63
57
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
58
|
+
it "should be a protected method" do
|
59
|
+
expect { TestBaseChild.new('12345').repair }.to raise_error NoMethodError
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should strip whitespaces and capitalize everything" do
|
63
|
+
expect( TestBaseChild.new(' 123 45 abc %&/ ').to_s ).to eq '12345ABC%&/'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should make it a string" do
|
67
|
+
expect( TestBaseChild.new(:symbol).to_s ).to eq 'SYMBOL'
|
68
|
+
expect( TestBaseChild.new(1234).to_s ).to eq '1234'
|
69
|
+
expect( TestBaseChild.new(nil).to_s ).to eq ''
|
70
|
+
end
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
+
it "should strip newlines and tabs" do
|
73
|
+
expect( TestBaseChild.new("one\ntwo\tthree\n").to_s ).to eq 'ONETWOTHREE'
|
74
|
+
end
|
72
75
|
end
|
73
76
|
|
74
77
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'resident'
|
3
|
+
|
4
|
+
describe NationalIdentificationNumber::Danish do
|
5
|
+
describe '#valid?' do
|
6
|
+
it 'recognizes valid numbers' do
|
7
|
+
expect(described_class.new('311257-1735')).to be_valid
|
8
|
+
expect(described_class.new('290444-0305')).to be_valid
|
9
|
+
expect(described_class.new('300168-0330')).to be_valid
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'recognizes invalid numbers' do
|
13
|
+
expect(described_class.new('251379-4001')).not_to be_valid # invalid month
|
14
|
+
expect(described_class.new('300279-4001')).not_to be_valid # invalid day
|
15
|
+
expect(described_class.new('asdf')).not_to be_valid
|
16
|
+
expect(described_class.new('1234567890')).not_to be_valid
|
17
|
+
expect(described_class.new('0000000000000')).not_to be_valid
|
18
|
+
expect(described_class.new('000000-0000')).not_to be_valid
|
19
|
+
expect(described_class.new('')).not_to be_valid
|
20
|
+
expect(described_class.new(1234567890)).not_to be_valid
|
21
|
+
expect(described_class.new(:really_bad_input_value)).not_to be_valid
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'sanitize' do
|
26
|
+
context 'with valid numbers' do
|
27
|
+
it 'is the formatted number' do
|
28
|
+
expect(described_class.new('3112571735').sanitize).to eq '311257-1735'
|
29
|
+
expect(described_class.new('290444.0305').sanitize).to eq '290444-0305'
|
30
|
+
expect(described_class.new('30.01.68.03.30').sanitize).to eq '300168-0330'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with invalid numbers' do
|
35
|
+
it 'is nil' do
|
36
|
+
expect(described_class.new('251379-4001').sanitize).to be_nil
|
37
|
+
expect(described_class.new('300279-4001').sanitize).to be_nil
|
38
|
+
expect(described_class.new('asdf').sanitize).to be_nil
|
39
|
+
expect(described_class.new('1234567890').sanitize).to be_nil
|
40
|
+
expect(described_class.new('0000000000000').sanitize).to be_nil
|
41
|
+
expect(described_class.new('000000-0000').sanitize).to be_nil
|
42
|
+
expect(described_class.new('').sanitize).to be_nil
|
43
|
+
expect(described_class.new(1234567890).sanitize).to be_nil
|
44
|
+
expect(described_class.new(:really_bad_input_value).sanitize).to be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'age' do
|
50
|
+
before do
|
51
|
+
Timecop.freeze Date.parse('2022-03-04')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'recognizes valid numbers' do
|
55
|
+
expect(described_class.new('110779-4101').age).to eq 42
|
56
|
+
expect(described_class.new('010100-1000').age).to eq 122
|
57
|
+
expect(described_class.new('110736-4002').age).to be_nil # Birthday in the future
|
58
|
+
expect(described_class.new('030320-5006').age).to eq 2
|
59
|
+
expect(described_class.new('110952-3113').age).to eq 69
|
60
|
+
expect(described_class.new('211164-2234').age).to eq 57
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'is nil for invalid numbers' do
|
64
|
+
expect(described_class.new('251379-4001').age).to be_nil # invalid month
|
65
|
+
expect(described_class.new('300279-4001').age).to be_nil # invalid day
|
66
|
+
expect(described_class.new('asdf').age).to be_nil
|
67
|
+
expect(described_class.new('1234567890').age).to be_nil
|
68
|
+
expect(described_class.new('0000000000000').age).to be_nil
|
69
|
+
expect(described_class.new('000000-0000').age).to be_nil
|
70
|
+
expect(described_class.new('').age).to be_nil
|
71
|
+
expect(described_class.new(1234567890).age).to be_nil
|
72
|
+
expect(described_class.new(:really_bad_input_value).age).to be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#to_s' do
|
77
|
+
it 'returns the number normalized regardless of wether its valid' do
|
78
|
+
expect(described_class.new('251.379.4001').to_s).to eq '251379-4001'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -3,58 +3,126 @@ require 'resident'
|
|
3
3
|
|
4
4
|
include NationalIdentificationNumber
|
5
5
|
|
6
|
-
describe Finnish
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
describe Finnish do
|
7
|
+
describe '#valid?' do
|
8
|
+
it "recognizes valid numbers" do
|
9
|
+
expect( Finnish.new('311280-999J') ).to be_valid
|
10
|
+
expect( Finnish.new('131052-308T') ).to be_valid
|
11
|
+
expect( Finnish.new('290164-862u') ).to be_valid
|
12
|
+
expect( Finnish.new('270368A172X') ).to be_valid
|
13
|
+
expect( Finnish.new('310145A586a') ).to be_valid
|
14
|
+
expect( Finnish.new('080266+183P') ).to be_valid
|
15
|
+
expect( Finnish.new('290248+145c') ).to be_valid
|
16
|
+
end
|
17
|
+
|
18
|
+
it "recognizes invalid numbers" do
|
19
|
+
expect( Finnish.new('671301A172V') ).to_not be_valid # valid checksum, invalid month
|
20
|
+
expect( Finnish.new('830231A172M') ).to_not be_valid # valid checksum, invalid day
|
21
|
+
expect( Finnish.new('311180-999J') ).to_not be_valid
|
22
|
+
expect( Finnish.new('131052-308S') ).to_not be_valid
|
23
|
+
expect( Finnish.new('290164X862U') ).to_not be_valid
|
24
|
+
expect( Finnish.new('670368A172X') ).to_not be_valid
|
25
|
+
expect( Finnish.new('310145--586A') ).to_not be_valid
|
26
|
+
expect( Finnish.new('asdf') ).to_not be_valid
|
27
|
+
expect( Finnish.new('1234567890') ).to_not be_valid
|
28
|
+
expect( Finnish.new('0000000000000') ).to_not be_valid
|
29
|
+
expect( Finnish.new('000000-0000') ).to_not be_valid
|
30
|
+
expect( Finnish.new('') ).to_not be_valid
|
31
|
+
expect( Finnish.new(1234567890) ).to_not be_valid
|
32
|
+
expect( Finnish.new(:really_bad_input_value) ).to_not be_valid
|
33
|
+
end
|
16
34
|
end
|
17
35
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
describe 'sanitize' do
|
37
|
+
context 'valid numbers' do
|
38
|
+
it 'is the formatted number' do
|
39
|
+
expect(Finnish.new('311280-999J').sanitize).to eq '311280-999J'
|
40
|
+
expect(Finnish.new('131052-308T').sanitize).to eq '131052-308T'
|
41
|
+
expect(Finnish.new('290164-862u').sanitize).to eq '290164-862U'
|
42
|
+
expect(Finnish.new('270368A172X').sanitize).to eq '270368A172X'
|
43
|
+
expect(Finnish.new('310145A586a').sanitize).to eq '310145A586A'
|
44
|
+
expect(Finnish.new('080266+183P').sanitize).to eq '080266+183P'
|
45
|
+
expect(Finnish.new('290248+145c').sanitize).to eq '290248+145C'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'invalid numbers' do
|
50
|
+
it 'is nil' do
|
51
|
+
expect(Finnish.new('671301A172V').sanitize).to be nil
|
52
|
+
expect(Finnish.new('830231A172M').sanitize).to be nil
|
53
|
+
expect(Finnish.new('311180-999J').sanitize).to be nil
|
54
|
+
expect(Finnish.new('131052-308S').sanitize).to be nil
|
55
|
+
expect(Finnish.new('290164X862U').sanitize).to be nil
|
56
|
+
expect(Finnish.new('670368A172X').sanitize).to be nil
|
57
|
+
expect(Finnish.new('310145--586A').sanitize).to be nil
|
58
|
+
expect(Finnish.new('asdf').sanitize).to be nil
|
59
|
+
expect(Finnish.new('1234567890').sanitize).to be nil
|
60
|
+
expect(Finnish.new('0000000000000').sanitize).to be nil
|
61
|
+
expect(Finnish.new('000000-0000').sanitize).to be nil
|
62
|
+
expect(Finnish.new('').sanitize).to be nil
|
63
|
+
expect(Finnish.new(1234567890).sanitize).to be nil
|
64
|
+
expect(Finnish.new(:really_bad_input_value).sanitize).to be nil
|
65
|
+
end
|
66
|
+
end
|
33
67
|
end
|
34
68
|
|
35
|
-
|
69
|
+
describe 'age' do
|
36
70
|
|
37
|
-
|
71
|
+
before do
|
72
|
+
Timecop.freeze Date.parse('2014-05-20')
|
73
|
+
end
|
38
74
|
|
39
|
-
|
40
|
-
|
41
|
-
|
75
|
+
it "recognizes valid numbers" do
|
76
|
+
expect( Finnish.new('230118-999H').age ).to eq 96
|
77
|
+
expect( Finnish.new('311280-999J').age ).to eq 33
|
78
|
+
expect( Finnish.new('131052-308T').age ).to eq 61
|
79
|
+
expect( Finnish.new('290164-862u').age ).to eq 50
|
80
|
+
expect( Finnish.new('270368A172X').age ).to be_nil # Birthday in the future
|
81
|
+
expect( Finnish.new('310145A586a').age ).to be_nil # Birthday in the future
|
82
|
+
expect( Finnish.new('080266+183P').age ).to eq 148
|
83
|
+
expect( Finnish.new('290248+145c').age ).to eq 166
|
84
|
+
end
|
42
85
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
86
|
+
it "is nil for invalid numbers" do
|
87
|
+
expect( Finnish.new('671301A172V').age ).to be_nil
|
88
|
+
expect( Finnish.new('830231A172M').age ).to be_nil
|
89
|
+
expect( Finnish.new('311180-999J').age ).to be_nil
|
90
|
+
expect( Finnish.new('131052-308S').age ).to be_nil
|
91
|
+
expect( Finnish.new('290164X862U').age ).to be_nil
|
92
|
+
expect( Finnish.new('670368A172X').age ).to be_nil
|
93
|
+
expect( Finnish.new('310145--586A').age ).to be_nil
|
94
|
+
expect( Finnish.new('asdf').age ).to be_nil
|
95
|
+
expect( Finnish.new('1234567890').age ).to be_nil
|
96
|
+
expect( Finnish.new('0000000000000').age ).to be_nil
|
97
|
+
expect( Finnish.new('000000-0000').age ).to be_nil
|
98
|
+
expect( Finnish.new('').age ).to be_nil
|
99
|
+
expect( Finnish.new(1234567890).age ).to be_nil
|
100
|
+
expect( Finnish.new(:really_bad_input_value).age ).to be_nil
|
101
|
+
end
|
49
102
|
end
|
50
103
|
|
51
|
-
|
52
|
-
Finnish.new(%Q{270368"A172 \tX}).to_s.should == '270368A172X'
|
53
|
-
Finnish.new(%Q{270368"A172\tX\n\n}).to_s.should == '270368A172X'
|
54
|
-
Finnish.new(%Q{270368"A172X}).to_s.should == '270368A172X'
|
55
|
-
Finnish.new(%Q{270368A<172X}).to_s.should == '270368A172X'
|
56
|
-
Finnish.new(%Q{270368A'172X}).to_s.should == '270368A172X'
|
57
|
-
Finnish.new(%Q{270368A>172X}).to_s.should == '270368A172X'
|
58
|
-
end
|
104
|
+
describe '#to_s' do
|
59
105
|
|
60
|
-
|
106
|
+
it "repairs missing dashes, even if the number is invalid" do
|
107
|
+
expect( Finnish.new('311280999K').to_s ).to eq '311280-999K'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns the number normalized if the number is valid" do
|
111
|
+
expect( Finnish.new('311280999J').to_s ).to eq '311280-999J'
|
112
|
+
expect( Finnish.new('270368A172X ').to_s ).to eq '270368A172X'
|
113
|
+
expect( Finnish.new('xx270368A172X ').to_s ).to eq '270368A172X'
|
114
|
+
expect( Finnish.new('xxx270368A172Xt ').to_s ).to eq '270368A172X'
|
115
|
+
expect( Finnish.new('\t050126-1853').to_s ).to eq '050126-1853'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "is always injection safe, valid or not" do
|
119
|
+
expect( Finnish.new(%Q{270368"A172 \tX}).to_s ).to eq '270368A172X'
|
120
|
+
expect( Finnish.new(%Q{270368"A172\tX\n\n}).to_s ).to eq '270368A172X'
|
121
|
+
expect( Finnish.new(%Q{270368"A172X}).to_s ).to eq '270368A172X'
|
122
|
+
expect( Finnish.new(%Q{270368A<172X}).to_s ).to eq '270368A172X'
|
123
|
+
expect( Finnish.new(%Q{270368A'172X}).to_s ).to eq '270368A172X'
|
124
|
+
expect( Finnish.new(%Q{270368A>172X}).to_s ).to eq '270368A172X'
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'resident'
|
3
|
+
|
4
|
+
describe NationalIdentificationNumber::Norwegian do
|
5
|
+
describe '#valid?' do
|
6
|
+
it 'recognizes valid numbers' do
|
7
|
+
expect(described_class.new('11077941012')).to be_valid
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'recognizes invalid numbers' do
|
11
|
+
expect(described_class.new('671301A172V')).not_to be_valid # valid checksum, invalid month
|
12
|
+
expect(described_class.new('830231A172M')).not_to be_valid # valid checksum, invalid day
|
13
|
+
expect(described_class.new('11077941010')).not_to be_valid
|
14
|
+
expect(described_class.new('670368A172X')).not_to be_valid
|
15
|
+
expect(described_class.new('310145--586A')).not_to be_valid
|
16
|
+
expect(described_class.new('asdf')).not_to be_valid
|
17
|
+
expect(described_class.new('1234567890')).not_to be_valid
|
18
|
+
expect(described_class.new('0000000000000')).not_to be_valid
|
19
|
+
expect(described_class.new('000000-0000')).not_to be_valid
|
20
|
+
expect(described_class.new('')).not_to be_valid
|
21
|
+
expect(described_class.new(1234567890)).not_to be_valid
|
22
|
+
expect(described_class.new(:really_bad_input_value)).not_to be_valid
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'sanitize' do
|
27
|
+
context 'with valid numbers' do
|
28
|
+
it 'is the formatted number' do
|
29
|
+
expect(described_class.new('11077941012').sanitize).to eq '11077941012'
|
30
|
+
expect(described_class.new('11.07.79.410.12').sanitize).to eq '11077941012'
|
31
|
+
expect(described_class.new('11 07 79 41012').sanitize).to eq '11077941012'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with invalid numbers' do
|
36
|
+
it 'is nil' do
|
37
|
+
expect(described_class.new('11077941010').sanitize).to be_nil
|
38
|
+
expect(described_class.new('671301A172V').sanitize).to be_nil
|
39
|
+
expect(described_class.new('830231A172M').sanitize).to be_nil
|
40
|
+
expect(described_class.new('311180-999J').sanitize).to be_nil
|
41
|
+
expect(described_class.new('131052-308S').sanitize).to be_nil
|
42
|
+
expect(described_class.new('290164X862U').sanitize).to be_nil
|
43
|
+
expect(described_class.new('670368A172X').sanitize).to be_nil
|
44
|
+
expect(described_class.new('310145--586A').sanitize).to be_nil
|
45
|
+
expect(described_class.new('asdf').sanitize).to be_nil
|
46
|
+
expect(described_class.new('1234567890').sanitize).to be_nil
|
47
|
+
expect(described_class.new('0000000000000').sanitize).to be_nil
|
48
|
+
expect(described_class.new('000000-0000').sanitize).to be_nil
|
49
|
+
expect(described_class.new('').sanitize).to be_nil
|
50
|
+
expect(described_class.new(1234567890).sanitize).to be_nil
|
51
|
+
expect(described_class.new(:really_bad_input_value).sanitize).to be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'age' do
|
57
|
+
before do
|
58
|
+
Timecop.freeze Date.parse('2022-03-04')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'recognizes valid numbers' do
|
62
|
+
expect(described_class.new('11077941012').age).to eq 42
|
63
|
+
expect(described_class.new('01010010000').age).to eq 122
|
64
|
+
expect(described_class.new('11077950020').age).to be_nil # Birthday in the future
|
65
|
+
expect(described_class.new('03032050068').age).to eq 2
|
66
|
+
expect(described_class.new('11095231138').age).to eq 69
|
67
|
+
expect(described_class.new('21116422341').age).to eq 57
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'is nil for invalid numbers' do
|
71
|
+
expect(described_class.new('671301A172V').age).to be_nil
|
72
|
+
expect(described_class.new('830231A172M').age).to be_nil
|
73
|
+
expect(described_class.new('311180-999J').age).to be_nil
|
74
|
+
expect(described_class.new('131052-308S').age).to be_nil
|
75
|
+
expect(described_class.new('290164X862U').age).to be_nil
|
76
|
+
expect(described_class.new('670368A172X').age).to be_nil
|
77
|
+
expect(described_class.new('310145--586A').age).to be_nil
|
78
|
+
expect(described_class.new('asdf').age).to be_nil
|
79
|
+
expect(described_class.new('1234567890').age).to be_nil
|
80
|
+
expect(described_class.new('0000000000000').age).to be_nil
|
81
|
+
expect(described_class.new('000000-0000').age).to be_nil
|
82
|
+
expect(described_class.new('').age).to be_nil
|
83
|
+
expect(described_class.new(1234567890).age).to be_nil
|
84
|
+
expect(described_class.new(:really_bad_input_value).age).to be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#to_s' do
|
89
|
+
it 'returns the number normalized regardless of wether it is valid' do
|
90
|
+
expect(described_class.new('311280999J').to_s).to eq '311280999'
|
91
|
+
expect(described_class.new('27..036.8A172X ').to_s).to eq '270368172'
|
92
|
+
expect(described_class.new('xx270368A172X ').to_s).to eq '270368172'
|
93
|
+
expect(described_class.new('xxx270368A172Xt ').to_s).to eq '270368172'
|
94
|
+
expect(described_class.new('\t050126-1853').to_s).to eq '0501261853'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,147 +1,218 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require '
|
2
|
+
require 'national_identification_number/swedish'
|
3
3
|
|
4
4
|
include NationalIdentificationNumber
|
5
5
|
|
6
6
|
describe Swedish, '.generate' do
|
7
7
|
|
8
|
-
it "
|
9
|
-
50.times { Swedish.new(Swedish.generate).
|
8
|
+
it "generates valid numbers" do
|
9
|
+
50.times { expect( Swedish.new(Swedish.generate) ).to be_valid } # I know, it feels weird :)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
Swedish.new(:really_bad_input).should_not be_valid
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
describe Swedish, 'to_s' do
|
47
|
-
|
48
|
-
it "should repair missing dashes and a superfluous century, even if the number is invalid" do
|
49
|
-
Swedish.new('1234561239').to_s.should == '123456-1239'
|
50
|
-
Swedish.new('123456-1239').to_s.should == '123456-1239'
|
51
|
-
Swedish.new("191234561239").to_s.should == '123456-1239'
|
52
|
-
Swedish.new("19123456-1239").to_s.should == '123456-1239'
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should return the number normalized if the number is valid" do
|
56
|
-
Swedish.new('0501261853').to_s.should == '050126-1853'
|
57
|
-
Swedish.new('050126-1853').to_s.should == '050126-1853'
|
58
|
-
Swedish.new("190501261853").to_s.should == '050126-1853'
|
59
|
-
Swedish.new("19050126-1853").to_s.should == '050126-1853'
|
60
|
-
Swedish.new("19050126-185d3").to_s.should == '050126-1853'
|
61
|
-
Swedish.new("19050126-185d3\n").to_s.should == '050126-1853'
|
62
|
-
end
|
12
|
+
describe '#valid?' do
|
13
|
+
|
14
|
+
it "recognizes valid numbers" do
|
15
|
+
expect( Swedish.new("19180123-2669") ).to be_valid
|
16
|
+
expect( Swedish.new("00180123-2669") ).to be_valid
|
17
|
+
expect( Swedish.new("000180123-2669") ).to be_valid
|
18
|
+
expect( Swedish.new("050126-1853") ).to be_valid
|
19
|
+
expect( Swedish.new("0asdfghj501261853") ).to be_valid
|
20
|
+
expect( Swedish.new("050112-2451") ).to be_valid
|
21
|
+
expect( Swedish.new("450202-6950") ).to be_valid
|
22
|
+
expect( Swedish.new("19450202-6950") ).to be_valid
|
23
|
+
end
|
24
|
+
|
25
|
+
it "recognizes invalid numbers" do
|
26
|
+
expect( Swedish.new("991301-1236") ).to_not be_valid # valid checksum, invalid month
|
27
|
+
expect( Swedish.new("830231-5554") ).to_not be_valid # valid checksum, invalid day
|
28
|
+
expect( Swedish.new("050112--2451") ).to_not be_valid
|
29
|
+
expect( Swedish.new("123456-1239") ).to_not be_valid
|
30
|
+
expect( Swedish.new("180123-2668") ).to_not be_valid
|
31
|
+
expect( Swedish.new("150D1261853") ).to_not be_valid
|
32
|
+
expect( Swedish.new("750112-2451") ).to_not be_valid
|
33
|
+
expect( Swedish.new("123") ).to_not be_valid
|
34
|
+
expect( Swedish.new("000000-0000") ).to_not be_valid
|
35
|
+
expect( Swedish.new("0000000000") ).to_not be_valid
|
36
|
+
expect( Swedish.new("asdfghj") ).to_not be_valid
|
37
|
+
expect( Swedish.new("") ).to_not be_valid
|
38
|
+
expect( Swedish.new(12345678) ).to_not be_valid
|
39
|
+
expect( Swedish.new(:really_bad_input) ).to_not be_valid
|
40
|
+
end
|
63
41
|
|
64
|
-
it "should always be injection safe, valid or not" do
|
65
|
-
Swedish.new(" 180 123 - 2669 \n\n\t").to_s.should == '180123-2669'
|
66
|
-
Swedish.new(" 180 123 - 2669 \n").to_s.should == '180123-2669'
|
67
|
-
Swedish.new(%Q{180123-"2669}).to_s.should == '180123-2669'
|
68
|
-
Swedish.new(%Q{180123-<2669}).to_s.should == '180123-2669'
|
69
|
-
Swedish.new(%Q{1801D23-'2669}).to_s.should == '180123-2669'
|
70
|
-
Swedish.new(%Q{180s123->2669}).to_s.should == '180123-2669'
|
71
|
-
Swedish.new(%Q{19180s123->2669}).to_s.should == '180123-2669'
|
72
42
|
end
|
73
43
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
44
|
+
describe 'sanitize' do
|
45
|
+
context 'invalid numbers' do
|
46
|
+
it 'is nil' do
|
47
|
+
expect(Swedish.new('991301-1236').sanitize).to be nil # valid checksum, invalid month
|
48
|
+
expect(Swedish.new('830231-5554').sanitize).to be nil # valid checksum, invalid day
|
49
|
+
expect(Swedish.new('050112--2451').sanitize).to be nil
|
50
|
+
expect(Swedish.new('123456-1239').sanitize).to be nil
|
51
|
+
expect(Swedish.new('180123-2668').sanitize).to be nil
|
52
|
+
expect(Swedish.new('150D1261853').sanitize).to be nil
|
53
|
+
expect(Swedish.new('750112-2451').sanitize).to be nil
|
54
|
+
expect(Swedish.new('123').sanitize).to be nil
|
55
|
+
expect(Swedish.new('000000-0000').sanitize).to be nil
|
56
|
+
expect(Swedish.new('0000000000').sanitize).to be nil
|
57
|
+
expect(Swedish.new('asdfghj').sanitize).to be nil
|
58
|
+
expect(Swedish.new('').sanitize).to be nil
|
59
|
+
expect(Swedish.new(12345678).sanitize).to be nil
|
60
|
+
expect(Swedish.new(:really_bad_input).sanitize).to be nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'valid numbers' do
|
65
|
+
it 'is the sanitize dnumber' do
|
66
|
+
expect(Swedish.new('19180123-2669').sanitize).to eq '180123-2669'
|
67
|
+
expect(Swedish.new('00180123-2669').sanitize).to eq '180123-2669'
|
68
|
+
expect(Swedish.new('000180123-2669').sanitize).to eq '180123-2669'
|
69
|
+
expect(Swedish.new('050126-1853').sanitize).to eq '050126-1853'
|
70
|
+
expect(Swedish.new('0asdfghj501261853').sanitize).to eq '050126-1853'
|
71
|
+
expect(Swedish.new('050112-2451').sanitize).to eq '050112-2451'
|
72
|
+
expect(Swedish.new('450202-6950').sanitize).to eq '450202-6950'
|
73
|
+
expect(Swedish.new('19450202-6950').sanitize).to eq '450202-6950'
|
74
|
+
end
|
75
|
+
end
|
83
76
|
end
|
84
77
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
78
|
+
describe '#age' do
|
79
|
+
|
80
|
+
before do
|
81
|
+
Timecop.freeze Date.parse('2014-01-20')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "knows the age" do
|
85
|
+
expect( Swedish.new("19180123-2669").age ).to eq 95
|
86
|
+
expect( Swedish.new("19180123-2669").age ).to eq 95
|
87
|
+
expect( Swedish.new("00180123-2669").age ).to eq 95
|
88
|
+
expect( Swedish.new("000180123-2669").age ).to eq 95
|
89
|
+
expect( Swedish.new("050126-1853").age ).to eq 8
|
90
|
+
expect( Swedish.new("0asdfghj501261853").age ).to eq 8
|
91
|
+
expect( Swedish.new("050112-2451").age ).to eq 9
|
92
|
+
expect( Swedish.new("450202-6950").age ).to eq 68
|
93
|
+
expect( Swedish.new("19450202-6950").age ).to eq 68
|
94
|
+
end
|
95
|
+
|
96
|
+
it "is nil for invalid numbers" do
|
97
|
+
expect( Swedish.new("991301-1236").age ).to be_nil
|
98
|
+
expect( Swedish.new("830231-5554").age ).to be_nil
|
99
|
+
expect( Swedish.new("050112--2451").age ).to be_nil
|
100
|
+
expect( Swedish.new("123456-1239").age ).to be_nil
|
101
|
+
expect( Swedish.new("180123-2668").age ).to be_nil
|
102
|
+
expect( Swedish.new("150D1261853").age ).to be_nil
|
103
|
+
expect( Swedish.new("750112-2451").age ).to be_nil
|
104
|
+
expect( Swedish.new("123").age ).to be_nil
|
105
|
+
expect( Swedish.new("000000-0000").age ).to be_nil
|
106
|
+
expect( Swedish.new("0000000000").age ).to be_nil
|
107
|
+
expect( Swedish.new("asdfghj").age ).to be_nil
|
108
|
+
expect( Swedish.new("").age ).to be_nil
|
109
|
+
expect( Swedish.new(12345678).age ).to be_nil
|
110
|
+
expect( Swedish.new(:really_bad_input).age ).to be_nil
|
111
|
+
end
|
91
112
|
|
92
|
-
it "should recognize people born in the year 2000" do
|
93
|
-
beginning_of_year = Swedish.new("000101-0008")
|
94
|
-
beginning_of_year.should be_valid
|
95
|
-
beginning_of_year.date.should == Date.new(2000, 1, 1)
|
96
|
-
leap_year = Swedish.new("000229-0005") # 2000 was a leap year, 1900 not
|
97
|
-
leap_year.should be_valid
|
98
|
-
leap_year.date.should == Date.new(2000, 2, 29)
|
99
|
-
end_of_year = Swedish.new("001231-0009")
|
100
|
-
end_of_year.should be_valid
|
101
|
-
end_of_year.date.should == Date.new(2000, 12, 31)
|
102
113
|
end
|
103
114
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
115
|
+
describe '#to_s' do
|
116
|
+
|
117
|
+
it "repair missing dashes and a superfluous century, even if the number is invalid" do
|
118
|
+
expect( Swedish.new('1234561239').to_s ).to eq '123456-1239'
|
119
|
+
expect( Swedish.new('123456-1239').to_s ).to eq '123456-1239'
|
120
|
+
expect( Swedish.new("191234561239").to_s ).to eq '123456-1239'
|
121
|
+
expect( Swedish.new("19123456-1239").to_s ).to eq '123456-1239'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "return the number normalized if the number is valid" do
|
125
|
+
expect( Swedish.new('0501261853').to_s ).to eq '050126-1853'
|
126
|
+
expect( Swedish.new('050126-1853').to_s ).to eq '050126-1853'
|
127
|
+
expect( Swedish.new('0asdfghj501261853').to_s).to eq '050126-1853'
|
128
|
+
expect( Swedish.new("190501261853").to_s ).to eq '050126-1853'
|
129
|
+
expect( Swedish.new("19050126-1853").to_s ).to eq '050126-1853'
|
130
|
+
expect( Swedish.new("19050126-185d3").to_s ).to eq '050126-1853'
|
131
|
+
expect( Swedish.new("19050126-185d3\n").to_s ).to eq '050126-1853'
|
132
|
+
end
|
133
|
+
|
134
|
+
it "always be injection safe, valid or not" do
|
135
|
+
expect( Swedish.new(" 180 123 - 2669 \n\n\t").to_s ).to eq '180123-2669'
|
136
|
+
expect( Swedish.new(" 180 123 - 2669 \n").to_s ).to eq '180123-2669'
|
137
|
+
expect( Swedish.new(%Q{180123-"2669}).to_s ).to eq '180123-2669'
|
138
|
+
expect( Swedish.new(%Q{180123-<2669}).to_s ).to eq '180123-2669'
|
139
|
+
expect( Swedish.new(%Q{1801D23-'2669}).to_s ).to eq '180123-2669'
|
140
|
+
expect( Swedish.new(%Q{180s123->2669}).to_s ).to eq '180123-2669'
|
141
|
+
expect( Swedish.new(%Q{19180s123->2669}).to_s ).to eq '180123-2669'
|
142
|
+
end
|
112
143
|
|
113
|
-
it "should recognize all other people less than 100 years old" do
|
114
|
-
will_turn_99_this_year = Date.new(Date.today.year - 99, 12, 31).strftime("%y%m%d")
|
115
|
-
soon_99 = Swedish.new("#{will_turn_99_this_year}-000#{Swedish.luhn_algorithm("#{will_turn_99_this_year}000")}")
|
116
|
-
soon_99.should be_valid
|
117
|
-
soon_99.date.should == Date.new(Date.today.year - 99, 12, 31)
|
118
|
-
turned_99_this_year = Date.new(Date.today.year - 99, 1, 1).strftime("%y%m%d")
|
119
|
-
already_99 = Swedish.new("#{turned_99_this_year}-000#{Swedish.luhn_algorithm("#{turned_99_this_year}000")}")
|
120
|
-
already_99.should be_valid
|
121
|
-
already_99.date.should == Date.new(Date.today.year - 99, 1, 1)
|
122
144
|
end
|
123
145
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
146
|
+
describe '#date' do
|
147
|
+
|
148
|
+
it "recognizes babies born today" do
|
149
|
+
today = Date.today.strftime("%y%m%d")
|
150
|
+
born_today = Swedish.new("#{today}-000#{Swedish.luhn_algorithm("#{today}000")}")
|
151
|
+
expect( born_today ).to be_valid
|
152
|
+
expect( born_today.date).to eq Date.today
|
153
|
+
end
|
154
|
+
|
155
|
+
it "recognizes babies born yesterday" do
|
156
|
+
today = (Date.today - 1).strftime("%y%m%d")
|
157
|
+
born_yesterday = Swedish.new("#{today}-000#{Swedish.luhn_algorithm("#{today}000")}")
|
158
|
+
expect( born_yesterday ).to be_valid
|
159
|
+
expect( born_yesterday.date ).to eq (Date.today - 1)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "recognizes people born in the year 2000" do
|
163
|
+
beginning_of_year = Swedish.new("000101-0008")
|
164
|
+
expect( beginning_of_year ).to be_valid
|
165
|
+
expect( beginning_of_year.date ).to eq Date.new(2000, 1, 1)
|
166
|
+
leap_year = Swedish.new("000229-0005") # 2000 was a leap year, 1900 not
|
167
|
+
expect( leap_year ).to be_valid
|
168
|
+
expect( leap_year.date ).to eq Date.new(2000, 2, 29)
|
169
|
+
end_of_year = Swedish.new("001231-0009")
|
170
|
+
expect( end_of_year ).to be_valid
|
171
|
+
expect( end_of_year.date ).to eq Date.new(2000, 12, 31)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "recognizes people born in the year 1999" do
|
175
|
+
beginning_of_year = Swedish.new("990101-0000")
|
176
|
+
expect( beginning_of_year ).to be_valid
|
177
|
+
expect( beginning_of_year.date ).to eq Date.new(1999, 1, 1)
|
178
|
+
end_of_year = Swedish.new("991231-0001")
|
179
|
+
expect( end_of_year ).to be_valid
|
180
|
+
expect( end_of_year.date ).to eq Date.new(1999, 12, 31)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "recognizes all other people less than 100 years old" do
|
184
|
+
will_turn_99_this_year = Date.new(Date.today.year - 99, 12, 31).strftime("%y%m%d")
|
185
|
+
soon_99 = Swedish.new("#{will_turn_99_this_year}-000#{Swedish.luhn_algorithm("#{will_turn_99_this_year}000")}")
|
186
|
+
expect( soon_99 ).to be_valid
|
187
|
+
expect( soon_99.date ).to eq Date.new(Date.today.year - 99, 12, 31)
|
188
|
+
turned_99_this_year = Date.new(Date.today.year - 99, 1, 1).strftime("%y%m%d")
|
189
|
+
already_99 = Swedish.new("#{turned_99_this_year}-000#{Swedish.luhn_algorithm("#{turned_99_this_year}000")}")
|
190
|
+
expect( already_99 ).to be_valid
|
191
|
+
expect( already_99.date ).to eq Date.new(Date.today.year - 99, 1, 1)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "recognizes people that turn 100 years in this year" do
|
195
|
+
will_turn_100_this_year = Date.new(Date.today.year - 100, 12, 31).strftime("%y%m%d")
|
196
|
+
soon_100 = Swedish.new("#{will_turn_100_this_year}+000#{Swedish.luhn_algorithm("#{will_turn_100_this_year}000")}")
|
197
|
+
expect( soon_100 ).to be_valid
|
198
|
+
expect( soon_100.date ).to eq Date.new(Date.today.year - 100, 12, 31)
|
199
|
+
turned_100_this_year = Date.new(Date.today.year - 100, 1, 1).strftime("%y%m%d")
|
200
|
+
already_100 = Swedish.new("#{turned_100_this_year}+000#{Swedish.luhn_algorithm("#{turned_100_this_year}000")}")
|
201
|
+
expect( already_100 ).to be_valid
|
202
|
+
expect( already_100.date ).to eq Date.new(Date.today.year - 100, 1, 1)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "recognizes people older than 100 years born after 1900" do
|
206
|
+
normal = Swedish.new("010101+0007")
|
207
|
+
expect( normal ).to be_valid
|
208
|
+
expect( normal.date ).to eq Date.new(1901, 1, 1)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "recognizes people older than 100 years born before 1900" do
|
212
|
+
normal = Swedish.new("991231+0001")
|
213
|
+
expect( normal ).to be_valid
|
214
|
+
expect( normal.date ).to eq Date.new(1899, 12, 31)
|
215
|
+
end
|
133
216
|
end
|
134
217
|
|
135
|
-
|
136
|
-
normal = Swedish.new("010101+0007")
|
137
|
-
normal.should be_valid
|
138
|
-
normal.date.should == Date.new(1901, 1, 1)
|
139
|
-
end
|
140
|
-
|
141
|
-
it "should recognize people older than 100 years born before 1900" do
|
142
|
-
normal = Swedish.new("991231+0001")
|
143
|
-
normal.should be_valid
|
144
|
-
normal.date.should == Date.new(1899, 12, 31)
|
145
|
-
end
|
146
|
-
|
147
|
-
end
|
218
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
|
3
|
+
require 'timecop'
|
4
|
+
require 'resident'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
|
8
|
+
config.after(:each) do
|
9
|
+
# Preventing the mistake of forgetting to return to present time
|
10
|
+
# See http://www.51degrees.net/2010/01/18/global-after-blocks-or-keeping-timcop-happy.html
|
11
|
+
Timecop.return
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
metadata
CHANGED
@@ -1,98 +1,86 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: resident
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 9
|
10
|
-
version: 0.0.9
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.12
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Bukowskis
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2022-03-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
22
14
|
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
23
21
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: timecop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
27
31
|
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
33
34
|
type: :development
|
34
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
35
41
|
description:
|
36
42
|
email:
|
37
43
|
executables: []
|
38
|
-
|
39
44
|
extensions: []
|
40
|
-
|
41
|
-
|
42
|
-
- README.rdoc
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
43
47
|
- MIT-LICENSE
|
44
|
-
|
48
|
+
- README.md
|
49
|
+
- lib/national_identification_number.rb
|
45
50
|
- lib/national_identification_number/base.rb
|
51
|
+
- lib/national_identification_number/danish.rb
|
46
52
|
- lib/national_identification_number/finnish.rb
|
53
|
+
- lib/national_identification_number/norwegian.rb
|
47
54
|
- lib/national_identification_number/swedish.rb
|
48
|
-
- lib/national_identification_number.rb
|
49
55
|
- lib/resident.rb
|
50
|
-
- MIT-LICENSE
|
51
|
-
- README.rdoc
|
52
|
-
- .gemtest
|
53
56
|
- spec/national_identification_number/base_spec.rb
|
57
|
+
- spec/national_identification_number/danish_spec.rb
|
54
58
|
- spec/national_identification_number/finnish_spec.rb
|
59
|
+
- spec/national_identification_number/norwegian_spec.rb
|
55
60
|
- spec/national_identification_number/swedish_spec.rb
|
56
|
-
|
61
|
+
- spec/spec_helper.rb
|
57
62
|
homepage: http://github.com/bukowskis/national_identification_number/
|
58
|
-
licenses:
|
63
|
+
licenses:
|
59
64
|
- MIT-LICENSE
|
65
|
+
metadata: {}
|
60
66
|
post_install_message:
|
61
|
-
rdoc_options:
|
62
|
-
|
63
|
-
- README.rdoc
|
64
|
-
- --charset=UTF-8
|
65
|
-
require_paths:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
66
69
|
- lib
|
67
70
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
-
|
70
|
-
requirements:
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
71
73
|
- - ">="
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
- 8
|
77
|
-
- 7
|
78
|
-
version: 1.8.7
|
79
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
-
none: false
|
81
|
-
requirements:
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.9.3
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
82
78
|
- - ">="
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
|
85
|
-
segments:
|
86
|
-
- 0
|
87
|
-
version: "0"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
88
81
|
requirements: []
|
89
|
-
|
90
|
-
rubyforge_project:
|
91
|
-
rubygems_version: 1.5.3
|
82
|
+
rubygems_version: 3.0.3.1
|
92
83
|
signing_key:
|
93
|
-
specification_version:
|
84
|
+
specification_version: 4
|
94
85
|
summary: Validate National Identification Numbers.
|
95
|
-
test_files:
|
96
|
-
- spec/national_identification_number/base_spec.rb
|
97
|
-
- spec/national_identification_number/finnish_spec.rb
|
98
|
-
- spec/national_identification_number/swedish_spec.rb
|
86
|
+
test_files: []
|
data/.gemtest
DELETED
File without changes
|