Return to Snippet

Revision: 52589
at July 8, 2012 01:37 by mabafu


Updated Code
# Generic Module 11 validator

class Module11
protected
   #returns the next validation 'digit' of the 'input'. 
   #It will calcultes the next 'digit' based on the 
   #given 'formula' (as block)   
   def Module11.getDigit (input, formula)
      digit = 0
      input.each_with_index do |item, index|
         #passing the current item, its index and the whole array 
         #to the formula
         digit += formula.call(item, index, input)    
      end   
      digit = 11 - (digit % 11)
      digit = 0 if digit > 9
      
      return digit
   end      

   #calculates the new 'input' digits based on the given 'formula' 
   #and the 'size' of the desired 'output' array
   def Module11.calculate (input, formula, size)      
      output = Array.new (input)
      while output.size < size do
         output << getDigit(output, formula)
      end
      return output
   end
   
public
   attr_reader :value
   
   def initialize(input, formula, size, number_of_digits)      
      if input.kind_of? String
         @value = input.scan(/\d/).collect{ |item| item.to_i }       
      else
         @value = [0]
      end
      
      if formula.kind_of? Proc
         @formula = formula
      else
         @formula = nil
      end      
      
      if size.kind_of? Fixnum
         @size = size
      else
         @size = 0
      end
            
      if number_of_digits.kind_of? Fixnum
         @number_of_digits = number_of_digits
      else
         @number_of_digits = 0
      end
            
      if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
         @result = Module11.calculate(@value[0,@size-@number_of_digits], @formula, @size)
      else
         @result = []
      end
   end
   
   def inspect
      "< @value = " + @value.to_s + ">"
   end
   
   def to_s
      @value.join("")
   end
         
   def is_valid?
      @value == @result
   end
   
   def validated
      if is_valid?      
         self
      else        
         Module11.new @result.join, @formula, @size, @number_of_digits
      end   
   end
      
   def is_obvious?   
      @result.join("").to_i % ("1"*@size).to_i == 0
   end
   
   def digits
      if @value.size == @size
         @value[@size-@number_of_digits, @number_of_digits]
      else
         []
      end
   end

end

class Cpf < Module11
private
   def Cpf.formula
      Proc.new do |item, index, updatedInput|
         item * (updatedInput.size + 1 - index)
      end
   end
   
public
   def initialize(input)            
      super input, Cpf.formula, 11, 2  
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cpf.new @result.join
      end   
   end
end

class Cnpj < Module11
private
   def Cnpj.formula
      Proc.new do |item, index, updatedInput|
         coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
         item * coefs[index+13-updatedInput.size]
      end
   end
   
public
   def initialize(input)
      super input, Cnpj.formula, 14, 2 
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cnpj.new @result.join
      end   
   end
end

Revision: 52588
at November 5, 2011 12:34 by mabafu


Updated Code
# Generic Module 11 validator

class Module11
protected
   #returns the next validation 'digit' of the 'input'. 
   #It will calcultes the next 'digit' based on the 
   #given 'formula' (as block)   
   def Module11.getDigit (input, formula)
      digit = 0
      input.each_with_index do |item, index|
         #passing the current item, its index and the whole matrix 
         #to the formula
         digit += formula.call(item, index, input)    
      end   
      digit = 11 - (digit % 11)
      digit = 0 if digit > 9
      
      return digit
   end      

   #calculates the new 'input' digits based on the given 'formula' 
   #and the 'size' of the desired 'output' matrix
   def Module11.calculate (input, formula, size)      
      output = Array.new (input)
      while output.size < size do
         output << getDigit(output, formula)
      end
      return output
   end
   
public
   attr_reader :value
   
   def initialize(input, formula, size, number_of_digits)      
      if input.kind_of? String
         @value = input.scan(/\d/).collect{ |item| item.to_i }       
      else
         @value = [0]
      end
      
      if formula.kind_of? Proc
         @formula = formula
      else
         @formula = nil
      end      
      
      if size.kind_of? Fixnum
         @size = size
      else
         @size = 0
      end
            
      if number_of_digits.kind_of? Fixnum
         @number_of_digits = number_of_digits
      else
         @number_of_digits = 0
      end
            
      if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
         @result = Module11.calculate(@value[0,@size-@number_of_digits], @formula, @size)
      else
         @result = []
      end
   end
   
   def inspect
      "< @value = " + @value.to_s + ">"
   end
   
   def to_s
      @value.join("")
   end
         
   def is_valid?
      @value == @result
   end
   
   def validated
      if is_valid?      
         self
      else        
         Module11.new @result.join, @formula, @size, @number_of_digits
      end   
   end
      
   def is_obvious?   
      @result.join("").to_i % ("1"*@size).to_i == 0
   end
   
   def digits
      if @value.size == @size
         @value[@size-@number_of_digits, @number_of_digits]
      else
         []
      end
   end

end

class Cpf < Module11
private
   def Cpf.formula
      Proc.new do |item, index, updatedInput|
         item * (updatedInput.size + 1 - index)
      end
   end
   
public
   def initialize(input)            
      super input, Cpf.formula, 11, 2  
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cpf.new @result.join
      end   
   end
end

class Cnpj < Module11
private
   def Cnpj.formula
      Proc.new do |item, index, updatedInput|
         coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
         item * coefs[index+13-updatedInput.size]
      end
   end
   
public
   def initialize(input)
      super input, Cnpj.formula, 14, 2 
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cnpj.new @result.join
      end   
   end
end

Revision: 52587
at October 27, 2011 08:26 by mabafu


Updated Code
# Generic Module 11 validator

class Module11
protected
   #returns the next validation 'digit' of the 'input'. 
   #It will calcultes the next 'digit' based on the 
   #given 'formula' (as block)   
   def Module11.getDigit (input, formula)
      digit = 0
      input.each_with_index do |item, index|
         #passing the current item, its index and the whole matrix 
         #to the formula
         digit += formula.call(item, index, input)    
      end   
      digit = 11 - (digit % 11)
      digit = 0 if digit > 9
      
      return digit
   end      

   #calculates the new 'input' digits based on the given 'formula' 
   #and the 'size' of the desired 'output' matrix
   def Module11.calculate (input, formula, size)      
      output = Array.new (input)
      while output.size < size do
         output << getDigit(output, formula)
      end
      return output
   end
   
public
   attr_reader :value
   
   def initialize(input, formula, size, number_of_digits)      
      if input.kind_of? String
         @value = input.scan(/\d/).collect{ |item| item.to_i }        
      else
         @value = [0]
      end
      
      if formula.kind_of? Proc
         @formula = formula
      else
         @formula = nil
      end      
      
      if size.kind_of? Fixnum
         @size = size
      else
         @size = 0
      end
            
      if number_of_digits.kind_of? Fixnum
         @number_of_digits = number_of_digits
      else
         @number_of_digits = 0
      end
            
      if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
         @result = Module11.calculate(@value, @formula, @size)
      else
         @result = []
      end
   end
   
   def inspect
      "< @value = " + @value.to_s + ">"
   end
   
   def to_s
      @value.join("")
   end
         
   def is_valid?
      valueDigits = @value[@size-@number_of_digits, @number_of_digits]
      resultDigits = @result[@size-@number_of_digits, @number_of_digits]
      
      @value.size == @size and (valueDigits == resultDigits )     
   end
   
   def validated
      if is_valid?      
         self
      else        
         Module11.new @result.join, @formula, @size, @number_of_digits
      end   
   end
      
   def is_obvious?   
      @result.join("").to_i % ("1"*@size).to_i == 0
   end
   
   def digits
      if @value.size == @size
         @value[@size-@number_of_digits, @number_of_digits]
      else
         []
      end
   end

end

class Cpf < Module11
private
   def Cpf.formula
      Proc.new do |item, index, updatedInput|
         item * (updatedInput.size + 1 - index)
      end
   end
   
public
   def initialize(input)            
      super input, Cpf.formula, 11, 2  
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cpf.new @result.join
      end   
   end
end

class Cnpj < Module11
private
   def Cnpj.formula
      Proc.new do |item, index, updatedInput|
         coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
         item * coefs[index+13-updatedInput.size]
      end
   end
   
public
   def initialize(input)
      super input, Cnpj.formula, 14, 2 
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cnpj.new @result.join
      end   
   end
end

Revision: 52586
at October 27, 2011 05:25 by mabafu


Updated Code
# Generic Module 11 validator

class Module11
protected
   #returns the next validation 'digit' of the 'input'. 
   #It will calcultes the next 'digit' based on the 
   #given 'formula' (as block)   
   def Module11.getDigit (input, formula)
      digit = 0
      input.each_with_index do |item, index|
         #passing the current item, its index and the whole matrix 
         #to the formula
         digit += formula.call(item, index, input)    
      end   
      digit = 11 - (digit % 11)
      digit = 0 if digit > 9
      
      return digit
   end      

   #calculates the new 'input' digits based on the given 'formula' 
   #and the 'size' of the desired 'output' matrix
   def Module11.calculate (input, formula, size)      
      output = Array.new (input)
      while output.size < size do
         output << getDigit(output, formula)
      end
      return output
   end
   
public
   attr_reader :value
   
   def initialize(input, formula, size, number_of_digits)      
      if input.kind_of? String
         @value = input.split("").collect{ |item| item.to_i }        
      else
         @value = [0]
      end
      
      if formula.kind_of? Proc
         @formula = formula
      else
         @formula = nil
      end      
      
      if size.kind_of? Fixnum
         @size = size
      else
         @size = 0
      end
            
      if number_of_digits.kind_of? Fixnum
         @number_of_digits = number_of_digits
      else
         @number_of_digits = 0
      end
            
      if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
         @result = Module11.calculate(@value, @formula, @size)
      else
         @result = []
      end
   end
   
   def inspect
      "< @value = " + @value.to_s + ">"
   end
   
   def to_s
      @value.join("")
   end
         
   def is_valid?
      valueDigits = @value[@size-@number_of_digits, @number_of_digits]
      resultDigits = @result[@size-@number_of_digits, @number_of_digits]
      
      @value.size == @size and (valueDigits == resultDigits )     
   end
   
   def validated
      if is_valid?      
         self
      else        
         Module11.new @result.join, @formula, @size, @number_of_digits
      end   
   end
      
   def is_obvious?   
      @result.join("").to_i % ("1"*@size).to_i == 0
   end
   
   def digits
      if @value.size == @size
         @value[@size-@number_of_digits, @number_of_digits]
      else
         []
      end
   end

end

class Cpf < Module11
private
   def Cpf.formula
      Proc.new do |item, index, updatedInput|
         item * (updatedInput.size + 1 - index)
      end
   end
   
public
   def initialize(input)            
      super input, Cpf.formula, 11, 2  
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cpf.new @result.join
      end   
   end
end

class Cnpj < Module11
private
   def Cnpj.formula
      Proc.new do |item, index, updatedInput|
         coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
         item * coefs[index+13-updatedInput.size]
      end
   end
   
public
   def initialize(input)
      super input, Cnpj.formula, 14, 2 
   end
   
   def validated
      if is_valid?      
         self
      else        
         Cnpj.new @result.join
      end   
   end
end

Revision: 52585
at October 27, 2011 03:06 by mabafu


Initial Code
# Generic Module 11 Validation Class
class Module11
protected
   #returns the next validation 'digit' of the 'input'. 
   #It will calcultes the next 'digit' based on the 
   #given 'formula' (as block)   
   def Module11.getDigit (input, formula)
      digit = 0
      input.each_with_index do |item, index|
         #passing the current item, its index and the whole matrix 
         #to the formula
         digit += formula.call(item, index, input)    
      end   
      digit = 11 - (digit % 11)
      digit = 0 if digit > 9
      
      return digit
   end      

   #calculates the new 'input' digits based on the given 'formula' 
   #and the 'size' of the desired 'output' matrix
   def Module11.calculate (input, formula, size)      
      output = Array.new (input)
      while output.size < size do
         output << getDigit(output, formula)
      end
      return output
   end
   
public
   attr_reader :value, :validated   
   
   def initialize(input, formula, size, number_of_digits)      
      if input.kind_of? String
         @value = input.split("").collect{ |item| item.to_i }        
      else
         @value = [0]
      end
      
      if formula.kind_of? Proc
         @formula = formula
      else
         @formula = nil
      end      
      
      if size.kind_of? Fixnum
         @size = size
      else
         @size = 0
      end
            
      if number_of_digits.kind_of? Fixnum
         @number_of_digits = number_of_digits
      else
         @number_of_digits = 0
      end
            
      if (@size > 0) and (@value.size > 0) and (@number_of_digits > 0) and (not @formula.nil?)
         @result = Module11.calculate(@value, @formula, @size)
      else
         @result = []
      end
      
      if is_valid?      
         @validated = self
      else        
         @validated = Module11.new @result.join, @formula, @size, @number_of_digits
      end            
      
   end
   
   def inspect
      "< @value = " + @value.to_s + ">"
   end
   
   def to_s
      @value.join("")
   end
         
   def is_valid?
      valueDigits = @value[@size-@number_of_digits, @number_of_digits]
      resultDigits = @result[@size-@number_of_digits, @number_of_digits]
      
      @value.size == @size and (valueDigits == resultDigits )     
   end
      
   def is_obvious?   
      @result.join("").to_i % ("1"*@size).to_i == 0
   end
   
   def digits
      if @value.size == @size
         @value[@size-@number_of_digits, @number_of_digits]
      else
         []
      end
   end

end

#Cpf Validation Class
class Cpf < Module11
   def initialize(input)      
      formula = Proc.new do |item, index, updatedInput|
         item * (updatedInput.size + 1 - index)
      end
      super input, formula, 11, 2   
   end
end

#Cnpj Validation Class
class Cnpj < Module11
   def initialize(input)      
      formula = Proc.new do |item, index, updatedInput|
         coefs = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
         item * coefs[index+13-updatedInput.size]
      end
      super input, formula, 14, 2   
   end
end

Initial URL


Initial Description
#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, number_of_digits)

Initial Title
CPF and CNPJ validation classes using the Brazilian Government official algorithms

Initial Tags


Initial Language
Ruby