codice-fiscale 0.0.2
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Guardfile +33 -0
- data/LICENSE +22 -0
- data/README.md +74 -0
- data/Rakefile +2 -0
- data/codice_fiscale.gemspec +24 -0
- data/lib/codice_fiscale.rb +98 -0
- data/lib/codice_fiscale/alphabet.rb +17 -0
- data/lib/codice_fiscale/codes.rb +49 -0
- data/lib/codice_fiscale/codes/city_codes.csv +1 -0
- data/lib/codice_fiscale/codes/country_codes.csv +1 -0
- data/lib/codice_fiscale/configuration.rb +36 -0
- data/lib/codice_fiscale/version.rb +3 -0
- data/spec/fixtures/city_codes.csv +1 -0
- data/spec/fixtures/country_codes.csv +1 -0
- data/spec/lib/codice_fiscale/alphabet_spec.rb +25 -0
- data/spec/lib/codice_fiscale/codes_spec.rb +23 -0
- data/spec/lib/codice_fiscale_spec.rb +183 -0
- data/spec/spec_helper.rb +7 -0
- metadata +135 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard_options = {
|
5
|
+
:all_after_pass => false,
|
6
|
+
:all_on_start => false,
|
7
|
+
:bundler => true,
|
8
|
+
:notification => true,
|
9
|
+
:keep_failed => false,
|
10
|
+
:cli => "-c -f doc"
|
11
|
+
}
|
12
|
+
|
13
|
+
guard('rspec', guard_options) do
|
14
|
+
watch(%r{^spec/.+_spec\.rb$})
|
15
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
16
|
+
watch('spec/spec_helper.rb') { "spec" }
|
17
|
+
|
18
|
+
# Rails example
|
19
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
20
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
21
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
22
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
23
|
+
watch('config/routes.rb') { "spec/routing" }
|
24
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
25
|
+
|
26
|
+
# Capybara request specs
|
27
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
28
|
+
|
29
|
+
# Turnip features and steps
|
30
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
31
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
32
|
+
end
|
33
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Daniele Molteni
|
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,74 @@
|
|
1
|
+
# Codice fiscale
|
2
|
+
|
3
|
+
A ruby gem to support the calculation of the italian fiscal code ("Cofice fiscale"),
|
4
|
+
that is an ID assigned to each italian citizen by the "Agenzia delle entrate".
|
5
|
+
|
6
|
+
To calculate the fiscal code you need the following information: name, surname,
|
7
|
+
gender, birthdate and the birthplace. Read more on [wikipedia](http://en.wikipedia.org/wiki/Italian_fiscal_code_card).
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'codice_fiscale'
|
13
|
+
|
14
|
+
CodiceFiscale.calculate 'mario', 'rossi', :male, Date.new(1987, 1, 1), 'italia', 'lc', 'Abbadia Lariana'
|
15
|
+
|
16
|
+
# RSSMRA87A01A005V
|
17
|
+
```
|
18
|
+
|
19
|
+
## City codes (Codici catastali)
|
20
|
+
As explained above, one of the information required to calculate the fiscal code is the birthplace.
|
21
|
+
If a person was born outside Italy, only the italian name of the county is required.
|
22
|
+
For example, an italian citizen born in France:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
CodiceFiscale.calculate 'mario', 'rossi', :male, Date.new(1987, 1, 1), 'francia'
|
26
|
+
```
|
27
|
+
If a person was born in Italy you have to specify the *code* of the province and the *name* of the city. These informations are actually contained in an XLS
|
28
|
+
document downloaded from [agenziaterritorio.it](http://www.agenziaterritorio.it/?id=721), converted to CSV and shipped with this gem.
|
29
|
+
|
30
|
+
**But what if you have your own table with all those codes?**
|
31
|
+
|
32
|
+
In this case, you can add a custom block that fetches the codes from your tables/files:
|
33
|
+
|
34
|
+
|
35
|
+
*config/initializers/codice_fiscale_initializer.rb*:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# Fetching the codes using ActiveRecord:
|
39
|
+
|
40
|
+
CodiceFiscale.config.country_code do |country_name|
|
41
|
+
Country.find_by_name(country_name).code
|
42
|
+
end
|
43
|
+
|
44
|
+
CodiceFiscale.config.city_code do |city_name, province_code|
|
45
|
+
City.in_italy.find_by_province_and_city(province_code, city_name).code
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
## Installation
|
50
|
+
|
51
|
+
I'm currently supporting only **ruby 1.9+**
|
52
|
+
|
53
|
+
Add this line to your application's Gemfile:
|
54
|
+
|
55
|
+
gem 'codice_fiscale'
|
56
|
+
|
57
|
+
And then execute:
|
58
|
+
|
59
|
+
$ bundle
|
60
|
+
|
61
|
+
## Testing
|
62
|
+
|
63
|
+
I'm using RSpec + guard (+ growl for notifications)
|
64
|
+
|
65
|
+
$ bundle exec guard
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
1. Fork it
|
70
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
71
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
72
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
73
|
+
5. Create new Pull Request
|
74
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/codice_fiscale/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Daniele Molteni"]
|
6
|
+
gem.email = ["dani.m.mobile@gmail.com"]
|
7
|
+
gem.description = %q{Calculate the italian fiscal code}
|
8
|
+
gem.summary = %q{Calculate the italian fiscal code}
|
9
|
+
gem.homepage = "https://github.com/daniele-m/codice_fiscale"
|
10
|
+
gem.platform = Gem::Platform::RUBY
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "codice-fiscale"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = CodiceFiscale::VERSION
|
18
|
+
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'guard-rspec'
|
21
|
+
gem.add_development_dependency 'rb-fsevent', '~> 0.9.1'
|
22
|
+
# The growl app must be separately downloaded and installed
|
23
|
+
gem.add_development_dependency 'growl'
|
24
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'date'
|
3
|
+
require 'csv'
|
4
|
+
require 'codice_fiscale/version'
|
5
|
+
require 'codice_fiscale/alphabet'
|
6
|
+
require 'codice_fiscale/codes'
|
7
|
+
require 'codice_fiscale/configuration'
|
8
|
+
|
9
|
+
module CodiceFiscale
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def calculate name, surname, gender, birthdate, country_name, province_code = nil, city_name = nil
|
13
|
+
code = birthplace_part country_name, city_name, province_code
|
14
|
+
return nil unless code
|
15
|
+
code = surname_part(surname) + name_part(name) + birthdate_part(birthdate, gender) + code
|
16
|
+
puts code
|
17
|
+
code + check_character(code)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Methods to generate each part of the code
|
22
|
+
|
23
|
+
def surname_part surname
|
24
|
+
surname.upcase!
|
25
|
+
code = first_three_consonants surname
|
26
|
+
code << first_three_vocals(surname)
|
27
|
+
truncate_and_right_pad_with_three_x code
|
28
|
+
end
|
29
|
+
|
30
|
+
def name_part name
|
31
|
+
name.upcase!
|
32
|
+
consonants_of_name = consonants name
|
33
|
+
return consonants_of_name[0]+consonants_of_name[2..3] if consonants_of_name.size >= 4
|
34
|
+
code = first_three_consonants name
|
35
|
+
code << first_three_vocals(name)
|
36
|
+
truncate_and_right_pad_with_three_x code
|
37
|
+
end
|
38
|
+
|
39
|
+
def birthdate_part birthdate, gender
|
40
|
+
code = birthdate.year.to_s[2..3]
|
41
|
+
code << Codes.month_letter(birthdate.month)
|
42
|
+
day_part = gender.to_s.downcase[0] == 'f' ? birthdate.day + 40 : birthdate.day
|
43
|
+
code << "#{day_part}".rjust(2, '0')
|
44
|
+
end
|
45
|
+
|
46
|
+
def city_code city_name, province_code
|
47
|
+
return config.city_code.call(city_name, province_code) if config.city_code
|
48
|
+
Codes.city city_name, province_code
|
49
|
+
end
|
50
|
+
|
51
|
+
def country_code country_name
|
52
|
+
return config.country_code.call(country_name) if config.country_code
|
53
|
+
Codes.country country_name
|
54
|
+
end
|
55
|
+
|
56
|
+
def birthplace_part country_name, city_name = nil, province_code = nil
|
57
|
+
if %w[italia italy].include?(country_name.downcase.strip)
|
58
|
+
city_code city_name, province_code
|
59
|
+
else
|
60
|
+
country_code country_name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_character partial_fiscal_code
|
65
|
+
numeric_value = 0
|
66
|
+
partial_fiscal_code.split('').each_with_index do |chr, index|
|
67
|
+
numeric_value += ((index+1) % 2 == 0) ? Codes.even_character(chr) : Codes.odd_character(chr)
|
68
|
+
end
|
69
|
+
Codes.check_character numeric_value % 26
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Helper methods
|
74
|
+
|
75
|
+
# Intersect two strings or a string and an array of characters.
|
76
|
+
def intersects string_a, string_or_array_b
|
77
|
+
letters_a = string_a.split ''
|
78
|
+
letters_b = string_or_array_b.respond_to?(:split) ? string_or_array_b.split('') : string_or_array_b
|
79
|
+
selected_letters = letters_a.select { |letter| letters_b.include? letter }
|
80
|
+
selected_letters.join ''
|
81
|
+
end
|
82
|
+
|
83
|
+
def consonants string
|
84
|
+
intersects string, Alphabet.consonants
|
85
|
+
end
|
86
|
+
|
87
|
+
def first_three_consonants string
|
88
|
+
intersects(string, Alphabet.consonants)[0..2]
|
89
|
+
end
|
90
|
+
|
91
|
+
def first_three_vocals string
|
92
|
+
intersects(string, Alphabet.vocals)[0..2]
|
93
|
+
end
|
94
|
+
|
95
|
+
def truncate_and_right_pad_with_three_x string
|
96
|
+
string[0..2].ljust 3, 'X'
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module CodiceFiscale
|
2
|
+
module Codes
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def config
|
6
|
+
CodiceFiscale.config
|
7
|
+
end
|
8
|
+
|
9
|
+
def month_letter month_number
|
10
|
+
decode = %w[A B C D E H L M P R S T]
|
11
|
+
month_number <= 0 ? nil : decode[month_number-1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def city city_name, province_code
|
15
|
+
CSV.foreach config.city_codes_csv_path do |row|
|
16
|
+
if city_name.casecmp(row[3].strip) == 0 and province_code.casecmp(row[2].strip) == 0
|
17
|
+
return row[0].strip.upcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def country country_name
|
24
|
+
CSV.foreach config.country_codes_csv_path do |row|
|
25
|
+
return row[3].strip.upcase if country_name.casecmp(row[2].strip) == 0
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def odd_character character
|
31
|
+
decode = {'0' => 1, '1' => 0, '2' => 5, '3' => 7, '4' => 9, '5' => 13, '6' => 15, '7' => 17, '8' => 19, '9' => 21, 'A' => 1, 'B' => 0,
|
32
|
+
'C' => 5, 'D' => 7, 'E' => 9, 'F' => 13, 'G' => 15, 'H' => 17, 'I' => 19, 'J' => 21, 'K' => 2, 'L' => 4, 'M' => 18, 'N' => 20,
|
33
|
+
'O' => 11, 'P' => 3, 'Q' => 6, 'R' => 8, 'S' => 12, 'T' => 14, 'U' => 16, 'V' => 10, 'W' => 22, 'X' => 25, 'Y' => 24, 'Z' => 23}
|
34
|
+
decode[character.upcase]
|
35
|
+
end
|
36
|
+
|
37
|
+
def even_character character
|
38
|
+
decode = {'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'A' => 0, 'B' => 1,
|
39
|
+
'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
|
40
|
+
'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25}
|
41
|
+
decode[character.upcase]
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_character number
|
45
|
+
decode = %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
|
46
|
+
decode[number]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
CODICE NAZIONALE,CODICE CATASTALE BELFIORE aggiornato al 1/9/1999 ora non pi in uso,PROVINCIA,DENOMINAZIONE COMUNE,ANNOTAZIONE,VARIAZIONE CODICE NAZAZIONALE,VARIAZIONE CODICE CATASTALE,VARIAZIONE PROVINCIA,VARIAZIONE DENOMINAZIONE DEL COMUNE,DATA COSTITUZIONE,DATA VARIAZIONE,,,,
|
@@ -0,0 +1 @@
|
|
1
|
+
CONTIN,SIGLA,DENOMINAZ,CODICE,DATAIST,DATASOP,CODRIF,DATAVARIAZ
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CodiceFiscale
|
2
|
+
class Configuration
|
3
|
+
def initialize
|
4
|
+
@options = default
|
5
|
+
end
|
6
|
+
|
7
|
+
def csv_folder
|
8
|
+
File.join File.dirname(__FILE__), 'codes'
|
9
|
+
end
|
10
|
+
|
11
|
+
def default
|
12
|
+
{
|
13
|
+
:city_codes_csv_path => "#{csv_folder}/city_codes.csv",
|
14
|
+
:country_codes_csv_path => "#{csv_folder}/country_codes.csv",
|
15
|
+
:city_code => nil,
|
16
|
+
:country_code => nil
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing name, *args, &block
|
21
|
+
name = remove_final_equal_char(name).to_sym
|
22
|
+
return @options[name] if args.empty? and !block_given?
|
23
|
+
@options[name] = block_given? && block || args.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_final_equal_char string
|
27
|
+
parts = string.to_s.scan(/\A(.*)(\=)\z/).flatten
|
28
|
+
parts.empty? ? string : parts.first
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def config
|
34
|
+
@config ||= Configuration.new
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
CODICE NAZIONALE,CODICE CATASTALE BELFIORE aggiornato al 1/9/1999 ora non pi in uso,PROVINCIA,DENOMINAZIONE COMUNE,ANNOTAZIONE,VARIAZIONE CODICE NAZAZIONALE,VARIAZIONE CODICE CATASTALE,VARIAZIONE PROVINCIA,VARIAZIONE DENOMINAZIONE DEL COMUNE,DATA COSTITUZIONE,DATA VARIAZIONE
|
@@ -0,0 +1 @@
|
|
1
|
+
CONTIN,SIGLA,DENOMINAZ,CODICE,DATAIST,DATASOP,CODRIF,DATAVARIAZ
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodiceFiscale::Alphabet do
|
4
|
+
describe '#letters' do
|
5
|
+
it 'is 26 long' do
|
6
|
+
subject.letters.size.should == 26
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'return only upcased letters' do
|
10
|
+
subject.letters.each { |letter| letter.upcase.should == letter }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#consonants' do
|
15
|
+
it 'is 21 long' do
|
16
|
+
subject.consonants.size.should == 21
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#vocals' do
|
21
|
+
it 'return only upcased letters' do
|
22
|
+
subject.letters.each { |letter| letter.upcase.should == letter }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodiceFiscale::Codes do
|
4
|
+
describe '#month_letter' do
|
5
|
+
context 'the given number is greater than 0 and less than 12' do
|
6
|
+
it 'return a letter' do
|
7
|
+
subject.month_letter(1).should == 'A'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'the given number is greater than 12' do
|
12
|
+
it 'return nil' do
|
13
|
+
subject.month_letter(13).should be_nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'the given number is less than 1' do
|
18
|
+
it 'return nil' do
|
19
|
+
subject.month_letter(0).should be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodiceFiscale do
|
4
|
+
before do
|
5
|
+
subject.config.city_codes_csv_path = "#{fixtures_path}/city_codes.csv"
|
6
|
+
subject.config.country_codes_csv_path = "#{fixtures_path}/country_codes.csv"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#surname_part' do
|
10
|
+
it 'takes the first 3 consonants' do
|
11
|
+
subject.surname_part('molteni').should == 'MLT'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is 3 chrs long' do
|
15
|
+
subject.surname_part('').size.should == 3
|
16
|
+
subject.surname_part('foobar').size.should == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'surname has only 1 consonant' do
|
20
|
+
it 'put the vocals after the consonants' do
|
21
|
+
subject.surname_part('oof').should == 'FOO'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'surname is less than 3 chrs long' do
|
26
|
+
it 'pad with the "X" character' do
|
27
|
+
subject.surname_part('m').should == 'MXX'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
describe '#name_part' do
|
34
|
+
it 'is 3 chrs long' do
|
35
|
+
subject.name_part('').size.should == 3
|
36
|
+
subject.name_part('foobar').size.should == 3
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'name has 4 or more consonants' do
|
40
|
+
it 'take the 1st the 3rd and the 4th' do
|
41
|
+
subject.name_part('danielino').should == 'DLN'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "name has 3 or less consonants" do
|
46
|
+
it 'take the first 3 consonants' do
|
47
|
+
subject.name_part('daniele').should == 'DNL'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'name has 2 consonants' do
|
52
|
+
it 'put the vocals after the consonants' do
|
53
|
+
subject.name_part('bar').should == 'BRA'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'name is less than 3 chrs long' do
|
58
|
+
it 'pad with the "X" character' do
|
59
|
+
subject.name_part('d').should == 'DXX'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
describe '#birthdate_part' do
|
66
|
+
let(:birthdate) { Date.new 1987, 12, 3 }
|
67
|
+
let(:male) { 'm' }
|
68
|
+
let(:female) { 'f' }
|
69
|
+
|
70
|
+
it 'start with the last 2 digit of the year' do
|
71
|
+
subject.birthdate_part(birthdate, male).should start_with '87'
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'the 3rd character' do
|
75
|
+
before { subject::Codes.stub(:month_letter).and_return('X') }
|
76
|
+
|
77
|
+
it('is the month code') { subject.birthdate_part(birthdate, male)[2].should == 'X' }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'the last 2 character' do
|
81
|
+
context 'gender is male' do
|
82
|
+
it('is the birth day') { subject.birthdate_part(birthdate, male)[3..5].should == '03' }
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'gender is female' do
|
86
|
+
it('is the birth day + 40') { subject.birthdate_part(birthdate, female)[3..5].should == '43' }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
describe '#city_code' do
|
93
|
+
context 'the city and the provice are founded' do
|
94
|
+
it 'return the associated code' do
|
95
|
+
subject.city_code('Abbadia Lariana', 'LC').should == 'A005'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'the city and the provice are not founded' do
|
100
|
+
it 'return nil' do
|
101
|
+
subject.city_code('Winterfell', 'SO').should be_nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'a block is configured to be called' do
|
106
|
+
before { subject.config.city_code { "foo" } }
|
107
|
+
|
108
|
+
it 'return the result of the block execution' do
|
109
|
+
subject.city_code('Lecco', 'LC').should == 'foo'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
describe '#country_code' do
|
116
|
+
context 'the country is founded' do
|
117
|
+
it 'return the associated code' do
|
118
|
+
subject.country_code('francia').should == 'Z110'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'a block is configured to be called' do
|
123
|
+
before { subject.config.country_code { "bar" } }
|
124
|
+
|
125
|
+
it 'return the result of the block execution' do
|
126
|
+
subject.country_code('francia').should == 'bar'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
describe '#birthplace_part' do
|
133
|
+
before do
|
134
|
+
subject.config.country_code = nil
|
135
|
+
subject.config.city_code = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'the country is Italy' do
|
139
|
+
it 'return the city_code' do
|
140
|
+
subject.birthplace_part('Italia', 'Abbadia Lariana', 'LC').should == 'A005'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
describe '#check_character' do
|
147
|
+
it 'call #Codes.check_character and return its result' do
|
148
|
+
subject::Codes.should_receive :check_character
|
149
|
+
subject.check_character 'ABC'
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'call #Codes.odd_character for odd positioned chars' do
|
153
|
+
subject::Codes.should_receive(:odd_character).exactly(2).and_return 1
|
154
|
+
subject.check_character 'ABC'
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'call #Codes.even_character for odd positioned chars' do
|
158
|
+
subject::Codes.should_receive(:even_character).exactly(1).and_return 1
|
159
|
+
subject.check_character 'ABC'
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'works!' do
|
163
|
+
subject.check_character('RSSMRA87A01A005').should == 'V'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
describe '#calculate' do
|
169
|
+
context 'italian citizen' do
|
170
|
+
it 'return the expected code' do
|
171
|
+
params = ['mario', 'rossi', :male, Date.new(1987, 1, 1), 'italia', 'lc', 'Abbadia Lariana']
|
172
|
+
subject.calculate(*params).should == 'RSSMRA87A01A005V'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'return the expected code' do
|
177
|
+
it 'work' do
|
178
|
+
params = ['mario', 'rossi', :male, Date.new(1987, 1, 1), 'Albania']
|
179
|
+
subject.calculate(*params).should == 'RSSMRA87A01Z100H'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codice-fiscale
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniele Molteni
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: guard-rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rb-fsevent
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.1
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: growl
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Calculate the italian fiscal code
|
79
|
+
email:
|
80
|
+
- dani.m.mobile@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- Guardfile
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- codice_fiscale.gemspec
|
92
|
+
- lib/codice_fiscale.rb
|
93
|
+
- lib/codice_fiscale/alphabet.rb
|
94
|
+
- lib/codice_fiscale/codes.rb
|
95
|
+
- lib/codice_fiscale/codes/city_codes.csv
|
96
|
+
- lib/codice_fiscale/codes/country_codes.csv
|
97
|
+
- lib/codice_fiscale/configuration.rb
|
98
|
+
- lib/codice_fiscale/version.rb
|
99
|
+
- spec/fixtures/city_codes.csv
|
100
|
+
- spec/fixtures/country_codes.csv
|
101
|
+
- spec/lib/codice_fiscale/alphabet_spec.rb
|
102
|
+
- spec/lib/codice_fiscale/codes_spec.rb
|
103
|
+
- spec/lib/codice_fiscale_spec.rb
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
homepage: https://github.com/daniele-m/codice_fiscale
|
106
|
+
licenses: []
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Calculate the italian fiscal code
|
129
|
+
test_files:
|
130
|
+
- spec/fixtures/city_codes.csv
|
131
|
+
- spec/fixtures/country_codes.csv
|
132
|
+
- spec/lib/codice_fiscale/alphabet_spec.rb
|
133
|
+
- spec/lib/codice_fiscale/codes_spec.rb
|
134
|
+
- spec/lib/codice_fiscale_spec.rb
|
135
|
+
- spec/spec_helper.rb
|