resident 0.0.9 → 0.0.10
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} +7 -6
- data/lib/national_identification_number/base.rb +11 -0
- data/lib/national_identification_number/finnish.rb +6 -4
- data/lib/national_identification_number/swedish.rb +8 -1
- data/spec/national_identification_number/base_spec.rb +44 -41
- data/spec/national_identification_number/finnish_spec.rb +82 -45
- data/spec/national_identification_number/swedish_spec.rb +163 -127
- data/spec/spec_helper.rb +14 -0
- metadata +78 -65
- data/.gemtest +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d93a0b9f267f96e0a266917baa460796b855613a
|
4
|
+
data.tar.gz: b3fe8f7e4392247dd2f2184562a7c347ae8d2e62
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 206a9d30f1f4d83d75e007b192fa56fe682750fc7c1aaf9fc5b092eeb3f54c600e43c0f0ba7872637cfc523b451348e69d2cca941de579affc114ce6f7dafe77
|
7
|
+
data.tar.gz: a1e8a71fdbcc5b007ddf25e61e449254da96cfcf9f78452111bc4ec697db99f2ce2a700ed708efdba38ee4933aee8b4368a7b222f1767cb1f1509ba397308ee0
|
data/{README.rdoc → README.md}
RENAMED
@@ -1,4 +1,4 @@
|
|
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.
|
@@ -6,13 +6,13 @@ This gem currently only supports Swedish (Personnummer) and Finnish (Henkilöasi
|
|
6
6
|
|
7
7
|
There is a special focus on identifying these numbers robustly (i.e. you can safely validate a param[:number] directly, or cleanup your database by running every non-normalized value through this gem).
|
8
8
|
|
9
|
-
|
9
|
+
## Installation
|
10
10
|
|
11
11
|
gem install resident
|
12
12
|
|
13
|
-
|
13
|
+
## Usage
|
14
14
|
|
15
|
-
Really, you can just use <tt>valid?</tt> and <tt>
|
15
|
+
Really, you can just use <tt>valid?</tt>, <tt>to_s</tt>, and <tt>age</tt> like so:
|
16
16
|
|
17
17
|
require 'resident'
|
18
18
|
|
@@ -20,6 +20,7 @@ Really, you can just use <tt>valid?</tt> and <tt>to_s</tt> like so:
|
|
20
20
|
|
21
21
|
number.valid? #=> true
|
22
22
|
number.to_s #=> "050126-1853"
|
23
|
+
number.age #=> 9
|
23
24
|
|
24
25
|
Please have a look at the specs to see how the national identification numbers of various countries are handled.
|
25
26
|
|
@@ -27,7 +28,7 @@ An example of robustness:
|
|
27
28
|
|
28
29
|
NationalIdentificationNumber::Swedish.new("19050126-185d3\n").to_s => "050126-1853"
|
29
30
|
|
30
|
-
|
31
|
+
## License
|
31
32
|
|
32
33
|
Some marked parts of the code are inspired or taken from MIT licensed code of
|
33
34
|
|
@@ -36,7 +37,7 @@ Some marked parts of the code are inspired or taken from MIT licensed code of
|
|
36
37
|
|
37
38
|
Other than that you got:
|
38
39
|
|
39
|
-
Copyright (c) 2011 Bukowskis.
|
40
|
+
Copyright (c) 2011-2014 Bukowskis.
|
40
41
|
|
41
42
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
42
43
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -17,8 +17,19 @@ module NationalIdentificationNumber
|
|
17
17
|
@number
|
18
18
|
end
|
19
19
|
|
20
|
+
def age
|
21
|
+
age_for_dob date
|
22
|
+
end
|
23
|
+
|
20
24
|
protected
|
21
25
|
|
26
|
+
# stackoverflow.com/questions/819263
|
27
|
+
def age_for_dob(dob)
|
28
|
+
today = Time.now.utc.to_date
|
29
|
+
return nil unless dob && today >= dob
|
30
|
+
today.year - dob.year - ((today.month > dob.month || (today.month == dob.month && today.day >= dob.day)) ? 0 : 1)
|
31
|
+
end
|
32
|
+
|
22
33
|
def repair
|
23
34
|
@number = @number.to_s.upcase.gsub(/\s/, '')
|
24
35
|
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
|
@@ -54,7 +54,14 @@ module NationalIdentificationNumber
|
|
54
54
|
elsif divider == '+'
|
55
55
|
century = 1800
|
56
56
|
else
|
57
|
-
|
57
|
+
preliminary_age = age_for_dob(Date.parse("#{1900 + year}-#{month}-#{day}")) rescue 0
|
58
|
+
#raise preliminary_age.inspect
|
59
|
+
if preliminary_age > 99
|
60
|
+
# It's unlikely that the person is older than 99, so assume a child when no divider was provided.
|
61
|
+
century = 2000
|
62
|
+
else
|
63
|
+
century = 1900
|
64
|
+
end
|
58
65
|
end
|
59
66
|
|
60
67
|
begin
|
@@ -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
|
@@ -3,58 +3,95 @@ require 'resident'
|
|
3
3
|
|
4
4
|
include NationalIdentificationNumber
|
5
5
|
|
6
|
-
describe Finnish
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
describe Finnish do
|
7
|
+
describe '#valid?' do
|
8
|
+
|
9
|
+
it "recognizes valid numbers" do
|
10
|
+
expect( Finnish.new('311280-999J') ).to be_valid
|
11
|
+
expect( Finnish.new('131052-308T') ).to be_valid
|
12
|
+
expect( Finnish.new('290164-862u') ).to be_valid
|
13
|
+
expect( Finnish.new('270368A172X') ).to be_valid
|
14
|
+
expect( Finnish.new('310145A586a') ).to be_valid
|
15
|
+
expect( Finnish.new('080266+183P') ).to be_valid
|
16
|
+
expect( Finnish.new('290248+145c') ).to be_valid
|
17
|
+
end
|
18
|
+
|
19
|
+
it "recognizes invalid numbers" do
|
20
|
+
expect( Finnish.new('671301A172V') ).to_not be_valid # valid checksum, invalid month
|
21
|
+
expect( Finnish.new('830231A172M') ).to_not be_valid # valid checksum, invalid day
|
22
|
+
expect( Finnish.new('311180-999J') ).to_not be_valid
|
23
|
+
expect( Finnish.new('131052-308S') ).to_not be_valid
|
24
|
+
expect( Finnish.new('290164X862U') ).to_not be_valid
|
25
|
+
expect( Finnish.new('670368A172X') ).to_not be_valid
|
26
|
+
expect( Finnish.new('310145--586A') ).to_not be_valid
|
27
|
+
expect( Finnish.new('asdf') ).to_not be_valid
|
28
|
+
expect( Finnish.new('1234567890') ).to_not be_valid
|
29
|
+
expect( Finnish.new('0000000000000') ).to_not be_valid
|
30
|
+
expect( Finnish.new('000000-0000') ).to_not be_valid
|
31
|
+
expect( Finnish.new('') ).to_not be_valid
|
32
|
+
expect( Finnish.new(1234567890) ).to_not be_valid
|
33
|
+
expect( Finnish.new(:really_bad_input_value) ).to_not be_valid
|
34
|
+
end
|
17
35
|
|
18
|
-
it "should recognize invalid numbers" do
|
19
|
-
Finnish.new('671301A172V').should_not be_valid # valid checksum, invalid month
|
20
|
-
Finnish.new('830231A172M').should_not be_valid # valid checksum, invalid day
|
21
|
-
Finnish.new('311180-999J').should_not be_valid
|
22
|
-
Finnish.new('131052-308S').should_not be_valid
|
23
|
-
Finnish.new('290164X862U').should_not be_valid
|
24
|
-
Finnish.new('670368A172X').should_not be_valid
|
25
|
-
Finnish.new('310145--586A').should_not be_valid
|
26
|
-
Finnish.new('asdf').should_not be_valid
|
27
|
-
Finnish.new('1234567890').should_not be_valid
|
28
|
-
Finnish.new('0000000000000').should_not be_valid
|
29
|
-
Finnish.new('000000-0000').should_not be_valid
|
30
|
-
Finnish.new('').should_not be_valid
|
31
|
-
Finnish.new(1234567890).should_not be_valid
|
32
|
-
Finnish.new(:really_bad_input_value).should_not be_valid
|
33
36
|
end
|
34
37
|
|
35
|
-
|
38
|
+
describe 'age' do
|
36
39
|
|
37
|
-
|
40
|
+
before do
|
41
|
+
Timecop.freeze Date.parse('2014-05-20')
|
42
|
+
end
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
it "recognizes valid numbers" do
|
45
|
+
expect( Finnish.new('230118-999H').age ).to eq 96
|
46
|
+
expect( Finnish.new('311280-999J').age ).to eq 33
|
47
|
+
expect( Finnish.new('131052-308T').age ).to eq 61
|
48
|
+
expect( Finnish.new('290164-862u').age ).to eq 50
|
49
|
+
expect( Finnish.new('270368A172X').age ).to be_nil # Birthday in the future
|
50
|
+
expect( Finnish.new('310145A586a').age ).to be_nil # Birthday in the future
|
51
|
+
expect( Finnish.new('080266+183P').age ).to eq 148
|
52
|
+
expect( Finnish.new('290248+145c').age ).to eq 166
|
53
|
+
end
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
it "is nil for invalid numbers" do
|
56
|
+
expect( Finnish.new('671301A172V').age ).to be_nil
|
57
|
+
expect( Finnish.new('830231A172M').age ).to be_nil
|
58
|
+
expect( Finnish.new('311180-999J').age ).to be_nil
|
59
|
+
expect( Finnish.new('131052-308S').age ).to be_nil
|
60
|
+
expect( Finnish.new('290164X862U').age ).to be_nil
|
61
|
+
expect( Finnish.new('670368A172X').age ).to be_nil
|
62
|
+
expect( Finnish.new('310145--586A').age ).to be_nil
|
63
|
+
expect( Finnish.new('asdf').age ).to be_nil
|
64
|
+
expect( Finnish.new('1234567890').age ).to be_nil
|
65
|
+
expect( Finnish.new('0000000000000').age ).to be_nil
|
66
|
+
expect( Finnish.new('000000-0000').age ).to be_nil
|
67
|
+
expect( Finnish.new('').age ).to be_nil
|
68
|
+
expect( Finnish.new(1234567890).age ).to be_nil
|
69
|
+
expect( Finnish.new(:really_bad_input_value).age ).to be_nil
|
70
|
+
end
|
49
71
|
end
|
50
72
|
|
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
|
73
|
+
describe '#to_s' do
|
59
74
|
|
75
|
+
it "repairs missing dashes, even if the number is invalid" do
|
76
|
+
expect( Finnish.new('311280999K').to_s ).to eq '311280-999K'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns the number normalized if the number is valid" do
|
80
|
+
expect( Finnish.new('311280999J').to_s ).to eq '311280-999J'
|
81
|
+
expect( Finnish.new('270368A172X ').to_s ).to eq '270368A172X'
|
82
|
+
expect( Finnish.new('xx270368A172X ').to_s ).to eq '270368A172X'
|
83
|
+
expect( Finnish.new('xxx270368A172Xt ').to_s ).to eq '270368A172X'
|
84
|
+
expect( Finnish.new('\t050126-1853').to_s ).to eq '050126-1853'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "is always injection safe, valid or not" do
|
88
|
+
expect( Finnish.new(%Q{270368"A172 \tX}).to_s ).to eq '270368A172X'
|
89
|
+
expect( Finnish.new(%Q{270368"A172\tX\n\n}).to_s ).to eq '270368A172X'
|
90
|
+
expect( Finnish.new(%Q{270368"A172X}).to_s ).to eq '270368A172X'
|
91
|
+
expect( Finnish.new(%Q{270368A<172X}).to_s ).to eq '270368A172X'
|
92
|
+
expect( Finnish.new(%Q{270368A'172X}).to_s ).to eq '270368A172X'
|
93
|
+
expect( Finnish.new(%Q{270368A>172X}).to_s ).to eq '270368A172X'
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
60
97
|
end
|
@@ -1,147 +1,183 @@
|
|
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
|
-
|
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
|
13
41
|
|
14
|
-
describe Swedish, 'valid?' do
|
15
|
-
|
16
|
-
it "should recognize valid numbers" do
|
17
|
-
Swedish.new("19180123-2669").should be_valid
|
18
|
-
Swedish.new("00180123-2669").should be_valid
|
19
|
-
Swedish.new("000180123-2669").should be_valid
|
20
|
-
Swedish.new("050126-1853").should be_valid
|
21
|
-
Swedish.new("0asdfghj501261853").should be_valid
|
22
|
-
Swedish.new("050112-2451").should be_valid
|
23
|
-
Swedish.new("450202-6950").should be_valid
|
24
|
-
Swedish.new("19450202-6950").should be_valid
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should recognize invalid numbers" do
|
28
|
-
Swedish.new("991301-1236").should_not be_valid # valid checksum, invalid month
|
29
|
-
Swedish.new("830231-5554").should_not be_valid # valid checksum, invalid day
|
30
|
-
Swedish.new("050112--2451").should_not be_valid
|
31
|
-
Swedish.new("123456-1239").should_not be_valid
|
32
|
-
Swedish.new("180123-2668").should_not be_valid
|
33
|
-
Swedish.new("150D1261853").should_not be_valid
|
34
|
-
Swedish.new("750112-2451").should_not be_valid
|
35
|
-
Swedish.new("123").should_not be_valid
|
36
|
-
Swedish.new("000000-0000").should_not be_valid
|
37
|
-
Swedish.new("0000000000").should_not be_valid
|
38
|
-
Swedish.new("asdfghj").should_not be_valid
|
39
|
-
Swedish.new("").should_not be_valid
|
40
|
-
Swedish.new(12345678).should_not be_valid
|
41
|
-
Swedish.new(:really_bad_input).should_not be_valid
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
44
|
+
describe '#age' do
|
45
|
+
|
46
|
+
before do
|
47
|
+
Timecop.freeze Date.parse('2014-01-20')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "knows the age" do
|
51
|
+
expect( Swedish.new("19180123-2669").age ).to eq 95
|
52
|
+
expect( Swedish.new("19180123-2669").age ).to eq 95
|
53
|
+
expect( Swedish.new("00180123-2669").age ).to eq 95
|
54
|
+
expect( Swedish.new("000180123-2669").age ).to eq 95
|
55
|
+
expect( Swedish.new("050126-1853").age ).to eq 8
|
56
|
+
expect( Swedish.new("0asdfghj501261853").age ).to eq 8
|
57
|
+
expect( Swedish.new("050112-2451").age ).to eq 9
|
58
|
+
expect( Swedish.new("450202-6950").age ).to eq 68
|
59
|
+
expect( Swedish.new("19450202-6950").age ).to eq 68
|
60
|
+
end
|
61
|
+
|
62
|
+
it "is nil for invalid numbers" do
|
63
|
+
expect( Swedish.new("991301-1236").age ).to be_nil
|
64
|
+
expect( Swedish.new("830231-5554").age ).to be_nil
|
65
|
+
expect( Swedish.new("050112--2451").age ).to be_nil
|
66
|
+
expect( Swedish.new("123456-1239").age ).to be_nil
|
67
|
+
expect( Swedish.new("180123-2668").age ).to be_nil
|
68
|
+
expect( Swedish.new("150D1261853").age ).to be_nil
|
69
|
+
expect( Swedish.new("750112-2451").age ).to be_nil
|
70
|
+
expect( Swedish.new("123").age ).to be_nil
|
71
|
+
expect( Swedish.new("000000-0000").age ).to be_nil
|
72
|
+
expect( Swedish.new("0000000000").age ).to be_nil
|
73
|
+
expect( Swedish.new("asdfghj").age ).to be_nil
|
74
|
+
expect( Swedish.new("").age ).to be_nil
|
75
|
+
expect( Swedish.new(12345678).age ).to be_nil
|
76
|
+
expect( Swedish.new(:really_bad_input).age ).to be_nil
|
77
|
+
end
|
54
78
|
|
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
79
|
end
|
63
80
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
end
|
103
|
-
|
104
|
-
it "should recognize people born in the year 1999" do
|
105
|
-
beginning_of_year = Swedish.new("990101-0000")
|
106
|
-
beginning_of_year.should be_valid
|
107
|
-
beginning_of_year.date.should == Date.new(1999, 1, 1)
|
108
|
-
end_of_year = Swedish.new("991231-0001")
|
109
|
-
end_of_year.should be_valid
|
110
|
-
end_of_year.date.should == Date.new(1999, 12, 31)
|
111
|
-
end
|
112
|
-
|
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
|
-
end
|
123
|
-
|
124
|
-
it "should recognize people that turn 100 years in this year" do
|
125
|
-
will_turn_100_this_year = Date.new(Date.today.year - 100, 12, 31).strftime("%y%m%d")
|
126
|
-
soon_100 = Swedish.new("#{will_turn_100_this_year}+000#{Swedish.luhn_algorithm("#{will_turn_100_this_year}000")}")
|
127
|
-
soon_100.should be_valid
|
128
|
-
soon_100.date.should == Date.new(Date.today.year - 100, 12, 31)
|
129
|
-
turned_100_this_year = Date.new(Date.today.year - 100, 1, 1).strftime("%y%m%d")
|
130
|
-
already_100 = Swedish.new("#{turned_100_this_year}+000#{Swedish.luhn_algorithm("#{turned_100_this_year}000")}")
|
131
|
-
already_100.should be_valid
|
132
|
-
already_100.date.should == Date.new(Date.today.year - 100, 1, 1)
|
133
|
-
end
|
81
|
+
describe '#to_s' do
|
82
|
+
|
83
|
+
it "repair missing dashes and a superfluous century, even if the number is invalid" do
|
84
|
+
expect( Swedish.new('1234561239').to_s ).to eq '123456-1239'
|
85
|
+
expect( Swedish.new('123456-1239').to_s ).to eq '123456-1239'
|
86
|
+
expect( Swedish.new("191234561239").to_s ).to eq '123456-1239'
|
87
|
+
expect( Swedish.new("19123456-1239").to_s ).to eq '123456-1239'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "return the number normalized if the number is valid" do
|
91
|
+
expect( Swedish.new('0501261853').to_s ).to eq '050126-1853'
|
92
|
+
expect( Swedish.new('050126-1853').to_s ).to eq '050126-1853'
|
93
|
+
expect( Swedish.new("190501261853").to_s ).to eq '050126-1853'
|
94
|
+
expect( Swedish.new("19050126-1853").to_s ).to eq '050126-1853'
|
95
|
+
expect( Swedish.new("19050126-185d3").to_s ).to eq '050126-1853'
|
96
|
+
expect( Swedish.new("19050126-185d3\n").to_s ).to eq '050126-1853'
|
97
|
+
end
|
98
|
+
|
99
|
+
it "always be injection safe, valid or not" do
|
100
|
+
expect( Swedish.new(" 180 123 - 2669 \n\n\t").to_s ).to eq '180123-2669'
|
101
|
+
expect( Swedish.new(" 180 123 - 2669 \n").to_s ).to eq '180123-2669'
|
102
|
+
expect( Swedish.new(%Q{180123-"2669}).to_s ).to eq '180123-2669'
|
103
|
+
expect( Swedish.new(%Q{180123-<2669}).to_s ).to eq '180123-2669'
|
104
|
+
expect( Swedish.new(%Q{1801D23-'2669}).to_s ).to eq '180123-2669'
|
105
|
+
expect( Swedish.new(%Q{180s123->2669}).to_s ).to eq '180123-2669'
|
106
|
+
expect( Swedish.new(%Q{19180s123->2669}).to_s ).to eq '180123-2669'
|
107
|
+
end
|
134
108
|
|
135
|
-
it "should recognize people older than 100 years born after 1900" do
|
136
|
-
normal = Swedish.new("010101+0007")
|
137
|
-
normal.should be_valid
|
138
|
-
normal.date.should == Date.new(1901, 1, 1)
|
139
109
|
end
|
140
110
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
111
|
+
describe '#date' do
|
112
|
+
|
113
|
+
it "recognizes babies born today" do
|
114
|
+
today = Date.today.strftime("%y%m%d")
|
115
|
+
born_today = Swedish.new("#{today}-000#{Swedish.luhn_algorithm("#{today}000")}")
|
116
|
+
expect( born_today ).to be_valid
|
117
|
+
expect( born_today.date).to eq Date.today
|
118
|
+
end
|
119
|
+
|
120
|
+
it "recognizes babies born yesterday" do
|
121
|
+
today = (Date.today - 1).strftime("%y%m%d")
|
122
|
+
born_yesterday = Swedish.new("#{today}-000#{Swedish.luhn_algorithm("#{today}000")}")
|
123
|
+
expect( born_yesterday ).to be_valid
|
124
|
+
expect( born_yesterday.date ).to eq (Date.today - 1)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "recognizes people born in the year 2000" do
|
128
|
+
beginning_of_year = Swedish.new("000101-0008")
|
129
|
+
expect( beginning_of_year ).to be_valid
|
130
|
+
expect( beginning_of_year.date ).to eq Date.new(2000, 1, 1)
|
131
|
+
leap_year = Swedish.new("000229-0005") # 2000 was a leap year, 1900 not
|
132
|
+
expect( leap_year ).to be_valid
|
133
|
+
expect( leap_year.date ).to eq Date.new(2000, 2, 29)
|
134
|
+
end_of_year = Swedish.new("001231-0009")
|
135
|
+
expect( end_of_year ).to be_valid
|
136
|
+
expect( end_of_year.date ).to eq Date.new(2000, 12, 31)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "recognizes people born in the year 1999" do
|
140
|
+
beginning_of_year = Swedish.new("990101-0000")
|
141
|
+
expect( beginning_of_year ).to be_valid
|
142
|
+
expect( beginning_of_year.date ).to eq Date.new(1999, 1, 1)
|
143
|
+
end_of_year = Swedish.new("991231-0001")
|
144
|
+
expect( end_of_year ).to be_valid
|
145
|
+
expect( end_of_year.date ).to eq Date.new(1999, 12, 31)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "recognizes all other people less than 100 years old" do
|
149
|
+
will_turn_99_this_year = Date.new(Date.today.year - 99, 12, 31).strftime("%y%m%d")
|
150
|
+
soon_99 = Swedish.new("#{will_turn_99_this_year}-000#{Swedish.luhn_algorithm("#{will_turn_99_this_year}000")}")
|
151
|
+
expect( soon_99 ).to be_valid
|
152
|
+
expect( soon_99.date ).to eq Date.new(Date.today.year - 99, 12, 31)
|
153
|
+
turned_99_this_year = Date.new(Date.today.year - 99, 1, 1).strftime("%y%m%d")
|
154
|
+
already_99 = Swedish.new("#{turned_99_this_year}-000#{Swedish.luhn_algorithm("#{turned_99_this_year}000")}")
|
155
|
+
expect( already_99 ).to be_valid
|
156
|
+
expect( already_99.date ).to eq Date.new(Date.today.year - 99, 1, 1)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "recognizes people that turn 100 years in this year" do
|
160
|
+
will_turn_100_this_year = Date.new(Date.today.year - 100, 12, 31).strftime("%y%m%d")
|
161
|
+
soon_100 = Swedish.new("#{will_turn_100_this_year}+000#{Swedish.luhn_algorithm("#{will_turn_100_this_year}000")}")
|
162
|
+
expect( soon_100 ).to be_valid
|
163
|
+
expect( soon_100.date ).to eq Date.new(Date.today.year - 100, 12, 31)
|
164
|
+
turned_100_this_year = Date.new(Date.today.year - 100, 1, 1).strftime("%y%m%d")
|
165
|
+
already_100 = Swedish.new("#{turned_100_this_year}+000#{Swedish.luhn_algorithm("#{turned_100_this_year}000")}")
|
166
|
+
expect( already_100 ).to be_valid
|
167
|
+
expect( already_100.date ).to eq Date.new(Date.today.year - 100, 1, 1)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "recognizes people older than 100 years born after 1900" do
|
171
|
+
normal = Swedish.new("010101+0007")
|
172
|
+
expect( normal ).to be_valid
|
173
|
+
expect( normal.date ).to eq Date.new(1901, 1, 1)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "recognizes people older than 100 years born before 1900" do
|
177
|
+
normal = Swedish.new("991231+0001")
|
178
|
+
expect( normal ).to be_valid
|
179
|
+
expect( normal.date ).to eq Date.new(1899, 12, 31)
|
180
|
+
end
|
145
181
|
end
|
146
182
|
|
147
183
|
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,111 @@
|
|
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.10
|
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: 2014-06-24 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
|
21
|
+
prerelease: false
|
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: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
23
35
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rb-fsevent
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
27
45
|
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
33
48
|
type: :development
|
34
|
-
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: timecop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
35
69
|
description:
|
36
70
|
email:
|
37
71
|
executables: []
|
38
|
-
|
39
72
|
extensions: []
|
40
|
-
|
41
|
-
|
42
|
-
- README.rdoc
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
43
75
|
- MIT-LICENSE
|
44
|
-
|
76
|
+
- README.md
|
77
|
+
- lib/national_identification_number.rb
|
45
78
|
- lib/national_identification_number/base.rb
|
46
79
|
- lib/national_identification_number/finnish.rb
|
47
80
|
- lib/national_identification_number/swedish.rb
|
48
|
-
- lib/national_identification_number.rb
|
49
81
|
- lib/resident.rb
|
50
|
-
- MIT-LICENSE
|
51
|
-
- README.rdoc
|
52
|
-
- .gemtest
|
53
82
|
- spec/national_identification_number/base_spec.rb
|
54
83
|
- spec/national_identification_number/finnish_spec.rb
|
55
84
|
- spec/national_identification_number/swedish_spec.rb
|
56
|
-
|
85
|
+
- spec/spec_helper.rb
|
57
86
|
homepage: http://github.com/bukowskis/national_identification_number/
|
58
|
-
licenses:
|
87
|
+
licenses:
|
59
88
|
- MIT-LICENSE
|
89
|
+
metadata: {}
|
60
90
|
post_install_message:
|
61
|
-
rdoc_options:
|
62
|
-
|
63
|
-
- README.rdoc
|
64
|
-
- --charset=UTF-8
|
65
|
-
require_paths:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
66
93
|
- lib
|
67
94
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
-
|
70
|
-
requirements:
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
71
97
|
- - ">="
|
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:
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 1.9.3
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
82
102
|
- - ">="
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
|
85
|
-
segments:
|
86
|
-
- 0
|
87
|
-
version: "0"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
88
105
|
requirements: []
|
89
|
-
|
90
106
|
rubyforge_project:
|
91
|
-
rubygems_version:
|
107
|
+
rubygems_version: 2.2.2
|
92
108
|
signing_key:
|
93
|
-
specification_version:
|
109
|
+
specification_version: 4
|
94
110
|
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
|
111
|
+
test_files: []
|
data/.gemtest
DELETED
File without changes
|