birth_number 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +17 -0
- data/.gitignore +98 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/birth_number.gemspec +27 -0
- data/lib/birth_number.rb +173 -0
- data/lib/birth_number/version.rb +3 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aeaf0cc44d89627a61cf069d580984f3d82dc5c0
|
4
|
+
data.tar.gz: c448b9b77fed4cb920c4dd6d5e46c8394150a4b5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 681388466a5d1cc1e9f9b4e3476d8261600323dad0d2f7e211aebe5a5538bc4fd6d24ea475853c8906811af8c94280fbf32ad77358fe1b3c8d89629112ab924e
|
7
|
+
data.tar.gz: 36cd6e53cb0598226b84cecd5e8d1e7dceb084cfd05fd89659336546038cfa524bcb89e1a478fcfa96c8e13358bfea834e2abd9245c6b28e9bf3cd8909c4f75f
|
data/.editorconfig
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# EditorConfig is awesome: http://EditorConfig.org
|
2
|
+
|
3
|
+
# top-most EditorConfig file
|
4
|
+
root = true
|
5
|
+
|
6
|
+
# Unix-style newlines with a newline ending every file
|
7
|
+
[*]
|
8
|
+
charset = utf-8
|
9
|
+
end_of_line = lf
|
10
|
+
indent_size = 2
|
11
|
+
indent_style = space
|
12
|
+
insert_final_newline = true
|
13
|
+
trim_trailing_whitespace = true
|
14
|
+
|
15
|
+
# Markdown uses trailing whitespace for linebreaks.
|
16
|
+
[{*.markdown, *.md}]
|
17
|
+
trim_trailing_whitespace = false
|
data/.gitignore
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
### Ruby template
|
2
|
+
*.gem
|
3
|
+
*.rbc
|
4
|
+
/.config
|
5
|
+
/coverage/
|
6
|
+
/InstalledFiles
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalisation:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
# Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
37
|
+
|
38
|
+
|
39
|
+
### Linux template
|
40
|
+
*~
|
41
|
+
|
42
|
+
# KDE directory preferences
|
43
|
+
.directory
|
44
|
+
|
45
|
+
# Linux trash folder which might appear on any partition or disk
|
46
|
+
.Trash-*
|
47
|
+
|
48
|
+
|
49
|
+
### JetBrains template
|
50
|
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion
|
51
|
+
|
52
|
+
*.iml
|
53
|
+
|
54
|
+
## Directory-based project format:
|
55
|
+
.idea/
|
56
|
+
# if you remove the above rule, at least ignore the following:
|
57
|
+
|
58
|
+
# User-specific stuff:
|
59
|
+
# .idea/workspace.xml
|
60
|
+
# .idea/tasks.xml
|
61
|
+
# .idea/dictionaries
|
62
|
+
|
63
|
+
# Sensitive or high-churn files:
|
64
|
+
# .idea/dataSources.ids
|
65
|
+
# .idea/dataSources.xml
|
66
|
+
# .idea/sqlDataSources.xml
|
67
|
+
# .idea/dynamic.xml
|
68
|
+
# .idea/uiDesigner.xml
|
69
|
+
|
70
|
+
# Gradle:
|
71
|
+
# .idea/gradle.xml
|
72
|
+
# .idea/libraries
|
73
|
+
|
74
|
+
# Mongo Explorer plugin:
|
75
|
+
# .idea/mongoSettings.xml
|
76
|
+
|
77
|
+
## File-based project format:
|
78
|
+
*.ipr
|
79
|
+
*.iws
|
80
|
+
|
81
|
+
## Plugin-specific files:
|
82
|
+
|
83
|
+
# IntelliJ
|
84
|
+
/out/
|
85
|
+
|
86
|
+
# mpeltonen/sbt-idea plugin
|
87
|
+
.idea_modules/
|
88
|
+
|
89
|
+
# JIRA plugin
|
90
|
+
atlassian-ide-plugin.xml
|
91
|
+
|
92
|
+
# Crashlytics plugin (for Android Studio and IntelliJ)
|
93
|
+
com_crashlytics_export_strings.xml
|
94
|
+
crashlytics.properties
|
95
|
+
crashlytics-build.properties
|
96
|
+
|
97
|
+
|
98
|
+
.gitver
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Sonans Privatgymnas AS
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# BirthNumber
|
2
|
+
|
3
|
+
This is a simple Ruby gem for parsing and validating Birth Numbers, the national identification number used in Norway. It has been extracted from one of our internal projects for reuse, and released as open-source as it might be useful for others as well.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'birth_number'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install birth_number
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```rb
|
24
|
+
birth_number = BirthNumber.parse('01017000027')
|
25
|
+
birth_number.birth_date #=> #<Date: 1970-01-01 ((2440588j,0s,0n),+0s,2299161j)>
|
26
|
+
birth_number.personal_number # => "00027
|
27
|
+
birth_number.to_s #=> "01017000027"
|
28
|
+
|
29
|
+
birth_number = BirthNumber.new('1970-01-01', '00027')
|
30
|
+
birth_number.to_s #=> "01017000027"
|
31
|
+
|
32
|
+
birth_number.valid? #=> true
|
33
|
+
birth_number.male? #=> false
|
34
|
+
birth_number.female? #=> true
|
35
|
+
|
36
|
+
birth_number.to_s #=> "01017000027"
|
37
|
+
|
38
|
+
birth_number == '01017000027' #=> false
|
39
|
+
birth_number === '01017000027' #=> true
|
40
|
+
```
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Sonans/birth_number.
|
45
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'birth_number/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'birth_number'
|
8
|
+
spec.version = BirthNumber::VERSION
|
9
|
+
spec.authors = ['Jo-Herman Haugholt']
|
10
|
+
spec.email = ['jo-herman@sonans.no']
|
11
|
+
|
12
|
+
spec.summary = 'Gem for parsing and validating Norwegian Birth Numbers'
|
13
|
+
spec.description = <<END
|
14
|
+
This is a simple Ruby gem for parsing and validating Birth Numbers,
|
15
|
+
the national identification number used in Norway. It has been extracted from
|
16
|
+
one of our internal projects for reuse, and released as open-source as it might
|
17
|
+
be useful for others as well.
|
18
|
+
END
|
19
|
+
spec.homepage = 'https://github.com/Sonans/birth_number'
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
27
|
+
end
|
data/lib/birth_number.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'birth_number/version'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
# Class representing a Norwegian "Birth Number" ("Fødselsnummer").
|
5
|
+
#
|
6
|
+
# A birth number is a national identificaion number used in Norway,
|
7
|
+
# is unique for each person, and encodes birth date as well as gender.
|
8
|
+
# The last two digits are used as a checksum to verify a valid
|
9
|
+
# birth number.
|
10
|
+
#
|
11
|
+
# This implementation is based of the description on the Norwegian
|
12
|
+
# Wikipedia page.
|
13
|
+
#
|
14
|
+
# @see https://en.wikipedia.org/wiki/National_identification_number#Norway
|
15
|
+
# Birth Number on Wikipedia
|
16
|
+
# @see https://no.wikipedia.org/wiki/Fødselsnummer
|
17
|
+
# Fødselsnummer on Norwegian Wikipedia
|
18
|
+
#
|
19
|
+
# @author Jo-Herman Haugholt <jo-herman@sonans.no>
|
20
|
+
class BirthNumber
|
21
|
+
# Birth Date
|
22
|
+
# @return [Date]
|
23
|
+
attr_accessor :birth_date
|
24
|
+
|
25
|
+
# Personal Number
|
26
|
+
# @return [String]
|
27
|
+
attr_accessor :personal_number
|
28
|
+
|
29
|
+
# Parse a 11-digit Birth Number
|
30
|
+
#
|
31
|
+
# @param [#to_s] birth_number
|
32
|
+
# @return [BirthNumber]
|
33
|
+
# @raise [ArgumentError] if passed string is not 11 digits or invalid date
|
34
|
+
def self.parse(birth_number)
|
35
|
+
birth_number = birth_number.to_s
|
36
|
+
unless birth_number =~ /^\d{11}$/
|
37
|
+
fail ArgumentError, 'Birth number must be 11 digits'
|
38
|
+
end
|
39
|
+
|
40
|
+
birth_date = parse_birth_date(birth_number)
|
41
|
+
|
42
|
+
new(birth_date, birth_number[6, 5])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check if a given birth number is valid
|
46
|
+
# @param [#to_s] birth_number
|
47
|
+
def self.valid?(birth_number)
|
48
|
+
digits = birth_number.to_s.chars.map(&:to_i)
|
49
|
+
|
50
|
+
digits.last(2) == control_digits(digits)
|
51
|
+
|
52
|
+
rescue ArgumentError
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param [#to_date,#to_s] birth_date
|
57
|
+
# @param [#to_i] personal_number
|
58
|
+
def initialize(birth_date, personal_number)
|
59
|
+
if birth_date.respond_to? :to_date
|
60
|
+
self.birth_date = birth_date.to_date
|
61
|
+
else
|
62
|
+
self.birth_date = Date.parse(birth_date.to_s)
|
63
|
+
end
|
64
|
+
|
65
|
+
self.personal_number = format('%05d', personal_number.to_i)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check if this birth number is valid
|
69
|
+
def valid?
|
70
|
+
BirthNumber.valid?(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Is this birth number assigned to a man
|
74
|
+
def male?
|
75
|
+
personal_number[2].to_i.odd?
|
76
|
+
end
|
77
|
+
|
78
|
+
# Is this birth number assigned to a woman
|
79
|
+
def female?
|
80
|
+
personal_number[2].to_i.even?
|
81
|
+
end
|
82
|
+
|
83
|
+
# Formats this birthnumber in the proper 11-digit form
|
84
|
+
# @return [String]
|
85
|
+
def to_s
|
86
|
+
birth_date.strftime('%d%m%y') + format('%05d', personal_number.to_i)
|
87
|
+
end
|
88
|
+
|
89
|
+
def ==(other)
|
90
|
+
unless other.respond_to?(:birth_date) && other.respond_to?(:personal_number)
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
|
94
|
+
birth_date == other.birth_date && personal_number == other.personal_number
|
95
|
+
end
|
96
|
+
|
97
|
+
def ===(other)
|
98
|
+
to_s == other.to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
def eql?(other)
|
102
|
+
self == other
|
103
|
+
end
|
104
|
+
|
105
|
+
def hash
|
106
|
+
to_s.hash
|
107
|
+
end
|
108
|
+
|
109
|
+
# @!group Private Class Methods
|
110
|
+
BIRTH_NUMBER_REGEX = /^([0-2][0-9]|3[0-1])(0[1-9]|1[0-2])(\d{7})$/
|
111
|
+
BIRTH_NUMBER_WEIGHTS_1 = [3, 7, 6, 1, 8, 9, 4, 5, 2]
|
112
|
+
BIRTH_NUMBER_WEIGHTS_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
|
113
|
+
|
114
|
+
# Parses the date part of a birth number
|
115
|
+
# @param [String] birth_number
|
116
|
+
# @return [Date]
|
117
|
+
def self.parse_birth_date(birth_number)
|
118
|
+
day, month, year = birth_number.chars.take(6)
|
119
|
+
.each_slice(2).map(&:join).map(&:to_i)
|
120
|
+
individual_numbers = birth_number[6, 3].to_i
|
121
|
+
|
122
|
+
year += parse_century(year, individual_numbers)
|
123
|
+
|
124
|
+
Date.new(year, month, day)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Calculates the century of a year based on the individual numbers
|
128
|
+
# @param [Integer] year
|
129
|
+
# @param [Integer] individual_numbers
|
130
|
+
# @return [Integer]
|
131
|
+
def self.parse_century(year, individual_numbers)
|
132
|
+
case
|
133
|
+
when individual_numbers < 500 || (individual_numbers >= 900 && year >= 40)
|
134
|
+
1900
|
135
|
+
when individual_numbers < 750 && year >= 54
|
136
|
+
1800
|
137
|
+
else
|
138
|
+
2000
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Calculates the two control digits given an array of digits
|
143
|
+
# @param [Array<Integer>] digits
|
144
|
+
# @return [(Integer, Integer)]
|
145
|
+
def self.control_digits(digits)
|
146
|
+
[
|
147
|
+
control_digit(digits.take(9), BIRTH_NUMBER_WEIGHTS_1),
|
148
|
+
control_digit(digits.take(10), BIRTH_NUMBER_WEIGHTS_2)
|
149
|
+
]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Calculates the control digit, given an array of digits and weights.
|
153
|
+
# @param [Array<Integer>] digits
|
154
|
+
# @param [Array<Integer>] weights
|
155
|
+
# @return [Integer]
|
156
|
+
def self.control_digit(digits, weights)
|
157
|
+
control_digit = digits
|
158
|
+
.zip(weights)
|
159
|
+
.map { |digit, weight| digit * weight }
|
160
|
+
.reduce(:+)
|
161
|
+
control_digit = 11 - (control_digit % 11)
|
162
|
+
control_digit = 0 if control_digit == 11
|
163
|
+
control_digit
|
164
|
+
end
|
165
|
+
|
166
|
+
private_constant :BIRTH_NUMBER_REGEX,
|
167
|
+
:BIRTH_NUMBER_WEIGHTS_1,
|
168
|
+
:BIRTH_NUMBER_WEIGHTS_2
|
169
|
+
private_class_method :parse_birth_date,
|
170
|
+
:parse_century,
|
171
|
+
:control_digits,
|
172
|
+
:control_digit
|
173
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: birth_number
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jo-Herman Haugholt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.3'
|
55
|
+
description: |
|
56
|
+
This is a simple Ruby gem for parsing and validating Birth Numbers,
|
57
|
+
the national identification number used in Norway. It has been extracted from
|
58
|
+
one of our internal projects for reuse, and released as open-source as it might
|
59
|
+
be useful for others as well.
|
60
|
+
email:
|
61
|
+
- jo-herman@sonans.no
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- ".editorconfig"
|
67
|
+
- ".gitignore"
|
68
|
+
- ".rspec"
|
69
|
+
- Gemfile
|
70
|
+
- LICENSE
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- birth_number.gemspec
|
74
|
+
- lib/birth_number.rb
|
75
|
+
- lib/birth_number/version.rb
|
76
|
+
homepage: https://github.com/Sonans/birth_number
|
77
|
+
licenses: []
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.4.5
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Gem for parsing and validating Norwegian Birth Numbers
|
99
|
+
test_files: []
|
100
|
+
has_rdoc:
|