bra_documents 1.0.1 → 1.1.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/.github/workflows/main.yml +29 -0
- data/.mise.toml +2 -0
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +38 -24
- data/README.md +41 -1
- data/bin/console +4 -4
- data/bin/rake +27 -0
- data/bin/rdoc +27 -0
- data/bin/rspec +27 -0
- data/bra_documents.gemspec +2 -3
- data/lib/bra_documents/cnpj_generator.rb +14 -4
- data/lib/bra_documents/cpf_generator.rb +6 -2
- data/lib/bra_documents/formatter.rb +5 -5
- data/lib/bra_documents/matcher.rb +41 -3
- data/lib/bra_documents/national_register_base.rb +9 -9
- data/lib/bra_documents/testing/rspec/matchers/cnpj_matcher.rb +4 -12
- data/lib/bra_documents/testing/rspec/matchers/cpf_matcher.rb +3 -11
- data/lib/bra_documents/version.rb +1 -1
- metadata +12 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5edcee719c06808ad9d7a4bb17c38aac505275489576e0864bc7ac85dcf1541d
|
|
4
|
+
data.tar.gz: 9f86a8ff44a78bab3e2a82c93c7107667c78baafc683fecb81345ec2060c6df7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 289d2e3fefb83ef555f8e64c85301c17c3262361ffc984be09111181c481edd235000d0ad5bd438afed6909d046ff9c4533fa07db1148857312bd8dc6381d92a
|
|
7
|
+
data.tar.gz: 02c03f625084618ffc291f2d5257ecd84af8ba942a884f1abaf8b99730360be3e6c151a13e033dbd81445ddbe42280e9c0f0534e1dcf06cf36ef6c3ac142fe9f
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Ruby
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
name: Ruby ${{ matrix.ruby }}
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
ruby:
|
|
17
|
+
- '3.3.7'
|
|
18
|
+
- '3.4.2'
|
|
19
|
+
- '4.0.0'
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v5
|
|
23
|
+
- name: Set up Ruby
|
|
24
|
+
uses: ruby/setup-ruby@v1
|
|
25
|
+
with:
|
|
26
|
+
ruby-version: ${{ matrix.ruby }}
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
- name: Run the default task
|
|
29
|
+
run: bundle exec rake
|
data/.mise.toml
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [1.1.0] - 2026-01-14
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Alphanumeric CNPJ support: company number and branch/subsidiary number now accept letters (A-Z) and numbers (0-9);
|
|
16
|
+
- Enhanced CNPJ generation with alphanumeric character support;
|
|
17
|
+
- Updated CNPJ formatter to handle alphanumeric characters (outputs uppercase);
|
|
18
|
+
- Enhanced CNPJ matcher with alphanumeric pattern validation;
|
|
19
|
+
- RSpec matchers (`be_a_formatted_cnpj`, `be_a_raw_cnpj`, `a_formatted_cnpj`, `a_raw_cnpj`) now support alphanumeric CNPJ validation;
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- CNPJ verification digit calculation now supports alphanumeric characters in company and branch numbers;
|
|
24
|
+
- `Formatter.raw` method now accepts `kind:` parameter to properly handle CNPJ alphanumeric characters;
|
|
25
|
+
- Matcher patterns now reject documents where all characters are identical (e.g., '11111111111' for CPF, 'AAAAAAAAAAAAAA' for CNPJ);
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Ruby 4.0 compatibility: removed `__FILE__` argument from `IRB.start` in bin/console;
|
|
30
|
+
- Added `irb` gem as development dependency for Ruby 4.0+;
|
|
31
|
+
|
|
32
|
+
## [1.0.2] - 2020-22-10
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- CPFGenerator.valid_verification_digit? returning false if document does not have CPF format;
|
|
37
|
+
- CNPJGenerator.valid_verification_digit? returning false if document does not have CNPJ format;
|
|
38
|
+
|
|
11
39
|
## [1.0.1] - 2020-22-10
|
|
12
40
|
|
|
13
41
|
### Added
|
data/Gemfile.lock
CHANGED
|
@@ -1,43 +1,57 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
bra_documents (1.0
|
|
4
|
+
bra_documents (1.1.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
|
|
10
|
-
diff-lcs (1.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
date (3.5.1)
|
|
10
|
+
diff-lcs (1.6.2)
|
|
11
|
+
erb (6.0.1)
|
|
12
|
+
io-console (0.8.2)
|
|
13
|
+
irb (1.16.0)
|
|
14
|
+
pp (>= 0.6.0)
|
|
15
|
+
rdoc (>= 4.0.0)
|
|
16
|
+
reline (>= 0.4.2)
|
|
17
|
+
pp (0.6.3)
|
|
18
|
+
prettyprint
|
|
19
|
+
prettyprint (0.2.0)
|
|
20
|
+
psych (5.3.1)
|
|
21
|
+
date
|
|
22
|
+
stringio
|
|
23
|
+
rake (13.3.1)
|
|
24
|
+
rdoc (7.1.0)
|
|
25
|
+
erb
|
|
26
|
+
psych (>= 4.0.0)
|
|
27
|
+
tsort
|
|
28
|
+
reline (0.6.3)
|
|
29
|
+
io-console (~> 0.5)
|
|
30
|
+
rspec (3.13.2)
|
|
31
|
+
rspec-core (~> 3.13.0)
|
|
32
|
+
rspec-expectations (~> 3.13.0)
|
|
33
|
+
rspec-mocks (~> 3.13.0)
|
|
34
|
+
rspec-core (3.13.6)
|
|
35
|
+
rspec-support (~> 3.13.0)
|
|
36
|
+
rspec-expectations (3.13.5)
|
|
25
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
26
|
-
rspec-support (~> 3.
|
|
27
|
-
rspec-mocks (3.
|
|
38
|
+
rspec-support (~> 3.13.0)
|
|
39
|
+
rspec-mocks (3.13.7)
|
|
28
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
29
|
-
rspec-support (~> 3.
|
|
30
|
-
rspec-support (3.
|
|
41
|
+
rspec-support (~> 3.13.0)
|
|
42
|
+
rspec-support (3.13.6)
|
|
43
|
+
stringio (3.2.0)
|
|
44
|
+
tsort (0.2.0)
|
|
31
45
|
|
|
32
46
|
PLATFORMS
|
|
33
47
|
ruby
|
|
48
|
+
x86_64-darwin-24
|
|
34
49
|
|
|
35
50
|
DEPENDENCIES
|
|
36
51
|
bra_documents!
|
|
37
|
-
|
|
38
|
-
pry-nav
|
|
52
|
+
irb
|
|
39
53
|
rake
|
|
40
54
|
rspec
|
|
41
55
|
|
|
42
56
|
BUNDLED WITH
|
|
43
|
-
|
|
57
|
+
4.0.3
|
data/README.md
CHANGED
|
@@ -6,6 +6,8 @@ This gem make us able to generate Brazilian documents, such as CPF and CNPJ.
|
|
|
6
6
|
We can generate a tottaly random number, or pass the number and the gem completes with the verification digits.
|
|
7
7
|
If you already have a CPF or CNPJ only their numbers, you can also put the mask using the formatter.
|
|
8
8
|
|
|
9
|
+
**Note:** Starting with recent regulations, CNPJ numbers now support alphanumeric characters (letters A-Z and numbers 0-9) in the company number and branch/subsidiary number portions, while the verification digits remain numeric only.
|
|
10
|
+
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
11
13
|
Add this line to your application's Gemfile:
|
|
@@ -55,6 +57,8 @@ BraDocuments::CPFGenerator.valid_verification_digit?(document: '123.123.123-88')
|
|
|
55
57
|
|
|
56
58
|
### CNPJ Generation
|
|
57
59
|
|
|
60
|
+
**Note:** CNPJ now supports alphanumeric characters (A-Z, 0-9) in company and branch numbers.
|
|
61
|
+
|
|
58
62
|
```rb
|
|
59
63
|
BraDocuments::CNPJGenerator.generate
|
|
60
64
|
#=> "62885807804809"
|
|
@@ -73,10 +77,19 @@ BraDocuments::CNPJGenerator.generate(company_number: '53855973', matrix_subsidia
|
|
|
73
77
|
|
|
74
78
|
BraDocuments::CNPJGenerator.generate(company_number: '53855973', matrix_subsidiary_number: '0001', formatted: true)
|
|
75
79
|
#=> "53.855.973/0001-79"
|
|
80
|
+
|
|
81
|
+
# Alphanumeric CNPJ examples
|
|
82
|
+
BraDocuments::CNPJGenerator.generate(company_number: 'AB12CD34')
|
|
83
|
+
#=> "AB12CD34EUJW83"
|
|
84
|
+
|
|
85
|
+
BraDocuments::CNPJGenerator.generate(company_number: 'AB12CD34', matrix_subsidiary_number: '0A01', formatted: true)
|
|
86
|
+
#=> "AB.12C.D34/0A01-60"
|
|
76
87
|
```
|
|
77
88
|
|
|
78
89
|
### CNPJ digit verification
|
|
79
90
|
|
|
91
|
+
**Note:** Validation now supports alphanumeric CNPJ numbers.
|
|
92
|
+
|
|
80
93
|
```rb
|
|
81
94
|
BraDocuments::CNPJGenerator.valid_verification_digit?(document: '62885807804809')
|
|
82
95
|
#=> true
|
|
@@ -86,6 +99,13 @@ BraDocuments::CNPJGenerator.valid_verification_digit?(document: '53.855.973/0001
|
|
|
86
99
|
|
|
87
100
|
BraDocuments::CNPJGenerator.valid_verification_digit?(document: '53855973000177')
|
|
88
101
|
#=> false
|
|
102
|
+
|
|
103
|
+
# Alphanumeric CNPJ validation
|
|
104
|
+
BraDocuments::CNPJGenerator.valid_verification_digit?(document: 'AB12CD340A0160')
|
|
105
|
+
#=> true (if valid digits)
|
|
106
|
+
|
|
107
|
+
BraDocuments::CNPJGenerator.valid_verification_digit?(document: 'AB.12C.D34/0A01-60')
|
|
108
|
+
#=> true (if valid digits)
|
|
89
109
|
```
|
|
90
110
|
|
|
91
111
|
### Formatting
|
|
@@ -99,22 +119,42 @@ BraDocuments::Formatter.format('53855973879456', as: :cnpj)
|
|
|
99
119
|
|
|
100
120
|
BraDocuments::Formatter.raw('53.855.973/8794-56')
|
|
101
121
|
#=> "53855973879456"
|
|
122
|
+
|
|
123
|
+
# Alphanumeric CNPJ formatting
|
|
124
|
+
BraDocuments::Formatter.format('AB12CD3400A179', as: :cnpj)
|
|
125
|
+
#=> "AB.12C.D34/00A1-79"
|
|
126
|
+
|
|
127
|
+
BraDocuments::Formatter.raw('AB.12C.D34/00A1-79', kind: :cnpj)
|
|
128
|
+
#=> "AB12CD3400A179"
|
|
102
129
|
```
|
|
103
130
|
|
|
104
131
|
### Matching
|
|
105
132
|
|
|
106
133
|
```rb
|
|
107
134
|
BraDocuments::Matcher.match?('11111111111', kind: :cpf, mode: :raw)
|
|
135
|
+
#=> false (rejected - all same digits)
|
|
136
|
+
|
|
137
|
+
BraDocuments::Matcher.match?('12345678901', kind: :cpf, mode: :raw)
|
|
108
138
|
#=> true
|
|
109
139
|
|
|
110
140
|
BraDocuments::Matcher.match?('11111111111', kind: :cpf, mode: :formatted)
|
|
111
141
|
#=> false
|
|
112
142
|
|
|
113
|
-
BraDocuments::Matcher.match?('
|
|
143
|
+
BraDocuments::Matcher.match?('11111111111111', kind: :cnpj, mode: :raw)
|
|
114
144
|
#=> false
|
|
115
145
|
|
|
116
146
|
BraDocuments::Matcher.match?('90.978.812/0001-07', kind: :cnpj, mode: :formatted)
|
|
117
147
|
#=> true
|
|
148
|
+
|
|
149
|
+
# Alphanumeric CNPJ matching
|
|
150
|
+
BraDocuments::Matcher.match?('AB12CD3400A179', kind: :cnpj, mode: :raw)
|
|
151
|
+
#=> true
|
|
152
|
+
|
|
153
|
+
BraDocuments::Matcher.match?('AB.12C.D34/00A1-79', kind: :cnpj, mode: :formatted)
|
|
154
|
+
#=> true
|
|
155
|
+
|
|
156
|
+
BraDocuments::Matcher.match?('AAAAAAAAAAAAAA', kind: :cnpj, mode: :raw)
|
|
157
|
+
#=> false (rejected - all same characters)
|
|
118
158
|
```
|
|
119
159
|
|
|
120
160
|
### Tests Matching
|
data/bin/console
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'bra_documents'
|
|
5
5
|
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
|
@@ -10,5 +10,5 @@ require "bra_documents"
|
|
|
10
10
|
# require "pry"
|
|
11
11
|
# Pry.start
|
|
12
12
|
|
|
13
|
-
require
|
|
14
|
-
IRB.start
|
|
13
|
+
require 'irb'
|
|
14
|
+
IRB.start
|
data/bin/rake
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rdoc
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rdoc' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rdoc", "rdoc")
|
data/bin/rspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bra_documents.gemspec
CHANGED
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.description = %q{Here we are able to generate CPNJ and CPF documents, only numbers or formatted.}
|
|
11
11
|
spec.homepage = 'https://github.com/bvicenzo/bra_documents'
|
|
12
12
|
spec.license = 'MIT'
|
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new('>=
|
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.3.0')
|
|
14
14
|
|
|
15
15
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
|
|
16
16
|
|
|
@@ -27,8 +27,7 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
28
28
|
spec.require_paths = ['lib']
|
|
29
29
|
|
|
30
|
-
spec.add_development_dependency 'pry'
|
|
31
|
-
spec.add_development_dependency 'pry-nav'
|
|
32
30
|
spec.add_development_dependency 'rake'
|
|
33
31
|
spec.add_development_dependency 'rspec'
|
|
32
|
+
spec.add_development_dependency 'irb'
|
|
34
33
|
end
|
|
@@ -7,6 +7,7 @@ module BraDocuments
|
|
|
7
7
|
class CNPJGenerator < NationalRegisterBase
|
|
8
8
|
COMPANY_NUMBER_SIZE = 8
|
|
9
9
|
MATRIX_SUBSIDIARY_SIZE = 4
|
|
10
|
+
ALPHANUM_UPPER = [*'A'..'Z', *'0'..'9'].freeze
|
|
10
11
|
|
|
11
12
|
class << self
|
|
12
13
|
# Generates a random CNPJ document number or add verifying digits to one if it's given.
|
|
@@ -34,8 +35,13 @@ module BraDocuments
|
|
|
34
35
|
# )
|
|
35
36
|
# # => "53.855.973/0001-79"
|
|
36
37
|
def generate(company_number: nil, matrix_subsidiary_number: nil, formatted: false)
|
|
37
|
-
company_number = number_for('Company', COMPANY_NUMBER_SIZE, company_number)
|
|
38
|
-
matrix_subsidiary_number = number_for(
|
|
38
|
+
company_number = number_for('Company', COMPANY_NUMBER_SIZE, company_number, kind: :cnpj)
|
|
39
|
+
matrix_subsidiary_number = number_for(
|
|
40
|
+
'Matrix or subsidiary',
|
|
41
|
+
MATRIX_SUBSIDIARY_SIZE,
|
|
42
|
+
matrix_subsidiary_number,
|
|
43
|
+
kind: :cnpj
|
|
44
|
+
)
|
|
39
45
|
numbers = company_number + matrix_subsidiary_number
|
|
40
46
|
|
|
41
47
|
full_number = complete!(numbers)
|
|
@@ -54,8 +60,8 @@ module BraDocuments
|
|
|
54
60
|
# BraDocuments::CPFGenerator.valid_verification_digit?(document: '29432530000190')
|
|
55
61
|
# # => true
|
|
56
62
|
def valid_verification_digit?(document:)
|
|
57
|
-
raw_document = Formatter.raw(document)
|
|
58
|
-
return false if raw_document
|
|
63
|
+
raw_document = Formatter.raw(document, kind: :cnpj)
|
|
64
|
+
return false if !Matcher.match?(raw_document, kind: :cnpj, mode: :raw)
|
|
59
65
|
|
|
60
66
|
company_number = raw_document.slice(0..(COMPANY_NUMBER_SIZE - 1))
|
|
61
67
|
matrix_subsidiary_number = raw_document
|
|
@@ -68,6 +74,10 @@ module BraDocuments
|
|
|
68
74
|
|
|
69
75
|
private
|
|
70
76
|
|
|
77
|
+
def number_with(size)
|
|
78
|
+
size.times.map { ALPHANUM_UPPER.sample }
|
|
79
|
+
end
|
|
80
|
+
|
|
71
81
|
def verification_digit_multiplicators_for(numbers)
|
|
72
82
|
(2..(numbers.size - 7)).to_a.reverse + (2..9).to_a.reverse
|
|
73
83
|
end
|
|
@@ -23,7 +23,7 @@ module BraDocuments
|
|
|
23
23
|
# BraDocuments::CPFGenerator.generate(person_number: '123123123', formatted: true)
|
|
24
24
|
# # => "123.123.123-87"
|
|
25
25
|
def generate(person_number: nil, formatted: false)
|
|
26
|
-
numbers = number_for('Person', PERSON_NUMBER_SIZE, person_number)
|
|
26
|
+
numbers = number_for('Person', PERSON_NUMBER_SIZE, person_number, kind: :cpf)
|
|
27
27
|
full_number = complete!(numbers)
|
|
28
28
|
|
|
29
29
|
formatted ? Formatter.format(full_number, as: :cpf) : full_number
|
|
@@ -41,7 +41,7 @@ module BraDocuments
|
|
|
41
41
|
# # => true
|
|
42
42
|
def valid_verification_digit?(document:)
|
|
43
43
|
raw_document = Formatter.raw(document)
|
|
44
|
-
return false if raw_document
|
|
44
|
+
return false if !Matcher.match?(raw_document, kind: :cpf, mode: :raw)
|
|
45
45
|
|
|
46
46
|
person_number = raw_document.slice(0..(PERSON_NUMBER_SIZE - 1))
|
|
47
47
|
verified_digit = raw_document.slice(PERSON_NUMBER_SIZE..(raw_document.size - 1))
|
|
@@ -51,6 +51,10 @@ module BraDocuments
|
|
|
51
51
|
|
|
52
52
|
private
|
|
53
53
|
|
|
54
|
+
def number_with(size)
|
|
55
|
+
size.times.map { rand(10) }
|
|
56
|
+
end
|
|
57
|
+
|
|
54
58
|
def verification_digit_multiplicators_for(numbers)
|
|
55
59
|
(2..numbers.size.next).to_a.reverse
|
|
56
60
|
end
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module BraDocuments
|
|
4
4
|
class Formatter
|
|
5
|
-
|
|
5
|
+
RAW_TRANSFORM_PATTERNS = { cpf: /[^[:digit:]]/, cnpj: /[^[:alnum:]]/ }.freeze
|
|
6
6
|
FORMATS = {
|
|
7
7
|
cpf: { pattern: /\A(\d{3})(\d{3})(\d{3})(\d{2})\z/, mask: '%s.%s.%s-%s' },
|
|
8
|
-
cnpj: { pattern: /\A(
|
|
8
|
+
cnpj: { pattern: /\A([A-Z0-9]{2})([A-Z0-9]{3})([A-Z0-9]{3})([A-Z0-9]{4})(\d{2})\z/i, mask: '%s.%s.%s/%s-%s' }
|
|
9
9
|
}.freeze
|
|
10
10
|
|
|
11
11
|
class << self
|
|
@@ -21,17 +21,17 @@ module BraDocuments
|
|
|
21
21
|
|
|
22
22
|
format_data = FORMATS[as]
|
|
23
23
|
|
|
24
|
-
Kernel.format(format_data[:mask], *format_data[:pattern].match(number).captures)
|
|
24
|
+
Kernel.format(format_data[:mask], *format_data[:pattern].match(number).captures).upcase
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Formats removing all not number caracters from string.
|
|
28
28
|
#
|
|
29
29
|
# BraDocuments::Formatter.raw('860.272.658-9') # => "286027265892"
|
|
30
30
|
# BraDocuments::Formatter.format('53.855.973/8794-56') # => "53855973879456"
|
|
31
|
-
def raw(number)
|
|
31
|
+
def raw(number, kind: :cpf)
|
|
32
32
|
raise ArgumentError, "\"#{number.inspect}\" must be a String." unless number.is_a?(String)
|
|
33
33
|
|
|
34
|
-
number.gsub(
|
|
34
|
+
number.gsub(RAW_TRANSFORM_PATTERNS[kind], '')
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
private
|
|
@@ -3,24 +3,62 @@
|
|
|
3
3
|
module BraDocuments
|
|
4
4
|
class Matcher
|
|
5
5
|
FORMATS = {
|
|
6
|
-
cpf: {
|
|
7
|
-
|
|
6
|
+
cpf: {
|
|
7
|
+
raw: /\A(?!([0-9])\1{10})\d{11}\z/,
|
|
8
|
+
formatted: /\A(?!([0-9])(?:[.\-]?\1){10}[.\-]?\d{2})(\d{3}\.){2}\d{3}-\d{2}\z/
|
|
9
|
+
},
|
|
10
|
+
cnpj: {
|
|
11
|
+
raw: /\A(?!([A-Z0-9])\1{11}\d{2})[A-Z0-9]{12}\d{2}\z/i,
|
|
12
|
+
formatted: /
|
|
13
|
+
\A
|
|
14
|
+
(?! # disallow all characters being the same
|
|
15
|
+
([A-Z0-9])
|
|
16
|
+
(?: [.\-\/]? \1 ){11}
|
|
17
|
+
[.\-\/]? \d{2}
|
|
18
|
+
)
|
|
19
|
+
[A-Z0-9]{2} \.
|
|
20
|
+
[A-Z0-9]{3} \.
|
|
21
|
+
[A-Z0-9]{3} \/
|
|
22
|
+
[A-Z0-9]{4} -
|
|
23
|
+
\d{2}
|
|
24
|
+
\z
|
|
25
|
+
/ix
|
|
26
|
+
}
|
|
8
27
|
}.freeze
|
|
9
28
|
|
|
29
|
+
|
|
10
30
|
class << self
|
|
11
31
|
# Macthes with Brazilian CPF and CNPJ documents.
|
|
12
32
|
#
|
|
13
33
|
# BraDocuments::Matcher.match?('11111111111', kind: :cpf, mode: :raw)
|
|
34
|
+
# # => false
|
|
35
|
+
#
|
|
36
|
+
# BraDocuments::Matcher.match?('12345678888', kind: :cpf, mode: :raw)
|
|
14
37
|
# # => true
|
|
15
38
|
#
|
|
16
39
|
# BraDocuments::Matcher.match?('11111111111', kind: :cpf, mode: :formatted)
|
|
17
40
|
# # => false
|
|
18
41
|
#
|
|
19
|
-
# BraDocuments::Matcher.match?('
|
|
42
|
+
# BraDocuments::Matcher.match?('11111111111111', kind: :cnpj, mode: :raw)
|
|
20
43
|
# # => false
|
|
21
44
|
#
|
|
45
|
+
# BraDocuments::Matcher.match?('11111B11111111', kind: :cnpj, mode: :raw)
|
|
46
|
+
# # => true
|
|
47
|
+
#
|
|
48
|
+
# BraDocuments::Matcher.match?('11111a11111111', kind: :cnpj, mode: :raw)
|
|
49
|
+
# # => true
|
|
50
|
+
#
|
|
22
51
|
# BraDocuments::Matcher.match?('90.978.812/0001-07', kind: :cnpj, mode: :formatted)
|
|
23
52
|
# # => true
|
|
53
|
+
#
|
|
54
|
+
# BraDocuments::Matcher.match?('90.97A.812/0001-07', kind: :cnpj, mode: :formatted)
|
|
55
|
+
# # => true
|
|
56
|
+
#
|
|
57
|
+
# BraDocuments::Matcher.match?('90.97b.812/0001-07', kind: :cnpj, mode: :formatted)
|
|
58
|
+
# # => true
|
|
59
|
+
#
|
|
60
|
+
# BraDocuments::Matcher.match?('dd.ccc.bbb/AAAA-00', kind: :cnpj, mode: :formatted)
|
|
61
|
+
# # => true
|
|
24
62
|
def match?(number, kind:, mode:)
|
|
25
63
|
raise ArgumentError, "\"#{number.inspect}\" must be a String." unless number.is_a?(String)
|
|
26
64
|
|
|
@@ -4,6 +4,7 @@ module BraDocuments
|
|
|
4
4
|
class NationalRegisterBase
|
|
5
5
|
class << self
|
|
6
6
|
BASE = 11
|
|
7
|
+
ZERO_ON_ASCII_CODE = 48
|
|
7
8
|
|
|
8
9
|
private
|
|
9
10
|
|
|
@@ -12,29 +13,28 @@ module BraDocuments
|
|
|
12
13
|
numbers.join
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
def number_for(number_description, number_size, given_value)
|
|
16
|
-
given_value = Formatter.raw(given_value.to_s)
|
|
16
|
+
def number_for(number_description, number_size, given_value, kind:)
|
|
17
|
+
given_value = Formatter.raw(given_value.to_s, kind:)
|
|
17
18
|
if !given_value.to_s.empty?
|
|
18
19
|
unless given_value.size == number_size
|
|
19
20
|
raise ArgumentError, "#{number_description} number must be a number with #{number_size} digits."
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
given_value.split('')
|
|
23
|
+
given_value.split('')
|
|
23
24
|
else
|
|
24
25
|
number_with(number_size)
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
def number_with(size)
|
|
29
|
-
size.times.map { rand(10) }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
29
|
def verification_digit_for(numbers)
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
numbers_to_calculate = calculable_numbers_for(numbers:)
|
|
31
|
+
verification_digit_multiplicators = verification_digit_multiplicators_for(numbers_to_calculate)
|
|
32
|
+
sum_and_multiplication = sum_and_multiply(numbers_to_calculate, verification_digit_multiplicators)
|
|
35
33
|
verified_digit(sum_and_multiplication)
|
|
36
34
|
end
|
|
37
35
|
|
|
36
|
+
def calculable_numbers_for(numbers:) = numbers.map { |number| number.to_s.upcase.ord - ZERO_ON_ASCII_CODE }
|
|
37
|
+
|
|
38
38
|
def verified_digit(sum_and_multiplication)
|
|
39
39
|
rest = sum_and_multiplication % BASE
|
|
40
40
|
rest < 2 ? 0 : BASE - rest
|
|
@@ -3,28 +3,20 @@
|
|
|
3
3
|
require 'rspec/expectations'
|
|
4
4
|
|
|
5
5
|
RSpec::Matchers.define :a_formatted_cnpj do
|
|
6
|
-
match
|
|
7
|
-
formatted_cnpj_pattern = /\A(\d{2}\.\d{3}\.\d{3}\/\d{4})-(\d{2})\z/
|
|
8
|
-
|
|
9
|
-
formatted_cnpj_pattern.match?(cnpj.to_s)
|
|
10
|
-
end
|
|
6
|
+
match { |cnpj| BraDocuments::Matcher.match?(cnpj.to_s, kind: :cnpj, mode: :formatted) }
|
|
11
7
|
|
|
12
8
|
failure_message do |cnpj|
|
|
13
9
|
"Was expected `#{cnpj.inspect}` to be a Brazilian CNPJ document number but it isn't.\n"\
|
|
14
|
-
"A CNPJ has the following format
|
|
10
|
+
"A CNPJ has the following format AA.AAA.AAA/AAAA-99 where X are numbers from 0 to 9.\n"
|
|
15
11
|
end
|
|
16
12
|
end
|
|
17
13
|
|
|
18
14
|
RSpec::Matchers.define :a_raw_cnpj do
|
|
19
|
-
match
|
|
20
|
-
raw_cnpj_pattern = /\A\d{14}\z/
|
|
21
|
-
|
|
22
|
-
raw_cnpj_pattern.match?(cnpj.to_s)
|
|
23
|
-
end
|
|
15
|
+
match { |cnpj| BraDocuments::Matcher.match?(cnpj.to_s, kind: :cnpj, mode: :raw) }
|
|
24
16
|
|
|
25
17
|
failure_message do |cnpj|
|
|
26
18
|
"Was expected `#{cnpj.inspect}` to be a raw Brazilian cnpj document number but it isn't.\n"\
|
|
27
|
-
"A raw CNPJ has the following format
|
|
19
|
+
"A raw CNPJ has the following format AAAAAAAAAAAAAA where X are numbers from 0 to 9.\n"
|
|
28
20
|
end
|
|
29
21
|
end
|
|
30
22
|
|
|
@@ -3,24 +3,16 @@
|
|
|
3
3
|
require 'rspec/expectations'
|
|
4
4
|
|
|
5
5
|
RSpec::Matchers.define :a_formatted_cpf do
|
|
6
|
-
match
|
|
7
|
-
formatted_cpf_pattern = /\A(\d{3}\.\d{3}\.\d{3})-(\d{2})\z/
|
|
8
|
-
|
|
9
|
-
formatted_cpf_pattern.match?(cpf.to_s)
|
|
10
|
-
end
|
|
6
|
+
match { |cpf| BraDocuments::Matcher.match?(cpf.to_s, kind: :cpf, mode: :formatted) }
|
|
11
7
|
|
|
12
8
|
failure_message do |cpf|
|
|
13
9
|
"Was expected `#{cpf.inspect}` to be a Brazilian CPF document number but it isn't.\n"\
|
|
14
|
-
"A CPF has the following format
|
|
10
|
+
"A CPF has the following format 999.999.999-99 where X are numbers from 0 to 9.\n"
|
|
15
11
|
end
|
|
16
12
|
end
|
|
17
13
|
|
|
18
14
|
RSpec::Matchers.define :a_raw_cpf do
|
|
19
|
-
match
|
|
20
|
-
raw_cpf_pattern = /\A\d{11}\z/
|
|
21
|
-
|
|
22
|
-
raw_cpf_pattern.match?(cpf.to_s)
|
|
23
|
-
end
|
|
15
|
+
match { |cpf| BraDocuments::Matcher.match?(cpf.to_s, kind: :cpf, mode: :raw) }
|
|
24
16
|
|
|
25
17
|
failure_message do |cpf|
|
|
26
18
|
"Was expected `#{cpf.inspect}` to be a raw Brazilian CPF document number but it isn't.\n"\
|
metadata
CHANGED
|
@@ -1,31 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bra_documents
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bruno Vicenzo
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
20
|
-
type: :development
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: pry-nav
|
|
13
|
+
name: rake
|
|
29
14
|
requirement: !ruby/object:Gem::Requirement
|
|
30
15
|
requirements:
|
|
31
16
|
- - ">="
|
|
@@ -39,7 +24,7 @@ dependencies:
|
|
|
39
24
|
- !ruby/object:Gem::Version
|
|
40
25
|
version: '0'
|
|
41
26
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
27
|
+
name: rspec
|
|
43
28
|
requirement: !ruby/object:Gem::Requirement
|
|
44
29
|
requirements:
|
|
45
30
|
- - ">="
|
|
@@ -53,7 +38,7 @@ dependencies:
|
|
|
53
38
|
- !ruby/object:Gem::Version
|
|
54
39
|
version: '0'
|
|
55
40
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
41
|
+
name: irb
|
|
57
42
|
requirement: !ruby/object:Gem::Requirement
|
|
58
43
|
requirements:
|
|
59
44
|
- - ">="
|
|
@@ -75,7 +60,9 @@ extensions: []
|
|
|
75
60
|
extra_rdoc_files: []
|
|
76
61
|
files:
|
|
77
62
|
- ".github/dependabot.yml"
|
|
63
|
+
- ".github/workflows/main.yml"
|
|
78
64
|
- ".gitignore"
|
|
65
|
+
- ".mise.toml"
|
|
79
66
|
- ".rspec"
|
|
80
67
|
- ".travis.yml"
|
|
81
68
|
- CHANGELOG.md
|
|
@@ -86,6 +73,9 @@ files:
|
|
|
86
73
|
- README.md
|
|
87
74
|
- Rakefile
|
|
88
75
|
- bin/console
|
|
76
|
+
- bin/rake
|
|
77
|
+
- bin/rdoc
|
|
78
|
+
- bin/rspec
|
|
89
79
|
- bin/setup
|
|
90
80
|
- bra_documents.gemspec
|
|
91
81
|
- lib/bra_documents.rb
|
|
@@ -106,7 +96,6 @@ metadata:
|
|
|
106
96
|
homepage_uri: https://github.com/bvicenzo/bra_documents
|
|
107
97
|
source_code_uri: https://github.com/bvicenzo/bra_documents
|
|
108
98
|
changelog_uri: https://github.com/bvicenzo/bra_documents/blob/master/CHANGELOG.md
|
|
109
|
-
post_install_message:
|
|
110
99
|
rdoc_options: []
|
|
111
100
|
require_paths:
|
|
112
101
|
- lib
|
|
@@ -114,15 +103,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
114
103
|
requirements:
|
|
115
104
|
- - ">="
|
|
116
105
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
106
|
+
version: 3.3.0
|
|
118
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
108
|
requirements:
|
|
120
109
|
- - ">="
|
|
121
110
|
- !ruby/object:Gem::Version
|
|
122
111
|
version: '0'
|
|
123
112
|
requirements: []
|
|
124
|
-
rubygems_version:
|
|
125
|
-
signing_key:
|
|
113
|
+
rubygems_version: 4.0.3
|
|
126
114
|
specification_version: 4
|
|
127
115
|
summary: A implementation for generating Brazilian CPF and CNPJ document numbers.
|
|
128
116
|
test_files: []
|