cpf_cnpj_plus 0.2.0 → 0.4.0

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
  SHA256:
3
- metadata.gz: 3471ac722167a65351c70e1e5d5cc0942bd915ba0420eaef56050778bc05809b
4
- data.tar.gz: d108eadcb37093bccfe1aca2b5ce65c5c4a1bfad4ebdb312a0d111fca8e0ff95
3
+ metadata.gz: 0be5c78bb01f594041dc6648af5e88c793a37909288d2e805ec4df415b1e80f3
4
+ data.tar.gz: c44eb35f3cd67072ba120f5c74960b295ba2abf8a902262743c2688f5ca8fad9
5
5
  SHA512:
6
- metadata.gz: d4aa54004da35e9333beb2fdfce720ffec85f171cee7beb9d1204e27c576dddd7d319659581ed20569810c73468fe84c5633674536b3fa6870bee22b76c0e499
7
- data.tar.gz: 22d11338440ada66d77bd93d05b74297a6a10642f25f7e634d93b44b595e6b08c55ffe06cdb5ca5f74305e44133f3f6f54d32a09001850a084a30c98b57f39be
6
+ metadata.gz: 4437f396b413c092653cd6f1960d5686e392fdb1bc488bb9244b919443d3de9c992d4187ef88f29e88b939a8bc3a086f49d4f71ac53e95b3fa1d8711c97c8a00
7
+ data.tar.gz: 685071ce041e859639aa0cd3c6091133481c725234b419bd49f18e36761339bcd55455ce751ac01fdf12643f08e8bd7f44f9c3c3976dee0c5bb6986f298bab79
data/.rubocop.yml CHANGED
@@ -6,3 +6,6 @@ Style/StringLiterals:
6
6
 
7
7
  Style/StringLiteralsInInterpolation:
8
8
  EnforcedStyle: double_quotes
9
+
10
+ Metrics/BlockLength:
11
+ Max: 60
data/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2026-08-01
4
+
5
+ - Adicionada API unificada que detecta CPF ou CNPJ pelo tamanho do
6
+ documento: `CpfCnpjPlus.valid?`, `CpfCnpjPlus.format` e
7
+ `CpfCnpjPlus.generate(:cpf | :cnpj, alphanumeric:)`.
8
+ - Adicionado `CpfCnpjPlus.alphanumeric_cnpj?`, que identifica se um CNPJ
9
+ válido já usa o novo padrão alfanumérico (útil para auditar bases de
10
+ dados antes da migração de julho de 2026).
11
+ - `format_cpf`/`format_cnpj` (e a nova `format`) agora aceitam a opção
12
+ `strict: true`, que retorna `nil` quando os dígitos verificadores ou a
13
+ estrutura do documento são inválidos, em vez de formatar um documento
14
+ incorreto silenciosamente.
15
+ - Adicionado validador opcional para ActiveModel/Rails
16
+ (`require "cpf_cnpj_plus/active_model_validator"`), permitindo
17
+ `validates :campo, cpf_cnpj: true` (ou `type: :cpf`/`type: :cnpj`) em
18
+ models. Não é carregado por padrão e não adiciona `activemodel` como
19
+ dependência de runtime.
20
+ - Testes adicionados para todas as features acima (100% de cobertura de
21
+ linhas).
22
+
23
+ ## [0.3.1] - 2026-08-01
24
+
25
+ - Corrigido `exe/cnpj_plus --check`, que chamava um método inexistente
26
+ (`CpfCnpjPlus.valid?`) e quebrava com `NoMethodError`; agora usa
27
+ `valid_cnpj?`.
28
+ - Corrigida a rejeição de CNPJs alfanuméricos "conhecidamente inválidos":
29
+ antes só bases numéricas com todos os dígitos iguais eram rejeitadas;
30
+ agora qualquer base de 12 caracteres repetidos é rejeitada, incluindo
31
+ letras (ex.: `"AAAAAAAAAAAA45"`).
32
+ - Removida dependência morta de `byebug` nos specs do validator, que
33
+ quebrava `bundle exec rspec` em ambiente limpo (CI).
34
+ - Corrigido o workflow de CI, que disparava em push apenas na branch
35
+ `master` e nunca era executado em `main`.
36
+ - Corrigida a documentação do README, que citava um método
37
+ `CpfCnpjPlus.generate` inexistente (o correto é `generate_cpf`/`generate_cnpj`).
38
+ - Adicionados testes para os casos acima e para os executáveis
39
+ `cnpj_plus`/`cpf_plus`.
40
+
3
41
  ## [0.1.0] - 2025-07-06
4
42
 
5
43
  - Initial release
@@ -9,5 +47,12 @@
9
47
 
10
48
  - Adjustment to be able to create the two new generation and formatting methods
11
49
 
50
+ ## [0.3.0] - 2026-04-27
51
+
52
+ - Added the `generate_cpf` method to generate valid CPF numbers.
53
+ - Added the `generate_cnpj` method to generate valid CNPJ numbers.
54
+ - Added the `format_cpf` method to format CPF numbers in the standard format (XXX.XXX.XXX-XX).
55
+ - Added the `format_cnpj` method to format CNPJ numbers in the standard format (XX.XXX.XXX/XXXX-XX).
56
+ - Updated the README.md file to include examples of the new generation and formatting methods.
12
57
 
13
58
 
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # CPF CNPJ Plus
2
2
 
3
- **cpf_cnpj_plus** é uma biblioteca Ruby para **validar, gerar e formatar** números de CPF e CNPJ brasileiros, tanto via código Ruby quanto pela linha de comando.
3
+ [![Gem Version](https://img.shields.io/gem/v/cpf_cnpj_plus.svg)](https://rubygems.org/gems/cpf_cnpj_plus)
4
+ [![Ruby](https://github.com/DougNeo/cpf_cnpj_plus/actions/workflows/main.yml/badge.svg)](https://github.com/DougNeo/cpf_cnpj_plus/actions/workflows/main.yml)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
6
+
7
+ **cpf_cnpj_plus** é uma biblioteca Ruby para **validar, gerar e formatar** números de CPF e CNPJ brasileiros. Funciona em **Ruby puro** (sem dependências de runtime), tem um **validador opcional para Rails/ActiveModel**, e oferece **ferramentas de linha de comando**.
4
8
 
5
9
  ---
6
10
 
@@ -40,22 +44,57 @@ A gem oferece uma API unificada para CPF e CNPJ. Exemplos:
40
44
  ```ruby
41
45
  require "cpf_cnpj_plus"
42
46
 
43
- CPF
47
+ # CPF
44
48
  CpfCnpjPlus.valid_cpf?("123.456.789-09") # => true ou false
45
49
  CpfCnpjPlus.format_cpf("12345678909") # => "123.456.789-09"
46
- CpfCnpjPlus.generate # => Gera um CPF válido
50
+ CpfCnpjPlus.generate_cpf # => Gera um CPF válido
47
51
 
48
- CNPJ
49
- CpfCnpjPlus.valid?("12.345.678/0001-95") # => true ou false
52
+ # CNPJ
53
+ CpfCnpjPlus.valid_cnpj?("12.345.678/0001-95") # => true ou false
50
54
  CpfCnpjPlus.format_cnpj("12345678000195") # => "12.345.678/0001-95"
51
- CpfCnpjPlus.generate # => Gera um CNPJ válido
55
+ CpfCnpjPlus.generate_cnpj # => Gera um CNPJ válido
56
+
57
+ # CNPJ Alfanumérico (novo formato)
58
+ CpfCnpjPlus.valid_cnpj?("12.ABC.345/01DE-35") # => true
59
+ CpfCnpjPlus.format_cnpj("12ABC34501DE35") # => "12.ABC.345/01DE-35"
60
+ CpfCnpjPlus.generate_cnpj(alphanumeric: true) # => Gera um CNPJ alfanumérico válido
61
+ CpfCnpjPlus.alphanumeric_cnpj?("12ABC34501DE35") # => true (identifica se já usa o novo padrão)
62
+
63
+ # API unificada (detecta CPF ou CNPJ pelo tamanho do documento)
64
+ CpfCnpjPlus.valid?("123.456.789-09") # => true ou false
65
+ CpfCnpjPlus.valid?("12.345.678/0001-95") # => true ou false
66
+ CpfCnpjPlus.format("12345678909") # => "123.456.789-09"
67
+ CpfCnpjPlus.format("12345678000195") # => "12.345.678/0001-95"
68
+ CpfCnpjPlus.generate(:cpf) # => Gera um CPF válido
69
+ CpfCnpjPlus.generate(:cnpj, alphanumeric: true) # => Gera um CNPJ alfanumérico válido
70
+
71
+ # Formatação estrita (retorna nil se os dígitos verificadores forem inválidos)
72
+ CpfCnpjPlus.format_cpf("12345678900", strict: true) # => nil (dígitos verificadores errados)
73
+ CpfCnpjPlus.format_cnpj("12345678000199", strict: true) # => nil (dígitos verificadores errados)
74
+ ```
75
+
76
+ ### Validação em Rails/ActiveModel
77
+
78
+ A gem também traz um validador opcional para uso com `ActiveModel::Validations`
79
+ (inclusive em models Rails). Ele **não** é carregado junto com
80
+ `require "cpf_cnpj_plus"` — é preciso requerê-lo explicitamente, e `activemodel`
81
+ precisa estar disponível na sua aplicação:
82
+
83
+ ```ruby
84
+ require "cpf_cnpj_plus/active_model_validator"
85
+
86
+ class Empresa
87
+ include ActiveModel::Model
88
+ attr_accessor :cnpj, :cpf
52
89
 
53
- CNPJ Alfanumérico (novo formato)
54
- CpfCnpjPlus.valid?("A1234567B00195") # => true ou false
55
- CpfCnpjPlus.format_cnpj("A1234567B00195") # => "A12.345.67B/0019-5"
56
- CpfCnpjPlus.generate # => Gera um CNPJ alfanumérico válido
90
+ validates :cnpj, cpf_cnpj: { type: :cnpj } # aceita CNPJ numérico ou alfanumérico
91
+ validates :cpf, cpf_cnpj: { type: :cpf }
92
+ # ou, para detectar o tipo automaticamente pelo tamanho:
93
+ # validates :documento, cpf_cnpj: true
94
+ end
57
95
  ```
58
96
 
97
+ Suporta as opções padrão do Rails (`allow_nil`, `allow_blank`, `message`).
59
98
 
60
99
  ### Linha de comando
61
100
 
@@ -66,21 +105,27 @@ $ cpf_plus --check 123.456.789-09
66
105
  $ cpf_plus --format 12345678909
67
106
  $ cpf_plus --generate
68
107
  $ cnpj_plus --check 12.345.678/0001-95
69
- $ cnpj_plus --check A12.345.67B/0019-5
108
+ $ cnpj_plus --check 12.ABC.345/01DE-35
70
109
  $ cnpj_plus --generate
71
110
  ```
72
111
 
73
112
  ## Compatibilidade
74
113
 
75
- - Ruby >= 3.1.0
114
+ - Ruby >= 3.1.0 (testado em CI nas versões 3.1, 3.2, 3.3, 3.4 e 4.0).
115
+ - Sem dependências de runtime — funciona em qualquer projeto Ruby puro.
116
+ - Uso com Rails/ActiveModel é opcional: só é necessário se você requerer
117
+ `cpf_cnpj_plus/active_model_validator` (veja a seção "Validação em
118
+ Rails/ActiveModel" acima).
76
119
 
77
120
  ## Contribuição
78
121
 
79
122
  1. Faça um fork do projeto
80
123
  2. Crie sua branch (`git checkout -b minha-feature`)
81
- 3. Commit suas alterações (`git commit -am 'Adiciona nova feature'`)
82
- 4. Faça push para a branch (`git push origin minha-feature`)
83
- 5. Abra um Pull Request
124
+ 3. Rode `bundle install` e depois `bundle exec rake` (specs + rubocop) para
125
+ garantir que tudo continua passando
126
+ 4. Commit suas alterações (`git commit -am 'Adiciona nova feature'`)
127
+ 5. Faça push para a branch (`git push origin minha-feature`)
128
+ 6. Abra um Pull Request
84
129
 
85
130
  ## Licença
86
131
 
data/exe/cnpj_plus ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "optparse"
5
+ require_relative "../lib/cpf_cnpj_plus"
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Uso: cnpj_plus [opções]"
10
+ opts.on("--check CNPJ", "Valida um CNPJ (numérico ou alfanumérico)") { |v| options[:check] = v }
11
+ opts.on("--format CNPJ", "Formata um CNPJ") { |v| options[:format] = v }
12
+ opts.on("--generate", "Gera um CNPJ numérico válido") { options[:generate] = true }
13
+ opts.on("--alphanumeric", "Gera um CNPJ alfanumérico (com --generate)") { options[:alphanumeric] = true }
14
+ end.parse!
15
+
16
+ if options[:check]
17
+ valid = CpfCnpjPlus.valid_cnpj?(options[:check])
18
+ puts valid ? "✅ CNPJ válido" : "❌ CNPJ inválido"
19
+ elsif options[:format]
20
+ result = CpfCnpjPlus.format_cnpj(options[:format])
21
+ puts result || "❌ CNPJ inválido para formatação"
22
+ elsif options[:generate]
23
+ puts CpfCnpjPlus.generate_cnpj(alphanumeric: options[:alphanumeric] || false)
24
+ else
25
+ puts "Use --help para ver as opções disponíveis."
26
+ end
data/exe/cpf_plus ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "optparse"
5
+ require_relative "../lib/cpf_cnpj_plus"
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Uso: cpf_plus [opções]"
10
+ opts.on("--check CPF", "Valida um CPF") { |v| options[:check] = v }
11
+ opts.on("--format CPF", "Formata um CPF") { |v| options[:format] = v }
12
+ opts.on("--generate", "Gera um CPF válido") { options[:generate] = true }
13
+ end.parse!
14
+
15
+ if options[:check]
16
+ valid = CpfCnpjPlus.valid_cpf?(options[:check])
17
+ puts valid ? "✅ CPF válido" : "❌ CPF inválido"
18
+ elsif options[:format]
19
+ result = CpfCnpjPlus.format_cpf(options[:format])
20
+ puts result || "❌ CPF inválido para formatação"
21
+ elsif options[:generate]
22
+ puts CpfCnpjPlus.generate_cpf
23
+ else
24
+ puts "Use --help para ver as opções disponíveis."
25
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+ require_relative "../cpf_cnpj_plus"
5
+
6
+ # Validador ActiveModel opcional. Não é carregado por padrão junto com a gem —
7
+ # quem quiser usar em um model Rails/ActiveModel deve fazer:
8
+ #
9
+ # require "cpf_cnpj_plus/active_model_validator"
10
+ #
11
+ # class Empresa
12
+ # include ActiveModel::Model
13
+ # attr_accessor :cnpj
14
+ #
15
+ # validates :cnpj, cpf_cnpj: true # detecta CPF ou CNPJ pelo tamanho
16
+ # validates :cnpj, cpf_cnpj: { type: :cnpj } # aceita só CNPJ (numérico ou alfanumérico)
17
+ # validates :cpf, cpf_cnpj: { type: :cpf } # aceita só CPF
18
+ # end
19
+ class CpfCnpjValidator < ActiveModel::EachValidator
20
+ def validate_each(record, attribute, value)
21
+ return if options[:allow_nil] && value.nil?
22
+ return if options[:allow_blank] && (value.nil? || value.to_s.strip.empty?)
23
+
24
+ record.errors.add(attribute, options.fetch(:message, :invalid)) unless valid_document?(value)
25
+ end
26
+
27
+ private
28
+
29
+ def valid_document?(value)
30
+ case options[:type]&.to_sym
31
+ when :cpf then CpfCnpjPlus.valid_cpf?(value)
32
+ when :cnpj then CpfCnpjPlus.valid_cnpj?(value)
33
+ when nil then CpfCnpjPlus.valid?(value)
34
+ else
35
+ raise ArgumentError, "type deve ser :cpf ou :cnpj (recebido: #{options[:type].inspect})"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ module Formatter
5
+ # Responsável por formatar números de CNPJ para exibição.
6
+ # Suporta o formato numérico tradicional e o novo formato alfanumérico,
7
+ # aplicando a máscara padrão XX.XXX.XXX/XXXX-XX.
8
+ class Cnpj
9
+ def self.format(cnpj, strict: false)
10
+ cleaned = cnpj.to_s.upcase.gsub(/[^A-Z0-9]/, "")
11
+ return nil unless cleaned.length == 14
12
+ return nil if strict && !Validator::Cnpj.valid?(cleaned)
13
+
14
+ "#{cleaned[0..1]}.#{cleaned[2..4]}.#{cleaned[5..7]}/#{cleaned[8..11]}-#{cleaned[12..13]}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ module Formatter
5
+ # Responsável por formatar números de CPF para exibição.
6
+ # Aplica a máscara padrão XXX.XXX.XXX-XX a partir de uma string numérica.
7
+ class Cpf
8
+ def self.format(cpf, strict: false)
9
+ cleaned = cpf.to_s.gsub(/[^0-9]/, "")
10
+ return nil unless cleaned.length == 11
11
+ return nil if strict && !Validator::Cpf.valid?(cleaned)
12
+
13
+ "#{cleaned[0..2]}.#{cleaned[3..5]}.#{cleaned[6..8]}-#{cleaned[9..10]}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ # Módulo responsável por agrupar formatadores de CPF e CNPJ.
5
+ # Fornece métodos e classes auxiliares para formatação de documentos brasileiros,
6
+ # incluindo suporte a formatos tradicionais e CNPJ alfanumérico.
7
+ module Formatter
8
+ require_relative "formatter/cnpj"
9
+ require_relative "formatter/cpf"
10
+ end
11
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ module Generator
5
+ # Responsável por gerar números de CNPJ válidos aleatoriamente.
6
+ # Suporta geração no formato numérico tradicional e no novo formato
7
+ # alfanumérico, calculando os dígitos verificadores conforme a Receita Federal.
8
+ class Cnpj
9
+ DIGITS = ("0".."9").to_a.freeze
10
+ LETTERS = ("A".."Z").to_a.freeze
11
+ ALPHANUMERIC = (DIGITS + LETTERS).freeze
12
+
13
+ WEIGHTS_1D = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
14
+ WEIGHTS_2D = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
15
+
16
+ def self.generate(alphanumeric: false)
17
+ loop do
18
+ base = build_base(alphanumeric)
19
+ cnpj = build_cnpj(base)
20
+ return cnpj unless Validator::Cnpj.cnpj_not_valid?(cnpj)
21
+ end
22
+ end
23
+
24
+ def self.build_base(alphanumeric)
25
+ if alphanumeric
26
+ # Garante ao menos uma letra para ser genuinamente alfanumérico
27
+ base = Array.new(12) { ALPHANUMERIC.sample }
28
+ base[rand(0..11)] = LETTERS.sample
29
+ base
30
+ else
31
+ Array.new(12) { DIGITS.sample }
32
+ end
33
+ end
34
+
35
+ def self.build_cnpj(base)
36
+ values = base.map { |c| char_to_value(c) }
37
+ d1 = calculate_digit(values, WEIGHTS_1D)
38
+ d2 = calculate_digit(values + [d1], WEIGHTS_2D)
39
+ base.join + "#{d1}#{d2}"
40
+ end
41
+
42
+ def self.char_to_value(char)
43
+ char.ord - 48
44
+ end
45
+
46
+ def self.calculate_digit(values, weights)
47
+ soma = weights.each_with_index.sum { |w, i| values[i] * w }
48
+ result = (soma * 10) % 11
49
+ result == 10 ? 0 : result
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ module Generator
5
+ # Responsável por gerar números de CPF válidos aleatoriamente.
6
+ # Calcula os dígitos verificadores conforme o algoritmo oficial da Receita Federal.
7
+ class Cpf
8
+ def self.generate
9
+ loop do
10
+ base = Array.new(9) { rand(0..9) }
11
+ cpf = build_cpf(base)
12
+ return cpf unless Validator::Cpf.cpf_not_valid?(cpf)
13
+ end
14
+ end
15
+
16
+ def self.build_cpf(base)
17
+ d1 = calculate_digit(base, (2..10).to_a.reverse)
18
+ d2 = calculate_digit(base + [d1], (2..11).to_a.reverse)
19
+ (base + [d1, d2]).join
20
+ end
21
+
22
+ def self.calculate_digit(digits, weights)
23
+ soma = digits.each_with_index.sum { |d, i| d * weights[i] }
24
+ result = (soma * 10) % 11
25
+ result == 10 ? 0 : result
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CpfCnpjPlus
4
+ # Módulo responsável por agrupar geradores de CPF e CNPJ.
5
+ # Fornece métodos e classes auxiliares para geração de documentos brasileiros,
6
+ # incluindo suporte a formatos tradicionais e CNPJ alfanumérico.
7
+ module Generator
8
+ require_relative "generator/cnpj"
9
+ require_relative "generator/cpf"
10
+ end
11
+ end
@@ -8,7 +8,7 @@ module CpfCnpjPlus
8
8
  def self.valid?(cnpj)
9
9
  cnpj = normalize(cnpj)
10
10
  return false unless valid_length?(cnpj)
11
- return false if cpj_not_valid?(cnpj)
11
+ return false if cnpj_not_valid?(cnpj)
12
12
  return false unless valid_structure?(cnpj)
13
13
 
14
14
  base = cnpj[0..11].chars.map { |c| char_to_value(c) }
@@ -30,13 +30,7 @@ module CpfCnpjPlus
30
30
  end
31
31
 
32
32
  def self.char_to_value(char)
33
- if ("0".."9").include?(char)
34
- char.ord - 48
35
- elsif ("A".."Z").include?(char)
36
- char.ord - 48 # Ajuste para A=10, B=11, ..., Z=35
37
- else
38
- raise ArgumentError, "Caractere inválido"
39
- end
33
+ char.ord - 48
40
34
  end
41
35
 
42
36
  def self.calculate_cnpj_digits(base)
@@ -63,11 +57,14 @@ module CpfCnpjPlus
63
57
  digit
64
58
  end
65
59
 
66
- def self.cpj_not_valid?(cnpj)
67
- cnpj = cnpj.to_s.gsub(/[^0-9]/, "")
68
- %w[00000000000000 11111111111111 22222222222222 33333333333333
69
- 44444444444444 55555555555555 66666666666666 77777777777777
70
- 88888888888888 99999999999999].include?(cnpj)
60
+ def self.alphanumeric?(cnpj)
61
+ cnpj = normalize(cnpj)
62
+ valid?(cnpj) && cnpj[0..11].match?(/[A-Z]/)
63
+ end
64
+
65
+ def self.cnpj_not_valid?(cnpj)
66
+ base = cnpj.to_s[0..11]
67
+ base.to_s.length == 12 && base.chars.uniq.length == 1
71
68
  end
72
69
  end
73
70
  end
@@ -8,36 +8,35 @@ module CpfCnpjPlus
8
8
  def self.valid?(cpf)
9
9
  cpf = cpf.to_s.gsub(/[^0-9]/, "")
10
10
  return false unless cpf.length == 11 && cpf =~ /^\d{11}$/
11
- return false if cpj_not_valid?(cpf)
11
+ return false if cpf_not_valid?(cpf)
12
12
 
13
13
  first_digit(cpf) && second_digit(cpf)
14
14
  end
15
15
 
16
16
  def self.first_digit(cpf)
17
- first_digit = cpf[0..8]
17
+ base_digits = cpf[0..8]
18
18
  soma = 0
19
19
  ponteiro = 10
20
- first_digit.chars.each do |char|
21
- res = (char.to_i * ponteiro)
22
- soma += res
20
+ base_digits.chars.each do |char|
21
+ soma += char.to_i * ponteiro
23
22
  ponteiro -= 1
24
23
  end
25
- soma * 10 % 11 == cpf[9].to_i
24
+ result = soma * 10 % 11
25
+ result == cpf[9].to_i || (result == 10 && cpf[9].to_i.zero?)
26
26
  end
27
27
 
28
28
  def self.second_digit(cpf)
29
- second_digit = cpf[0..9]
29
+ base_digits = cpf[0..9]
30
30
  soma = 0
31
31
  ponteiro = 11
32
- second_digit.chars.each do |char|
33
- res = (char.to_i * ponteiro)
34
- soma += res
32
+ base_digits.chars.each do |char|
33
+ soma += char.to_i * ponteiro
35
34
  ponteiro -= 1
36
35
  end
37
36
  soma * 10 % 11 == cpf[10].to_i || (soma * 10 % 11 == 10 && cpf[10].to_i.zero?)
38
37
  end
39
38
 
40
- def self.cpj_not_valid?(cpf)
39
+ def self.cpf_not_valid?(cpf)
41
40
  cpf = cpf.to_s.gsub(/[^0-9]/, "")
42
41
  %w[00000000000 11111111111 22222222222 33333333333
43
42
  44444444444 55555555555 66666666666
@@ -3,7 +3,7 @@
3
3
  module CpfCnpjPlus
4
4
  # Módulo responsável por agrupar validadores de CPF e CNPJ.
5
5
  # Fornece métodos e classes auxiliares para validação de documentos brasileiros,
6
- # incluindo suporte a formatos tradicionais e futuros (como CNPJ alfanumérico).
6
+ # incluindo suporte a formatos tradicionais e CNPJ alfanumérico.
7
7
  module Validator
8
8
  require_relative "validator/cnpj"
9
9
  require_relative "validator/cpf"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CpfCnpjPlus
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/cpf_cnpj_plus.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require_relative "cpf_cnpj_plus/version"
4
4
  require_relative "cpf_cnpj_plus/validator"
5
+ require_relative "cpf_cnpj_plus/formatter"
6
+ require_relative "cpf_cnpj_plus/generator"
5
7
 
6
8
  # Módulo principal da gem cpf_cnpj_plus.
7
9
  # Fornece métodos para validação, geração e formatação de CPFs e CNPJs,
@@ -9,27 +11,68 @@ require_relative "cpf_cnpj_plus/validator"
9
11
  module CpfCnpjPlus
10
12
  class Error < StandardError; end
11
13
 
14
+ # CPF
15
+ def self.valid_cpf?(cpf)
16
+ CpfCnpjPlus::Validator::Cpf.valid?(cpf)
17
+ end
18
+
19
+ def self.format_cpf(cpf, strict: false)
20
+ CpfCnpjPlus::Formatter::Cpf.format(cpf, strict: strict)
21
+ end
22
+
23
+ def self.generate_cpf
24
+ CpfCnpjPlus::Generator::Cpf.generate
25
+ end
26
+
27
+ # CNPJ
28
+
12
29
  def self.valid_cnpj?(cnpj)
13
30
  CpfCnpjPlus::Validator::Cnpj.valid?(cnpj)
14
31
  end
15
32
 
16
- def self.valid_cpf?(cpf)
17
- CpfCnpjPlus::Validator::Cpf.valid?(cpf)
33
+ def self.format_cnpj(cnpj, strict: false)
34
+ CpfCnpjPlus::Formatter::Cnpj.format(cnpj, strict: strict)
18
35
  end
19
36
 
20
- def self.format_cpf(cpf)
21
- CpfCnpjPlus::Format::Cpf.format(cpf)
37
+ def self.generate_cnpj(alphanumeric: false)
38
+ CpfCnpjPlus::Generator::Cnpj.generate(alphanumeric: alphanumeric)
22
39
  end
23
40
 
24
- def self.format_cnpj(cnpj)
25
- CpfCnpjPlus::Format::Cnpj.format(cnpj)
41
+ def self.alphanumeric_cnpj?(cnpj)
42
+ CpfCnpjPlus::Validator::Cnpj.alphanumeric?(cnpj)
26
43
  end
27
44
 
28
- def self.generate_cpf
29
- CpfCnpjPlus::Generate::Cpf.generate
45
+ # API unificada (detecta CPF ou CNPJ pelo tamanho do documento)
46
+
47
+ def self.valid?(doc)
48
+ case document_type(doc)
49
+ when :cpf then valid_cpf?(doc)
50
+ when :cnpj then valid_cnpj?(doc)
51
+ else false
52
+ end
53
+ end
54
+
55
+ def self.format(doc, strict: false)
56
+ case document_type(doc)
57
+ when :cpf then format_cpf(doc, strict: strict)
58
+ when :cnpj then format_cnpj(doc, strict: strict)
59
+ end
60
+ end
61
+
62
+ def self.generate(type, alphanumeric: false)
63
+ case type.to_s.downcase
64
+ when "cpf" then generate_cpf
65
+ when "cnpj" then generate_cnpj(alphanumeric: alphanumeric)
66
+ else
67
+ raise ArgumentError, "type deve ser :cpf ou :cnpj (recebido: #{type.inspect})"
68
+ end
30
69
  end
31
70
 
32
- def self.generate_cnpj
33
- CpfCnpjPlus::Generate::Cnpj.generate
71
+ def self.document_type(doc)
72
+ case doc.to_s.upcase.gsub(/[^A-Z0-9]/, "").length
73
+ when 11 then :cpf
74
+ when 14 then :cnpj
75
+ end
34
76
  end
77
+ private_class_method :document_type
35
78
  end
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpf_cnpj_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DougNeo
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-07-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activemodel
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: simplecov
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -23,17 +37,17 @@ dependencies:
23
37
  - - ">="
24
38
  - !ruby/object:Gem::Version
25
39
  version: '0'
26
- description: |-
27
- Fornece métodos práticos para validar, gerar e formatar números de CPF e CNPJ, incluindo
28
- ferramentas de linha de comando para facilitar integrações em sistemas bancários,
29
- governamentais e aplicações Ruby em geral.
40
+ description: Fornece métodos práticos para validar, gerar e formatar números de CPF
41
+ e CNPJ (incluindo o novo CNPJ alfanumérico), com API para Ruby puro, validador opcional
42
+ para Rails/ActiveModel e ferramentas de linha de comando.
30
43
  email:
31
44
  - doug.neo@gmail.com
32
- executables: []
45
+ executables:
46
+ - cnpj_plus
47
+ - cpf_plus
33
48
  extensions: []
34
49
  extra_rdoc_files: []
35
50
  files:
36
- - ".byebug_history"
37
51
  - ".rspec"
38
52
  - ".rubocop.yml"
39
53
  - CHANGELOG.md
@@ -41,20 +55,29 @@ files:
41
55
  - LICENSE.txt
42
56
  - README.md
43
57
  - Rakefile
58
+ - exe/cnpj_plus
59
+ - exe/cpf_plus
44
60
  - lib/cpf_cnpj_plus.rb
61
+ - lib/cpf_cnpj_plus/active_model_validator.rb
62
+ - lib/cpf_cnpj_plus/formatter.rb
63
+ - lib/cpf_cnpj_plus/formatter/cnpj.rb
64
+ - lib/cpf_cnpj_plus/formatter/cpf.rb
65
+ - lib/cpf_cnpj_plus/generator.rb
66
+ - lib/cpf_cnpj_plus/generator/cnpj.rb
67
+ - lib/cpf_cnpj_plus/generator/cpf.rb
45
68
  - lib/cpf_cnpj_plus/validator.rb
46
69
  - lib/cpf_cnpj_plus/validator/cnpj.rb
47
70
  - lib/cpf_cnpj_plus/validator/cpf.rb
48
71
  - lib/cpf_cnpj_plus/version.rb
49
72
  - sig/cpf_cnpj_plus.rbs
50
- homepage: https://github.com/DougNeo/cpf_cnpj_plus.git
73
+ homepage: https://github.com/DougNeo/cpf_cnpj_plus
51
74
  licenses:
52
75
  - MIT
53
76
  metadata:
54
77
  allowed_push_host: https://rubygems.org
55
- homepage_uri: https://github.com/DougNeo/cpf_cnpj_plus.git
56
- source_code_uri: https://github.com/DougNeo/cpf_cnpj_plus.git
57
- changelog_uri: https://github.com/DougNeo/cpf_cnpj_plus.git/blob/main/CHANGELOG.md
78
+ rubygems_mfa_required: 'true'
79
+ source_code_uri: https://github.com/DougNeo/cpf_cnpj_plus
80
+ changelog_uri: https://github.com/DougNeo/cpf_cnpj_plus/blob/main/CHANGELOG.md
58
81
  rdoc_options: []
59
82
  require_paths:
60
83
  - lib
@@ -69,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
92
  - !ruby/object:Gem::Version
70
93
  version: '0'
71
94
  requirements: []
72
- rubygems_version: 3.6.5
95
+ rubygems_version: 4.0.6
73
96
  specification_version: 4
74
97
  summary: Validação, geração e formatação de números de CPF e CNPJ para o Brasil.
75
98
  test_files: []
data/.byebug_history DELETED
@@ -1,4 +0,0 @@
1
- c
2
- described_class.valid_cpf?("10321255780")
3
- described_class.valid_cpf?("103.212.557-80")
4
- described_class.valid_cpf?("10321255780")