bra_documents 1.0.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0dd0427b2b2196ffdda4f751c6857e36b0bfd0d86c426c4de8d85611bf67517
4
- data.tar.gz: f9330ff3775aaa84a1ec91e4df81fd5489e29760df6a087e0cdb38729f092a1b
3
+ metadata.gz: 5edcee719c06808ad9d7a4bb17c38aac505275489576e0864bc7ac85dcf1541d
4
+ data.tar.gz: 9f86a8ff44a78bab3e2a82c93c7107667c78baafc683fecb81345ec2060c6df7
5
5
  SHA512:
6
- metadata.gz: 8924fcf456e4ec22225b0911117d155cb97f5ea7e6b1a8cdcac21cf9f30653da76cb89166636a161f6f2e0750424c2c6afaf29504a7cef5d51e0b70246c2232f
7
- data.tar.gz: b9e333137523524838fedec86e55c96f9f2f1d198ae6527518e5214d129351c15287d3d60d6ca51af85f030c04bc594d8fcba12a4afa032c3a8d8fed53a9bb55
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
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "4.0.0"
data/CHANGELOG.md CHANGED
@@ -8,6 +8,27 @@ 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
+
11
32
  ## [1.0.2] - 2020-22-10
12
33
 
13
34
  ### Fixed
data/Gemfile.lock CHANGED
@@ -1,43 +1,57 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bra_documents (1.0.2)
4
+ bra_documents (1.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- coderay (1.1.3)
10
- diff-lcs (1.5.0)
11
- method_source (1.0.0)
12
- pry (0.14.1)
13
- coderay (~> 1.1)
14
- method_source (~> 1.0)
15
- pry-nav (1.0.0)
16
- pry (>= 0.9.10, < 0.15)
17
- rake (13.0.6)
18
- rspec (3.11.0)
19
- rspec-core (~> 3.11.0)
20
- rspec-expectations (~> 3.11.0)
21
- rspec-mocks (~> 3.11.0)
22
- rspec-core (3.11.0)
23
- rspec-support (~> 3.11.0)
24
- rspec-expectations (3.11.0)
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.11.0)
27
- rspec-mocks (3.11.0)
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.11.0)
30
- rspec-support (3.11.0)
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
- pry
38
- pry-nav
52
+ irb
39
53
  rake
40
54
  rspec
41
55
 
42
56
  BUNDLED WITH
43
- 2.1.4
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?('11111111111', kind: :cnpj, mode: :raw)
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 "bundler/setup"
4
- require "bra_documents"
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 "irb"
14
- IRB.start(__FILE__)
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")
@@ -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('>= 2.3.0')
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('Matrix or subsidiary', MATRIX_SUBSIDIARY_SIZE, matrix_subsidiary_number)
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 black_listed?(raw_document) || !Matcher.match?(raw_document, kind: :cnpj, mode: :raw)
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 black_listed?(raw_document) || !Matcher.match?(raw_document, kind: :cpf, mode: :raw)
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
- NOT_NUMBER = /\D/
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(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})\z/, mask: '%s.%s.%s/%s-%s' }
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(NOT_NUMBER, '')
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: { formatted: /\A(\d{3}\.){2}\d{3}-\d{2}\z/, raw: /\A\d{11}\z/ },
7
- cnpj: { formatted: /\A\d{2}.\d{3}\.\d{3}\/\d{4}-\d{2}\z/, raw: /\A\d{14}\z/ }
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?('11111111111', kind: :cnpj, mode: :raw)
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('').map(&:to_i)
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
- verification_digit_multiplicators = verification_digit_multiplicators_for(numbers)
34
- sum_and_multiplication = sum_and_multiply(numbers, verification_digit_multiplicators)
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
@@ -46,10 +46,6 @@ module BraDocuments
46
46
  .with_index { |multiplicator, position| numbers[position] * multiplicator }
47
47
  .sum
48
48
  end
49
-
50
- def black_listed?(numbers)
51
- numbers.chars.uniq.size == 1
52
- end
53
49
  end
54
50
  end
55
51
  end
@@ -3,28 +3,20 @@
3
3
  require 'rspec/expectations'
4
4
 
5
5
  RSpec::Matchers.define :a_formatted_cnpj do
6
- match do |cnpj|
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 XX.XXX.XXX/XXXX-XX where X are numbers from 0 to 9.\n"
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 do |cnpj|
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 XXXXXXXXXXXXXX where X are numbers from 0 to 9.\n"
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 do |cpf|
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 XXX.XXX.XXX-XX where X are numbers from 0 to 9.\n"
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 do |cpf|
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"\
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BraDocuments
4
- VERSION = '1.0.2'
4
+ VERSION = '1.1.0'
5
5
  end
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.2
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: 2022-03-31 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: pry
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: rake
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: rspec
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: 2.3.0
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: 3.3.7
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: []