citizenship 1.0.0
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/.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
|
+
[](http://badge.fury.io/rb/citizen)
|
4
|
+
[](https://travis-ci.org/runtimerevolution/citizenship)
|
5
|
+
[](https://codeclimate.com/github/runtimerevolution/citizenship)
|
6
|
+
[](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
|