cnpj-fmt 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/LICENSE +9 -0
- data/README.md +463 -0
- data/README.pt.md +448 -0
- data/src/cnpj-fmt/cnpj_fmt.rb +30 -0
- data/src/cnpj-fmt/cnpj_formatter.rb +169 -0
- data/src/cnpj-fmt/cnpj_formatter_options.rb +443 -0
- data/src/cnpj-fmt/errors.rb +175 -0
- data/src/cnpj-fmt/types.rb +66 -0
- data/src/cnpj-fmt/utils.rb +135 -0
- data/src/cnpj-fmt/version.rb +1 -1
- data/src/cnpj-fmt.rb +43 -3
- metadata +38 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de41b993d08e5fd1f5ae78715c3e53d258fbfa9317128b956bff8a0f85df229e
|
|
4
|
+
data.tar.gz: 0f1f079bc24c168dd6034725e1f182ce42bc147ec1631fee1aced8a2c9064558
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63db23a5ecaf644557b6d35b32070e011a4e62654d3ec758563e7722d6e081dd07d01a215a6c4c52ca282cac23e2cb615a67282735d703fc8d4a0dfa84e957a9
|
|
7
|
+
data.tar.gz: 738675dbee04c5f80969f4ec77f095070163b41e0ae2f75855cc24e18246618bc260fe1a9620f6a2b2edaa35e5dbb20274de740d594585baa50f983a6e13a028
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# cnpj-fmt
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### π Stable Version Released!
|
|
6
|
+
|
|
7
|
+
Utility module to format CNPJ (Brazilian legal entity ID) strings. Main features:
|
|
8
|
+
|
|
9
|
+
- **Multiple interfaces**: supports `CnpjFmt.cnpj_fmt` and `CnpjFmt::CnpjFormatter` with shared `CnpjFmt::CnpjFormatterOptions` defaults; an `options` argument (instance or `Hash`) is never merged with keyword overrides β passing both at once raises `InvalidArgumentCombinationError`.
|
|
10
|
+
- **Alphanumeric CNPJ**: formats 14-character alphanumeric input (digits and `AβZ`); strips punctuation and uppercases letters before delimiter insertion.
|
|
11
|
+
- **Flexible input**: accepts a `String` or `Array<String>` and concatenates sequence items before sanitization.
|
|
12
|
+
- **Customizable output**: configurable `dot_key`, `slash_key`, and `dash_key` delimiters for flexible `XX.XXX.XXX/XXXX-XX` layouts.
|
|
13
|
+
- **Privacy masking**: `hidden`, `hidden_key`, `hidden_start`, and `hidden_end` mask sensitive character ranges in the formatted string.
|
|
14
|
+
- **Post-format transforms**: optional `escape` (HTML) and `encode` (URL) applied after successful formatting.
|
|
15
|
+
- **Structured errors**: `CnpjFmt::Error` marker with misuse leaves (`TypeMismatchError`, `InvalidArgumentCombinationError`), domain leaves (`InvalidLengthError`, `OutOfRangeError`, `ValidationError` under `DomainError`); `on_fail` receives `(original_input, DomainError)` (length failures pass `InvalidLengthError`).
|
|
16
|
+
- **Strict options merging**: `CnpjFormatterOptions.new`/`#set` fold positional `Hash`/instance layers left to right, then apply keyword overrides with the highest precedence, filling any still-unresolved option with its `DEFAULT_*` value; property setters never accept `nil` directly β pass the matching `DEFAULT_*` constant (or use `#set_hidden_range`) to reset explicitly.
|
|
17
|
+
|
|
18
|
+
For detailed usage and API reference, see the [README](./README.md).
|
data/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Julio L. Muller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/cnpj-fmt)
|
|
4
|
+
[](https://rubygems.org/gems/cnpj-fmt)
|
|
5
|
+
[](https://www.ruby-lang.org/)
|
|
6
|
+
[](https://github.com/LacusSolutions/br-utils-ruby/actions)
|
|
7
|
+
[](https://github.com/LacusSolutions/br-utils-ruby)
|
|
8
|
+
[](https://github.com/LacusSolutions/br-utils-ruby/blob/main/LICENSE)
|
|
9
|
+
|
|
10
|
+
> π **Full support for the [new alphanumeric CNPJ format](https://github.com/user-attachments/files/23937961/calculodvcnpjalfanaumerico.pdf).**
|
|
11
|
+
|
|
12
|
+
> π [Acessar documentaΓ§Γ£o em portuguΓͺs](./README.pt.md)
|
|
13
|
+
|
|
14
|
+
A Ruby utility to format CNPJ (Brazilian Business Tax ID).
|
|
15
|
+
|
|
16
|
+
## Ruby Support
|
|
17
|
+
|
|
18
|
+
|  |  |  |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Passing β | Passing β | Passing β |
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- β
**Alphanumeric CNPJ**: Supports 14-character alphanumeric CNPJ (digits and letters, e.g. `RK0CMT3W000100`)
|
|
25
|
+
- β
**Flexible input**: Accepts `String` or `Array` of strings; array elements are concatenated in order
|
|
26
|
+
- β
**Format agnostic**: Strips non-alphanumeric characters and uppercases letters before formatting
|
|
27
|
+
- β
**Custom delimiters**: `dot_key`, `slash_key`, and `dash_key` may be empty, single-, or multi-character strings
|
|
28
|
+
- β
**Masking**: Optional hiding of a character range with a configurable replacement string (`hidden`, `hidden_key`, `hidden_start`, `hidden_end`)
|
|
29
|
+
- β
**HTML & URL output**: Optional `escape` (HTML entities) and `encode` (URI component encoding, similar to JavaScript `encodeURIComponent`)
|
|
30
|
+
- β
**Length errors without throwing**: Invalid length after sanitization is handled via `on_fail` (default returns an empty string)
|
|
31
|
+
- β
**Minimal dependencies**: Only [`lacus-utils`](https://rubygems.org/gems/lacus-utils)
|
|
32
|
+
- β
**Error handling**: API misuse vs domain errors with a `CnpjFmt::Error` marker for library-wide rescue
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Install the gem directly:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
gem install cnpj-fmt
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or add it to your `Gemfile` and run `bundle install`:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
gem 'cnpj-fmt'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Require
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
require 'cnpj-fmt'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
require 'cnpj-fmt'
|
|
58
|
+
|
|
59
|
+
formatter = CnpjFmt::CnpjFormatter.new
|
|
60
|
+
|
|
61
|
+
formatter.format('03603568000195') # => "03.603.568/0001-95"
|
|
62
|
+
formatter.format('12ABC34500DE99') # => "12.ABC.345/00DE-99"
|
|
63
|
+
formatter.format('RK0CMT3W000100') # => "RK.0CM.T3W/0001-00"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Basic helper usage:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
require 'cnpj-fmt'
|
|
70
|
+
|
|
71
|
+
cnpj = '03603568000195'
|
|
72
|
+
|
|
73
|
+
CnpjFmt.cnpj_fmt(cnpj) # => "03.603.568/0001-95"
|
|
74
|
+
CnpjFmt.cnpj_fmt(cnpj, hidden: true) # => "03.603.***/****-**"
|
|
75
|
+
CnpjFmt.cnpj_fmt( # => "03603568|0001_95"
|
|
76
|
+
cnpj,
|
|
77
|
+
dot_key: '',
|
|
78
|
+
slash_key: '|',
|
|
79
|
+
dash_key: '_'
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
The main entry points are the class `CnpjFmt::CnpjFormatter`, the options class `CnpjFmt::CnpjFormatterOptions`, and the helper `CnpjFmt.cnpj_fmt`.
|
|
86
|
+
|
|
87
|
+
### `CnpjFmt::CnpjFormatter`
|
|
88
|
+
|
|
89
|
+
- **`initialize(options = nil, **keywords)`**: Optional default formatting options. When `options` is given (a `CnpjFmt::CnpjFormatterOptions` instance or a `Hash`) alone, it determines the default options; a `CnpjFmt::CnpjFormatterOptions` instance is stored by reference (mutating it later affects future `format` calls that do not pass per-call options), while a `Hash` builds a new instance. When `options` is omitted (`nil`), the default options are built exclusively from the keyword arguments (`hidden:`, `hidden_key:`, `dot_key:`, β¦). Passing `options` together with any non-`nil` keyword raises `InvalidArgumentCombinationError` instead of silently ignoring the keywords. Example: `CnpjFmt::CnpjFormatter.new(hidden: true, slash_key: '|')`.
|
|
90
|
+
- **`options`**: Returns the instanceβs `CnpjFmt::CnpjFormatterOptions` (same object used internally).
|
|
91
|
+
- **`format(cnpj_input, options = nil, **keywords)`**: Formats a CNPJ value.
|
|
92
|
+
|
|
93
|
+
Input is normalized by removing non-alphanumeric characters and uppercasing. If the sanitized length is not exactly **14**, the **`on_fail`** callback is invoked with the original input and a `CnpjFmt::DomainError` (`InvalidLengthError`); its return value is the result (nothing is thrown for length).
|
|
94
|
+
|
|
95
|
+
If the input is not a `String` or an `Array` of strings, **`CnpjFmt::TypeMismatchError`** is raised.
|
|
96
|
+
|
|
97
|
+
Per-call `options` and keyword arguments are never merged: a given `options` argument alone fully overrides the instance defaults for this call; otherwise, any given keyword overrides the instance defaults for this call. When neither is given, the instance defaults are used as-is. The instance defaults are never mutated by a per-call override. Passing `options` together with any non-`nil` keyword raises `InvalidArgumentCombinationError`.
|
|
98
|
+
|
|
99
|
+
### `CnpjFmt::CnpjFormatterOptions`
|
|
100
|
+
|
|
101
|
+
Holds all formatter settings, with validation and merge support. Exposes properties: `hidden`, `hidden_key`, `hidden_start`, `hidden_end`, `dot_key`, `slash_key`, `dash_key`, `escape`, `encode`, `on_fail`.
|
|
102
|
+
|
|
103
|
+
- **`initialize(options = nil, *extra_overrides, **keywords)`**: Optional default options (plain `Hash`, `CnpjFmt::CnpjFormatterOptions` instance, or keyword arguments), plus extra override objects merged in order (later overrides win).
|
|
104
|
+
- **`all`**: Returns a shallow `Hash` copy of all current options.
|
|
105
|
+
- **`copy`**: Returns a shallow copy of this options instance.
|
|
106
|
+
- **`set(options)`**: Updates multiple fields at once; returns `self`. Accepts a `Hash` or another `CnpjFmt::CnpjFormatterOptions` instance. Explicit `nil` values in the update keep the current value.
|
|
107
|
+
- **`set_hidden_range(hidden_start, hidden_end)`**: Validates indices in **`[0, 13]`** (inclusive); if `hidden_start > hidden_end`, values are swapped. `nil` arguments fall back to defaults (`DEFAULT_HIDDEN_START` / `DEFAULT_HIDDEN_END`).
|
|
108
|
+
|
|
109
|
+
**`hidden_start` / `hidden_end`**: Indices refer to the **14-character normalized CNPJ string** (before inserting punctuation). The inclusive range is replaced internally by placeholders, then `hidden_key` is substituted (supports multi-character keys and empty string).
|
|
110
|
+
|
|
111
|
+
**Key options** (`hidden_key`, `dot_key`, `slash_key`, `dash_key`): Must be strings and must not contain any character in `CnpjFmt::CnpjFormatterOptions::DISALLOWED_KEY_CHARACTERS` (reserved for internal formatting).
|
|
112
|
+
|
|
113
|
+
### Functional helper
|
|
114
|
+
|
|
115
|
+
`CnpjFmt.cnpj_fmt` builds a new `CnpjFmt::CnpjFormatter` from the same constructor parameters and calls `format(cnpj_input)` once. Pass either keyword arguments **or** a `Hash`/`CnpjFmt::CnpjFormatterOptions` instance for options β not both (passing `options` with any non-`nil` keyword raises `InvalidArgumentCombinationError`):
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
require 'cnpj-fmt'
|
|
119
|
+
|
|
120
|
+
cnpj = '03603568000195'
|
|
121
|
+
|
|
122
|
+
CnpjFmt.cnpj_fmt(cnpj) # => "03.603.568/0001-95"
|
|
123
|
+
CnpjFmt.cnpj_fmt(cnpj, hidden: true) # masked with defaults
|
|
124
|
+
CnpjFmt.cnpj_fmt( # => "03603568|0001_95"
|
|
125
|
+
cnpj,
|
|
126
|
+
dot_key: '',
|
|
127
|
+
slash_key: '|',
|
|
128
|
+
dash_key: '_'
|
|
129
|
+
)
|
|
130
|
+
CnpjFmt.cnpj_fmt(cnpj, { # Hash form
|
|
131
|
+
hidden: true,
|
|
132
|
+
hidden_key: '#'
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Object-oriented examples
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
require 'cnpj-fmt'
|
|
140
|
+
|
|
141
|
+
formatter = CnpjFmt::CnpjFormatter.new
|
|
142
|
+
cnpj = '03603568000195'
|
|
143
|
+
|
|
144
|
+
formatter.format(cnpj) # => "03.603.568/0001-95"
|
|
145
|
+
formatter.format( # => "03.603.###/####-##"
|
|
146
|
+
cnpj,
|
|
147
|
+
hidden: true,
|
|
148
|
+
hidden_key: '#',
|
|
149
|
+
hidden_start: 5,
|
|
150
|
+
hidden_end: 13
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Default options on the instance; per-call overrides:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
require 'cnpj-fmt'
|
|
158
|
+
|
|
159
|
+
formatter = CnpjFmt::CnpjFormatter.new(hidden: true)
|
|
160
|
+
cnpj = '03603568000195'
|
|
161
|
+
|
|
162
|
+
formatter.format(cnpj) # uses instance masking
|
|
163
|
+
formatter.format(cnpj, hidden: false) # this call only: unmasked
|
|
164
|
+
formatter.format(cnpj) # back to instance defaults
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Alphanumeric input and array input:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
require 'cnpj-fmt'
|
|
171
|
+
|
|
172
|
+
formatter = CnpjFmt::CnpjFormatter.new
|
|
173
|
+
|
|
174
|
+
formatter.format('RK0CMT3W000100') # => "RK.0CM.T3W/0001-00"
|
|
175
|
+
formatter.format([ # => "RK.0CM.T3W/0001-00"
|
|
176
|
+
'RK',
|
|
177
|
+
'0CM',
|
|
178
|
+
'T3W',
|
|
179
|
+
'0001',
|
|
180
|
+
'00'
|
|
181
|
+
])
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Input formats
|
|
185
|
+
|
|
186
|
+
**String:** Raw digits and/or letters, or already formatted CNPJ (e.g. `12.345.678/0009-10`, `12.ABC.345/00DE-99`). Non-alphanumeric characters are removed; lowercase letters are uppercased.
|
|
187
|
+
|
|
188
|
+
**Array of strings:** Each element must be a `String`; values are concatenated (e.g. per digit, grouped segments, or mixed with punctuation β all are stripped during normalization). Non-string elements are not allowed.
|
|
189
|
+
|
|
190
|
+
### Formatting options
|
|
191
|
+
|
|
192
|
+
| Parameter | Type | Default | Description |
|
|
193
|
+
|-----------|------|---------|-------------|
|
|
194
|
+
| `hidden` | `Boolean`, `nil` | `false` | When truthy, replaces the inclusive index range `[hidden_start, hidden_end]` on the normalized 14-character string before punctuation is applied |
|
|
195
|
+
| `hidden_key` | `String`, `nil` | `'*'` | Replacement for each hidden position (may be multi-character or empty); must not use disallowed key characters |
|
|
196
|
+
| `hidden_start` | `Integer`, `nil` | `5` | Start index `0`β`13` (inclusive) |
|
|
197
|
+
| `hidden_end` | `Integer`, `nil` | `13` | End index `0`β`13` (inclusive); if `hidden_start > hidden_end`, they are swapped |
|
|
198
|
+
| `dot_key` | `String`, `nil` | `'.'` | Separator between groups `XX` / `XXX` / `XXX` |
|
|
199
|
+
| `slash_key` | `String`, `nil` | `'/'` | Separator before the branch block |
|
|
200
|
+
| `dash_key` | `String`, `nil` | `'-'` | Separator before the last two characters |
|
|
201
|
+
| `escape` | `Boolean`, `nil` | `false` | When truthy, HTML-escapes the final string |
|
|
202
|
+
| `encode` | `Boolean`, `nil` | `false` | When truthy, URL-encodes the final string (similar to `encodeURIComponent`) |
|
|
203
|
+
| `on_fail` | `Proc`, `nil` | see below | `(value, error) -> String` β used when sanitized length β 14 |
|
|
204
|
+
|
|
205
|
+
Default **`on_fail`** returns an empty string. Signature: `(original_input, error) -> String`, where `error` is a **`CnpjFmt::DomainError`** (currently an `InvalidLengthError` with `actual_input`, `evaluated_input`, `expected_length`). The callback return value must be a `String`; otherwise **`CnpjFmt::TypeMismatchError`** is raised.
|
|
206
|
+
|
|
207
|
+
Example with all options:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
require 'cnpj-fmt'
|
|
211
|
+
|
|
212
|
+
cnpj = '03603568000195'
|
|
213
|
+
|
|
214
|
+
CnpjFmt.cnpj_fmt(
|
|
215
|
+
cnpj,
|
|
216
|
+
hidden: true,
|
|
217
|
+
hidden_key: '#',
|
|
218
|
+
hidden_start: 5,
|
|
219
|
+
hidden_end: 11,
|
|
220
|
+
dot_key: ' ',
|
|
221
|
+
slash_key: '|',
|
|
222
|
+
dash_key: '_-_',
|
|
223
|
+
escape: true,
|
|
224
|
+
encode: true,
|
|
225
|
+
on_fail: ->(value, _error) { value.to_s }
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Error handling
|
|
230
|
+
|
|
231
|
+
Errors fall into two categories:
|
|
232
|
+
|
|
233
|
+
| Category | Meaning |
|
|
234
|
+
|---|---|
|
|
235
|
+
| **API misuse** | The caller invoked the library incorrectly (wrong type for input or options, or an invalid argument combination). |
|
|
236
|
+
| **Domain error** | The call was structurally correct, but a value violates a business rule (length, range, forbidden characters). |
|
|
237
|
+
|
|
238
|
+
Every custom error includes the `CnpjFmt::Error` marker module. Domain failures (`InvalidLengthError`, `OutOfRangeError`, `ValidationError`) inherit from `CnpjFmt::DomainError` (`RangeError`).
|
|
239
|
+
|
|
240
|
+
**Important:** length failures are **constructed as `InvalidLengthError` and passed to `on_fail` as a `DomainError`**, not raised from `format` / `cnpj_fmt`. Passing both an `options` instance/`Hash` and any non-`nil` keyword argument raises `InvalidArgumentCombinationError`.
|
|
241
|
+
|
|
242
|
+
#### Summary
|
|
243
|
+
|
|
244
|
+
| Class | Inherits from | Category | Trigger condition |
|
|
245
|
+
|---|---|---|---|
|
|
246
|
+
| `CnpjFmt::InvalidArgumentCombinationError` | `ArgumentError` (+ `include Error`) | API misuse | Both an `options` instance/`Hash` and any non-`nil` keyword argument are passed at once |
|
|
247
|
+
| `CnpjFmt::TypeMismatchError` | `TypeError` (+ `include Error`) | API misuse | CNPJ input or option has the wrong data type |
|
|
248
|
+
| `CnpjFmt::InvalidLengthError` | `CnpjFmt::DomainError` | Domain error | Sanitized length is not exactly 14 (passed to `on_fail` as `DomainError`) |
|
|
249
|
+
| `CnpjFmt::OutOfRangeError` | `CnpjFmt::DomainError` | Domain error | `hidden_start` / `hidden_end` outside `0`β`13` |
|
|
250
|
+
| `CnpjFmt::ValidationError` | `CnpjFmt::DomainError` | Domain error | Key option contains a disallowed character |
|
|
251
|
+
|
|
252
|
+
#### `CnpjFmt::Error` (marker module)
|
|
253
|
+
|
|
254
|
+
- **Inheritance:** module marker mixed into every library error via `include` (not a class).
|
|
255
|
+
- **Category:** N/A (rescue target only) β not a failure mode by itself.
|
|
256
|
+
- **When it is raised:** Never raised directly; included by every custom error the library raises or constructs for `on_fail`.
|
|
257
|
+
- **Example:** N/A
|
|
258
|
+
- **How to rescue it:**
|
|
259
|
+
|
|
260
|
+
```ruby
|
|
261
|
+
rescue CnpjFmt::Error
|
|
262
|
+
# everything this library raises
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### `CnpjFmt::DomainError`
|
|
266
|
+
|
|
267
|
+
- **Inheritance:** `CnpjFmt::DomainError < RangeError` (includes `CnpjFmt::Error`)
|
|
268
|
+
- **Category:** Domain error β ancestor for numeric/length domain failures.
|
|
269
|
+
- **When it is raised:** Not raised directly; prefer raising a leaf subclass.
|
|
270
|
+
- **Example:** Prefer `raise CnpjFmt::OutOfRangeError` / construct `InvalidLengthError` over raising `DomainError` directly.
|
|
271
|
+
- **How to rescue it:**
|
|
272
|
+
|
|
273
|
+
```ruby
|
|
274
|
+
rescue CnpjFmt::DomainError
|
|
275
|
+
# OutOfRangeError, InvalidLengthError, ValidationError, and other DomainError subclasses
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### `CnpjFmt::TypeMismatchError`
|
|
279
|
+
|
|
280
|
+
- **Inheritance:** `CnpjFmt::TypeMismatchError < TypeError` (includes `CnpjFmt::Error`)
|
|
281
|
+
- **Category:** API misuse β the caller passed a value of the wrong type.
|
|
282
|
+
- **When it is raised:** Raised when the CNPJ input is not a `String` or an `Array` of strings, when an option has the wrong type, or when `on_fail` does not return a `String`.
|
|
283
|
+
- **Example:**
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
CnpjFmt::CnpjFormatter.new.format(12_345) # raises CnpjFmt::TypeMismatchError
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
- **How to rescue it:**
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
rescue CnpjFmt::TypeMismatchError
|
|
293
|
+
# this library's type-contract violation
|
|
294
|
+
|
|
295
|
+
rescue TypeError
|
|
296
|
+
# native type errors, including this library's TypeMismatchError
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### `CnpjFmt::InvalidLengthError`
|
|
300
|
+
|
|
301
|
+
- **Inheritance:** `CnpjFmt::InvalidLengthError < CnpjFmt::DomainError < RangeError` (includes `CnpjFmt::Error`)
|
|
302
|
+
- **Category:** Domain error β a collection or string length violates a business rule.
|
|
303
|
+
- **When it is raised:** Not raised from `format`; constructed and passed as the `DomainError` second argument to `on_fail` when the sanitized CNPJ does not contain exactly 14 alphanumeric characters.
|
|
304
|
+
- **Example:**
|
|
305
|
+
|
|
306
|
+
```ruby
|
|
307
|
+
CnpjFmt::CnpjFormatter.new.format(
|
|
308
|
+
'short',
|
|
309
|
+
on_fail: ->(_value, error) {
|
|
310
|
+
error # => #<CnpjFmt::InvalidLengthError ...> (a DomainError)
|
|
311
|
+
'invalid'
|
|
312
|
+
}
|
|
313
|
+
) # => "invalid"
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
- **How to rescue it:** Handle inside `on_fail` (typical), or rescue if you re-raise:
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
rescue CnpjFmt::InvalidLengthError
|
|
321
|
+
# this exact length violation
|
|
322
|
+
|
|
323
|
+
rescue CnpjFmt::DomainError
|
|
324
|
+
# RangeError-rooted domain failures from this library
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
#### `CnpjFmt::InvalidArgumentCombinationError`
|
|
328
|
+
|
|
329
|
+
- **Inheritance:** `CnpjFmt::InvalidArgumentCombinationError < ArgumentError` (includes `CnpjFmt::Error`)
|
|
330
|
+
- **Category:** API misuse β the caller mixed mutually exclusive argument patterns.
|
|
331
|
+
- **When it is raised:** Raised when `CnpjFormatter.new`, `#format`, or `cnpj_fmt` receives both an `options` argument (instance or `Hash`) and any non-`nil` keyword argument at the same time.
|
|
332
|
+
- **Example:**
|
|
333
|
+
|
|
334
|
+
```ruby
|
|
335
|
+
begin
|
|
336
|
+
CnpjFmt::CnpjFormatter.new({ slash_key: '|' }, hidden: true)
|
|
337
|
+
rescue CnpjFmt::InvalidArgumentCombinationError => e
|
|
338
|
+
puts e.message
|
|
339
|
+
# Pass either an options instance/Hash to `options`, or keyword arguments (hidden:, ...), not both.
|
|
340
|
+
end
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
- **How to rescue it:**
|
|
344
|
+
|
|
345
|
+
```ruby
|
|
346
|
+
rescue CnpjFmt::InvalidArgumentCombinationError
|
|
347
|
+
# this library's invalid argument combination
|
|
348
|
+
|
|
349
|
+
rescue ArgumentError
|
|
350
|
+
# native argument errors, including this library's InvalidArgumentCombinationError
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### `CnpjFmt::OutOfRangeError`
|
|
354
|
+
|
|
355
|
+
- **Inheritance:** `CnpjFmt::OutOfRangeError < CnpjFmt::DomainError < RangeError` (includes `CnpjFmt::Error`)
|
|
356
|
+
- **Category:** Domain error β a numeric value violates a business range rule.
|
|
357
|
+
- **When it is raised:** Raised when `hidden_start` or `hidden_end` is outside the inclusive range `0`β`13`.
|
|
358
|
+
- **Example:**
|
|
359
|
+
|
|
360
|
+
```ruby
|
|
361
|
+
CnpjFmt::CnpjFormatterOptions.new(hidden_start: 14) # raises CnpjFmt::OutOfRangeError
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
- **How to rescue it:**
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
rescue CnpjFmt::OutOfRangeError
|
|
368
|
+
# this exact range violation
|
|
369
|
+
|
|
370
|
+
rescue CnpjFmt::DomainError
|
|
371
|
+
# RangeError-rooted domain failures from this library
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### `CnpjFmt::ValidationError`
|
|
375
|
+
|
|
376
|
+
- **Inheritance:** `CnpjFmt::ValidationError < CnpjFmt::DomainError < RangeError` (includes `CnpjFmt::Error`)
|
|
377
|
+
- **Category:** Domain error β a value fails a non-numeric, non-length domain rule.
|
|
378
|
+
- **When it is raised:** Raised when a key option (`hidden_key`, `dot_key`, `slash_key`, `dash_key`) contains a disallowed character.
|
|
379
|
+
- **Example:**
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
CnpjFmt::CnpjFormatterOptions.new(dot_key: 'Γ₯') # raises CnpjFmt::ValidationError
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
- **How to rescue it:**
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
rescue CnpjFmt::ValidationError
|
|
389
|
+
# this exact domain validation failure
|
|
390
|
+
|
|
391
|
+
rescue CnpjFmt::DomainError
|
|
392
|
+
# RangeError-rooted domain failures from this library
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
#### Rescue granularity
|
|
396
|
+
|
|
397
|
+
```ruby
|
|
398
|
+
# 1) Single native class β catches type misuse from this library (and other TypeErrors).
|
|
399
|
+
rescue TypeError
|
|
400
|
+
# CnpjFmt::TypeMismatchError and any other TypeError (library or not)
|
|
401
|
+
|
|
402
|
+
# 2) CnpjFmt::DomainError β catches business-rule violations under DomainError.
|
|
403
|
+
rescue CnpjFmt::DomainError
|
|
404
|
+
# CnpjFmt::OutOfRangeError, CnpjFmt::InvalidLengthError, CnpjFmt::ValidationError,
|
|
405
|
+
# and other DomainError subclasses
|
|
406
|
+
|
|
407
|
+
# 3) CnpjFmt::Error β catches everything the library raises.
|
|
408
|
+
rescue CnpjFmt::Error
|
|
409
|
+
# every custom error that includes CnpjFmt::Error
|
|
410
|
+
|
|
411
|
+
# 4) Specific leaf class β catches only that exact failure mode.
|
|
412
|
+
rescue CnpjFmt::OutOfRangeError
|
|
413
|
+
# only CnpjFmt::OutOfRangeError
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Notable attributes:
|
|
417
|
+
|
|
418
|
+
- `TypeMismatchError`: `actual_input`, `actual_type`, `expected_type`, `option_name` (nil for CNPJ input)
|
|
419
|
+
- `InvalidLengthError`: `actual_input`, `evaluated_input`, `expected_length`
|
|
420
|
+
- `OutOfRangeError`: `option_name`, `actual_input`, `min_expected_value`, `max_expected_value`
|
|
421
|
+
- `ValidationError`: `option_name`, `actual_input`, `forbidden_characters`
|
|
422
|
+
|
|
423
|
+
## API
|
|
424
|
+
|
|
425
|
+
### Exports
|
|
426
|
+
|
|
427
|
+
After `require 'cnpj-fmt'`:
|
|
428
|
+
|
|
429
|
+
- **`CnpjFmt.cnpj_fmt`**: `(cnpj_input, options = nil, **keywords) -> String` β convenience helper.
|
|
430
|
+
- **`CnpjFmt::CnpjFormatter`**: Class to format CNPJ with optional default options; accepts `String` or `Array<String>` in `format`.
|
|
431
|
+
- **`CnpjFmt::CnpjFormatterOptions`**: Class holding options; supports merge via constructor, `set`, and keyword arguments.
|
|
432
|
+
- **`CnpjFmt::CNPJ_LENGTH`**: `14` (constant).
|
|
433
|
+
- **`CnpjFmt::VERSION`**: gem version string.
|
|
434
|
+
- **Type predicate**: `CnpjFmt::CnpjInput` β `CnpjFmt::CnpjInput.accept?(value)` / `CnpjFmt::CnpjInput === value` is true only for `String` or `Array<String>`.
|
|
435
|
+
- **Errors**: `CnpjFmt::Error`, `CnpjFmt::DomainError`, `CnpjFmt::InvalidArgumentCombinationError`, `CnpjFmt::TypeMismatchError`, `CnpjFmt::InvalidLengthError`, `CnpjFmt::OutOfRangeError`, `CnpjFmt::ValidationError`.
|
|
436
|
+
|
|
437
|
+
### Other available resources
|
|
438
|
+
|
|
439
|
+
- **`CnpjFmt::CnpjFormatterOptions::CNPJ_LENGTH`**: `14`.
|
|
440
|
+
- **`CnpjFmt::CnpjFormatterOptions::DISALLOWED_KEY_CHARACTERS`**: Characters forbidden in `hidden_key`, `dot_key`, `slash_key`, `dash_key`.
|
|
441
|
+
- **`CnpjFmt::CnpjFormatterOptions::DEFAULT_*`**: Default values for each option.
|
|
442
|
+
- **`CnpjFmt::CnpjFormatterOptions.default_on_fail`**: Shared default failure callback.
|
|
443
|
+
|
|
444
|
+
## Contribution & Support
|
|
445
|
+
|
|
446
|
+
We welcome contributions! Please see our [Contributing Guidelines](https://github.com/LacusSolutions/br-utils-ruby/blob/main/CONTRIBUTING.md) for details. If you find this project helpful, please consider:
|
|
447
|
+
|
|
448
|
+
- β Starring the repository
|
|
449
|
+
- π€ Contributing to the codebase
|
|
450
|
+
- π‘ [Suggesting new features](https://github.com/LacusSolutions/br-utils-ruby/issues)
|
|
451
|
+
- π [Reporting bugs](https://github.com/LacusSolutions/br-utils-ruby/issues)
|
|
452
|
+
|
|
453
|
+
## License
|
|
454
|
+
|
|
455
|
+
This project is licensed under the MIT License β see the [LICENSE](https://github.com/LacusSolutions/br-utils-ruby/blob/main/LICENSE) file for details.
|
|
456
|
+
|
|
457
|
+
## Changelog
|
|
458
|
+
|
|
459
|
+
See [CHANGELOG](./CHANGELOG.md) for a list of changes and version history.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
Made with β€οΈ by [Lacus Solutions](https://github.com/LacusSolutions)
|