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 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