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.
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodiceFiscale
4
+ VERSION = "0.1.0"
5
+ 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
@@ -0,0 +1,4 @@
1
+ module CodiceFiscale
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ 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: []