citizenship 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/.gitignore +19 -0
- data/.travis.yml +11 -0
- data/CHANGELOG +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/Rakefile +34 -0
- data/citizenship.gemspec +30 -0
- data/lib/citizenship.rb +41 -0
- data/lib/citizenship/citizen_card.rb +36 -0
- data/lib/citizenship/email.rb +15 -0
- data/lib/citizenship/errors.rb +52 -0
- data/lib/citizenship/identification_card.rb +17 -0
- data/lib/citizenship/nib.rb +49 -0
- data/lib/citizenship/nif.rb +20 -0
- data/lib/citizenship/phone.rb +27 -0
- data/lib/citizenship/rails/validators.rb +47 -0
- data/lib/citizenship/version.rb +3 -0
- data/lib/citizenship/zip_code.rb +14 -0
- data/lib/locales/en.yml +24 -0
- data/lib/locales/pt-PT.yml +22 -0
- data/lib/locales/pt.yml +22 -0
- data/spec/citizenship/citizen_card_spec.rb +16 -0
- data/spec/citizenship/email_spec.rb +12 -0
- data/spec/citizenship/identification_card_spec.rb +19 -0
- data/spec/citizenship/nib_spec.rb +27 -0
- data/spec/citizenship/nif_spec.rb +21 -0
- data/spec/citizenship/phone_spec.rb +59 -0
- data/spec/citizenship/zip_code_spec.rb +13 -0
- data/spec/helper.rb +9 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e3144972c896bbb5b398689419c22a0a2b1a851
|
4
|
+
data.tar.gz: 5e104377c0d24d3df7eb08f0e9e6cf76f1cdaa61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1256fe4db0f000a8620cebbc32a2e7055b01e0c59ce3d1c51f361f2ff3eb67dbe900d0488ffc325dce56ae736db7e079894b51814bac5c2e345570e0328cca0
|
7
|
+
data.tar.gz: 33887abb5376484c9edeba657c8b5bc635ad1d067f3ed6ff7414bf397b939cd660439abf81062b04037483dd37105000bf0608ef0615473b3afe663eaabcb3aa
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Miguel Guinada
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Citizenship
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/citizen.svg)](http://badge.fury.io/rb/citizen)
|
4
|
+
[![Build Status](https://travis-ci.org/runtimerevolution/citizenship.svg?branch=master)](https://travis-ci.org/runtimerevolution/citizenship)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/runtimerevolution/citizenship/badges/gpa.svg)](https://codeclimate.com/github/runtimerevolution/citizenship)
|
6
|
+
[![Dependency Status](https://gemnasium.com/runtimerevolution/citizenship.svg)](https://gemnasium.com/runtimerevolution/citizenship)
|
7
|
+
|
8
|
+
Citizenship provides a set of easy validations on personal documents, addresses, bank account numbers and other personal information, of Portuguese citizens or of citizens living in Portugal ;)
|
9
|
+
|
10
|
+
It supports validation of:
|
11
|
+
|
12
|
+
- NIB (i.e. "banking account number")
|
13
|
+
- NIF (i.e. "fiscal number")
|
14
|
+
- local phone numbers
|
15
|
+
- identification card ('bilhetes de identidade'), were the old id Portuguese id documents. They are no longer issue, but many haven't yet expired, so are still used alongside the Citizen Card.
|
16
|
+
- citizen card ('cartão do cidadão'), are the new ID cards currently in use
|
17
|
+
- zip code (partial validation)
|
18
|
+
- e-mail (well, just because :) )
|
19
|
+
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your Rails application's Gemfile:
|
24
|
+
|
25
|
+
gem 'citizenship'
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install citizenship
|
34
|
+
|
35
|
+
and use it standalone.
|
36
|
+
|
37
|
+
## Validations
|
38
|
+
|
39
|
+
### NIB
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
result=Citizenship.valid_nib?("003503730000539151280") # returns true
|
43
|
+
result=Citizenship.valid_nib?('0035.03730000539.1512.80') # returns true
|
44
|
+
result=Citizenship.valid_nib?('38476129847') # returns false (since it fails proper size and CRC)
|
45
|
+
result=Citizenship.valid_nib?('0035.03730000539.1512.80', strict: true) # returns false
|
46
|
+
Citizenship.valid_nib!(nib) # raises Citizenship::Error if invalid
|
47
|
+
```
|
48
|
+
|
49
|
+
### NIF
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
result=Citizenship.valid_nif?("123456789") # returns true
|
53
|
+
Citizenship.valid_nif!(nif) # raises Citizenship::Error if invalid
|
54
|
+
nif=Citizenship.valid_nif!("123456789") # returns "123456789"
|
55
|
+
result=Citizenship.valid_nif?(' 123456789', strict: true) # returns false (strict validation disallows whitespaces and others)
|
56
|
+
```
|
57
|
+
|
58
|
+
### Phone Number
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
phone=Citizenship.valid_phone!('+351 96 933 2233', only_prefixes: ['93', '96']) # returns "+351 96 933 2233"
|
62
|
+
phone=Citizenship.valid_phone!('262-999-666') # returns "262-999-666"
|
63
|
+
result=Citizenship.valid_phone?('262999666', strict: true) # returns true
|
64
|
+
result=Citizenship.valid_phone?('+351 93 933 2233', allow_country_prefix: false) # returns false (since country prefix was used)
|
65
|
+
phone=Citizenship.valid_phone!('+351 93 933 2233') # returns "+351 93 933 2233"
|
66
|
+
```
|
67
|
+
|
68
|
+
### Identification Card
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
result=Citizenship.valid_identification_card?('156 944 80', '4') # returns true
|
72
|
+
id=Citizenship.valid_identification_card!('156 944 8', '8') # returns '156 944 8'
|
73
|
+
```
|
74
|
+
|
75
|
+
### Citizen Card
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
result=Citizenship.valid_citizen_card?('00000000 0 ZZ 4') # returns true
|
79
|
+
id=Citizenship.valid_citizen_card('00000000-0-ZZ-4') # returns '00000000-0-ZZ-4'
|
80
|
+
```
|
81
|
+
|
82
|
+
### Zip Code
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
result=Citizenship.valid_zip_code?('1000-100') # returns true
|
86
|
+
```
|
87
|
+
|
88
|
+
### E-mail
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
result=Citizenship.valid_email?("user@example.org") # returns true
|
92
|
+
result=Citizenship.valid_email?(" user@example.org ") # returns false (due to whitespaces)
|
93
|
+
result=Citizenship.valid_email?("@example.org") # returns false (due to missing user)
|
94
|
+
```
|
95
|
+
|
96
|
+
## Rails Validators
|
97
|
+
|
98
|
+
We provide a useful range of Rails validators that you can include in your models, namely:
|
99
|
+
|
100
|
+
* NifValidator
|
101
|
+
* NibValidator
|
102
|
+
* PhoneValidator
|
103
|
+
* EmailValidator
|
104
|
+
* ZipCodeValidor
|
105
|
+
|
106
|
+
### Example
|
107
|
+
|
108
|
+
|
109
|
+
class User < ActiveRecord::Base
|
110
|
+
validates :fiscal_number, nif: true
|
111
|
+
...
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
## Future Developments
|
116
|
+
|
117
|
+
* Support full zip code validation
|
118
|
+
* Support IBAN
|
119
|
+
* Support validating documents for other EU countries
|
120
|
+
|
121
|
+
## References
|
122
|
+
|
123
|
+
* [NIB](http://pt.wikipedia.org/wiki/N%C3%BAmero_de_Identifica%C3%A7%C3%A3o_Banc%C3%A1ria)
|
124
|
+
* [NIF](http://pt.wikipedia.org/wiki/N%C3%BAmero_de_identifica%C3%A7%C3%A3o_fiscal)
|
125
|
+
* [Citizen Card](http://www.cartaodecidadao.pt/images/stories/Algoritmo_Num_Documento_CC.pdf)
|
126
|
+
* [(old) Identification Card](http://geramat.blogs.sapo.pt/13528.html)
|
127
|
+
* [ZIP codes](http://pt.wikipedia.org/wiki/N%C3%BAmero_de_Identifica%C3%A7%C3%A3o_Banc%C3%A1ria)
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
## Contributing
|
132
|
+
|
133
|
+
1. Fork it
|
134
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
135
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
136
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
137
|
+
5. Create new Pull Request
|
138
|
+
|
139
|
+
## License
|
140
|
+
Copyright © 2015 [Runtime Revolution](http://www.runtime-revolution.com), released under the MIT license.
|
141
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'simplecov'
|
7
|
+
|
8
|
+
task :test => :spec
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new do |task|
|
12
|
+
task.rspec_opts = ["-c", "-f documentation", "-r ./spec/helper.rb"]
|
13
|
+
task.pattern = 'spec/**/*_spec.rb'
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Open an interactive session preloaded with this gem's code"
|
17
|
+
task :console do
|
18
|
+
if gem_available?("pry")
|
19
|
+
sh "pry -I lib -r citizenship.rb"
|
20
|
+
else
|
21
|
+
sh "irb -rubygems -I lib -r citizenship.rb"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Determins if a gem is available at the current runtime
|
27
|
+
#
|
28
|
+
def gem_available?(name)
|
29
|
+
Gem::Specification.find_by_name(name)
|
30
|
+
rescue Gem::LoadError
|
31
|
+
false
|
32
|
+
rescue
|
33
|
+
Gem.available?(name) #for backwards compatibility
|
34
|
+
end
|
data/citizenship.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'citizenship/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "citizenship"
|
8
|
+
gem.version = Citizenship::VERSION
|
9
|
+
gem.platform = Gem::Platform::RUBY
|
10
|
+
gem.authors = ["Runtime Revolution"]
|
11
|
+
gem.description = %q{citizenship checks validity of civil id numbers and similar used in Portugal}
|
12
|
+
gem.summary = %q{citizenship checks validity of civil id numbers and similar used in Portugal}
|
13
|
+
gem.homepage = "https://github.com/runtimerevolution/citizenship"
|
14
|
+
gem.email = 'info@runtime-revolution.com'
|
15
|
+
gem.license = "MIT"
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($/)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
|
22
|
+
gem.add_dependency 'i18n', ['>= 0.6.4', '<= 0.7.0']
|
23
|
+
|
24
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
gem.add_development_dependency "rake"
|
26
|
+
gem.add_development_dependency "rspec", "~> 3.2.0"
|
27
|
+
|
28
|
+
gem.add_development_dependency 'simplecov'
|
29
|
+
gem.add_development_dependency 'pry'
|
30
|
+
end
|
data/lib/citizenship.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'citizenship/version'
|
2
|
+
require 'citizenship/errors'
|
3
|
+
require 'citizenship/nif'
|
4
|
+
require 'citizenship/nib'
|
5
|
+
require 'citizenship/citizen_card'
|
6
|
+
require 'citizenship/identification_card'
|
7
|
+
require 'citizenship/phone'
|
8
|
+
require 'citizenship/email'
|
9
|
+
require 'citizenship/zip_code'
|
10
|
+
require 'citizenship/rails/validators' if defined?(ActiveModel)
|
11
|
+
|
12
|
+
module Citizenship
|
13
|
+
private
|
14
|
+
#Decimal check bit common processing
|
15
|
+
def self.decimal_check_digit(number, cover_digit_collision_flaw = true)
|
16
|
+
number = String(number)
|
17
|
+
|
18
|
+
multiplier = 1
|
19
|
+
result = number.delete(' ').split('').map(&:to_i).reverse.map do |digit|
|
20
|
+
digit * (multiplier += 1)
|
21
|
+
end.reduce(:+) || 0
|
22
|
+
|
23
|
+
#Cover for the digit collision flaw?
|
24
|
+
return 0 if (control_number = 11 - result % 11) > 9 and cover_digit_collision_flaw
|
25
|
+
control_number
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.decimal_check_digit_match?(number, check_digit, cover_digit_collision_flaw = true)
|
29
|
+
decimal_check_digit(number, cover_digit_collision_flaw) == check_digit.to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.is_number?(i)
|
33
|
+
true if Float(i) rescue false
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.remove_special_chars(str)
|
37
|
+
String(str).delete(' ').delete('-').delete('.')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
I18n.load_path += Dir.glob( File.join(File.dirname(__FILE__), 'locales'.freeze, '*.yml'.freeze) )
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Citizenship
|
2
|
+
#http://www.cartaodecidadao.pt/images/stories/Algoritmo_Num_Documento_CC.pdf
|
3
|
+
def self.valid_citizen_card!(number)
|
4
|
+
id_number = remove_special_chars(number)
|
5
|
+
|
6
|
+
raise CitizenCardError, :size if id_number.size != 12
|
7
|
+
|
8
|
+
double_digit = false
|
9
|
+
conversion_table = ('a'..'z').to_a
|
10
|
+
check_digit = id_number.reverse.split('').map do |element|
|
11
|
+
#switch letters for the value in the conversion table (see 2.3. on Algoritmo_Num_Documento_CC.pdf)
|
12
|
+
is_number?(element) ? element : conversion_table.find_index(element.downcase) + 10
|
13
|
+
end.map(&:to_i).map do |digit|
|
14
|
+
begin
|
15
|
+
if double_digit #starting on the 2nd value double every value steping by 2
|
16
|
+
value = digit * 2
|
17
|
+
value >= 10 ? value - 9 : value #If the doubling result is 10 or more, subtract 9
|
18
|
+
else
|
19
|
+
digit
|
20
|
+
end
|
21
|
+
ensure
|
22
|
+
double_digit = not(double_digit)
|
23
|
+
end
|
24
|
+
end.reduce(:+) #sum everything
|
25
|
+
|
26
|
+
raise CitizenCardError, :invalid_check_digit if check_digit % 10 != 0
|
27
|
+
number
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.valid_citizen_card?(number)
|
31
|
+
valid_citizen_card!(number)
|
32
|
+
true
|
33
|
+
rescue CitizenCardError
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Citizenship
|
2
|
+
EMAIL_REGEXP = /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/i
|
3
|
+
|
4
|
+
def self.valid_email!(email)
|
5
|
+
raise EmailError, :invalid_email unless email.match(EMAIL_REGEXP)
|
6
|
+
email
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.valid_email?(email)
|
10
|
+
valid_email!(email)
|
11
|
+
true
|
12
|
+
rescue EmailError
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'i18n'
|
3
|
+
|
4
|
+
module Citizenship
|
5
|
+
class Error < StandardError
|
6
|
+
def initialize(key, values = {}, scope)
|
7
|
+
super(I18n.t(key, values.merge(scope: "citizenship.#{scope}")))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NIFError < Error
|
12
|
+
def initialize(key, values = {})
|
13
|
+
super(key, values, :nif)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NIBError < Error
|
18
|
+
def initialize(key, values = {})
|
19
|
+
super(key, values, :nib)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class CitizenCardError < Error
|
24
|
+
def initialize(key, values = {})
|
25
|
+
super(key, values, :citizen_card)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class IdentificationCardError < Error
|
30
|
+
def initialize(key, values = {})
|
31
|
+
super(key, values, :identification_card)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class PhoneError < Error
|
36
|
+
def initialize(key, values = {})
|
37
|
+
super(key, values, :phone)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class EmailError < Error
|
42
|
+
def initialize(key, values = {})
|
43
|
+
super(key, values, :email)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ZipCodeError < Error
|
48
|
+
def initialize(key, values = {})
|
49
|
+
super(key, values, :zip_code)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#see: http://geramat.blogs.sapo.pt/13528.html
|
2
|
+
module Citizenship
|
3
|
+
def self.valid_identification_card!(number, check_digit)
|
4
|
+
id_number, check_digit = String(number).delete(' '), String(check_digit)
|
5
|
+
|
6
|
+
raise IdentificationCardError, :size unless id_number.size == 7 or id_number.size == 8
|
7
|
+
raise IdentificationCardError, :invalid_check_digit unless decimal_check_digit_match?(id_number, check_digit)
|
8
|
+
number
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.valid_identification_card?(number, check_digit)
|
12
|
+
valid_identification_card!(number, check_digit)
|
13
|
+
true
|
14
|
+
rescue IdentificationCardError
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#see: http://pt.wikipedia.org/wiki/N%C3%BAmero_de_Identifica%C3%A7%C3%A3o_Banc%C3%A1ria
|
2
|
+
module Citizenship
|
3
|
+
def self.valid_nib!(nib, options = {})
|
4
|
+
strict = options.fetch(:strict, false)
|
5
|
+
bank_codes = ['0007', #BES
|
6
|
+
'0010', #BPI
|
7
|
+
'0018', #Santander
|
8
|
+
'0019', #BBVA
|
9
|
+
'0025', #Caixa BI
|
10
|
+
'0032', #Barclays
|
11
|
+
'0033', #BCP
|
12
|
+
'0034', #BNP Paribas
|
13
|
+
'0035', #CGD
|
14
|
+
'0036', #Montepio
|
15
|
+
'0038', #Banif
|
16
|
+
'0043', #Deutsche Bank
|
17
|
+
'0045', #CA Crédito Agrícola
|
18
|
+
'0046', #Banco Popular
|
19
|
+
'0061', #BiG
|
20
|
+
'0065', #Best
|
21
|
+
'0076', #Finibanco
|
22
|
+
'0079', #BPN
|
23
|
+
'0781', #Direcção Geral do Tesouro
|
24
|
+
'5180'] #Caixa Central de Crédito Agrícola Mútuo
|
25
|
+
|
26
|
+
escaped_nib = strict ? nib : remove_special_chars(nib)
|
27
|
+
raise NIBError.new(:size) unless escaped_nib.size == 21
|
28
|
+
raise NIBError.new(:invalid_bank_code, bank_code: escaped_nib[0..3]) unless bank_codes.include?(escaped_nib[0..3])
|
29
|
+
|
30
|
+
check_digit = escaped_nib[19..20].to_i
|
31
|
+
escaped_nib = escaped_nib[0..18]
|
32
|
+
|
33
|
+
conversion_table = [73, 17, 89, 38, 62, 45, 53, 15, 50, 5, 49, 34, 81, 76, 27, 90, 9, 30, 3]
|
34
|
+
sum = (0..18).map do |i|
|
35
|
+
escaped_nib.slice(i).to_i * conversion_table[i]
|
36
|
+
end.reduce(:+)
|
37
|
+
|
38
|
+
control_number = 98 - sum % 97
|
39
|
+
raise NIBError.new(:invalid_check_digit) unless check_digit == control_number
|
40
|
+
nib
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.valid_nib?(nib, options = {})
|
44
|
+
valid_nib!(nib, options)
|
45
|
+
true
|
46
|
+
rescue NIBError
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#see: http://pt.wikipedia.org/wiki/N%C3%BAmero_de_identifica%C3%A7%C3%A3o_fiscal
|
2
|
+
module Citizenship
|
3
|
+
def self.valid_nif!(number, options = {})
|
4
|
+
strict = options.fetch(:strict, false)
|
5
|
+
id_number = strict ? number : String(number).delete(' ')
|
6
|
+
first_digit_universe = [1, 2, 5, 6, 8, 9]
|
7
|
+
|
8
|
+
raise NIFError.new(:size) if id_number.size != 9
|
9
|
+
raise NIFError.new(:prefix, prefixes: first_digit_universe.join(', ')) unless first_digit_universe.include?(id_number[0].to_i)
|
10
|
+
raise NIFError.new(:invalid_check_digit) unless decimal_check_digit_match?(id_number[0..-2], id_number[-1])
|
11
|
+
number
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.valid_nif?(number, options = {})
|
15
|
+
valid_nif!(number, options)
|
16
|
+
true
|
17
|
+
rescue NIFError
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Citizenship
|
2
|
+
def self.valid_phone!(number, opts = {})
|
3
|
+
allow_country_prefix = opts.fetch(:allow_country_prefix, true)
|
4
|
+
prefix_whitelist = network_prefix_white_list(opts[:only_prefixes])
|
5
|
+
strict = opts.fetch(:strict, false)
|
6
|
+
|
7
|
+
country_prefix = allow_country_prefix ? '((\+351|00351|351)?)' : ''
|
8
|
+
regexp_template = "^#{country_prefix}(#{prefix_whitelist}\\d{7})$"
|
9
|
+
|
10
|
+
phone_number = strict ? number : String(number).delete(' ').delete('-')
|
11
|
+
raise PhoneError, :invalid_phone_number unless phone_number.match(Regexp.new(regexp_template))
|
12
|
+
number
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.valid_phone?(number, opts = {})
|
16
|
+
valid_phone!(number, opts)
|
17
|
+
true
|
18
|
+
rescue Error
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def self.network_prefix_white_list(prefixes)
|
24
|
+
return '(2\d{1}|(9(3|6|2|1)))' if prefixes.nil?
|
25
|
+
prefixes.is_a?(Array) ? "(#{prefixes.map(&:to_s).join('|')})" : "(#{prefixes})"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Citizenship
|
2
|
+
module Rails
|
3
|
+
module Validators
|
4
|
+
class NifValidator < ActiveModel::EachValidator
|
5
|
+
def validate_each(record, attribute, value)
|
6
|
+
Citizenship.valid_nif!(value, options) if value.present?
|
7
|
+
rescue Citizenship::NIFError => e
|
8
|
+
record.errors[attribute] << (options[:message] || e.message)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NibValidator < ActiveModel::EachValidator
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
Citizenship.valid_nib!(value, options) if value.present?
|
15
|
+
rescue Citizenship::NIBError => e
|
16
|
+
record.errors[attribute] << (options[:message] || e.message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class PhoneValidator < ActiveModel::EachValidator
|
21
|
+
def validate_each(record, attribute, value)
|
22
|
+
Citizenship.valid_phone!(value, options) if value.present?
|
23
|
+
rescue Citizenship::PhoneError => e
|
24
|
+
record.errors[attribute] << (options[:message] || e.message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class EmailValidator < ActiveModel::EachValidator
|
29
|
+
def validate_each(record, attribute, value)
|
30
|
+
Citizenship.valid_email!(value) if value.present?
|
31
|
+
rescue Citizenship::EmailError => e
|
32
|
+
record.errors[attribute] << (options[:message] || e.message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ZipCodeValidator < ActiveModel::EachValidator
|
37
|
+
def validate_each(record, attribute, value)
|
38
|
+
Citizenship.valid_zip_code!(value) if value.present?
|
39
|
+
rescue Citizenship::ZipCodeError => e
|
40
|
+
record.errors[attribute] << (options[:message] || e.message)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ActiveRecord::Base.send(:include, Citizenship::Rails::Validators)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Citizenship
|
2
|
+
def self.valid_zip_code!(zip_code)
|
3
|
+
regexp = /^(\d{4})-(\d{3})$/
|
4
|
+
raise ZipCodeError, :invalid_zip_code unless zip_code.match(regexp)
|
5
|
+
zip_code
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.valid_zip_code?(zip_code)
|
9
|
+
valid_zip_code!(zip_code)
|
10
|
+
true
|
11
|
+
rescue ZipCodeError
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
data/lib/locales/en.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
en:
|
2
|
+
citizenship:
|
3
|
+
nif:
|
4
|
+
size: "must have 9 digits"
|
5
|
+
prefix: "first number has to be one of the following: %{prefixes}"
|
6
|
+
invalid_check_digit: "Invalid check digit"
|
7
|
+
nib:
|
8
|
+
size: "must have 21 digits"
|
9
|
+
invalid_bank_code: "Invalid bank code: %{bank_code}"
|
10
|
+
invalid_check_digit: "Invalid check digit"
|
11
|
+
citizen_card:
|
12
|
+
size: "Invalid size"
|
13
|
+
invalid_check_digit: "Invalid check digit"
|
14
|
+
identification_card:
|
15
|
+
size: "Invalid size"
|
16
|
+
invalid_check_digit: "Invalid check digit"
|
17
|
+
phone:
|
18
|
+
invalid_phone_number: "Invalid phone number"
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"pt-PT":
|
2
|
+
citizenship:
|
3
|
+
nif:
|
4
|
+
size: "deve conter 9 digitos"
|
5
|
+
prefix: "o primeiro digito tem de ser um dos seguintes: %{prefixes}"
|
6
|
+
invalid_check_digit: "inválido"
|
7
|
+
nib:
|
8
|
+
size: "deve conter 21 digitos"
|
9
|
+
invalid_bank_code: "Código bancário inválido: %{bank_code}"
|
10
|
+
invalid_check_digit: "inválido"
|
11
|
+
citizen_card:
|
12
|
+
size: "Tamanho inválido"
|
13
|
+
invalid_check_digit: "Cartão de cidadão inválido"
|
14
|
+
identification_card:
|
15
|
+
size: "Tamanho inválido"
|
16
|
+
invalid_check_digit: "inválido"
|
17
|
+
phone:
|
18
|
+
invalid_phone_number: "inválido"
|
19
|
+
email:
|
20
|
+
invalid_email: "inválido"
|
21
|
+
zip_code:
|
22
|
+
invalid_zip_code: "inválido"
|
data/lib/locales/pt.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
"pt":
|
2
|
+
citizenship:
|
3
|
+
nif:
|
4
|
+
size: "deve conter 9 digitos"
|
5
|
+
prefix: "o primeiro digito tem de ser um dos seguintes: %{prefixes}"
|
6
|
+
invalid_check_digit: "inválido"
|
7
|
+
nib:
|
8
|
+
size: "deve conter 21 digitos"
|
9
|
+
invalid_bank_code: "Código bancário inválido: %{bank_code}"
|
10
|
+
invalid_check_digit: "inválido"
|
11
|
+
citizen_card:
|
12
|
+
size: "Tamanho inválido"
|
13
|
+
invalid_check_digit: "Cartão de cidadão inválido"
|
14
|
+
identification_card:
|
15
|
+
size: "Tamanho inválido"
|
16
|
+
invalid_check_digit: "inválido"
|
17
|
+
phone:
|
18
|
+
invalid_phone_number: "inválido"
|
19
|
+
email:
|
20
|
+
invalid_email: "inválido"
|
21
|
+
zip_code:
|
22
|
+
invalid_zip_code: "inválido"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe 'citizen card validation' do
|
2
|
+
it 'passes on valid citizen card numbers' do
|
3
|
+
cc_number = '00000000 0 ZZ 4'
|
4
|
+
|
5
|
+
expect(Citizenship.valid_citizen_card?(cc_number)).to be_truthy
|
6
|
+
expect(Citizenship.valid_citizen_card!(cc_number)).to eq(cc_number)
|
7
|
+
expect(Citizenship.valid_citizen_card!('00000000-0-ZZ-4')).to eq('00000000-0-ZZ-4')
|
8
|
+
expect(Citizenship.valid_citizen_card!('00000000.0.ZZ.4')).to eq('00000000.0.ZZ.4')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'fails on invalid citizen card numbers' do
|
12
|
+
expect(Citizenship.valid_citizen_card?('')).to be_falsy
|
13
|
+
expect { Citizenship.valid_citizen_card!(nil) }.to raise_error(Citizenship::Error)
|
14
|
+
expect { Citizenship.valid_citizen_card!('12345678 9 ZZ8') }.to raise_error(Citizenship::Error)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
describe 'Email validation' do
|
2
|
+
it 'passes on valid emails' do
|
3
|
+
expect(Citizenship.valid_email?('user@example.org')).to be_truthy
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'falid on invalid emails' do
|
7
|
+
expect {Citizenship.valid_email!(' user@example.org')}.to raise_error(Citizenship::EmailError)
|
8
|
+
expect(Citizenship.valid_email?('user@example.org ')).to be_falsy
|
9
|
+
expect(Citizenship.valid_email?('email@')).to be_falsy
|
10
|
+
expect(Citizenship.valid_email?('@example.com')).to be_falsy
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe 'identification card validation' do
|
2
|
+
it 'passes on valid identification card numbers' do
|
3
|
+
expect(Citizenship.valid_identification_card?('156 944 8', '8')).to be_truthy
|
4
|
+
expect(Citizenship.valid_identification_card?('156 944 80', '4')).to be_truthy
|
5
|
+
expect(Citizenship.valid_identification_card!('156 944 8', '8')).to eq('156 944 8')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'fails on invalid identification card numbers' do
|
9
|
+
expect(Citizenship.valid_identification_card?('156 944 8', '7')).to be_falsy
|
10
|
+
expect { Citizenship.valid_identification_card!('156 944 8', '7') }.to raise_error(Citizenship::Error)
|
11
|
+
expect { Citizenship.valid_identification_card!('', '0') }.to raise_error(Citizenship::Error)
|
12
|
+
expect { Citizenship.valid_identification_card!(nil, nil) }.to raise_error(Citizenship::Error)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'covers control digit collision flaw' do
|
16
|
+
#see http://dokatano.blogspot.pt/2008/10/o-mistrio-do-bilhete-de-identidade.html
|
17
|
+
expect(Citizenship.valid_identification_card?('6617080', 0)).to be_truthy
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe 'NIB validation' do
|
2
|
+
it 'passes for valid NIBs', focus: true do
|
3
|
+
nib = '003503730000539151280'
|
4
|
+
|
5
|
+
expect(Citizenship.valid_nib!(nib)).to eq(nib)
|
6
|
+
expect(Citizenship.valid_nib?(nib)).to be_truthy
|
7
|
+
expect(Citizenship.valid_nib?('0035-03730000539-1512-80')).to be_truthy
|
8
|
+
expect(Citizenship.valid_nib?('0035.03730000539.1512.80')).to be_truthy
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'fails for invalid NIBs' do
|
12
|
+
nib = '003503730000539151200'
|
13
|
+
|
14
|
+
expect{ Citizenship.valid_nib!(nib) }.to raise_error(Citizenship::Error)
|
15
|
+
expect{ Citizenship.valid_nib!('000003730000539151252') }.to raise_error(Citizenship::Error) #invalid bank code
|
16
|
+
expect(Citizenship.valid_nib?(nib)).to be_falsy
|
17
|
+
expect(Citizenship.valid_nib?('')).to be_falsy
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'strict validation disallow whitspaces, dashes and dots' do
|
21
|
+
expect(Citizenship.valid_nib?('0035-03730000539-1512-80', strict: true)).to be_falsy
|
22
|
+
expect(Citizenship.valid_nib?('0035.03730000539.1512.80', strict: true)).to be_falsy
|
23
|
+
expect(Citizenship.valid_nib?('0035 03730000539 1512 80', strict: true)).to be_falsy
|
24
|
+
expect(Citizenship.valid_nib?('0035 03730000539 1512 80 ', strict: true)).to be_falsy
|
25
|
+
expect(Citizenship.valid_nib?('003503730000539151280', strict: true)).to be_truthy
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
describe 'NIF validation' do
|
2
|
+
it 'passes for valid NIFs' do
|
3
|
+
expect(Citizenship.valid_nif?('123456789')).to be_truthy
|
4
|
+
expect(Citizenship.valid_nif!('123456789')).to eq('123456789')
|
5
|
+
expect(Citizenship.valid_nif!('123456789')).to eq('123456789')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'fails on invalid NIFs' do
|
9
|
+
expect(Citizenship.valid_nif?('223456789')).to be_falsy
|
10
|
+
expect(Citizenship.valid_nif?('12345678')).to be_falsy
|
11
|
+
expect { Citizenship.valid_nif!('223456789') }.to raise_error(Citizenship::Error)
|
12
|
+
expect(Citizenship.valid_nif?(nil)).to be_falsy
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'strict validation disallow whitspaces and others' do
|
16
|
+
expect(Citizenship.valid_nif?(' 123456789', strict: true)).to be_falsy
|
17
|
+
expect(Citizenship.valid_nif?('123456789 ', strict: true)).to be_falsy
|
18
|
+
expect(Citizenship.valid_nif?('12345 6789', strict: true)).to be_falsy
|
19
|
+
expect(Citizenship.valid_nif?('123456789', strict: true)).to be_truthy
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
describe 'phone number validation' do
|
2
|
+
context 'passes for valid phone numbers' do
|
3
|
+
it 'land lines' do
|
4
|
+
expect(Citizenship.valid_phone!('262-999-666')).to eq('262-999-666')
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'mobile' do
|
8
|
+
expect(Citizenship.valid_phone!('939332233')).to eq('939332233')
|
9
|
+
expect(Citizenship.valid_phone!('969332233')).to eq('969332233')
|
10
|
+
expect(Citizenship.valid_phone!('929332233')).to eq('929332233')
|
11
|
+
expect(Citizenship.valid_phone?('919332233')).to be_truthy
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'with country prefix' do
|
15
|
+
expect(Citizenship.valid_phone!('+351 93 933 2233')).to eq('+351 93 933 2233')
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'without countryprefix' do
|
20
|
+
expect(Citizenship.valid_phone?('+351 93 933 2233', allow_country_prefix: false)).to be_falsy
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'by designated prefix', focus: true do
|
24
|
+
expect(Citizenship.valid_phone!('+351 93 933 2233', only_prefixes: ['93', '96'])).to eq('+351 93 933 2233')
|
25
|
+
expect(Citizenship.valid_phone!('+351 96 933 2233', only_prefixes: ['93', '96'])).to eq('+351 96 933 2233')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'strict validation disallow whitspaces, dashes and dots' do
|
29
|
+
expect(Citizenship.valid_phone?('262999666', strict: true)).to be_truthy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'fails for invalid phone numbers' do
|
34
|
+
it 'land lines' do
|
35
|
+
expect { Citizenship.valid_phone!('662-999-666') }.to raise_error(Citizenship::Error)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'mobile' do
|
39
|
+
expect(Citizenship.valid_phone?('999332233')).to be_falsy
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'with country prefix' do
|
43
|
+
expect(Citizenship.valid_phone?('+350 93 933 2233')).to be_falsy
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'by designated prefix' do
|
47
|
+
expect(Citizenship.valid_phone?('96 933 2233', only_prefixes: '93')).to be_falsy
|
48
|
+
expect(Citizenship.valid_phone?('96 933 2233', only_prefixes: ['91', '93'])).to be_falsy
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
it 'strict validation disallow whitspaces, dashes and dots' do
|
53
|
+
expect(Citizenship.valid_phone?('262-999-666', strict: true)).to be_falsy
|
54
|
+
expect(Citizenship.valid_phone?('262 999 666', strict: true)).to be_falsy
|
55
|
+
expect(Citizenship.valid_phone?(' 262999666', strict: true)).to be_falsy
|
56
|
+
expect(Citizenship.valid_phone?(' 262999666 ', strict: true)).to be_falsy
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe 'Zip code validation' do
|
2
|
+
it 'passes for valid Zip codes' do
|
3
|
+
expect(Citizenship.valid_zip_code?('1000-100')).to be_truthy
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'fails for invalid Zip codes' do
|
7
|
+
expect {Citizenship.valid_zip_code!('1000')}.to raise_error(Citizenship::ZipCodeError)
|
8
|
+
expect(Citizenship.valid_zip_code?('1000-00')).to be_falsy
|
9
|
+
expect(Citizenship.valid_zip_code?(' 1000-000')).to be_falsy
|
10
|
+
expect(Citizenship.valid_zip_code?('1000-100 ')).to be_falsy
|
11
|
+
expect(Citizenship.valid_zip_code?('1000 - 100')).to be_falsy
|
12
|
+
end
|
13
|
+
end
|
data/spec/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: citizenship
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Runtime Revolution
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: i18n
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.6.4
|
20
|
+
- - "<="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.7.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.6.4
|
30
|
+
- - "<="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.7.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.3'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.3'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 3.2.0
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 3.2.0
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: simplecov
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: pry
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
description: citizenship checks validity of civil id numbers and similar used in Portugal
|
104
|
+
email: info@runtime-revolution.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- ".gitignore"
|
110
|
+
- ".travis.yml"
|
111
|
+
- CHANGELOG
|
112
|
+
- Gemfile
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- citizenship.gemspec
|
117
|
+
- lib/citizenship.rb
|
118
|
+
- lib/citizenship/citizen_card.rb
|
119
|
+
- lib/citizenship/email.rb
|
120
|
+
- lib/citizenship/errors.rb
|
121
|
+
- lib/citizenship/identification_card.rb
|
122
|
+
- lib/citizenship/nib.rb
|
123
|
+
- lib/citizenship/nif.rb
|
124
|
+
- lib/citizenship/phone.rb
|
125
|
+
- lib/citizenship/rails/validators.rb
|
126
|
+
- lib/citizenship/version.rb
|
127
|
+
- lib/citizenship/zip_code.rb
|
128
|
+
- lib/locales/en.yml
|
129
|
+
- lib/locales/pt-PT.yml
|
130
|
+
- lib/locales/pt.yml
|
131
|
+
- spec/citizenship/citizen_card_spec.rb
|
132
|
+
- spec/citizenship/email_spec.rb
|
133
|
+
- spec/citizenship/identification_card_spec.rb
|
134
|
+
- spec/citizenship/nib_spec.rb
|
135
|
+
- spec/citizenship/nif_spec.rb
|
136
|
+
- spec/citizenship/phone_spec.rb
|
137
|
+
- spec/citizenship/zip_code_spec.rb
|
138
|
+
- spec/helper.rb
|
139
|
+
homepage: https://github.com/runtimerevolution/citizenship
|
140
|
+
licenses:
|
141
|
+
- MIT
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.4.5
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: citizenship checks validity of civil id numbers and similar used in Portugal
|
163
|
+
test_files:
|
164
|
+
- spec/citizenship/citizen_card_spec.rb
|
165
|
+
- spec/citizenship/email_spec.rb
|
166
|
+
- spec/citizenship/identification_card_spec.rb
|
167
|
+
- spec/citizenship/nib_spec.rb
|
168
|
+
- spec/citizenship/nif_spec.rb
|
169
|
+
- spec/citizenship/phone_spec.rb
|
170
|
+
- spec/citizenship/zip_code_spec.rb
|
171
|
+
- spec/helper.rb
|