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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 589e0576ee9e9cc2ddfeaf94c5f745792880885d7ea8dfcfb0953695b32a8981
4
- data.tar.gz: 6662f13dfc238ea843cb79b14d1aaaf526c311e31f63dfc47937846a82ea3a2f
3
+ metadata.gz: 8d6109a8bd760c61186dc99ec5503bb42880d9ebb3c19745962ba5a0d97c6cfc
4
+ data.tar.gz: 47242e1f246d23ebab4d8c3be97d7d7b46060c974e011ad0412a93595fb69767
5
5
  SHA512:
6
- metadata.gz: a3dbe7e29ebf3299714c285c90fbf170c6fb8a41e028e9fe64216d411233505cb7bb0230369e82d1a71dd14829c1b0031a046fefd21b96f0589af82af34bba09
7
- data.tar.gz: 3a9f8a328af8c39185dc607db7529da03596235aa194ac57ad2fcdf623b5aad7f4a54124f6926f727a79fd89e9872212b21027a8e707e48d7d7961f902c1b86f
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**: Specific types for type, length, and invalid CNPJ scenarios (`TypeError` vs `StandardError` semantics)
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
- ### Errors & exceptions handling
128
+ ### Error handling
129
129
 
130
- This package uses **TypeError vs StandardError** semantics: *type errors* indicate incorrect API use (e.g. wrong type); *exceptions* indicate invalid or ineligible data (e.g. invalid length or business rules). You can rescue specific classes or use the base classes.
130
+ Errors fall into two categories:
131
131
 
132
- - `CnpjDV::CnpjCheckDigitsTypeError` — base class for type errors; extends Ruby’s `TypeError`
133
- - `CnpjDV::CnpjCheckDigitsInputTypeError` — input is not `String` or `Array` of strings (or array contains a non-string element)
134
- - `CnpjDV::CnpjCheckDigitsException` — base class for data/flow exceptions; extends `StandardError`
135
- - `CnpjDV::CnpjCheckDigitsInputLengthException` — sanitized length is not 12–14
136
- - `CnpjDV::CnpjCheckDigitsInputInvalidException` — base ID `00000000`, branch ID `0000`, or 12 identical numeric digits (repeated-digit pattern)
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
- require 'cnpj-dv'
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
- # Input type (e.g. integer not allowed)
142
- begin
143
- CnpjDV::CnpjCheckDigits.new(12_345_678_000_100)
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
- - `CnpjCheckDigitsInputTypeError`: `actual_input`, `actual_type`, `expected_type`
176
- - `CnpjCheckDigitsInputLengthException`: `actual_input`, `evaluated_input`, `min_expected_length`, `max_expected_length`
177
- - `CnpjCheckDigitsInputInvalidException`: `actual_input`, `reason`
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
- - **Exceptions**: see above
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**: Tipos específicos para tipo, tamanho e CNPJ inválido (semântica `TypeError` vs `StandardError`)
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
- ### Erros e exceções
99
+ ### Tratamento de erros
100
100
 
101
- Este pacote usa a distinção **TypeError vs StandardError**: *erros de tipo* indicam uso incorreto da API (ex.: tipo errado); *exceções* indicam dados inválidos ou inelegíveis (ex.: tamanho ou regras de negócio). Você pode resgatar classes específicas ou as classes base.
101
+ Os erros se dividem em duas categorias:
102
102
 
103
- - **`CnpjDV::CnpjCheckDigitsTypeError`** — classe base para erros de tipo; estende o `TypeError` do Ruby
104
- - **`CnpjDV::CnpjCheckDigitsInputTypeError`** — entrada não é `String` nem `Array` de strings (ou o array contém elemento que não é string)
105
- - **`CnpjDV::CnpjCheckDigitsException`** — classe base para exceções de dados/fluxo; estende `StandardError`
106
- - **`CnpjDV::CnpjCheckDigitsInputLengthException`** — tamanho após sanitização não é 12–14
107
- - **`CnpjDV::CnpjCheckDigitsInputInvalidException`** — base `00000000`, filial `0000`, ou 12 dígitos numéricos idênticos (padrão de repetição)
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
- require 'cnpj-dv'
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
- # Tipo de entrada (ex.: inteiro não permitido)
113
- begin
114
- CnpjDV::CnpjCheckDigits.new(12_345_678_000_100)
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
- - `CnpjCheckDigitsInputTypeError`: `actual_input`, `actual_type`, `expected_type`
147
- - `CnpjCheckDigitsInputLengthException`: `actual_input`, `evaluated_input`, `min_expected_length`, `max_expected_length`
148
- - `CnpjCheckDigitsInputInvalidException`: `actual_input`, `reason`
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
- - **Exceções**: veja acima
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 'exceptions'
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 [CnpjCheckDigitsInputTypeError] when input is not a +String+ or
49
- # +Array<String>+
50
- # @raise [CnpjCheckDigitsInputLengthException] when character count is not
51
- # between 12 and 14
52
- # @raise [CnpjCheckDigitsInputInvalidException] when base ID is all zero
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 [CnpjCheckDigitsInputTypeError] when input is not a +String+ or
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 CnpjCheckDigitsInputTypeError.new(cnpj_input, 'string or string[]')
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 [CnpjCheckDigitsInputTypeError] when input is not a +String+ or
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 CnpjCheckDigitsInputTypeError.new(cnpj_array, 'string or string[]') unless cnpj_array.all?(String)
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 [CnpjCheckDigitsInputLengthException] when character count is not
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 CnpjCheckDigitsInputLengthException.new(
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 [CnpjCheckDigitsInputInvalidException] when base ID is all zeros
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 CnpjCheckDigitsInputInvalidException.new(
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 [CnpjCheckDigitsInputInvalidException] when branch ID is all zeros
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 CnpjCheckDigitsInputInvalidException.new(
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 [CnpjCheckDigitsInputInvalidException] when all digits are numeric
230
- # the same (repeated digits, e.g. +77.777.777/7777-...+)
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 CnpjCheckDigitsInputInvalidException.new(
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
- # Base error for all `cnpj-dv` type-related errors.
21
+ # Marker module mixed into every custom error raised by this library.
22
22
  #
23
- # This class extends the native {TypeError} and serves as the base for all
24
- # type validation errors in {CnpjCheckDigits}.
25
- class CnpjCheckDigitsTypeError < TypeError
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
- # @param actual_type [String] human-readable type of +actual_input+
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
- actual_input,
60
- actual_type,
61
- expected_type,
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
- # Base exception for all `cnpj-dv` rules-related errors.
68
- #
69
- # This class extends the native {StandardError} and serves as the base for all
70
- # non-type-related errors in {CnpjCheckDigits}. It is suitable for validation
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
- # Error raised when the input (after optional processing) does not have the
77
- # required length to calculate the check digits. A valid CNPJ input must
78
- # contain between 12 and 14 alphanumeric characters. The error message
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
- # Exception raised when the CNPJ input contains invalid character sequences,
123
- # like all digits are repeated. This is a business logic exception and it is
124
- # highly recommended that users of the library catch it and handle it
125
- # appropriately.
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CnpjDV
4
- VERSION = '1.0.0'
4
+ VERSION = '2.0.0'
5
5
  end
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/exceptions'
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
- # The package distinguishes between **errors** and **exceptions**:
9
+ # Errors fall into two categories:
10
10
  #
11
- # - {CnpjDV::CnpjCheckDigitsTypeError} (extends the native {TypeError})
12
- # signals incorrect API usage (the input is of the wrong *type*).
13
- # - {CnpjDV::CnpjCheckDigitsException} (extends the native {StandardError})
14
- # signals invalid or ineligible data (right type, bad value).
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
- # - Exception hierarchy under {CnpjDV::CnpjCheckDigitsTypeError} /
21
- # {CnpjDV::CnpjCheckDigitsException}
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: 1.0.0
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-08 00:00:00.000000000 Z
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/exceptions.rb
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: