identificamex 0.0.2 → 0.0.3
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 +4 -4
- data/.travis.yml +3 -0
- data/README.md +47 -5
- data/Rakefile +1 -1
- data/lib/identificamex.rb +26 -1
- data/lib/identificamex/nombre/mayusculas.rb +35 -0
- data/lib/identificamex/nombre/nombre_completo.rb +96 -0
- data/lib/identificamex/nombre/normalizador_apellido.rb +30 -0
- data/lib/identificamex/nombre/normalizador_cadena.rb +47 -0
- data/lib/identificamex/nombre/normalizador_nombre.rb +42 -0
- data/lib/identificamex/nombre/palabra_inconveniente.rb +55 -0
- data/lib/identificamex/nombre/razon_social.rb +92 -0
- data/lib/identificamex/rfc/homoclave.rb +209 -0
- data/lib/identificamex/rfc/rfc_base.rb +32 -0
- data/lib/identificamex/rfc/rfc_generator.rb +95 -0
- data/lib/identificamex/version.rb +1 -1
- data/lib/rfc_format_validator.rb +2 -2
- data/test/identificamex/methods_validator_test.rb +35 -0
- data/test/identificamex/nombre/nombre_completo_test.rb +64 -0
- data/test/identificamex/nombre/normalizador_apellido_test.rb +30 -0
- data/test/identificamex/nombre/normalizador_nombre_test.rb +62 -0
- data/test/identificamex/nombre/razon_social_test.rb +68 -0
- data/test/identificamex/rfc/homoclave_test.rb +24 -0
- data/test/identificamex/rfc/rfc_base_test.rb +24 -0
- data/test/identificamex/rfc/rfc_generator_test.rb +170 -0
- data/test/identificamex/rfc_format_validator_test.rb +4 -4
- data/test/test_helper.rb +7 -1
- metadata +30 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65fa3e6fd8638d2aa972815f35ed94ba3df0424b
|
4
|
+
data.tar.gz: 71497ea86147ae06abeaf84624dc081557771612
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56f512d4a89955f1b52e70a561f54463815a705e257fd60401a2f91515fdb5a03ce71426c3a23bcfc5133b8f88cb9a41c28b561a5f14f9f170b3c32759dd9088
|
7
|
+
data.tar.gz: c9896b42a2261fd5bd3bfc3ed4a1913fe8f2fe91807ebe2227de77c59246995d026551d27aef551afc3ade2c9f324e1e9d702ba8de3e296e91a1691e7b846abf
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
[](https://travis-ci.org/LogicalBricks/identificamex)
|
2
|
+
|
3
|
+
|
1
4
|
# Identificamex
|
2
5
|
|
3
|
-
Gema con validadores para los formatos de la Clave Única de Registro de
|
4
|
-
|
6
|
+
Gema con validadores para los formatos de la Clave Única de Registro de
|
7
|
+
Población (CURP) y el Registro Federal de Contribuyentes (RFC) utilizados en
|
8
|
+
México.
|
9
|
+
|
10
|
+
Los validadores se integran con el mecanismo que implementa ActiveModel
|
11
|
+
para el resto de validadores de Rails.
|
5
12
|
|
6
13
|
## Instalación
|
7
14
|
|
@@ -21,14 +28,49 @@ O instálala por ti mismo de esta manera:
|
|
21
28
|
|
22
29
|
Agrega las validaciones de formato a los campos correspondientes.
|
23
30
|
|
24
|
-
|
25
31
|
```ruby
|
26
|
-
class Employee <
|
32
|
+
class Employee < ActiveRecord::Base
|
27
33
|
validates :curp, presence: true, curp_format: true
|
28
|
-
validates :rfc, rfc_format: true, allow_blank: true
|
34
|
+
validates :rfc, rfc_format: { force_homoclave: true }, allow_blank: true
|
29
35
|
end
|
30
36
|
```
|
31
37
|
|
38
|
+
### valid_rfc?
|
39
|
+
|
40
|
+
En el caso del RFC, es posible verificar no sólo el formato sino también el
|
41
|
+
contenido. Para esto, se debe utilizar el método `valid_rfc?`. Este método se
|
42
|
+
encuentra en el módulo `Identificamex::Methods` y no se agrega
|
43
|
+
automáticamente a la base de ActiveRecord o ActiveModel, por lo que es
|
44
|
+
necesario agregarlo manualmente.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class Employee < ActiveRecord::Base
|
48
|
+
|
49
|
+
include Identificamex::Methods
|
50
|
+
|
51
|
+
def un_metodo
|
52
|
+
valid_rfc? 'BAFJ701213SBA', nombre: 'Juan',
|
53
|
+
primer_apellido: 'Barrios',
|
54
|
+
segundo_apellido: 'Fernández',
|
55
|
+
fecha_nacimiento: Date.new(1970, 12, 13)
|
56
|
+
|
57
|
+
valid_rfc? 'APB830305QS6', razon_social: 'U.S. Ruber Mexicana, S.A.',
|
58
|
+
fecha_creacion: Date.new(1983, 03, 05)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
NOTA: _Esta versión todavía no valida correctamente el RFC de personas
|
64
|
+
morales que incluyan números o caracteres especiales en su razón social.
|
65
|
+
Por ejemplo: 'Cyber @ SA de CV', 'Cooperativa 5 de mayo SC',
|
66
|
+
'Estudio Siglo XXI SA'. Es una funcionalidad que se piensa incluir
|
67
|
+
posteriormente, al igual que la generación de la CURP_
|
68
|
+
|
69
|
+
El método `valid_rfc?` es auxiliar y ha funcionado con los casos que he
|
70
|
+
probado, pero no hay garantía que funcione en todos los casos, así que debe
|
71
|
+
usarse con precaución. Si detectas algún caso en el que no funciona, agrega
|
72
|
+
un _issue_ para corregirlo.
|
73
|
+
|
32
74
|
## Contribución
|
33
75
|
|
34
76
|
1. Haz un fork de este repositorio
|
data/Rakefile
CHANGED
data/lib/identificamex.rb
CHANGED
@@ -2,7 +2,32 @@ require 'active_model'
|
|
2
2
|
require_relative "identificamex/version"
|
3
3
|
require_relative "curp_format_validator"
|
4
4
|
require_relative "rfc_format_validator"
|
5
|
+
require_relative "identificamex/rfc/rfc_generator"
|
5
6
|
|
6
7
|
module Identificamex
|
7
|
-
|
8
|
+
module Methods
|
9
|
+
|
10
|
+
# Valida si un RFC está correctamente formado. Recibe como parámetros el
|
11
|
+
# RFC a comparar y la razón social y fecha de creación (en caso de ser
|
12
|
+
# persona moral) o el nombre, primer apellido, segundo apellido y fecha
|
13
|
+
# de nacimiento (en caso de ser persona física).
|
14
|
+
#
|
15
|
+
# Ejemplos:
|
16
|
+
#
|
17
|
+
# params = { razon_social: 'Sonora Industrial Azucarera, S. de R.L',
|
18
|
+
# fecha_creacion: Date.new(1983, 03, 05) }
|
19
|
+
# valid_rfc? 'SIA8303054L5', params
|
20
|
+
# # => true
|
21
|
+
#
|
22
|
+
# params = { nombre: 'Juan',
|
23
|
+
# primer_apellido: 'Barrios',
|
24
|
+
# segundo_apellido: 'Fernández',
|
25
|
+
# fecha_nacimiento: Date.new(1970, 12, 13) }
|
26
|
+
# valid_rfc? 'BAFJ701213SBA', params
|
27
|
+
# # => true
|
28
|
+
#
|
29
|
+
def valid_rfc?(rfc, options)
|
30
|
+
::Identificamex::Rfc::RfcGenerator.new(options).rfc == rfc
|
31
|
+
end
|
32
|
+
end
|
8
33
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Identificamex
|
2
|
+
module Nombre
|
3
|
+
|
4
|
+
module Mayusculas
|
5
|
+
def mayusculas(str)
|
6
|
+
return if str.nil?
|
7
|
+
str
|
8
|
+
.gsub(/[ÁÉÍÓÚÜáéíóúü]/, hash_vocales)
|
9
|
+
.upcase
|
10
|
+
.gsub(/ñ/, 'Ñ')
|
11
|
+
.gsub(/,/, '')
|
12
|
+
.gsub(/'/, '')
|
13
|
+
.gsub(/\./, ' ')
|
14
|
+
.squeeze(' ')
|
15
|
+
.strip
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash_vocales
|
19
|
+
@hash_vocales ||= {'á' => 'a',
|
20
|
+
'é' => 'e',
|
21
|
+
'í' => 'i',
|
22
|
+
'ó' => 'o',
|
23
|
+
'ú' => 'u',
|
24
|
+
'ü' => 'u',
|
25
|
+
'Á' => 'A',
|
26
|
+
'É' => 'E',
|
27
|
+
'Í' => 'I',
|
28
|
+
'Ó' => 'O',
|
29
|
+
'Ú' => 'U',
|
30
|
+
'Ü' => 'U'}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative 'normalizador_nombre'
|
2
|
+
require_relative 'normalizador_apellido'
|
3
|
+
require_relative 'palabra_inconveniente'
|
4
|
+
|
5
|
+
module Identificamex
|
6
|
+
module Nombre
|
7
|
+
class NombreCompleto
|
8
|
+
include Mayusculas
|
9
|
+
|
10
|
+
def initialize(params)
|
11
|
+
@nombre = mayusculas(params[:nombre])
|
12
|
+
@primer_apellido = mayusculas(params[:primer_apellido])
|
13
|
+
@segundo_apellido = mayusculas(params[:segundo_apellido])
|
14
|
+
@nombre_simplificado = normalizar_nombre(@nombre)
|
15
|
+
@primer_apellido_simplificado = normalizar_apellido(@primer_apellido)
|
16
|
+
@segundo_apellido_simplificado = normalizar_apellido(@segundo_apellido)
|
17
|
+
end
|
18
|
+
|
19
|
+
def siglas
|
20
|
+
@siglas ||= PalabraInconveniente.convertir(extraer_siglas)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#{@primer_apellido} #{@segundo_apellido} #{@nombre}"
|
25
|
+
end
|
26
|
+
|
27
|
+
#=====================
|
28
|
+
private
|
29
|
+
#=====================
|
30
|
+
|
31
|
+
def normalizar_nombre(nombre)
|
32
|
+
NormalizadorNombre.new(nombre).normalizar if nombre
|
33
|
+
end
|
34
|
+
|
35
|
+
def normalizar_apellido(apellido)
|
36
|
+
NormalizadorApellido.new(apellido).normalizar if apellido
|
37
|
+
end
|
38
|
+
|
39
|
+
def extraer_siglas
|
40
|
+
if siglas_apellidos_completa?
|
41
|
+
siglas_apellidos + primera_letra_nombre
|
42
|
+
else
|
43
|
+
siglas_apellidos + primeras_dos_letras_nombre
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def siglas_apellidos
|
48
|
+
@siglas_apellidos ||= generar_siglas_apellidos
|
49
|
+
end
|
50
|
+
|
51
|
+
def siglas_apellidos_completa?
|
52
|
+
siglas_apellidos.length == 3
|
53
|
+
end
|
54
|
+
|
55
|
+
def generar_siglas_apellidos
|
56
|
+
return @segundo_apellido_simplificado[0, 2] if sin_primer_apellido?
|
57
|
+
return @primer_apellido_simplificado[0, 2] if sin_segundo_apellido?
|
58
|
+
primera_letra_primer_apellido +
|
59
|
+
primera_vocal_interna_primer_apellido.to_s +
|
60
|
+
primera_letra_segundo_apellido
|
61
|
+
end
|
62
|
+
|
63
|
+
def sin_primer_apellido?
|
64
|
+
@primer_apellido_simplificado.nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
def sin_segundo_apellido?
|
68
|
+
@segundo_apellido_simplificado.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def primera_letra_primer_apellido
|
72
|
+
@primer_apellido_simplificado[0] if @primer_apellido_simplificado.present?
|
73
|
+
end
|
74
|
+
|
75
|
+
def primera_vocal_interna_primer_apellido
|
76
|
+
return unless @primer_apellido_simplificado.present?
|
77
|
+
apellido = @primer_apellido_simplificado[1..-1]
|
78
|
+
posicion_primera_vocal = apellido =~ /[AEIOU]/
|
79
|
+
apellido[posicion_primera_vocal] if posicion_primera_vocal
|
80
|
+
end
|
81
|
+
|
82
|
+
def primera_letra_segundo_apellido
|
83
|
+
@segundo_apellido_simplificado[0] if @segundo_apellido_simplificado.present?
|
84
|
+
end
|
85
|
+
|
86
|
+
def primera_letra_nombre
|
87
|
+
@nombre_simplificado[0] if @nombre_simplificado.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def primeras_dos_letras_nombre
|
91
|
+
@nombre_simplificado[0, 2] if @nombre_simplificado.present?
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'normalizador_cadena'
|
2
|
+
|
3
|
+
module Identificamex
|
4
|
+
module Nombre
|
5
|
+
|
6
|
+
# Clase que hereda de `NormalizadorCadena` y define los nombres a ignorar
|
7
|
+
# como `%w[DE LA DEL LOS]` que son los únicos que se ignoran para los
|
8
|
+
# apellidos.
|
9
|
+
#
|
10
|
+
# Ejemplo:
|
11
|
+
#
|
12
|
+
# NormalizadorApellido.new('De la Rosa').normalizar
|
13
|
+
# # => ROSA
|
14
|
+
#
|
15
|
+
# NormalizadorApellido.new('Del Toro').normalizar
|
16
|
+
# # => TORO
|
17
|
+
#
|
18
|
+
# NormalizadorApellido.new('Pérez').normalizar
|
19
|
+
# # => PEREZ
|
20
|
+
class NormalizadorApellido < NormalizadorCadena
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def nombres_ignorados
|
25
|
+
%w[DE LA DEL LOS Y]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'mayusculas'
|
2
|
+
|
3
|
+
module Identificamex
|
4
|
+
module Nombre
|
5
|
+
|
6
|
+
# Clase base para normalizar las cadenas de nombres y apellidos. La clase
|
7
|
+
# se encarga de convertir a mayúsculas las cadenas y recorre los nombres para
|
8
|
+
# descartar los nombres ignorados.
|
9
|
+
#
|
10
|
+
# Los nombres ignorados deben ser provistos por las clases que hereden.
|
11
|
+
class NormalizadorCadena
|
12
|
+
|
13
|
+
include Mayusculas
|
14
|
+
|
15
|
+
def initialize(nombre)
|
16
|
+
@nombre = mayusculas(nombre)
|
17
|
+
end
|
18
|
+
|
19
|
+
def normalizar
|
20
|
+
nombre_aceptado || primer_nombre
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def nombre_aceptado
|
26
|
+
nombres.find{|nombre| no_ignorado?(nombre) } if nombres.count > 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def no_ignorado?(nombre)
|
30
|
+
!nombres_ignorados.member?(nombre)
|
31
|
+
end
|
32
|
+
|
33
|
+
def primer_nombre
|
34
|
+
nombres.first
|
35
|
+
end
|
36
|
+
|
37
|
+
def nombres_ignorados
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
def nombres
|
42
|
+
@nombres ||= @nombre.split
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'normalizador_cadena'
|
2
|
+
|
3
|
+
module Identificamex
|
4
|
+
module Nombre
|
5
|
+
|
6
|
+
# Clase que hereda de `NormalizadorCadena` y define los nombres a ignorar
|
7
|
+
# como `%w[JOSE MARIA DE LA DEL LOS]` que son los que se ignoran para los
|
8
|
+
# nombres.
|
9
|
+
#
|
10
|
+
# Ejemplo:
|
11
|
+
#
|
12
|
+
# NormalizadorNombre.new('María del Carmen').normalizar
|
13
|
+
# # => CARMEN
|
14
|
+
#
|
15
|
+
# NormalizadorNombre.new('José Mario').normalizar
|
16
|
+
# # => MARIO
|
17
|
+
#
|
18
|
+
# NormalizadorNombre.new('María de los Ángeles').normalizar
|
19
|
+
# # => ANGELES
|
20
|
+
#
|
21
|
+
# NormalizadorNombre.new('José de Jesús').normalizar
|
22
|
+
# # => JESUS
|
23
|
+
#
|
24
|
+
# NormalizadorNombre.new('María').normalizar
|
25
|
+
# # => MARIA
|
26
|
+
#
|
27
|
+
# NormalizadorNombre.new('José Mario').normalizar
|
28
|
+
# # => MARIO
|
29
|
+
#
|
30
|
+
# NormalizadorNombre.new('José').normalizar
|
31
|
+
# # => JOSE
|
32
|
+
class NormalizadorNombre < NormalizadorCadena
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def nombres_ignorados
|
37
|
+
%w[JOSE MARIA DE LA DEL LOS]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Identificamex
|
2
|
+
module Nombre
|
3
|
+
|
4
|
+
class PalabraInconveniente
|
5
|
+
def self.convertir(palabra)
|
6
|
+
hash_palabras[palabra] || palabra
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.hash_palabras
|
10
|
+
@hash_palabras ||= {
|
11
|
+
'BUEI' => 'BUEX',
|
12
|
+
'BUEY' => 'BUEX',
|
13
|
+
'CACA' => 'CACX',
|
14
|
+
'CACO' => 'CACX',
|
15
|
+
'CAGA' => 'CAGX',
|
16
|
+
'CAGO' => 'CAGX',
|
17
|
+
'CAKA' => 'CAKX',
|
18
|
+
'COGE' => 'COGX',
|
19
|
+
'COJA' => 'COJX',
|
20
|
+
'COJE' => 'COJX',
|
21
|
+
'COJI' => 'COJX',
|
22
|
+
'COJO' => 'COJX',
|
23
|
+
'CULO' => 'CULX',
|
24
|
+
'FETO' => 'FETX',
|
25
|
+
'GUEY' => 'GUEX',
|
26
|
+
'JOTO' => 'JOTX',
|
27
|
+
'KACA' => 'KACX',
|
28
|
+
'KACO' => 'KACX',
|
29
|
+
'KAGA' => 'KAGX',
|
30
|
+
'KAGO' => 'KAGX',
|
31
|
+
'KOGE' => 'KOGX',
|
32
|
+
'KOJO' => 'KOJX',
|
33
|
+
'KAKA' => 'KAKX',
|
34
|
+
'KULO' => 'KULX',
|
35
|
+
'MAME' => 'MAMX',
|
36
|
+
'MAMO' => 'MAMX',
|
37
|
+
'MEAR' => 'MEAX',
|
38
|
+
'MEON' => 'MEOX',
|
39
|
+
'MION' => 'MIOX',
|
40
|
+
'MOCO' => 'MOCX',
|
41
|
+
'MULA' => 'MULX',
|
42
|
+
'PEDA' => 'PEDX',
|
43
|
+
'PEDO' => 'PEDX',
|
44
|
+
'PENE' => 'PENX',
|
45
|
+
'PUTA' => 'PUTX',
|
46
|
+
'PUTO' => 'PUTX',
|
47
|
+
'QULO' => 'QULX',
|
48
|
+
'RATA' => 'RATX',
|
49
|
+
'RUIN' => 'RUIX'
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|