identificamex 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/LogicalBricks/identificamex.png)](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
|