cpf-utilities 0.0.0 → 1.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.
data/README.pt.md ADDED
@@ -0,0 +1,642 @@
1
+ ![cpf-utilities para Ruby](https://br-utils.vercel.app/img/cover_cpf-utils.jpg)
2
+
3
+ > 🌎 [Access documentation in English](./README.md)
4
+
5
+ Kit em Ruby para formatar, gerar e validar CPF (Cadastro de Pessoa Física). Envolve [`cpf-fmt`](https://rubygems.org/gems/cpf-fmt), [`cpf-gen`](https://rubygems.org/gems/cpf-gen) e [`cpf-val`](https://rubygems.org/gems/cpf-val) em uma única classe fachada (`CpfUtils`).
6
+
7
+ ## Recursos
8
+
9
+ - ✅ **API unificada**: Helpers de classe `CpfUtils.format` / `.generate` / `.is_valid` (aliases de `CpfUtils::DEFAULT`); `DEFAULT` mutável para ajustes compartilhados
10
+ - ✅ **Acesso em dois níveis**: Prefira `CpfUtils::CpfFormatter` / `CpfGenerator` / `CpfValidator` para as classes principais; Options, helpers e erros ficam em `CpfUtils::CpfFmt` / `CpfGen` / `CpfVal` (os irmãos na raiz `CpfFmt` / `CpfGen` / `CpfVal` continuam funcionando)
11
+ - ✅ **CPF numérico**: Formatar, gerar e validar CPF de 11 dígitos (`XXX.XXX.XXX-XX`)
12
+ - ✅ **Instância reutilizável**: Classe `CpfUtils` com configurações padrão opcionais (opções ou instâncias do formatador/gerador; instância do validador)
13
+ - ✅ **Entrada flexível**: `#format` e `#is_valid` aceitam `String` ou `Array` de strings (elementos concatenados na ordem)
14
+ - ✅ **Sobrescritas por chamada**: Padrões da instância mais um `Hash`/instância `*Options` por chamada **ou** sobrescritas por palavra-chave em `#format` / `#generate` (não ambos); `#is_valid` recebe apenas a entrada
15
+ - ✅ **Tratamento de erros**: Erros dos componentes propagam inalterados; esta gem define `CpfUtils::TypeMismatchError` e `CpfUtils::InvalidArgumentCombinationError` para uso indevido da API
16
+
17
+ ## Instalação
18
+
19
+ Instale a gem diretamente:
20
+
21
+ ```bash
22
+ gem install cpf-utilities
23
+ ```
24
+
25
+ Ou adicione ao seu `Gemfile` e execute `bundle install`:
26
+
27
+ ```ruby
28
+ gem 'cpf-utilities'
29
+ ```
30
+
31
+ Isso instala **`cpf-utilities`** junto com [`cpf-fmt`](https://rubygems.org/gems/cpf-fmt), [`cpf-gen`](https://rubygems.org/gems/cpf-gen) e [`cpf-val`](https://rubygems.org/gems/cpf-val). Você **não** precisa de `gem install` / linhas `gem` separados para os pacotes componentes ao usar **`cpf-utilities`**.
32
+
33
+ ## Require
34
+
35
+ ```ruby
36
+ require 'cpf-utilities'
37
+ ```
38
+
39
+ ## Início rápido
40
+
41
+ Uso básico com helpers de classe (aliases de `CpfUtils::DEFAULT`):
42
+
43
+ ```ruby
44
+ require 'cpf-utilities'
45
+
46
+ cpf = '12345678909'
47
+
48
+ CpfUtils.format(cpf) # => "123.456.789-09"
49
+ CpfUtils.format(cpf, hidden: true) # => "123.***.***-**"
50
+ CpfUtils.format( # => "123456789_09"
51
+ cpf,
52
+ dot_key: '',
53
+ dash_key: '_'
54
+ )
55
+
56
+ CpfUtils.generate # => ex.: "47844241055" (11 dígitos numéricos)
57
+ CpfUtils.generate(format: true) # => ex.: "478.442.410-55"
58
+ CpfUtils.generate(prefix: '528250911') # => ex.: "52825091138"
59
+
60
+ CpfUtils.is_valid('12345678909') # => true
61
+ CpfUtils.is_valid('123.456.789-09') # => true
62
+ CpfUtils.is_valid('12345678900') # => false
63
+ ```
64
+
65
+ ## Utilização
66
+
67
+ Você pode trabalhar destas formas equivalentes:
68
+
69
+ 1. **`CpfUtils.format` / `.generate` / `.is_valid`** — helpers de classe para chamadas rápidas (encaminham para `DEFAULT`).
70
+ 2. **`CpfUtils::DEFAULT`** — singleton compartilhado mutável (o mesmo objeto usado pelos helpers de classe; em todo o processo / não isolado por thread).
71
+ 3. **`CpfUtils.new`** — instância configurável com padrões compartilhados entre formatar, gerar e validar.
72
+ 4. **Classes principais sob `CpfUtils`** — `CpfUtils::CpfFormatter`, `CpfUtils::CpfGenerator`, `CpfUtils::CpfValidator`.
73
+ 5. **Módulos aninhados do pacote** — Options, helpers, erros e tipos via `CpfUtils::CpfFmt` / `CpfGen` / `CpfVal` (ex.: `CpfUtils::CpfFmt::CpfFormatterOptions`, `CpfUtils::CpfFmt.cpf_fmt`).
74
+ 6. **Módulos irmãos na raiz** (ainda suportados) — `CpfFmt`, `CpfGen`, `CpfVal` inalterados.
75
+
76
+ Todas as abordagens expõem as mesmas opções e comportamento. Para tabelas de opções exaustivas e detalhes específicos de cada componente, consulte o README de cada [pacote incluído](#pacotes-incluídos).
77
+
78
+ ### Opções do formatador
79
+
80
+ Em `#format(cpf_input, options = nil, **keywords)`, todas as opções são opcionais:
81
+
82
+ | Opção | Tipo | Padrão | Descrição |
83
+ |--------|------|---------|-------------|
84
+ | `hidden` | `Boolean` | `false` | Se `true`, mascara dígitos entre `hidden_start` e `hidden_end` com `hidden_key` |
85
+ | `hidden_key` | `String` | `'*'` | Caractere(s) usados para substituir os dígitos mascarados |
86
+ | `hidden_start` | `Integer` | `3` | Índice inicial (0–10, inclusivo) do intervalo a ocultar |
87
+ | `hidden_end` | `Integer` | `10` | Índice final (0–10, inclusivo) do intervalo a ocultar |
88
+ | `dot_key` | `String` | `'.'` | Delimitador de ponto (ex.: em `123.456.789`) |
89
+ | `dash_key` | `String` | `'-'` | Delimitador de hífen (ex.: antes dos dígitos verificadores `…-09`) |
90
+ | `escape` | `Boolean` | `false` | Se `true`, escapa caracteres especiais HTML no resultado |
91
+ | `encode` | `Boolean` | `false` | Se `true`, codifica o resultado para URL (similar ao `encodeURIComponent` do JavaScript) |
92
+ | `on_fail` | `Proc` / invocável | retorna `''` | Callback quando o tamanho da entrada sanitizada ≠ 11; o retorno é usado como resultado |
93
+
94
+ ### Opções do gerador
95
+
96
+ Em `#generate(options = nil, **keywords)`, todas as opções são opcionais:
97
+
98
+ | Opção | Tipo | Padrão | Descrição |
99
+ |--------|------|---------|-------------|
100
+ | `format` | `Boolean` | `false` | Se `true`, retorna o CPF gerado no formato padrão (`000.000.000-00`) |
101
+ | `prefix` | `String` | `''` | String inicial parcial (0–9 dígitos). Não-dígitos são removidos; os caracteres faltantes são gerados e os dígitos verificadores calculados. Prefixos com mais de 9 dígitos são truncados silenciosamente. |
102
+
103
+ Regras do prefixo: a base (primeiros 9 dígitos) não pode ser todos zeros; 9 dígitos repetidos (ex.: `999999999`) também não são permitidos.
104
+
105
+ ### Helpers de classe (`CpfUtils.format` / `.generate` / `.is_valid`)
106
+
107
+ Esses métodos de classe são aliases dos mesmos métodos em `CpfUtils::DEFAULT`. Prefira-os para chamadas pontuais:
108
+
109
+ ```ruby
110
+ CpfUtils.format('12345678909')
111
+ CpfUtils.generate(format: true)
112
+ CpfUtils.is_valid('12345678909')
113
+ ```
114
+
115
+ ### `CpfUtils::DEFAULT` (instância padrão)
116
+
117
+ `CpfUtils::DEFAULT` é o singleton pré-construído e **mutável** por trás dos helpers de classe (paridade com o export padrão do JS / `cpf_utils` do Python). A configuração é **em todo o processo e compartilhada entre threads**: mutá-lo (ex.: `DEFAULT.formatter = …`) afeta chamadas seguintes a `CpfUtils.format` / `.generate` / `.is_valid` para todos os chamadores no processo. Prefira `CpfUtils.new` ou opções por chamada para trabalho concorrente ou isolado; instâncias personalizadas permanecem independentes de `DEFAULT`:
118
+
119
+ ```ruby
120
+ CpfUtils::DEFAULT.formatter = { dash_key: '|' }
121
+ CpfUtils.format('12345678909') # => "123.456.789|09"
122
+
123
+ custom = CpfUtils.new
124
+ custom.format('12345678909') # => "123.456.789-09" (não afetado)
125
+ ```
126
+
127
+ Métodos de instância em `DEFAULT` (e em qualquer instância de `CpfUtils`):
128
+
129
+ - **`#format(cpf_input, options = nil, **keywords)`**: Formata uma string CPF ou array de strings. Delega ao formatador interno. A entrada deve ter 11 dígitos (após sanitização); caso contrário, `on_fail` é usado.
130
+ - **`#generate(options = nil, **keywords)`**: Gera um CPF válido. Delega ao gerador interno.
131
+ - **`#is_valid(cpf_input)`**: Retorna `true` se o CPF for válido. Delega ao validador interno. Sem opções por chamada — o validador de CPF não tem nenhuma.
132
+
133
+ ### `CpfUtils` (classe)
134
+
135
+ Para formatador, gerador ou validador padrão personalizados, crie sua própria instância:
136
+
137
+ ```ruby
138
+ require 'cpf-utilities'
139
+
140
+ utils = CpfUtils.new(
141
+ formatter: { hidden: true, hidden_key: '#' },
142
+ generator: { format: true, prefix: '123' }
143
+ )
144
+
145
+ utils.format('47844241055') # => "478.###.###-##"
146
+ utils.generate # => ex.: "123.456.789-09"
147
+ utils.is_valid('123.456.789-09') # => true
148
+
149
+ # Acessar ou substituir instâncias internas
150
+ utils.formatter # => CpfFmt::CpfFormatter
151
+ utils.generator # => CpfGen::CpfGenerator
152
+ utils.validator # => CpfVal::CpfValidator
153
+ ```
154
+
155
+ - **`CpfUtils.new(settings = nil, **keywords)`**: Configurações opcionais. Passe um `Hash` de settings com as chaves `:formatter`, `:generator` e/ou `:validator`, **ou** as mesmas chaves como argumentos nomeados — não ambos (passar ambos lança `CpfUtils::InvalidArgumentCombinationError`). Para `:formatter` / `:generator`, cada valor pode ser uma instância de componente, uma instância `*Options` (armazenada por referência — mutá-la depois afeta chamadas subsequentes sem sobrescrita por chamada), um `Hash` de opções, ou omitido/`nil` para os padrões. Para `:validator`, passe uma instância de `CpfVal::CpfValidator`, `nil` ou um objeto duck-typed — **não** um `Hash` de opções (não existe `CpfValidatorOptions`).
156
+ - **`#format(cpf_input, options = nil, **keywords)`**: Igual à instância padrão; opções por chamada sobrescrevem os padrões do formatador apenas nessa chamada. Passe um `Hash`/`CpfFmt::CpfFormatterOptions` **ou** sobrescritas por palavra-chave — não ambos.
157
+ - **`#generate(options = nil, **keywords)`**: Igual à instância padrão; opções por chamada sobrescrevem os padrões do gerador. Passe um `Hash`/`CpfGen::CpfGeneratorOptions` **ou** sobrescritas por palavra-chave — não ambos.
158
+ - **`#is_valid(cpf_input)`**: Igual à instância padrão. Sem opções por chamada.
159
+ - **`#formatter`**, **`#generator`**, **`#validator`**: Acessores (getters e setters) dos componentes internos. Os setters aceitam as mesmas formas do construtor. Para alterar uma única opção do formatador/gerador sem substituir a instância, mute as opções do componente (ex.: `utils.formatter.options.hidden = true`).
160
+
161
+ Padrões da instância e sobrescritas por chamada:
162
+
163
+ ```ruby
164
+ require 'cpf-utilities'
165
+
166
+ utils = CpfUtils.new(
167
+ formatter: { hidden: true, hidden_key: '#' },
168
+ generator: { format: true }
169
+ )
170
+
171
+ cpf = '12345678909'
172
+
173
+ utils.format(cpf) # mascarado (padrões do formatador da instância)
174
+ utils.format(cpf, hidden: false) # só nesta chamada: sem máscara
175
+ utils.generate(format: false) # só nesta chamada: saída compacta
176
+ utils.is_valid(cpf) # => true
177
+ ```
178
+
179
+ As opções também podem ser passadas como `Hash` (ou instância de opções) em `#format` / `#generate` — sem sobrescritas por palavra-chave:
180
+
181
+ ```ruby
182
+ utils.format(cpf, { dash_key: '|' })
183
+ utils.generate({ prefix: '12345', format: true })
184
+ ```
185
+
186
+ ### Usando classes de componente e módulos aninhados
187
+
188
+ Caminhos preferidos após `require 'cpf-utilities'`:
189
+
190
+ ```ruby
191
+ require 'cpf-utilities'
192
+
193
+ # Classes principais na raiz da fachada
194
+ formatter = CpfUtils::CpfFormatter.new(hidden: true)
195
+ generator = CpfUtils::CpfGenerator.new(format: true)
196
+ validator = CpfUtils::CpfValidator.new
197
+
198
+ formatter.format('47844241055') # => "478.***.***-**"
199
+
200
+ # Options, helpers e erros sob os módulos aninhados do pacote
201
+ options = CpfUtils::CpfFmt::CpfFormatterOptions.new(dash_key: '|')
202
+ CpfUtils::CpfFmt.cpf_fmt('12345678909') # => "123.456.789-09"
203
+
204
+ begin
205
+ CpfUtils::CpfFmt.cpf_fmt(12_345)
206
+ rescue CpfUtils::CpfFmt::TypeMismatchError
207
+ # tipo de entrada incorreto
208
+ end
209
+ ```
210
+
211
+ Os irmãos na raiz continuam suportados (os mesmos objetos que os aninhados):
212
+
213
+ ```ruby
214
+ CpfFmt.cpf_fmt('12345678909', dash_key: '|') # => "123.456.789|09"
215
+ CpfGen.cpf_gen(format: true) # => ex.: "478.442.410-55"
216
+ CpfVal.cpf_val('12345678909') # => true
217
+ CpfFmt::CpfFormatter.new(hidden: true)
218
+ ```
219
+
220
+ Consulte [`cpf-fmt`](../cpf-fmt/README.pt.md), [`cpf-gen`](../cpf-gen/README.pt.md) e [`cpf-val`](../cpf-val/README.pt.md) para detalhes completos de opções e erros.
221
+
222
+ ## API
223
+
224
+ ### Exportações
225
+
226
+ Após `require 'cpf-utilities'`:
227
+
228
+ - **`CpfUtils`**: Classe fachada para criar uma instância com configurações padrão opcionais de formatador, gerador e validador.
229
+ - **`CpfUtils.format` / `.generate` / `.is_valid`**: Helpers de classe que encaminham para `CpfUtils::DEFAULT`.
230
+ - **`CpfUtils::DEFAULT`**: Instância pré-construída mutável de `CpfUtils` (o mesmo objeto usado pelos helpers de classe). Em todo o processo / compartilhada entre threads — prefira `CpfUtils.new` ou opções por chamada sob concorrência.
231
+ - **`CpfUtils::VERSION`**: String da versão da gem.
232
+ - **Atalhos das classes principais**: `CpfUtils::CpfFormatter`, `CpfUtils::CpfGenerator`, `CpfUtils::CpfValidator` (os mesmos objetos das classes irmãs).
233
+ - **Módulos aninhados do pacote**: `CpfUtils::CpfFmt`, `CpfUtils::CpfGen`, `CpfUtils::CpfVal` — superfície completa do irmão (Options, helpers, erros, tipos). Options/helpers/erros **não** são aliasados na raiz de `CpfUtils`.
234
+ - **Módulos irmãos na raiz** (ainda suportados): `CpfFmt`, `CpfGen`, `CpfVal` — os mesmos objetos que os aninhados.
235
+
236
+ ### Erros e exceções
237
+
238
+ `CpfUtils` define apenas erros de uso indevido da API para as regras de argumentos desta gem. Erros de componentes são lançados pelos pacotes incluídos e propagam inalterados.
239
+
240
+ #### Definidos por `cpf-utilities`
241
+
242
+ Os erros definidos por esta gem são apenas de **uso indevido da API** (tipo incorreto ou combinação inválida de argumentos). Todo erro customizado inclui o módulo marcador `CpfUtils::Error`. Esta gem **não** define `CpfUtils::DomainError` nem folhas de domínio — falhas de domínio vêm apenas dos [pacotes incluídos](#propagados-dos-pacotes-incluídos) e mantêm os namespaces desses pacotes (`CpfFmt::…`, `CpfGen::…`, `CpfVal::…`).
243
+
244
+ `rescue CpfUtils::Error` captura **apenas** erros que esta gem lança. **Não** captura erros de componentes que propagam inalterados.
245
+
246
+ ##### Resumo
247
+
248
+ | Classe | Herda de | Categoria | Condição de disparo |
249
+ |--------|----------|-----------|---------------------|
250
+ | `CpfUtils::InvalidArgumentCombinationError` | `CpfUtils::InvalidArgumentCombinationError < ArgumentError < StandardError` (+ `include CpfUtils::Error`) | Uso indevido da API | Construtor: `Hash` de settings não-`nil` com qualquer argumento nomeado não-`nil`; ou `#format`/`#generate`/helpers de classe: `Hash`/instância `*Options` de options não-`nil` com qualquer argumento nomeado não-`nil` |
251
+ | `CpfUtils::TypeMismatchError` | `CpfUtils::TypeMismatchError < TypeError < StandardError` (+ `include CpfUtils::Error`) | Uso indevido da API | Argumento `settings` não-`nil` de `CpfUtils.new` não é um `Hash` |
252
+
253
+ ##### `CpfUtils::Error` (módulo marcador)
254
+
255
+ - **Herança:** módulo marcador misturado em todo erro customizado que esta gem lança via `include` (não é uma classe).
256
+ - **Categoria:** N/A (apenas alvo de `rescue`) — não é um modo de falha por si só.
257
+ - **Quando é lançado:** Nunca é lançado diretamente; incluído em todo erro customizado que esta gem lança.
258
+ - **Exemplo:** N/A
259
+ - **Como resgatá-lo:**
260
+
261
+ ```ruby
262
+ rescue CpfUtils::Error
263
+ # TypeMismatchError e InvalidArgumentCombinationError apenas desta gem
264
+ # (não CpfFmt::*, CpfGen::* nem CpfVal::*)
265
+ ```
266
+
267
+ ##### `CpfUtils::TypeMismatchError`
268
+
269
+ - **Herança:** `CpfUtils::TypeMismatchError < TypeError < StandardError` (inclui `CpfUtils::Error`)
270
+ - **Categoria:** Uso indevido da API — o chamador passou um valor do tipo errado.
271
+ - **Quando é lançado:** Quando `CpfUtils.new` recebe um argumento `settings` não-`nil` que não é um `Hash`.
272
+ - **Exemplo:**
273
+
274
+ ```ruby
275
+ CpfUtils.new('not-a-hash') # lança CpfUtils::TypeMismatchError
276
+ CpfUtils.new(false) # lança CpfUtils::TypeMismatchError (false é não-nil)
277
+ ```
278
+
279
+ - **Como resgatá-lo:**
280
+
281
+ ```ruby
282
+ rescue CpfUtils::TypeMismatchError
283
+ # violação de contrato de tipo desta gem
284
+
285
+ rescue TypeError
286
+ # erros nativos de tipo, incluindo TypeMismatchError desta gem
287
+ ```
288
+
289
+ ##### `CpfUtils::InvalidArgumentCombinationError`
290
+
291
+ - **Herança:** `CpfUtils::InvalidArgumentCombinationError < ArgumentError < StandardError` (inclui `CpfUtils::Error`)
292
+ - **Categoria:** Uso indevido da API — o chamador misturou padrões de argumentos mutuamente exclusivos.
293
+ - **Quando é lançado:** Quando `CpfUtils.new` recebe ao mesmo tempo um `Hash` de settings não-`nil` e qualquer argumento nomeado não-`nil` (`formatter:`, `generator:`, `validator:`); ou quando `#format`, `#generate` ou os helpers de classe recebem ao mesmo tempo um `Hash`/instância `*Options` de options não-`nil` e qualquer argumento nomeado não-`nil`. `#is_valid` não tem caminho de options e não lança este erro.
294
+ - **Exemplo:**
295
+
296
+ ```ruby
297
+ CpfUtils.new({ formatter: { hidden: true } }, generator: { format: true })
298
+ # lança CpfUtils::InvalidArgumentCombinationError
299
+
300
+ CpfUtils.format('12345678909', { hidden: true }, dash_key: '|')
301
+ # lança CpfUtils::InvalidArgumentCombinationError
302
+ ```
303
+
304
+ - **Como resgatá-lo:**
305
+
306
+ ```ruby
307
+ rescue CpfUtils::InvalidArgumentCombinationError
308
+ # combinação de assinatura inválida desta gem
309
+
310
+ rescue ArgumentError
311
+ # erros nativos de argumento, incluindo InvalidArgumentCombinationError desta gem
312
+ ```
313
+
314
+ ##### Granularidade de rescue
315
+
316
+ Cada nível é mostrado como exemplo isolado (não os una numa única escada de `rescue` — um handler nativo amplo tornaria as cláusulas mais estreitas inalcançáveis).
317
+
318
+ ```ruby
319
+ require 'cpf-utilities'
320
+
321
+ # 1) Uma classe nativa — captura erros de uso indevido daquele tipo,
322
+ # inclusive outros TypeError/ArgumentError já tratados no código do consumidor.
323
+ begin
324
+ CpfUtils.new('not-a-hash')
325
+ rescue TypeError
326
+ # CpfUtils::TypeMismatchError e qualquer outro TypeError (da biblioteca ou não)
327
+ end
328
+
329
+ begin
330
+ CpfUtils.new({ formatter: { hidden: true } }, generator: { format: true })
331
+ rescue ArgumentError
332
+ # CpfUtils::InvalidArgumentCombinationError e qualquer outro ArgumentError (da biblioteca ou não)
333
+ end
334
+ ```
335
+
336
+ ```ruby
337
+ require 'cpf-utilities'
338
+
339
+ # 2) DomainError dos pacotes — esta gem não define DomainError; falhas de domínio
340
+ # vêm dos pacotes de componente e mantêm esses namespaces (ex.: CpfFmt).
341
+ begin
342
+ CpfUtils.new.format('12345678909', hidden_start: -1)
343
+ rescue CpfFmt::DomainError
344
+ # CpfFmt::OutOfRangeError, CpfFmt::ValidationError e outras subclasses de DomainError
345
+ end
346
+ ```
347
+
348
+ ```ruby
349
+ require 'cpf-utilities'
350
+
351
+ # 3) CpfUtils::Error — captura tudo o que esta gem lança, independentemente da ancestralidade nativa.
352
+ # Não captura erros CpfFmt::*, CpfGen::* nem CpfVal::*.
353
+ begin
354
+ CpfUtils.new('not-a-hash')
355
+ rescue CpfUtils::Error
356
+ # todo erro customizado que inclui CpfUtils::Error
357
+ end
358
+ ```
359
+
360
+ ```ruby
361
+ require 'cpf-utilities'
362
+
363
+ # 4) Classe folha específica — captura apenas aquele modo de falha.
364
+ begin
365
+ CpfUtils.new('not-a-hash')
366
+ rescue CpfUtils::TypeMismatchError
367
+ # apenas CpfUtils::TypeMismatchError
368
+ end
369
+ ```
370
+
371
+ #### Propagados dos pacotes incluídos
372
+
373
+ Os erros de componentes mantêm os namespaces dos pacotes e propagam inalterados pela fachada (e pelas APIs aninhadas / irmãos na raiz). Cada pacote também expõe um módulo marcador `*::Error` para rescue em toda a biblioteca. **Dados** de CPF inválidos em `#is_valid` retornam `false` (sem raise de domínio). Falha de comprimento na formatação **não** é lançada por `#format` — é entregue a **`on_fail`** como `CpfFmt::InvalidLengthError` (`on_fail` padrão retorna `''`).
374
+
375
+ ##### Resumo
376
+
377
+ | Classe | Herda de | Categoria | Condição de disparo |
378
+ |--------|----------|-----------|---------------------|
379
+ | `CpfFmt::InvalidArgumentCombinationError` | `CpfFmt::InvalidArgumentCombinationError < ArgumentError < StandardError` (+ `include CpfFmt::Error`) | Uso indevido da API | Instância/`Hash` de `options` e qualquer argumento nomeado não-`nil` em `CpfFormatter` / `cpf_fmt` |
380
+ | `CpfFmt::TypeMismatchError` | `CpfFmt::TypeMismatchError < TypeError < StandardError` (+ `include CpfFmt::Error`) | Uso indevido da API | Entrada de CPF ou opção do formatador com tipo errado (ou retorno de `on_fail` que não é `String`) |
381
+ | `CpfGen::InvalidArgumentCombinationError` | `CpfGen::InvalidArgumentCombinationError < ArgumentError < StandardError` (+ `include CpfGen::Error`) | Uso indevido da API | Instância/`Hash` de `options` e qualquer argumento nomeado não-`nil` em `CpfGenerator` / `cpf_gen` |
382
+ | `CpfGen::TypeMismatchError` | `CpfGen::TypeMismatchError < TypeError < StandardError` (+ `include CpfGen::Error`) | Uso indevido da API | Opção do gerador (`format` / `prefix`) com tipo errado |
383
+ | `CpfVal::TypeMismatchError` | `CpfVal::TypeMismatchError < TypeError < StandardError` (+ `include CpfVal::Error`) | Uso indevido da API | Entrada de CPF não é `String` nem `Array` de strings |
384
+ | `CpfFmt::InvalidLengthError` | `CpfFmt::InvalidLengthError < CpfFmt::DomainError < RangeError < StandardError` (+ `include CpfFmt::Error`) | Erro de domínio | Comprimento sanitizado ≠ 11 — **passado a `on_fail`**, não lançado por `#format` |
385
+ | `CpfFmt::OutOfRangeError` | `CpfFmt::OutOfRangeError < CpfFmt::DomainError < RangeError < StandardError` (+ `include CpfFmt::Error`) | Erro de domínio | `hidden_start` / `hidden_end` fora de `0`–`10` |
386
+ | `CpfFmt::ValidationError` | `CpfFmt::ValidationError < CpfFmt::DomainError < RangeError < StandardError` (+ `include CpfFmt::Error`) | Erro de domínio | `hidden_key` / `dot_key` / `dash_key` contém caractere proibido |
387
+ | `CpfGen::ValidationError` | `CpfGen::ValidationError < CpfGen::DomainError < RangeError < StandardError` (+ `include CpfGen::Error`) | Erro de domínio | `prefix` inelegível (base zerada ou 9 dígitos repetidos) |
388
+
389
+ ##### `CpfFmt::DomainError`
390
+
391
+ - **Herança:** `CpfFmt::DomainError < RangeError < StandardError` (inclui `CpfFmt::Error`)
392
+ - **Categoria:** Erro de domínio — ancestral das folhas de domínio do formatador.
393
+ - **Quando é lançado:** Não é lançado diretamente; alvo de rescue para `OutOfRangeError`, `ValidationError` e `InvalidLengthError` re-lançado.
394
+ - **Exemplo:** Prefira resgatar uma folha, ou `CpfFmt::DomainError` para todas as falhas de domínio do formatador.
395
+ - **Como resgatá-lo:**
396
+
397
+ ```ruby
398
+ rescue CpfFmt::DomainError
399
+ # OutOfRangeError, ValidationError, InvalidLengthError (se re-lançado de on_fail)
400
+ ```
401
+
402
+ ##### `CpfFmt::TypeMismatchError`
403
+
404
+ - **Herança:** `CpfFmt::TypeMismatchError < TypeError < StandardError` (inclui `CpfFmt::Error`)
405
+ - **Categoria:** Uso indevido da API — tipo errado para entrada de CPF ou opção do formatador.
406
+ - **Quando é lançado:** Quando `#format` / `cpf_fmt` recebe entrada que não é `String` / `Array<String>`, uma opção tem tipo errado, ou `on_fail` não retorna `String`.
407
+ - **Exemplo:**
408
+
409
+ ```ruby
410
+ CpfUtils.new.format(12_345) # lança CpfFmt::TypeMismatchError
411
+ ```
412
+
413
+ - **Como resgatá-lo:**
414
+
415
+ ```ruby
416
+ rescue CpfFmt::TypeMismatchError
417
+ # violação de contrato de tipo do formatador
418
+
419
+ rescue TypeError
420
+ # erros nativos de tipo, incluindo CpfFmt::TypeMismatchError
421
+ ```
422
+
423
+ ##### `CpfFmt::InvalidArgumentCombinationError`
424
+
425
+ - **Herança:** `CpfFmt::InvalidArgumentCombinationError < ArgumentError < StandardError` (inclui `CpfFmt::Error`)
426
+ - **Categoria:** Uso indevido da API — `options` e keywords misturados na API do formatador.
427
+ - **Quando é lançado:** Por `CpfFmt::CpfFormatter` / `CpfFmt.cpf_fmt` quando uma instância/`Hash` de `options` e qualquer argumento nomeado não-`nil` são passados juntos. (A fachada lança `CpfUtils::InvalidArgumentCombinationError` para o mesmo padrão em `CpfUtils#format`.)
428
+ - **Exemplo:**
429
+
430
+ ```ruby
431
+ CpfFmt::CpfFormatter.new({ dash_key: '_' }, hidden: true)
432
+ # lança CpfFmt::InvalidArgumentCombinationError
433
+ ```
434
+
435
+ - **Como resgatá-lo:**
436
+
437
+ ```ruby
438
+ rescue CpfFmt::InvalidArgumentCombinationError
439
+ # combinação de assinatura inválida do formatador
440
+
441
+ rescue ArgumentError
442
+ # erros nativos de argumento, incluindo este
443
+ ```
444
+
445
+ ##### `CpfFmt::InvalidLengthError` (entregue via callback)
446
+
447
+ - **Herança:** `CpfFmt::InvalidLengthError < CpfFmt::DomainError < RangeError < StandardError` (inclui `CpfFmt::Error`)
448
+ - **Categoria:** Erro de domínio — comprimento sanitizado do CPF não é exatamente 11.
449
+ - **Quando é lançado:** **Não é lançado** por `#format` / `cpf_fmt`; é construído e passado como segundo argumento de `on_fail`.
450
+ - **Exemplo:**
451
+
452
+ ```ruby
453
+ custom_fail = ->(value, error) {
454
+ error # => #<CpfFmt::InvalidLengthError ...>
455
+ "CPF inválido: #{value}"
456
+ }
457
+
458
+ CpfUtils.new.format('123', on_fail: custom_fail) # => "CPF inválido: 123"
459
+ CpfUtils.new.format('123') # => "" (on_fail padrão)
460
+ ```
461
+
462
+ - **Como resgatá-lo:** Trate dentro de `on_fail` (típico), ou faça rescue se re-lançar:
463
+
464
+ ```ruby
465
+ rescue CpfFmt::InvalidLengthError
466
+ # esta violação exata de comprimento
467
+
468
+ rescue CpfFmt::DomainError
469
+ # falhas de domínio com raiz em RangeError de cpf-fmt
470
+ ```
471
+
472
+ ##### `CpfFmt::OutOfRangeError`
473
+
474
+ - **Herança:** `CpfFmt::OutOfRangeError < CpfFmt::DomainError < RangeError < StandardError` (inclui `CpfFmt::Error`)
475
+ - **Categoria:** Erro de domínio — `hidden_start` / `hidden_end` fora de `0`–`10`.
476
+ - **Quando é lançado:** Ao construir ou aplicar opções do formatador com índice de ocultação fora da faixa.
477
+ - **Exemplo:**
478
+
479
+ ```ruby
480
+ CpfUtils.new.format('12345678909', hidden_start: -1) # lança CpfFmt::OutOfRangeError
481
+ ```
482
+
483
+ - **Como resgatá-lo:**
484
+
485
+ ```ruby
486
+ rescue CpfFmt::OutOfRangeError
487
+ # esta violação exata de faixa
488
+
489
+ rescue CpfFmt::DomainError
490
+ # falhas de domínio com raiz em RangeError de cpf-fmt
491
+ ```
492
+
493
+ ##### `CpfFmt::ValidationError`
494
+
495
+ - **Herança:** `CpfFmt::ValidationError < CpfFmt::DomainError < RangeError < StandardError` (inclui `CpfFmt::Error`)
496
+ - **Categoria:** Erro de domínio — opção de chave com caractere proibido.
497
+ - **Quando é lançado:** Quando `hidden_key`, `dot_key` ou `dash_key` contém um caractere proibido.
498
+ - **Exemplo:**
499
+
500
+ ```ruby
501
+ CpfUtils.new(formatter: { dot_key: 'å' }) # lança CpfFmt::ValidationError
502
+ ```
503
+
504
+ - **Como resgatá-lo:**
505
+
506
+ ```ruby
507
+ rescue CpfFmt::ValidationError
508
+ # esta falha exata de validação de domínio
509
+
510
+ rescue CpfFmt::DomainError
511
+ # falhas de domínio com raiz em RangeError de cpf-fmt
512
+ ```
513
+
514
+ ##### `CpfGen::DomainError`
515
+
516
+ - **Herança:** `CpfGen::DomainError < RangeError < StandardError` (inclui `CpfGen::Error`)
517
+ - **Categoria:** Erro de domínio — ancestral das folhas de domínio do gerador.
518
+ - **Quando é lançado:** Não é lançado diretamente; alvo de rescue para `CpfGen::ValidationError`.
519
+ - **Exemplo:** Prefira `rescue CpfGen::ValidationError` ou `CpfGen::DomainError`.
520
+ - **Como resgatá-lo:**
521
+
522
+ ```ruby
523
+ rescue CpfGen::DomainError
524
+ # ValidationError e outras subclasses de DomainError de cpf-gen
525
+ ```
526
+
527
+ ##### `CpfGen::TypeMismatchError`
528
+
529
+ - **Herança:** `CpfGen::TypeMismatchError < TypeError < StandardError` (inclui `CpfGen::Error`)
530
+ - **Categoria:** Uso indevido da API — tipo errado para opção do gerador.
531
+ - **Quando é lançado:** Quando `format` ou `prefix` tem o tipo de runtime errado.
532
+ - **Exemplo:**
533
+
534
+ ```ruby
535
+ CpfUtils.new.generate(prefix: 123) # lança CpfGen::TypeMismatchError
536
+ ```
537
+
538
+ - **Como resgatá-lo:**
539
+
540
+ ```ruby
541
+ rescue CpfGen::TypeMismatchError
542
+ # violação de contrato de tipo do gerador
543
+
544
+ rescue TypeError
545
+ # erros nativos de tipo, incluindo CpfGen::TypeMismatchError
546
+ ```
547
+
548
+ ##### `CpfGen::InvalidArgumentCombinationError`
549
+
550
+ - **Herança:** `CpfGen::InvalidArgumentCombinationError < ArgumentError < StandardError` (inclui `CpfGen::Error`)
551
+ - **Categoria:** Uso indevido da API — `options` e keywords misturados na API do gerador.
552
+ - **Quando é lançado:** Por `CpfGen::CpfGenerator` / `CpfGen.cpf_gen` quando uma instância/`Hash` de `options` e qualquer argumento nomeado não-`nil` são passados juntos. (A fachada lança `CpfUtils::InvalidArgumentCombinationError` para o mesmo padrão em `CpfUtils#generate`.)
553
+ - **Exemplo:**
554
+
555
+ ```ruby
556
+ CpfGen::CpfGenerator.new({ format: true }, prefix: '123')
557
+ # lança CpfGen::InvalidArgumentCombinationError
558
+ ```
559
+
560
+ - **Como resgatá-lo:**
561
+
562
+ ```ruby
563
+ rescue CpfGen::InvalidArgumentCombinationError
564
+ # combinação de assinatura inválida do gerador
565
+
566
+ rescue ArgumentError
567
+ # erros nativos de argumento, incluindo este
568
+ ```
569
+
570
+ ##### `CpfGen::ValidationError`
571
+
572
+ - **Herança:** `CpfGen::ValidationError < CpfGen::DomainError < RangeError < StandardError` (inclui `CpfGen::Error`)
573
+ - **Categoria:** Erro de domínio — `prefix` inelegível.
574
+ - **Quando é lançado:** Quando `prefix` é base zerada (`'000000000'`) ou 9 dígitos repetidos (ex.: `'999999999'`).
575
+ - **Exemplo:**
576
+
577
+ ```ruby
578
+ CpfUtils.new.generate(prefix: '000000000') # lança CpfGen::ValidationError
579
+ ```
580
+
581
+ - **Como resgatá-lo:**
582
+
583
+ ```ruby
584
+ rescue CpfGen::ValidationError
585
+ # esta falha exata de validação de domínio
586
+
587
+ rescue CpfGen::DomainError
588
+ # falhas de domínio com raiz em RangeError de cpf-gen
589
+ ```
590
+
591
+ ##### `CpfVal::TypeMismatchError`
592
+
593
+ - **Herança:** `CpfVal::TypeMismatchError < TypeError < StandardError` (inclui `CpfVal::Error`)
594
+ - **Categoria:** Uso indevido da API — tipo errado para entrada de CPF.
595
+ - **Quando é lançado:** Quando `#is_valid` / `cpf_val` recebe valor que não é `String` nem `Array` de strings (incluindo elemento não-string no array). **Dados** de CPF inválidos retornam `false` e não lançam.
596
+ - **Exemplo:**
597
+
598
+ ```ruby
599
+ CpfUtils.new.is_valid(12_345_678_909) # lança CpfVal::TypeMismatchError
600
+ CpfUtils.new.is_valid('12345678900') # => false (dados inválidos, sem raise)
601
+ ```
602
+
603
+ - **Como resgatá-lo:**
604
+
605
+ ```ruby
606
+ rescue CpfVal::TypeMismatchError
607
+ # violação de contrato de tipo do validador
608
+
609
+ rescue TypeError
610
+ # erros nativos de tipo, incluindo CpfVal::TypeMismatchError
611
+ ```
612
+
613
+ ### Pacotes incluídos
614
+
615
+ | Pacote | Principais recursos | README |
616
+ |--------|---------------------|--------|
617
+ | [`cpf-fmt`](https://rubygems.org/gems/cpf-fmt) | `CpfFmt::CpfFormatter`, `CpfFmt::CpfFormatterOptions`, `CpfFmt.cpf_fmt` | [docs](../cpf-fmt/README.pt.md) |
618
+ | [`cpf-gen`](https://rubygems.org/gems/cpf-gen) | `CpfGen::CpfGenerator`, `CpfGen::CpfGeneratorOptions`, `CpfGen.cpf_gen` | [docs](../cpf-gen/README.pt.md) |
619
+ | [`cpf-val`](https://rubygems.org/gems/cpf-val) | `CpfVal::CpfValidator`, `CpfVal.cpf_val` | [docs](../cpf-val/README.pt.md) |
620
+
621
+ Todos os pacotes acima são instalados como dependências de **`cpf-utilities`**. Para tabelas de opções exaustivas, listas de exceções e comportamento em casos extremos, consulte o README de cada pacote.
622
+
623
+ ## Contribuição e suporte
624
+
625
+ Contribuições são bem-vindas! Consulte as [Diretrizes de contribuição](https://github.com/LacusSolutions/br-utils-ruby/blob/main/CONTRIBUTING.md). Se o projeto for útil para você, considere:
626
+
627
+ - ⭐ Dar uma estrela no repositório
628
+ - 🤝 Contribuir com código
629
+ - 💡 [Sugerir novas funcionalidades](https://github.com/LacusSolutions/br-utils-ruby/issues)
630
+ - 🐛 [Reportar bugs](https://github.com/LacusSolutions/br-utils-ruby/issues)
631
+
632
+ ## Licença
633
+
634
+ Este projeto está sob a licença MIT — veja o arquivo [LICENSE](https://github.com/LacusSolutions/br-utils-ruby/blob/main/LICENSE).
635
+
636
+ ## Changelog
637
+
638
+ Veja o [CHANGELOG](./CHANGELOG.md) para alterações e histórico de versões.
639
+
640
+ ---
641
+
642
+ Feito com ❤️ por [Lacus Solutions](https://github.com/LacusSolutions)
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CpfUtils
4
+ # Nested package module — same object as +::CpfFmt+ (Options, helpers, errors, types).
5
+ CpfFmt = ::CpfFmt
6
+
7
+ CpfFormatter = CpfFmt::CpfFormatter
8
+ CpfFormatterOptions = CpfFmt::CpfFormatterOptions
9
+ CpfFormatterError = CpfFmt::Error
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CpfUtils
4
+ # Nested package module — same object as +::CpfGen+ (Options, helpers, errors, types).
5
+ CpfGen = ::CpfGen
6
+
7
+ CpfGenerator = CpfGen::CpfGenerator
8
+ CpfGeneratorOptions = CpfGen::CpfGeneratorOptions
9
+ CpfGeneratorError = CpfGen::Error
10
+ end