codicefiscale_ruby 0.1.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/.rspec +1 -0
- data/.rubocop.yml +16 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +35 -0
- data/Rakefile +8 -0
- data/codice_fiscale.gemspec +40 -0
- data/lib/codice_fiscale/data/places.json +39998 -0
- data/lib/codice_fiscale/generator.rb +94 -0
- data/lib/codice_fiscale/place_lookup.rb +21 -0
- data/lib/codice_fiscale/validator.rb +15 -0
- data/lib/codice_fiscale/version.rb +5 -0
- data/lib/codice_fiscale.rb +44 -0
- data/sig/codice_fiscale.rbs +4 -0
- metadata +63 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module CodiceFiscale
|
|
6
|
+
# Generator class to create Italian and foreign Codice Fiscale codes
|
|
7
|
+
# based on personal information such as name, date of birth, gender,
|
|
8
|
+
# and place of birth.
|
|
9
|
+
class Generator
|
|
10
|
+
MONTH_CODES = {
|
|
11
|
+
1 => "A", 2 => "B", 3 => "C", 4 => "D", 5 => "E", 6 => "H",
|
|
12
|
+
7 => "L", 8 => "M", 9 => "P", 10 => "R", 11 => "S", 12 => "T"
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
ODD_TABLE = {
|
|
16
|
+
"0" => 1, "1" => 0, "2" => 5, "3" => 7, "4" => 9,
|
|
17
|
+
"5" => 13, "6" => 15, "7" => 17, "8" => 19, "9" => 21,
|
|
18
|
+
"A" => 1, "B" => 0, "C" => 5, "D" => 7, "E" => 9,
|
|
19
|
+
"F" => 13, "G" => 15, "H" => 17, "I" => 19, "J" => 21,
|
|
20
|
+
"K" => 2, "L" => 4, "M" => 18, "N" => 20, "O" => 11,
|
|
21
|
+
"P" => 3, "Q" => 6, "R" => 8, "S" => 12, "T" => 14,
|
|
22
|
+
"U" => 16, "V" => 10, "W" => 22, "X" => 25, "Y" => 24, "Z" => 23
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
EVEN_TABLE = {
|
|
26
|
+
"0" => 0, "1" => 1, "2" => 2, "3" => 3, "4" => 4,
|
|
27
|
+
"5" => 5, "6" => 6, "7" => 7, "8" => 8, "9" => 9,
|
|
28
|
+
"A" => 0, "B" => 1, "C" => 2, "D" => 3, "E" => 4,
|
|
29
|
+
"F" => 5, "G" => 6, "H" => 7, "I" => 8, "J" => 9,
|
|
30
|
+
"K" => 10, "L" => 11, "M" => 12, "N" => 13, "O" => 14,
|
|
31
|
+
"P" => 15, "Q" => 16, "R" => 17, "S" => 18, "T" => 19,
|
|
32
|
+
"U" => 20, "V" => 21, "W" => 22, "X" => 23, "Y" => 24, "Z" => 25
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
def initialize(params)
|
|
36
|
+
@first_name = params[:first_name].upcase.strip
|
|
37
|
+
@last_name = params[:last_name].upcase.strip
|
|
38
|
+
@gender = params[:gender].upcase.strip
|
|
39
|
+
@date_of_birth = params[:date_of_birth]
|
|
40
|
+
@place_of_birth = params[:place_of_birth].upcase.strip
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def generate
|
|
44
|
+
cf = surname_code + name_code + date_code + place_code
|
|
45
|
+
cf + control_character(cf)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def formatted
|
|
49
|
+
raw = generate
|
|
50
|
+
"#{raw[0, 3]} #{raw[3, 3]} #{raw[6, 5]} #{raw[11, 4]} #{raw[15]}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def surname_code
|
|
56
|
+
code_letters(@last_name)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def name_code
|
|
60
|
+
consonants = @first_name.gsub(/[^BCDFGHJKLMNPQRSTVWXYZ]/, "").chars
|
|
61
|
+
vowels = @first_name.gsub(/[^AEIOU]/, "").chars
|
|
62
|
+
letters = consonants.size >= 4 ? consonants[0] + consonants[2] + consonants[3] : consonants.join
|
|
63
|
+
(letters + vowels.join)[0, 3].ljust(3, "X")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def code_letters(name)
|
|
67
|
+
consonants = name.gsub(/[^BCDFGHJKLMNPQRSTVWXYZ]/, "")
|
|
68
|
+
vowels = name.gsub(/[^AEIOU]/, "")
|
|
69
|
+
(consonants + vowels)[0, 3].ljust(3, "X")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def date_code
|
|
73
|
+
year = @date_of_birth.year.to_s[-2..]
|
|
74
|
+
month = MONTH_CODES[@date_of_birth.month]
|
|
75
|
+
day = @gender == "F" ? (@date_of_birth.day + 40).to_s.rjust(2, "0") : @date_of_birth.day.to_s.rjust(2, "0")
|
|
76
|
+
"#{year}#{month}#{day}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def place_code
|
|
80
|
+
code = CodiceFiscale::PlaceLookup.find(@place_of_birth)
|
|
81
|
+
raise CodiceFiscale::Error, "Unknown place #{@place_of_birth}" unless code
|
|
82
|
+
|
|
83
|
+
code
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Computes the control character of a CF
|
|
87
|
+
def control_character(cf_first)
|
|
88
|
+
total = cf_first.chars.each_with_index.reduce(0) do |sum, (c, idx)|
|
|
89
|
+
sum + (idx.even? ? ODD_TABLE[c] : EVEN_TABLE[c])
|
|
90
|
+
end
|
|
91
|
+
("A".ord + (total % 26)).chr
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module CodiceFiscale
|
|
6
|
+
# Module to look up Italian and foreign place codes for CF generation
|
|
7
|
+
module PlaceLookup
|
|
8
|
+
DATA_PATH = File.join(__dir__, "data", "places.json")
|
|
9
|
+
PLACE_DATA = JSON.parse(File.read(DATA_PATH)).freeze
|
|
10
|
+
|
|
11
|
+
def self.find(str)
|
|
12
|
+
return nil if str.nil? || str.strip.empty?
|
|
13
|
+
|
|
14
|
+
normalized = str.upcase.strip
|
|
15
|
+
place = PLACE_DATA.find do |p|
|
|
16
|
+
p["name"].upcase == normalized || p["code"].upcase == normalized
|
|
17
|
+
end
|
|
18
|
+
place&.dig("code")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodiceFiscale
|
|
4
|
+
# Validator for Codice Fiscale codes
|
|
5
|
+
class Validator
|
|
6
|
+
# Returns true if the CF code is valid, false otherwise
|
|
7
|
+
def self.valid?(_code)
|
|
8
|
+
# Replace the following line with your actual validation logic
|
|
9
|
+
# For example, you might call: CodiceFiscale::Generator.validate(_code)
|
|
10
|
+
false
|
|
11
|
+
rescue StandardError
|
|
12
|
+
false
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "codice_fiscale/version"
|
|
4
|
+
require_relative "codice_fiscale/place_lookup"
|
|
5
|
+
require_relative "codice_fiscale/generator"
|
|
6
|
+
require_relative "codice_fiscale/validator"
|
|
7
|
+
|
|
8
|
+
module CodiceFiscale
|
|
9
|
+
# Generator class to create Italian and foreign Codice Fiscale codes
|
|
10
|
+
# using personal information like first name, last name, date of birth,
|
|
11
|
+
# gender, and place of birth.
|
|
12
|
+
class Generator
|
|
13
|
+
class Error < StandardError; end
|
|
14
|
+
|
|
15
|
+
# Store generated CFs in memory (hash)
|
|
16
|
+
@generated_cfs = {}
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Generate CF and store it
|
|
20
|
+
def generate(params)
|
|
21
|
+
cf = Generator.new(params).generate
|
|
22
|
+
# Key can be anything, e.g., user's full name or a unique ID
|
|
23
|
+
key = "#{params[:first_name].upcase}-#{params[:last_name].upcase}-#{params[:date_of_birth]}"
|
|
24
|
+
@generated_cfs[key] = cf
|
|
25
|
+
cf
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get all stored CFs
|
|
29
|
+
def all_generated
|
|
30
|
+
@generated_cfs
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Validate CF against stored ones
|
|
34
|
+
def validate(code)
|
|
35
|
+
@generated_cfs.value?(code)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Formatted CF
|
|
39
|
+
def formatted(params)
|
|
40
|
+
Generator.new(params).formatted
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: codicefiscale_ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Amshu Pokharel
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-01-13 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: |
|
|
14
|
+
A Ruby gem to generate Codice Fiscale for Italian and foreign individuals
|
|
15
|
+
and validate given CF codes.
|
|
16
|
+
email:
|
|
17
|
+
- pokharelamshu@gmail.com
|
|
18
|
+
executables: []
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- ".rspec"
|
|
23
|
+
- ".rubocop.yml"
|
|
24
|
+
- CHANGELOG.md
|
|
25
|
+
- LICENSE.txt
|
|
26
|
+
- README.md
|
|
27
|
+
- Rakefile
|
|
28
|
+
- codice_fiscale.gemspec
|
|
29
|
+
- lib/codice_fiscale.rb
|
|
30
|
+
- lib/codice_fiscale/data/places.json
|
|
31
|
+
- lib/codice_fiscale/generator.rb
|
|
32
|
+
- lib/codice_fiscale/place_lookup.rb
|
|
33
|
+
- lib/codice_fiscale/validator.rb
|
|
34
|
+
- lib/codice_fiscale/version.rb
|
|
35
|
+
- sig/codice_fiscale.rbs
|
|
36
|
+
homepage: https://github.com/udira-re/codice-fiscale
|
|
37
|
+
licenses:
|
|
38
|
+
- MIT
|
|
39
|
+
metadata:
|
|
40
|
+
allowed_push_host: https://rubygems.org
|
|
41
|
+
homepage_uri: https://github.com/udira-re/codice-fiscale
|
|
42
|
+
source_code_uri: https://github.com/udira-re/CF-gem-.git
|
|
43
|
+
changelog_uri: https://github.com/udira-re/codice-fiscale/blob/main/CHANGELOG.md
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: 2.6.0
|
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0'
|
|
58
|
+
requirements: []
|
|
59
|
+
rubygems_version: 3.4.10
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: Generate and validate Italian and foreign Codice Fiscale
|
|
63
|
+
test_files: []
|