cnpj-dv 1.0.0 → 2.0.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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +126 -43
- data/README.pt.md +126 -43
- data/src/cnpj-dv/cnpj_check_digits.rb +19 -26
- data/src/cnpj-dv/{exceptions.rb → errors.rb} +27 -46
- data/src/cnpj-dv/version.rb +1 -1
- data/src/cnpj-dv.rb +14 -8
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d6109a8bd760c61186dc99ec5503bb42880d9ebb3c19745962ba5a0d97c6cfc
|
|
4
|
+
data.tar.gz: 47242e1f246d23ebab4d8c3be97d7d7b46060c974e011ad0412a93595fb69767
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 85686458b90a155cf2263ef4517f66732efbead21d29cc6683827ad2fae6a0f6e3949b17bbbbd2cd1a842c5cd1ff57a827e6ec1b10bc8cdb451d910ab954f383
|
|
7
|
+
data.tar.gz: 11dbfd7b80b6f25695678bc0a5e8804b08ae17fbbc7cf24aea2071f717092ebbc4e79db8945ed66d02bceef6e5f4ea467a8e7cd65c679c02381b087fd751b921
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# cnpj-dv
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### 🎉 v2 at a glance 🎊
|
|
6
|
+
|
|
7
|
+
- **Error hierarchy**: Aligns with the monorepo standard — API misuse vs domain errors, `CnpjDV::Error` marker, and native-compatible rescue.
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
- **Error classes**: Removed `CnpjCheckDigitsTypeError`, `CnpjCheckDigitsInputTypeError`, `CnpjCheckDigitsException`, `CnpjCheckDigitsInputLengthException`, and `CnpjCheckDigitsInputInvalidException`.
|
|
12
|
+
- **Migration map**: `InputTypeError` → `TypeMismatchError`; `InputLengthException` → `InvalidLengthError`; `InputInvalidException` → `ValidationError`.
|
|
13
|
+
- **Rescue targets**: `rescue CnpjCheckDigitsException` no longer applies; use `rescue CnpjDV::Error` for a library-wide catch, or `rescue DomainError` for `InvalidLengthError` and `ValidationError`.
|
|
14
|
+
- **Docs**: READMEs now document misuse vs domain categories, per-class rescue guidance, and four rescue granularity levels — see [README](./README.md).
|
|
15
|
+
|
|
3
16
|
## 1.0.0
|
|
4
17
|
|
|
5
18
|
### 🚀 Stable Version Released!
|
data/README.md
CHANGED
|
@@ -33,7 +33,7 @@ A Ruby utility to calculate check digits on CNPJ (Brazilian Business Tax ID).
|
|
|
33
33
|
- ✅ **Lazy evaluation**: Check digits are calculated only when accessed (via methods)
|
|
34
34
|
- ✅ **Caching**: Calculated values are cached for subsequent access
|
|
35
35
|
- ✅ **Minimal dependencies**: Only `[lacus-utils](https://rubygems.org/gems/lacus-utils)`
|
|
36
|
-
- ✅ **Error handling**:
|
|
36
|
+
- ✅ **Error handling**: API misuse vs domain errors with a `CnpjDV::Error` marker for library-wide rescue
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
|
|
@@ -125,56 +125,139 @@ CnpjDV::CnpjCheckDigits.new(%w[MG KGM J9X 0001])
|
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
###
|
|
128
|
+
### Error handling
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
Errors fall into two categories:
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
| Category | Meaning |
|
|
133
|
+
|---|---|
|
|
134
|
+
| **API misuse** | The caller invoked the library incorrectly (wrong type). Detectable from the call shape. |
|
|
135
|
+
| **Domain error** | The call was structurally correct, but a value violates a business rule (length, eligibility, format). |
|
|
136
|
+
|
|
137
|
+
Every custom error includes the `CnpjDV::Error` marker module. Domain failures (`InvalidLengthError`, `ValidationError`) inherit from `CnpjDV::DomainError` (`RangeError`).
|
|
138
|
+
|
|
139
|
+
#### Summary
|
|
140
|
+
|
|
141
|
+
| Class | Inherits from | Category | Trigger condition |
|
|
142
|
+
|---|---|---|---|
|
|
143
|
+
| `CnpjDV::TypeMismatchError` | `TypeError` (+ `include Error`) | API misuse | Argument has the wrong data type |
|
|
144
|
+
| `CnpjDV::InvalidLengthError` | `CnpjDV::DomainError` | Domain error | Sanitized length is not 12–14 |
|
|
145
|
+
| `CnpjDV::ValidationError` | `CnpjDV::DomainError` | Domain error | Ineligible base/branch ID or repeated numeric digits |
|
|
146
|
+
|
|
147
|
+
#### `CnpjDV::Error` (marker module)
|
|
148
|
+
|
|
149
|
+
- **Inheritance:** module marker mixed into every library error via `include` (not a class).
|
|
150
|
+
- **Category:** N/A (rescue target only) — not a failure mode by itself.
|
|
151
|
+
- **When it is raised:** Never raised directly; included by every custom error the library raises.
|
|
152
|
+
- **Example:** N/A
|
|
153
|
+
- **How to rescue it:**
|
|
137
154
|
|
|
138
155
|
```ruby
|
|
139
|
-
|
|
156
|
+
rescue CnpjDV::Error
|
|
157
|
+
# everything this library raises
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### `CnpjDV::DomainError`
|
|
161
|
+
|
|
162
|
+
- **Inheritance:** `CnpjDV::DomainError < RangeError` (includes `CnpjDV::Error`)
|
|
163
|
+
- **Category:** Domain error — ancestor for numeric/length domain failures.
|
|
164
|
+
- **When it is raised:** Not raised directly; prefer raising a leaf subclass.
|
|
165
|
+
- **Example:** Prefer `raise CnpjDV::InvalidLengthError` over raising `DomainError` directly.
|
|
166
|
+
- **How to rescue it:**
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
rescue CnpjDV::DomainError
|
|
170
|
+
# InvalidLengthError, ValidationError, and any other DomainError subclass
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `CnpjDV::TypeMismatchError`
|
|
174
|
+
|
|
175
|
+
- **Inheritance:** `CnpjDV::TypeMismatchError < TypeError` (includes `CnpjDV::Error`)
|
|
176
|
+
- **Category:** API misuse — the caller passed a value of the wrong type.
|
|
177
|
+
- **When it is raised:** Raised when the CNPJ input is not a `String` or an `Array` of strings (or an array contains a non-string element).
|
|
178
|
+
- **Example:**
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
CnpjDV::CnpjCheckDigits.new(12_345_678_000_100) # raises CnpjDV::TypeMismatchError
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- **How to rescue it:**
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
rescue CnpjDV::TypeMismatchError
|
|
188
|
+
# this library's type-contract violation
|
|
189
|
+
|
|
190
|
+
rescue TypeError
|
|
191
|
+
# native type errors, including this library's TypeMismatchError
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### `CnpjDV::InvalidLengthError`
|
|
195
|
+
|
|
196
|
+
- **Inheritance:** `CnpjDV::InvalidLengthError < CnpjDV::DomainError < RangeError` (includes `CnpjDV::Error`)
|
|
197
|
+
- **Category:** Domain error — a collection or string length violates a business rule.
|
|
198
|
+
- **When it is raised:** Raised when the sanitized CNPJ input does not contain 12 to 14 alphanumeric characters.
|
|
199
|
+
- **Example:**
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
CnpjDV::CnpjCheckDigits.new('12345678901') # raises CnpjDV::InvalidLengthError
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
- **How to rescue it:**
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
rescue CnpjDV::InvalidLengthError
|
|
209
|
+
# this exact length violation
|
|
210
|
+
|
|
211
|
+
rescue CnpjDV::DomainError
|
|
212
|
+
# RangeError-rooted domain failures from this library
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `CnpjDV::ValidationError`
|
|
216
|
+
|
|
217
|
+
- **Inheritance:** `CnpjDV::ValidationError < CnpjDV::DomainError < RangeError` (includes `CnpjDV::Error`)
|
|
218
|
+
- **Category:** Domain error — a value fails a non-numeric, non-length domain rule.
|
|
219
|
+
- **When it is raised:** Raised when the base ID is `00000000`, the branch ID is `0000`, or the first 12 characters are the same numeric digit.
|
|
220
|
+
- **Example:**
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
CnpjDV::CnpjCheckDigits.new('000000000001') # raises CnpjDV::ValidationError
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- **How to rescue it:**
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
rescue CnpjDV::ValidationError
|
|
230
|
+
# this exact domain validation failure
|
|
231
|
+
|
|
232
|
+
rescue CnpjDV::DomainError
|
|
233
|
+
# RangeError-rooted domain failures from this library
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### Rescue granularity
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
# 1) Single native class — catches type misuse from this library (and other TypeErrors).
|
|
240
|
+
rescue TypeError
|
|
241
|
+
# CnpjDV::TypeMismatchError and any other TypeError (library or not)
|
|
242
|
+
|
|
243
|
+
# 2) CnpjDV::DomainError — catches business-rule violations under DomainError.
|
|
244
|
+
rescue CnpjDV::DomainError
|
|
245
|
+
# CnpjDV::InvalidLengthError, CnpjDV::ValidationError, and other DomainError subclasses
|
|
246
|
+
|
|
247
|
+
# 3) CnpjDV::Error — catches everything the library raises.
|
|
248
|
+
rescue CnpjDV::Error
|
|
249
|
+
# every custom error that includes CnpjDV::Error
|
|
140
250
|
|
|
141
|
-
#
|
|
142
|
-
|
|
143
|
-
CnpjDV::
|
|
144
|
-
rescue CnpjDV::CnpjCheckDigitsInputTypeError => e
|
|
145
|
-
puts e.message
|
|
146
|
-
# => CNPJ input must be of type string or string[]. Got integer number.
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Length (must be 12–14 alphanumeric characters after sanitization)
|
|
150
|
-
begin
|
|
151
|
-
CnpjDV::CnpjCheckDigits.new('12345678901')
|
|
152
|
-
rescue CnpjDV::CnpjCheckDigitsInputLengthException => e
|
|
153
|
-
puts e.message
|
|
154
|
-
# => CNPJ input "12345678901" does not contain 12 to 14 characters. Got 11.
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Invalid (e.g. all-zero base or branch, or repeated numeric digits)
|
|
158
|
-
begin
|
|
159
|
-
CnpjDV::CnpjCheckDigits.new('000000000001')
|
|
160
|
-
rescue CnpjDV::CnpjCheckDigitsInputInvalidException => e
|
|
161
|
-
puts e.message
|
|
162
|
-
# => CNPJ input "000000000001" is invalid. Base ID "00000000" is not eligible.
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Any data exception from the package
|
|
166
|
-
begin
|
|
167
|
-
CnpjDV::CnpjCheckDigits.new('000000000001')
|
|
168
|
-
rescue CnpjDV::CnpjCheckDigitsException => e
|
|
169
|
-
puts e.message
|
|
170
|
-
end
|
|
251
|
+
# 4) Specific leaf class — catches only that exact failure mode.
|
|
252
|
+
rescue CnpjDV::InvalidLengthError
|
|
253
|
+
# only CnpjDV::InvalidLengthError
|
|
171
254
|
```
|
|
172
255
|
|
|
173
256
|
Notable attributes on raised errors:
|
|
174
257
|
|
|
175
|
-
- `
|
|
176
|
-
- `
|
|
177
|
-
- `
|
|
258
|
+
- `TypeMismatchError`: `actual_input`, `actual_type`, `expected_type`
|
|
259
|
+
- `InvalidLengthError`: `actual_input`, `evaluated_input`, `min_expected_length`, `max_expected_length`
|
|
260
|
+
- `ValidationError`: `actual_input`, `reason`
|
|
178
261
|
|
|
179
262
|
|
|
180
263
|
|
|
@@ -184,7 +267,7 @@ After `require 'cnpj-dv'`:
|
|
|
184
267
|
|
|
185
268
|
- `CnpjDV::CNPJ_MIN_LENGTH`: `12`
|
|
186
269
|
- `CnpjDV::CNPJ_MAX_LENGTH`: `14`
|
|
187
|
-
- **
|
|
270
|
+
- **Errors**: see above (`CnpjDV::Error`, `DomainError`, and raised leaves)
|
|
188
271
|
|
|
189
272
|
|
|
190
273
|
|
data/README.pt.md
CHANGED
|
@@ -16,7 +16,7 @@ Utilitário em Ruby para calcular os dÃgitos verificadores de CNPJ (Cadastro Na
|
|
|
16
16
|
- ✅ **Avaliação lazy**: DÃgitos verificadores são calculados apenas quando acessados (via métodos)
|
|
17
17
|
- ✅ **Cache**: Valores calculados são armazenados em cache para acessos subsequentes
|
|
18
18
|
- ✅ **Dependências mÃnimas**: Apenas [`lacus-utils`](https://rubygems.org/gems/lacus-utils)
|
|
19
|
-
- ✅ **Tratamento de erros**:
|
|
19
|
+
- ✅ **Tratamento de erros**: Erros de uso da API vs erros de domÃnio, com o marcador `CnpjDV::Error` para resgate em nÃvel de biblioteca
|
|
20
20
|
|
|
21
21
|
## Instalação
|
|
22
22
|
|
|
@@ -96,56 +96,139 @@ CnpjDV::CnpjCheckDigits.new(%w[9141 5732 0007])
|
|
|
96
96
|
CnpjDV::CnpjCheckDigits.new(%w[MG KGM J9X 0001])
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
###
|
|
99
|
+
### Tratamento de erros
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Os erros se dividem em duas categorias:
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
| Categoria | Significado |
|
|
104
|
+
|---|---|
|
|
105
|
+
| **Uso incorreto da API** | O chamador usou a biblioteca de forma incorreta (tipo errado). Detectável pela forma da chamada. |
|
|
106
|
+
| **Erro de domÃnio** | A chamada estava estruturalmente correta, mas um valor viola uma regra de negócio (tamanho, elegibilidade, formato). |
|
|
107
|
+
|
|
108
|
+
Todo erro customizado inclui o módulo marcador `CnpjDV::Error`. Falhas de domÃnio (`InvalidLengthError`, `ValidationError`) herdam de `CnpjDV::DomainError` (`RangeError`).
|
|
109
|
+
|
|
110
|
+
#### Resumo
|
|
111
|
+
|
|
112
|
+
| Classe | Herda de | Categoria | Condição de disparo |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `CnpjDV::TypeMismatchError` | `TypeError` (+ `include Error`) | Uso incorreto da API | Argumento com tipo de dado incorreto |
|
|
115
|
+
| `CnpjDV::InvalidLengthError` | `CnpjDV::DomainError` | Erro de domÃnio | Tamanho após sanitização não é 12–14 |
|
|
116
|
+
| `CnpjDV::ValidationError` | `CnpjDV::DomainError` | Erro de domÃnio | Base/filial inelegÃvel ou dÃgitos numéricos repetidos |
|
|
117
|
+
|
|
118
|
+
#### `CnpjDV::Error` (módulo marcador)
|
|
119
|
+
|
|
120
|
+
- **Herança:** módulo marcador misturado em todo erro da biblioteca via `include` (não é uma classe).
|
|
121
|
+
- **Categoria:** N/A (apenas alvo de `rescue`) — não é um modo de falha por si só.
|
|
122
|
+
- **Quando é levantado:** Nunca diretamente; incluÃdo por todo erro customizado que a biblioteca levanta.
|
|
123
|
+
- **Exemplo:** N/A
|
|
124
|
+
- **Como resgatar:**
|
|
108
125
|
|
|
109
126
|
```ruby
|
|
110
|
-
|
|
127
|
+
rescue CnpjDV::Error
|
|
128
|
+
# tudo o que esta biblioteca levanta
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### `CnpjDV::DomainError`
|
|
132
|
+
|
|
133
|
+
- **Herança:** `CnpjDV::DomainError < RangeError` (inclui `CnpjDV::Error`)
|
|
134
|
+
- **Categoria:** Erro de domÃnio — ancestral das falhas numéricas/de tamanho.
|
|
135
|
+
- **Quando é levantado:** Não é levantado diretamente; prefira uma subclasse folha.
|
|
136
|
+
- **Exemplo:** Prefira `raise CnpjDV::InvalidLengthError` a levantar `DomainError` diretamente.
|
|
137
|
+
- **Como resgatar:**
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
rescue CnpjDV::DomainError
|
|
141
|
+
# InvalidLengthError, ValidationError e qualquer outra subclasse de DomainError
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### `CnpjDV::TypeMismatchError`
|
|
145
|
+
|
|
146
|
+
- **Herança:** `CnpjDV::TypeMismatchError < TypeError` (inclui `CnpjDV::Error`)
|
|
147
|
+
- **Categoria:** Uso incorreto da API — o chamador passou um valor do tipo errado.
|
|
148
|
+
- **Quando é levantado:** Levantado quando a entrada de CNPJ não é `String` nem `Array` de strings (ou o array contém elemento que não é string).
|
|
149
|
+
- **Exemplo:**
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
CnpjDV::CnpjCheckDigits.new(12_345_678_000_100) # levanta CnpjDV::TypeMismatchError
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- **Como resgatar:**
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
rescue CnpjDV::TypeMismatchError
|
|
159
|
+
# violação de contrato de tipo desta biblioteca
|
|
160
|
+
|
|
161
|
+
rescue TypeError
|
|
162
|
+
# erros nativos de tipo, incluindo TypeMismatchError desta biblioteca
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### `CnpjDV::InvalidLengthError`
|
|
166
|
+
|
|
167
|
+
- **Herança:** `CnpjDV::InvalidLengthError < CnpjDV::DomainError < RangeError` (inclui `CnpjDV::Error`)
|
|
168
|
+
- **Categoria:** Erro de domÃnio — o tamanho de uma coleção ou string viola uma regra de negócio.
|
|
169
|
+
- **Quando é levantado:** Levantado quando a entrada de CNPJ sanitizada não contém de 12 a 14 caracteres alfanuméricos.
|
|
170
|
+
- **Exemplo:**
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
CnpjDV::CnpjCheckDigits.new('12345678901') # levanta CnpjDV::InvalidLengthError
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- **Como resgatar:**
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
rescue CnpjDV::InvalidLengthError
|
|
180
|
+
# esta violação exata de tamanho
|
|
181
|
+
|
|
182
|
+
rescue CnpjDV::DomainError
|
|
183
|
+
# falhas de domÃnio enraizadas em RangeError desta biblioteca
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `CnpjDV::ValidationError`
|
|
187
|
+
|
|
188
|
+
- **Herança:** `CnpjDV::ValidationError < CnpjDV::DomainError < RangeError` (inclui `CnpjDV::Error`)
|
|
189
|
+
- **Categoria:** Erro de domÃnio — um valor falha uma regra de domÃnio que não é numérica nem de tamanho.
|
|
190
|
+
- **Quando é levantado:** Levantado quando a base é `00000000`, a filial é `0000`, ou os 12 primeiros caracteres são o mesmo dÃgito numérico.
|
|
191
|
+
- **Exemplo:**
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
CnpjDV::CnpjCheckDigits.new('000000000001') # levanta CnpjDV::ValidationError
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- **Como resgatar:**
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
rescue CnpjDV::ValidationError
|
|
201
|
+
# esta falha exata de validação de domÃnio
|
|
202
|
+
|
|
203
|
+
rescue CnpjDV::DomainError
|
|
204
|
+
# falhas de domÃnio enraizadas em RangeError desta biblioteca
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Granularidade de rescue
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
# 1) Uma classe nativa — captura uso incorreto de tipo desta biblioteca (e outros TypeError).
|
|
211
|
+
rescue TypeError
|
|
212
|
+
# CnpjDV::TypeMismatchError e qualquer outro TypeError (da biblioteca ou não)
|
|
213
|
+
|
|
214
|
+
# 2) CnpjDV::DomainError — captura violações de regra de negócio sob DomainError.
|
|
215
|
+
rescue CnpjDV::DomainError
|
|
216
|
+
# CnpjDV::InvalidLengthError, CnpjDV::ValidationError e outras subclasses de DomainError
|
|
217
|
+
|
|
218
|
+
# 3) CnpjDV::Error — captura tudo o que a biblioteca levanta.
|
|
219
|
+
rescue CnpjDV::Error
|
|
220
|
+
# todo erro customizado que inclui CnpjDV::Error
|
|
111
221
|
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
CnpjDV::
|
|
115
|
-
rescue CnpjDV::CnpjCheckDigitsInputTypeError => e
|
|
116
|
-
puts e.message
|
|
117
|
-
# => CNPJ input must be of type string or string[]. Got integer number.
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Tamanho (deve ser 12–14 caracteres alfanuméricos após sanitização)
|
|
121
|
-
begin
|
|
122
|
-
CnpjDV::CnpjCheckDigits.new('12345678901')
|
|
123
|
-
rescue CnpjDV::CnpjCheckDigitsInputLengthException => e
|
|
124
|
-
puts e.message
|
|
125
|
-
# => CNPJ input "12345678901" does not contain 12 to 14 characters. Got 11.
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# Inválido (ex.: base ou filial zeradas, ou dÃgitos numéricos repetidos)
|
|
129
|
-
begin
|
|
130
|
-
CnpjDV::CnpjCheckDigits.new('000000000001')
|
|
131
|
-
rescue CnpjDV::CnpjCheckDigitsInputInvalidException => e
|
|
132
|
-
puts e.message
|
|
133
|
-
# => CNPJ input "000000000001" is invalid. Base ID "00000000" is not eligible.
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Qualquer exceção de dados do pacote
|
|
137
|
-
begin
|
|
138
|
-
CnpjDV::CnpjCheckDigits.new('000000000001')
|
|
139
|
-
rescue CnpjDV::CnpjCheckDigitsException => e
|
|
140
|
-
puts e.message
|
|
141
|
-
end
|
|
222
|
+
# 4) Classe folha especÃfica — captura apenas aquele modo de falha.
|
|
223
|
+
rescue CnpjDV::InvalidLengthError
|
|
224
|
+
# apenas CnpjDV::InvalidLengthError
|
|
142
225
|
```
|
|
143
226
|
|
|
144
227
|
Atributos relevantes nos erros:
|
|
145
228
|
|
|
146
|
-
- `
|
|
147
|
-
- `
|
|
148
|
-
- `
|
|
229
|
+
- `TypeMismatchError`: `actual_input`, `actual_type`, `expected_type`
|
|
230
|
+
- `InvalidLengthError`: `actual_input`, `evaluated_input`, `min_expected_length`, `max_expected_length`
|
|
231
|
+
- `ValidationError`: `actual_input`, `reason`
|
|
149
232
|
|
|
150
233
|
### Outros recursos disponÃveis
|
|
151
234
|
|
|
@@ -153,7 +236,7 @@ Após `require 'cnpj-dv'`:
|
|
|
153
236
|
|
|
154
237
|
- **`CnpjDV::CNPJ_MIN_LENGTH`**: `12`
|
|
155
238
|
- **`CnpjDV::CNPJ_MAX_LENGTH`**: `14`
|
|
156
|
-
- **
|
|
239
|
+
- **Erros**: veja acima (`CnpjDV::Error`, `DomainError` e folhas levantadas)
|
|
157
240
|
|
|
158
241
|
## Algoritmo de cálculo
|
|
159
242
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
3
|
+
require_relative 'errors'
|
|
4
4
|
|
|
5
5
|
module CnpjDV
|
|
6
6
|
# Minimum number of characters required for the CNPJ check digits calculation.
|
|
@@ -45,13 +45,11 @@ module CnpjDV
|
|
|
45
45
|
#
|
|
46
46
|
# @param cnpj_input [String, Array<String>] alphanumeric CNPJ with or without
|
|
47
47
|
# formatting, or an array of strings
|
|
48
|
-
# @raise [
|
|
49
|
-
#
|
|
50
|
-
# @raise [
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
# (+00.000.000+), branch ID is all zero (+0000+) or all digits are numeric
|
|
54
|
-
# the same (repeated digits, e.g. +77.777.777/7777-...+)
|
|
48
|
+
# @raise [TypeMismatchError] when input is not a +String+ or +Array<String>+
|
|
49
|
+
# @raise [InvalidLengthError] when character count is not between 12 and 14
|
|
50
|
+
# @raise [ValidationError] when base ID is all zero (+00.000.000+), branch ID
|
|
51
|
+
# is all zero (+0000+) or all digits are numeric the same (repeated digits,
|
|
52
|
+
# e.g. +77.777.777/7777-...+)
|
|
55
53
|
def initialize(cnpj_input)
|
|
56
54
|
parsed_input = parse_input(cnpj_input)
|
|
57
55
|
|
|
@@ -126,13 +124,12 @@ module CnpjDV
|
|
|
126
124
|
#
|
|
127
125
|
# @param cnpj_input [Object] candidate CNPJ input
|
|
128
126
|
# @return [Array<String>] uppercase alphanumeric characters
|
|
129
|
-
# @raise [
|
|
130
|
-
# +Array<String>+
|
|
127
|
+
# @raise [TypeMismatchError] when input is not a +String+ or +Array<String>+
|
|
131
128
|
def parse_input(cnpj_input)
|
|
132
129
|
return parse_string_input(cnpj_input) if cnpj_input.is_a?(String)
|
|
133
130
|
return parse_array_input(cnpj_input) if cnpj_input.is_a?(Array)
|
|
134
131
|
|
|
135
|
-
raise
|
|
132
|
+
raise TypeMismatchError.new(cnpj_input, 'string or string[]')
|
|
136
133
|
end
|
|
137
134
|
|
|
138
135
|
# Strips non-alphanumeric characters and uppercases the remainder.
|
|
@@ -158,12 +155,11 @@ module CnpjDV
|
|
|
158
155
|
#
|
|
159
156
|
# @param cnpj_array [Array] candidate array of string chunks
|
|
160
157
|
# @return [Array<String>] uppercase alphanumeric characters
|
|
161
|
-
# @raise [
|
|
162
|
-
# +Array<String>+
|
|
158
|
+
# @raise [TypeMismatchError] when input is not a +String+ or +Array<String>+
|
|
163
159
|
def parse_array_input(cnpj_array)
|
|
164
160
|
return [] if cnpj_array.empty?
|
|
165
161
|
|
|
166
|
-
raise
|
|
162
|
+
raise TypeMismatchError.new(cnpj_array, 'string or string[]') unless cnpj_array.all?(String)
|
|
167
163
|
|
|
168
164
|
parse_string_input(cnpj_array.join)
|
|
169
165
|
end
|
|
@@ -173,14 +169,13 @@ module CnpjDV
|
|
|
173
169
|
#
|
|
174
170
|
# @param cnpj_chars [Array<String>] normalized characters
|
|
175
171
|
# @param original_input [String, Array<String>] original caller input
|
|
176
|
-
# @raise [
|
|
177
|
-
# between 12 and 14
|
|
172
|
+
# @raise [InvalidLengthError] when character count is not between 12 and 14
|
|
178
173
|
def validate_length(cnpj_chars, original_input)
|
|
179
174
|
chars_count = cnpj_chars.length
|
|
180
175
|
|
|
181
176
|
return if chars_count.between?(CNPJ_MIN_LENGTH, CNPJ_MAX_LENGTH)
|
|
182
177
|
|
|
183
|
-
raise
|
|
178
|
+
raise InvalidLengthError.new(
|
|
184
179
|
original_input,
|
|
185
180
|
cnpj_chars.join,
|
|
186
181
|
CNPJ_MIN_LENGTH,
|
|
@@ -192,12 +187,11 @@ module CnpjDV
|
|
|
192
187
|
#
|
|
193
188
|
# @param cnpj_chars [Array<String>] normalized characters
|
|
194
189
|
# @param original_input [String, Array<String>] original caller input
|
|
195
|
-
# @raise [
|
|
196
|
-
# (+00.000.000+)
|
|
190
|
+
# @raise [ValidationError] when base ID is all zeros (+00.000.000+)
|
|
197
191
|
def validate_base_id(cnpj_chars, original_input)
|
|
198
192
|
return unless cnpj_chars[0, CNPJ_BASE_ID_LENGTH].all? { |char| char == '0' }
|
|
199
193
|
|
|
200
|
-
raise
|
|
194
|
+
raise ValidationError.new(
|
|
201
195
|
original_input,
|
|
202
196
|
"Base ID \"#{CNPJ_INVALID_BASE_ID}\" is not eligible."
|
|
203
197
|
)
|
|
@@ -207,8 +201,7 @@ module CnpjDV
|
|
|
207
201
|
#
|
|
208
202
|
# @param cnpj_chars [Array<String>] normalized characters
|
|
209
203
|
# @param original_input [String, Array<String>] original caller input
|
|
210
|
-
# @raise [
|
|
211
|
-
# (+0000+)
|
|
204
|
+
# @raise [ValidationError] when branch ID is all zeros (+0000+)
|
|
212
205
|
def validate_branch_id(cnpj_chars, original_input)
|
|
213
206
|
branch_start = CNPJ_BASE_ID_LENGTH
|
|
214
207
|
branch_end = branch_start + CNPJ_BRANCH_ID_LENGTH
|
|
@@ -216,7 +209,7 @@ module CnpjDV
|
|
|
216
209
|
|
|
217
210
|
return unless branch_id.all? { |char| char == '0' }
|
|
218
211
|
|
|
219
|
-
raise
|
|
212
|
+
raise ValidationError.new(
|
|
220
213
|
original_input,
|
|
221
214
|
"Branch ID \"#{CNPJ_INVALID_BRANCH_ID}\" is not eligible."
|
|
222
215
|
)
|
|
@@ -226,14 +219,14 @@ module CnpjDV
|
|
|
226
219
|
#
|
|
227
220
|
# @param cnpj_chars [Array<String>] normalized characters
|
|
228
221
|
# @param original_input [String, Array<String>] original caller input
|
|
229
|
-
# @raise [
|
|
230
|
-
#
|
|
222
|
+
# @raise [ValidationError] when all digits are numeric the same (repeated
|
|
223
|
+
# digits, e.g. +77.777.777/7777-...+)
|
|
231
224
|
def validate_non_repeated_digits(cnpj_chars, original_input)
|
|
232
225
|
first_char = cnpj_chars[0]
|
|
233
226
|
return unless first_char.match?(/\A\d\z/)
|
|
234
227
|
return unless cnpj_chars[1, CNPJ_MIN_LENGTH - 1].all? { |char| char == first_char }
|
|
235
228
|
|
|
236
|
-
raise
|
|
229
|
+
raise ValidationError.new(
|
|
237
230
|
original_input,
|
|
238
231
|
'Repeated digits are not considered valid.'
|
|
239
232
|
)
|
|
@@ -18,11 +18,17 @@ module CnpjDV
|
|
|
18
18
|
end
|
|
19
19
|
private_constant :FormatActualInput
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# Marker module mixed into every custom error raised by this library.
|
|
22
22
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
23
|
+
# Use +rescue CnpjDV::Error+ to catch every library error regardless of native
|
|
24
|
+
# ancestry.
|
|
25
|
+
module Error; end
|
|
26
|
+
|
|
27
|
+
# API misuse error raised when an argument's runtime type does not match the
|
|
28
|
+
# type required by the API contract.
|
|
29
|
+
class TypeMismatchError < TypeError
|
|
30
|
+
include Error
|
|
31
|
+
|
|
26
32
|
# @return [Object] the offending input value
|
|
27
33
|
attr_reader :actual_input
|
|
28
34
|
|
|
@@ -32,53 +38,29 @@ module CnpjDV
|
|
|
32
38
|
# @return [String] description of the expected type
|
|
33
39
|
attr_reader :expected_type
|
|
34
40
|
|
|
35
|
-
# @param actual_input [Object] the offending input value
|
|
36
|
-
#
|
|
37
|
-
# @param expected_type [String] description of the expected type
|
|
38
|
-
# @param message [String] error message
|
|
39
|
-
def initialize(actual_input, actual_type, expected_type, message)
|
|
40
|
-
super(message)
|
|
41
|
-
@actual_input = actual_input
|
|
42
|
-
@actual_type = actual_type
|
|
43
|
-
@expected_type = expected_type
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Error raised when the input provided to {CnpjCheckDigits} is not of the
|
|
48
|
-
# expected type (+String+ or +Array<String>+). The error message includes both
|
|
49
|
-
# the actual type of the input and the expected type.
|
|
50
|
-
class CnpjCheckDigitsInputTypeError < CnpjCheckDigitsTypeError
|
|
51
|
-
# @param actual_input [Object] the offending input value (the whole array when
|
|
52
|
-
# a non-string element is found)
|
|
41
|
+
# @param actual_input [Object] the offending input value (the whole array
|
|
42
|
+
# when a non-string element is found)
|
|
53
43
|
# @param expected_type [String] description of the expected type (e.g.
|
|
54
44
|
# +"string or string[]"+)
|
|
55
45
|
def initialize(actual_input, expected_type)
|
|
56
46
|
actual_type = LacusUtils.describe_type(actual_input)
|
|
57
47
|
|
|
58
|
-
super(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"CNPJ input must be of type #{expected_type}. Got #{actual_type}."
|
|
63
|
-
)
|
|
48
|
+
super("CNPJ input must be of type #{expected_type}. Got #{actual_type}.")
|
|
49
|
+
@actual_input = actual_input
|
|
50
|
+
@actual_type = actual_type
|
|
51
|
+
@expected_type = expected_type
|
|
64
52
|
end
|
|
65
53
|
end
|
|
66
54
|
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# errors, range errors, and other business logic exceptions that are not
|
|
72
|
-
# strictly type-related.
|
|
73
|
-
class CnpjCheckDigitsException < StandardError
|
|
55
|
+
# Domain error ancestor for business-rule failures (length, validation, and
|
|
56
|
+
# other domain leaves). Prefer raising a leaf subclass.
|
|
57
|
+
class DomainError < RangeError
|
|
58
|
+
include Error
|
|
74
59
|
end
|
|
75
60
|
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
# distinguishes between the original input and the evaluated one (which strips
|
|
80
|
-
# punctuation characters).
|
|
81
|
-
class CnpjCheckDigitsInputLengthException < CnpjCheckDigitsException
|
|
61
|
+
# Domain error raised when a string, array, or other collection has a length
|
|
62
|
+
# outside the bounds required by the domain rule.
|
|
63
|
+
class InvalidLengthError < DomainError
|
|
82
64
|
# @return [String, Array<String>] the original input
|
|
83
65
|
attr_reader :actual_input
|
|
84
66
|
|
|
@@ -119,11 +101,10 @@ module CnpjDV
|
|
|
119
101
|
end
|
|
120
102
|
end
|
|
121
103
|
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
class CnpjCheckDigitsInputInvalidException < CnpjCheckDigitsException
|
|
104
|
+
# Domain error raised when a value has a valid type and length but violates a
|
|
105
|
+
# validation rule that is not numeric-range or length-based (e.g. ineligible
|
|
106
|
+
# base/branch ID or repeated numeric digits).
|
|
107
|
+
class ValidationError < DomainError
|
|
127
108
|
# @return [String, Array<String>] the original input
|
|
128
109
|
attr_reader :actual_input
|
|
129
110
|
|
data/src/cnpj-dv/version.rb
CHANGED
data/src/cnpj-dv.rb
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'cnpj-dv/version'
|
|
4
|
-
require_relative 'cnpj-dv/
|
|
4
|
+
require_relative 'cnpj-dv/errors'
|
|
5
5
|
require_relative 'cnpj-dv/cnpj_check_digits'
|
|
6
6
|
|
|
7
7
|
# Check-digit calculation for Brazilian CNPJ (numeric and alphanumeric formats).
|
|
8
8
|
#
|
|
9
|
-
#
|
|
9
|
+
# Errors fall into two categories:
|
|
10
10
|
#
|
|
11
|
-
# -
|
|
12
|
-
#
|
|
13
|
-
# -
|
|
14
|
-
#
|
|
11
|
+
# - *API misuse* — the caller invoked the library incorrectly (wrong type).
|
|
12
|
+
# Raised as {CnpjDV::TypeMismatchError} (+TypeError+).
|
|
13
|
+
# - *Domain errors* — the call shape was valid, but a value violates a business
|
|
14
|
+
# rule (invalid length, ineligible base/branch, repeated digits). Length
|
|
15
|
+
# failures raise {CnpjDV::InvalidLengthError}; other domain failures raise
|
|
16
|
+
# {CnpjDV::ValidationError} (both under {CnpjDV::DomainError} / +RangeError+).
|
|
17
|
+
#
|
|
18
|
+
# Every custom error includes the {CnpjDV::Error} marker module so consumers can
|
|
19
|
+
# +rescue CnpjDV::Error+ for a library-wide catch.
|
|
15
20
|
#
|
|
16
21
|
# Public API:
|
|
17
22
|
#
|
|
18
23
|
# - {CnpjDV::CnpjCheckDigits}
|
|
19
24
|
# - {CnpjDV::CNPJ_MIN_LENGTH}, {CnpjDV::CNPJ_MAX_LENGTH}
|
|
20
|
-
# -
|
|
21
|
-
# {CnpjDV::
|
|
25
|
+
# - Error marker {CnpjDV::Error}; domain ancestor {CnpjDV::DomainError};
|
|
26
|
+
# raised leaves {CnpjDV::TypeMismatchError}, {CnpjDV::InvalidLengthError},
|
|
27
|
+
# {CnpjDV::ValidationError}
|
|
22
28
|
#
|
|
23
29
|
# @example
|
|
24
30
|
# require 'cnpj-dv'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cnpj-dv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julio L. Muller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lacus-utils
|
|
@@ -43,7 +43,7 @@ files:
|
|
|
43
43
|
- README.pt.md
|
|
44
44
|
- src/cnpj-dv.rb
|
|
45
45
|
- src/cnpj-dv/cnpj_check_digits.rb
|
|
46
|
-
- src/cnpj-dv/
|
|
46
|
+
- src/cnpj-dv/errors.rb
|
|
47
47
|
- src/cnpj-dv/version.rb
|
|
48
48
|
homepage: https://github.com/LacusSolutions/br-utils-ruby
|
|
49
49
|
licenses:
|