Posted By

mabafu on 10/27/11


Tagged

validator CPF cnpj


Versions (?)

CPF and CNPJ validation classes using the Brazilian Government official algorithms


 / Published in: Ruby
 

About

CPF and CNPJ are self-validated codes generated by Brazilian government. Being the CPF used to identify persons and CNJP to enterprises, organizations and so on.

That said, I use to code the CPF/CNPJ algorithm when learning new programming languages. With Ruby, it got very clean and powerful because it's particular way to deal with "closures" (i.e. the ruby blocks, Procs and lambdas).

To use Cpf or Cnpj classes, just instantite the respective classes passing the numbers to be validated. CPF has 11 digits and CNPJ has 14. In both cases the last two digits are calculated based on the previous ones.

Module11 is the parent class of Cpf and Cnpj. You can use this class if you want to implement your own Module 11 validation algorithm. In this case, inherit from Module11 and initialize the new class with the proper parameters (i.e. input, formula, size, numberofdigits)

  1. # Generic Module 11 validator
  2.  
  3. class Module11
  4. protected
  5. #returns the next validation 'digit' of the 'input'.
  6. #It will calcultes the next 'digit' based on the
  7. #given 'formula' (as block)
  8. def Module11.getDigit (input, formula)
  9. digit = 0
  10. input.each_with_index do |item, index|
  11. #passing the current item, its index and the whole array
  12. #to the formula
  13. digit += formula.call(item, index, input)
  14. end
  15. digit = 11 - (digit % 11)
  16. digit = 0 if digit > 9
  17.  
  18. return digit
  19. end
  20.  
  21. #calculates the new 'input' digits based on the given 'formula'
  22. #and the 'size' of the desired 'output' array
  23. def Module11.calculate (input, formula, size)
  24. output = Array.new (input)
  25. while output.size < size do
  26. output << getDigit(output, formula)
  27. end
  28. return output
  29. end
  30.  
  31. public
  32. attr_reader :value
  33.  
  34. def initialize(input, formula, size, number_of_digits)
  35. if input.kind_of? String
  36. @value = input.scan(/\d/).collect{ |item| item.to_i }
  37. else
  38. @value = [0]
  39. end
  40.  
  41. if formula.kind_of? Proc
  42. @formula = formula
  43. else
  44. @formula = nil
  45. end
  46.  
  47. if size.kind_of? Fixnum
  48. @size = size
  49. else
  50. @size = 0
  51. end
  52.  
  53. if number_of_digits.kind_of? Fixnum
  54. @number_of_digits = number_of_digits
  55. else
  56. @number_of_digits = 0
  57. end
  58.  
  59. if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
  60. @result = Module11.calculate(@value[0,@size-@number_of_digits], @formula, @size)
  61. else
  62. @result = []
  63. end
  64. end
  65.  
  66. def inspect
  67. "< @value = " + @value.to_s + ">"
  68. end
  69.  
  70. def to_s
  71. @value.join("")
  72. end
  73.  
  74. def is_valid?
  75. @value == @result
  76. end
  77.  
  78. def validated
  79. if is_valid?
  80. self
  81. else
  82. Module11.new @result.join, @formula, @size, @number_of_digits
  83. end
  84. end
  85.  
  86. def is_obvious?
  87. @result.join("").to_i % ("1"*@size).to_i == 0
  88. end
  89.  
  90. def digits
  91. if @value.size == @size
  92. @value[@size-@number_of_digits, @number_of_digits]
  93. else
  94. []
  95. end
  96. end
  97.  
  98. end
  99.  
  100. class Cpf < Module11
  101. private
  102. def Cpf.formula
  103. Proc.new do |item, index, updatedInput|
  104. item * (updatedInput.size + 1 - index)
  105. end
  106. end
  107.  
  108. public
  109. def initialize(input)
  110. super input, Cpf.formula, 11, 2
  111. end
  112.  
  113. def validated
  114. if is_valid?
  115. self
  116. else
  117. Cpf.new @result.join
  118. end
  119. end
  120. end
  121.  
  122. class Cnpj < Module11
  123. private
  124. def Cnpj.formula
  125. Proc.new do |item, index, updatedInput|
  126. coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
  127. item * coefs[index+13-updatedInput.size]
  128. end
  129. end
  130.  
  131. public
  132. def initialize(input)
  133. super input, Cnpj.formula, 14, 2
  134. end
  135.  
  136. def validated
  137. if is_valid?
  138. self
  139. else
  140. Cnpj.new @result.join
  141. end
  142. end
  143. end

Report this snippet  

You need to login to post a comment.