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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7582ffcdc522742b30de845539e2b75aa9f7207
4
- data.tar.gz: 5a9c321686aa075703734e80f55fc84fc1c4e03a
3
+ metadata.gz: 65fa3e6fd8638d2aa972815f35ed94ba3df0424b
4
+ data.tar.gz: 71497ea86147ae06abeaf84624dc081557771612
5
5
  SHA512:
6
- metadata.gz: bca3b17490e14c1572ec2d57ef673eb265632ffeae0171f80bf63f453523d1d608914a68042ba40e455ea6ecbd362f730f7cff50bc5e38930faa79bdcf1a7891
7
- data.tar.gz: b2e09aa117afd8f48254b4afe182a4e516e833c73b8c1517336463059a8e4c5baae0224066706feb8db054b2fb7fa06817f0a4a9250548811b593d13fae99748
6
+ metadata.gz: 56f512d4a89955f1b52e70a561f54463815a705e257fd60401a2f91515fdb5a03ce71426c3a23bcfc5133b8f88cb9a41c28b561a5f14f9f170b3c32759dd9088
7
+ data.tar.gz: c9896b42a2261fd5bd3bfc3ed4a1913fe8f2fe91807ebe2227de77c59246995d026551d27aef551afc3ade2c9f324e1e9d702ba8de3e296e91a1691e7b846abf
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
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 Población (CURP) y el Registro Federal de Contribuyentes (RFC) utilizados en México.
4
- Los validadores se integran con el mecanismo que implementa ActiveModel para el resto de validadores de Rails.
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 < ActiveRecor::Base
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
@@ -4,7 +4,7 @@ require 'rake/testtask'
4
4
 
5
5
  Rake::TestTask.new do |t|
6
6
  t.libs << 'lib/identificamex'
7
- t.test_files = FileList['test/identificamex/*_test.rb']
7
+ t.test_files = FileList['test/identificamex/**/*_test.rb']
8
8
  end
9
9
 
10
10
  task :default => :test
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
- # Your code goes here...
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