curp_generator 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a65ed003039b6871fef8ca8eca44a529706baf765010619457d8955d58ad032
4
+ data.tar.gz: 184facb4300807434ad265dd068b1924e2ad884c29333839564efa2e79be8d9c
5
+ SHA512:
6
+ metadata.gz: a3d031d50701c6554cdc9f7c024e472157c27d58d1d8c42f4ccc60399b3a4b4b824ef144a26ebf9fa56eca25c4aae41d2120d98b0b5e8fd26fe6a93dcc8a3283
7
+ data.tar.gz: c6647a39d66e0445feb5f1e0ccaf8508387f075916ce560750490e986d412976e5a3367bf821a9ac8103e65f0fbb611dbde2a9bccd63b7a1b37390b08ee48e75
@@ -0,0 +1,156 @@
1
+ module CurpGenerator::Catalogs
2
+ VALID_CHARACTERS = '0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ'.freeze
3
+
4
+ STATES = {
5
+ 'AGUASCALIENTES' => 'AS',
6
+ 'BAJA CALIFORNIA NORTE' => 'BC',
7
+ 'BAJA CALIFORNIA SUR' => 'BS',
8
+ 'CAMPECHE' => 'CC',
9
+ 'CHIAPAS' => 'CS',
10
+ 'CHIHUAHUA' => 'CH',
11
+ 'CIUDAD DE MEXICO' => 'DF',
12
+ 'COAHUILA' => 'CL',
13
+ 'COLIMA' => 'CM',
14
+ 'DURANGO' => 'DG',
15
+ 'GUANAJUATO' => 'GT',
16
+ 'GUERRERO' => 'GR',
17
+ 'HIDALGO' => 'HG',
18
+ 'JALISCO' => 'JC',
19
+ 'MEXICO' => 'MC',
20
+ 'MICHOACAN' => 'MN',
21
+ 'MORELOS' => 'MS',
22
+ 'NAYARIT' => 'NT',
23
+ 'NUEVO LEON' => 'NL',
24
+ 'OAXACA' => 'OC',
25
+ 'PUEBLA' => 'PL',
26
+ 'QUERETARO' => 'QT',
27
+ 'QUINTANA ROO' => 'QR',
28
+ 'SAN LUIS POTOSI' => 'SP',
29
+ 'SINALOA' => 'SL',
30
+ 'SONORA' => 'SR',
31
+ 'TABASCO' => 'TC',
32
+ 'TAMAULIPAS' => 'TS',
33
+ 'TLAXCALA' => 'TL',
34
+ 'VERACRUZ' => 'VZ',
35
+ 'YUCATAN' => 'YN',
36
+ 'ZACATECAS' => 'ZS'
37
+ }.freeze
38
+
39
+ FORBIDDEN_WORDS = {
40
+ 'BACA' => 'BXCA',
41
+ 'LOCO' => 'LXCO',
42
+ 'BAKA' => 'BXKA',
43
+ 'BUEI' => 'BXEI',
44
+ 'BUEY' => 'BXEY',
45
+ 'CACA' => 'CXCA',
46
+ 'CACO' => 'CXCO',
47
+ 'CAGA' => 'CXGA',
48
+ 'CAGO' => 'CXGO',
49
+ 'CAKA' => 'CXKA',
50
+ 'CAKO' => 'CXKO',
51
+ 'COGE' => 'CXGE',
52
+ 'COGI' => 'CXGI',
53
+ 'COJA' => 'CXJA',
54
+ 'COJE' => 'CXJE',
55
+ 'COJI' => 'CXJI',
56
+ 'COJO' => 'CXJO',
57
+ 'COLA' => 'CXLA',
58
+ 'CULO' => 'CXLO',
59
+ 'FALO' => 'FXLO',
60
+ 'FETO' => 'FXTO',
61
+ 'GETA' => 'GXTA',
62
+ 'GUEI' => 'GXEI',
63
+ 'GUEY' => 'GXEY',
64
+ 'JETA' => 'JXTA',
65
+ 'JOTO' => 'JXTO',
66
+ 'KACA' => 'KXCA',
67
+ 'KACO' => 'KXCO',
68
+ 'KAGA' => 'KXGA',
69
+ 'KAGO' => 'KXGO',
70
+ 'KAKA' => 'KXKA',
71
+ 'KAKO' => 'KXKO',
72
+ 'KOGE' => 'KXGE',
73
+ 'KOGI' => 'KXGI',
74
+ 'KOJA' => 'KXJA',
75
+ 'KOJE' => 'KXJE',
76
+ 'KOJI' => 'KXJI',
77
+ 'KOJO' => 'KXJO',
78
+ 'KOLA' => 'KXLA',
79
+ 'KULO' => 'KXLO',
80
+ 'LILO' => 'LXLO',
81
+ 'LOKA' => 'LXKA',
82
+ 'LOKO' => 'LXKO',
83
+ 'MAME' => 'MXME',
84
+ 'MAMO' => 'MXMO',
85
+ 'MEAR' => 'MXAR',
86
+ 'MEAS' => 'MXAS',
87
+ 'MEON' => 'MXON',
88
+ 'MIAR' => 'MXAR',
89
+ 'MION' => 'MXON',
90
+ 'MOCO' => 'MXCO',
91
+ 'MOKO' => 'MXKO',
92
+ 'MULA' => 'MXLA',
93
+ 'MULO' => 'MXLO',
94
+ 'NACA' => 'NXCA',
95
+ 'NACO' => 'NXCO',
96
+ 'PEDA' => 'PXDA',
97
+ 'PEDO' => 'PXDO',
98
+ 'PENE' => 'PXNE',
99
+ 'PIPI' => 'PXPI',
100
+ 'PITO' => 'PXTO',
101
+ 'POPO' => 'PXPO',
102
+ 'PUTA' => 'PXTA',
103
+ 'PUTO' => 'PXTO',
104
+ 'QULO' => 'QXLO',
105
+ 'RATA' => 'RXTA',
106
+ 'ROBA' => 'RXBA',
107
+ 'ROBE' => 'RXBE',
108
+ 'ROBO' => 'RXBO',
109
+ 'RUIN' => 'RXIN',
110
+ 'SENO' => 'SXNO',
111
+ 'TETA' => 'TXTA',
112
+ 'VACA' => 'VXCA',
113
+ 'VAGA' => 'VXGA',
114
+ 'VAGO' => 'VXGO',
115
+ 'VAKA' => 'VXKA',
116
+ 'VUEI' => 'VXEI',
117
+ 'VUEY' => 'VXEY',
118
+ 'WUEI' => 'WXEI',
119
+ 'WUEY' => 'WXEY'
120
+ }.freeze
121
+
122
+ COMMON_NAMES = [
123
+ 'MARIA DEL',
124
+ 'MARIA DE LOS',
125
+ 'MARIA',
126
+ 'JOSE DE',
127
+ 'JOSE',
128
+ 'MA.',
129
+ 'MA',
130
+ 'M.',
131
+ 'J.',
132
+ 'J'
133
+ ].freeze
134
+
135
+ COMPOSED_NAMES = [
136
+ 'DA ',
137
+ 'DAS ',
138
+ 'DE ',
139
+ 'DEL ',
140
+ 'DER ',
141
+ 'DI ',
142
+ 'DIE ',
143
+ 'DD ',
144
+ 'EL ',
145
+ 'LA ',
146
+ 'LOS ',
147
+ 'LAS ',
148
+ 'LE ',
149
+ 'LES ',
150
+ 'MAC ',
151
+ 'MC ',
152
+ 'VAN ',
153
+ 'VON ',
154
+ 'Y '
155
+ ].freeze
156
+ end
@@ -0,0 +1,98 @@
1
+ require 'version'
2
+ require 'catalogs'
3
+ require 'element'
4
+ require 'helpers'
5
+
6
+ class CurpGenerator::Curp
7
+ include CurpGenerator::Catalogs
8
+ include CurpGenerator::Helpers
9
+
10
+ MissingParamError = Class.new(StandardError)
11
+
12
+ PARAMS_TO_VALIDATE = %w(
13
+ first_last_name
14
+ first_name
15
+ birth_date
16
+ birth_state
17
+ gender
18
+ ).freeze
19
+
20
+ def initialize(data = {})
21
+ @first_name = data.dig(:first_name)
22
+ @second_name = data.dig(:second_name)
23
+ @first_last_name = parse_attribute(data.dig(:first_last_name))
24
+ @second_last_name = parse_attribute(data.dig(:second_last_name)) || ''
25
+ @birth_date = data.dig(:birth_date)
26
+ @birth_state = parse_attribute(data.dig(:birth_state))
27
+ @gender = data.dig(:gender)
28
+ end
29
+
30
+ def generate
31
+ validate_params
32
+
33
+ prefix = partial_curp
34
+ prefix + verifying_digit(prefix)
35
+ end
36
+
37
+ private
38
+
39
+ def validate_params
40
+ PARAMS_TO_VALIDATE.each do |param|
41
+ raise MissingParamError, "Missing #{param}" if blank_string?(instance_variable_get("@#{param}"))
42
+ end
43
+ end
44
+
45
+ def partial_curp
46
+ validate_first_four_curp_digits +
47
+ parse_date(@birth_date, "%y") +
48
+ parse_date(@birth_date, "%m") +
49
+ parse_date(@birth_date, "%d") +
50
+ gender_character +
51
+ state_code +
52
+ first_last_name_element.next_consonant +
53
+ second_last_name_element.next_consonant +
54
+ first_name_element.next_consonant +
55
+ homoclave_digit
56
+ end
57
+
58
+ def validate_first_four_curp_digits
59
+ FORBIDDEN_WORDS.dig(first_four_curp_digits) || first_four_curp_digits
60
+ end
61
+
62
+ def gender_character
63
+ @gender == 'male' ? 'H' : 'M'
64
+ end
65
+
66
+ def state_code
67
+ STATES.dig(@birth_state.upcase) || 'NE'
68
+ end
69
+
70
+ def homoclave_digit
71
+ @birth_date.year < 2000 ? '0' : 'A'
72
+ end
73
+
74
+ def first_four_curp_digits
75
+ @first_four_curp_digits ||=
76
+ first_last_name_element.first_character +
77
+ first_last_name_element.next_vowel +
78
+ second_last_name_element.first_character +
79
+ first_name_element.first_character
80
+ end
81
+
82
+ def first_last_name_element
83
+ @first_last_name_element ||= CurpGenerator::Element.new(@first_last_name)
84
+ end
85
+
86
+ def second_last_name_element
87
+ @second_last_name_element ||= CurpGenerator::Element.new(@second_last_name)
88
+ end
89
+
90
+ def first_name_element
91
+ @first_name_element ||= CurpGenerator::Element.new(validate_first_name)
92
+ end
93
+
94
+ def validate_first_name
95
+ name = parse_attribute(@first_name)
96
+ COMMON_NAMES.include?(name) ? @second_name : name
97
+ end
98
+ end
@@ -0,0 +1 @@
1
+ require 'curp'
@@ -0,0 +1,45 @@
1
+ require 'helpers'
2
+ require 'string_format'
3
+
4
+ class CurpGenerator::Element
5
+ include CurpGenerator::Helpers
6
+
7
+ attr_accessor :name, :consonant_index, :vowel_index
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ @consonant_index = 0
12
+ @vowel_index = 0
13
+ end
14
+
15
+ def first_character
16
+ return 'X' if blank_string?(name)
17
+
18
+ character = name[0].upcase
19
+ update_next_index_attribute(character)
20
+ character == 'Ñ' ? 'X' : character
21
+ end
22
+
23
+ def next_consonant
24
+ return 'X' if blank_string?(name)
25
+
26
+ consonants = CurpGenerator::StringFormat.new(name).remove_vowels.upcase
27
+ consonants.size < 2 ? consonants[0] : consonants[consonant_index]
28
+ end
29
+
30
+ def next_vowel
31
+ return 'X' if blank_string?(name)
32
+
33
+ consonants = CurpGenerator::StringFormat.new(name).remove_consonants.upcase
34
+ consonants.size < 2 ? 'X' : consonants[vowel_index]
35
+ end
36
+
37
+ private
38
+
39
+ def update_next_index_attribute(character)
40
+ new_consonant_value = CurpGenerator::StringFormat.new(character).consonant? ? 1 : 0
41
+ new_vowel_value = CurpGenerator::StringFormat.new(character).vowel? ? 1 : 0
42
+ self.consonant_index = new_consonant_value
43
+ self.vowel_index = new_vowel_value
44
+ end
45
+ end
@@ -0,0 +1,41 @@
1
+ require 'date'
2
+ require 'catalogs'
3
+ require 'string_format'
4
+
5
+ module CurpGenerator::Helpers
6
+ include CurpGenerator::Catalogs
7
+
8
+ def verifying_digit(partial_curp)
9
+ length_sum = 0.0
10
+
11
+ partial_curp.split('').each_with_index do |character, index|
12
+ length_sum += VALID_CHARACTERS.index(character) * (18 - index)
13
+ end
14
+
15
+ last_digit = 10 - (length_sum % 10)
16
+ last_digit == 10 ? '0' : last_digit.to_i.to_s
17
+ end
18
+
19
+ def remove_composed_names(name)
20
+ name = name.upcase
21
+
22
+ COMPOSED_NAMES.each do |composed|
23
+ next unless name.include?(composed)
24
+ name = name.gsub(composed, '')
25
+ end
26
+ name
27
+ end
28
+
29
+ def parse_attribute(attribute)
30
+ return if blank_string?(attribute)
31
+ CurpGenerator::StringFormat.new(remove_composed_names(attribute)).str
32
+ end
33
+
34
+ def parse_date(date, format)
35
+ date.strftime(format)
36
+ end
37
+
38
+ def blank_string?(value)
39
+ value.to_s.strip.empty?
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CurpGenerator::StringFormat
4
+
5
+ attr_accessor :str
6
+
7
+ def initialize(str)
8
+ @str = remove_special_chars(normalize(str.strip))
9
+ end
10
+
11
+ def remove_vowels
12
+ str.downcase.tr('aeiou', '')
13
+ end
14
+
15
+ def remove_consonants
16
+ str.downcase.tr('^aeiou', '')
17
+ end
18
+
19
+ def vowel?
20
+ %w(A E I O U).include?(str.upcase)
21
+ end
22
+
23
+ def consonant?
24
+ !vowel?
25
+ end
26
+
27
+ def first_vowel
28
+ str.downcase.match(/a|e|i|o|u/).to_s.upcase
29
+ end
30
+
31
+ private
32
+
33
+ def normalize(string)
34
+ string&.tr(
35
+ "ÀàÁáÄäÈèÉéËëÌìÍíÏïÒòÓóÖöÙùÚúÜüÑñ",
36
+ "AaAaAaEeEeEeIiIiIiOoOoOoUuUuUuNn"
37
+ )
38
+ end
39
+
40
+ def remove_special_chars(string)
41
+ string&.gsub(/[\.\'\d-]/, "")
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ module CurpGenerator
2
+ VERSION = '1.0.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: curp_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Juan Carlos Estebes
8
+ - Manuel de la Torre
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-11-03 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description:
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/catalogs.rb
21
+ - lib/curp.rb
22
+ - lib/curp_generator.rb
23
+ - lib/element.rb
24
+ - lib/helpers.rb
25
+ - lib/string_format.rb
26
+ - lib/version.rb
27
+ homepage: https://github.com/yotepresto-com/curp-generator
28
+ licenses:
29
+ - MIT
30
+ metadata:
31
+ homepage_uri: https://github.com/yotepresto-com/curp-generator
32
+ source_code_uri: https://github.com/yotepresto-com/curp-generator
33
+ changelog_uri: https://github.com/yotepresto-com/curp-generator/CHANGELOG.md
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '2.6'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.0.6
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Generates a mexican CURP given the information of a person
53
+ test_files: []