resident 0.0.11 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f353c0782a96c1d79d67c61cb7d29d7508ad45bb
4
- data.tar.gz: adfc48cdb9ca18ab426aff09572f8d5a1d4903cf
2
+ SHA256:
3
+ metadata.gz: f46bb28b43ee9e5b885a50fdad775f2730dfaf059d238bf78f2e4f687f015440
4
+ data.tar.gz: 3daabe1d914221094e18cc29032ffd365c3ce497150a3c92c2f9293255772214
5
5
  SHA512:
6
- metadata.gz: 87117786abbf0a70b38ec3a654fcf133fae1fbdac1c3e8c1b3b957bf037a8abec7b049225627d6d6233f0dcbe91ad6802b7c42eb225b492322a9030f0dcaedce
7
- data.tar.gz: 11458275db57866d20915a61cf480ca50ec7b3922f787f5bc2dd2cfe0bf70857dabd253b87500af7d13796e95393dabcaa4a6f20c7e7d37a6bef2cf66d65d2b3
6
+ metadata.gz: c7156a5215a04bf80888f46a88b9d84979dc45097c8480184e58aed0c1b2d6548dbe31dd3e4e018be71e3a0f73e65b30c4601ae2791e96c7e1456c64fd2ba24c
7
+ data.tar.gz: 5e3b40279eabe8e69113a8767985e281adc2f7d8d30ffd48e887d8c3d7e4f80072c3fc66ed96825c325e1720b64ed3c47de9af3548cea14dbe37414b62e8cde4
data/README.md CHANGED
@@ -2,9 +2,13 @@
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
- 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).
6
+ This gem currently only supports Swedish (Personnummer), Finnish
7
+ (Henkilöasiakkaat), Norwegian (Fødelsenummer) and Danish (CPR).
8
+
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).
8
12
 
9
13
  ## Installation
10
14
 
@@ -38,7 +42,7 @@ Some marked parts of the code are inspired or taken from MIT licensed code of
38
42
 
39
43
  Other than that you got:
40
44
 
41
- Copyright (c) 2011-2014 Bukowskis.
45
+ Copyright (c) 2011-2022 Bukowskis.
42
46
 
43
47
  Permission is hereby granted, free of charge, to any person obtaining a copy
44
48
  of this software and associated documentation files (the "Software"), to deal
@@ -41,6 +41,5 @@ module NationalIdentificationNumber
41
41
  def validate
42
42
  raise 'You need to implement at least this method in subclasses.'
43
43
  end
44
-
45
44
  end
46
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
@@ -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
@@ -1,2 +1,4 @@
1
1
  require 'national_identification_number/swedish'
2
2
  require 'national_identification_number/finnish'
3
+ require 'national_identification_number/norwegian'
4
+ require 'national_identification_number/danish'
@@ -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
@@ -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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resident
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bukowskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-16 00:00:00.000000000 Z
11
+ date: 2022-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,34 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
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
35
- prerelease: false
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:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: timecop
57
29
  requirement: !ruby/object:Gem::Requirement
@@ -76,11 +48,15 @@ files:
76
48
  - README.md
77
49
  - lib/national_identification_number.rb
78
50
  - lib/national_identification_number/base.rb
51
+ - lib/national_identification_number/danish.rb
79
52
  - lib/national_identification_number/finnish.rb
53
+ - lib/national_identification_number/norwegian.rb
80
54
  - lib/national_identification_number/swedish.rb
81
55
  - lib/resident.rb
82
56
  - spec/national_identification_number/base_spec.rb
57
+ - spec/national_identification_number/danish_spec.rb
83
58
  - spec/national_identification_number/finnish_spec.rb
59
+ - spec/national_identification_number/norwegian_spec.rb
84
60
  - spec/national_identification_number/swedish_spec.rb
85
61
  - spec/spec_helper.rb
86
62
  homepage: http://github.com/bukowskis/national_identification_number/
@@ -103,8 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
79
  - !ruby/object:Gem::Version
104
80
  version: '0'
105
81
  requirements: []
106
- rubyforge_project:
107
- rubygems_version: 2.5.1
82
+ rubygems_version: 3.0.3.1
108
83
  signing_key:
109
84
  specification_version: 4
110
85
  summary: Validate National Identification Numbers.