cpf_cnpj 0.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.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +70 -0
- data/Rakefile +2 -0
- data/bin/cnpj +3 -0
- data/bin/cpf +3 -0
- data/cpf_cnpj.gemspec +20 -0
- data/lib/cnpj.rb +66 -0
- data/lib/cnpj/cli.rb +102 -0
- data/lib/cnpj/formatter.rb +11 -0
- data/lib/cnpj/generator.rb +12 -0
- data/lib/cnpj/verifier_digit.rb +16 -0
- data/lib/cpf.rb +67 -0
- data/lib/cpf/cli.rb +103 -0
- data/lib/cpf/formatter.rb +11 -0
- data/lib/cpf/generator.rb +12 -0
- data/lib/cpf/verifier_digit.rb +14 -0
- data/lib/cpf_cnpj.rb +3 -0
- data/lib/cpf_cnpj/version.rb +7 -0
- data/spec/cnpj/cli_spec.rb +119 -0
- data/spec/cnpj/formatter_spec.rb +13 -0
- data/spec/cnpj/generator_spec.rb +15 -0
- data/spec/cnpj_spec.rb +38 -0
- data/spec/cpf/cli_spec.rb +119 -0
- data/spec/cpf/formatter_spec.rb +13 -0
- data/spec/cpf/generator_spec.rb +15 -0
- data/spec/cpf_spec.rb +72 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/capture_exit.rb +10 -0
- data/spec/support/validation_shared.rb +17 -0
- metadata +139 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --format documentation
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Nando Vieira
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# CPF/CNPJ
|
2
|
+
|
3
|
+
This gem does some [CPF](http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas)/[CNPJ](http://en.wikipedia.org/wiki/CNPJ) magic. It allows you to create, validate and format CPF/CNPJ, even through the command-line.
|
4
|
+
|
5
|
+
Just making my life easier when filling these damn numbers on internet bankings and government sites.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem "cpf_cnpj"
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install cpf_cnpj
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Ruby API
|
24
|
+
|
25
|
+
This library has the same API for both CNPJ/CPF, so only one of them is documented below.
|
26
|
+
|
27
|
+
require "cpf_cnpj"
|
28
|
+
|
29
|
+
CPF.valid?(number) # Check if a CPF is valid
|
30
|
+
CPF.generate # Generate a random CPF number
|
31
|
+
|
32
|
+
cpf = CPF.new(number)
|
33
|
+
cpf.formatted # Return formatted CPF (xxx.xxx.xxx-xx)
|
34
|
+
cpf.stripped # Return stripped CPF (xxxxxxxxxxx)
|
35
|
+
cpf.valid? # Check if CPF is valid
|
36
|
+
|
37
|
+
### Command-line
|
38
|
+
|
39
|
+
This library gives you two binaries: `cpf` and `cnpj`.
|
40
|
+
|
41
|
+
$ cpf --check 532.820.857-96
|
42
|
+
$ $?
|
43
|
+
0
|
44
|
+
|
45
|
+
$ cpf --check 53282085796
|
46
|
+
$ $?
|
47
|
+
0
|
48
|
+
|
49
|
+
$ cpf --format 53282085796
|
50
|
+
532.820.857-96
|
51
|
+
|
52
|
+
$ cpf --strip 532.820.857-96
|
53
|
+
53282085796
|
54
|
+
|
55
|
+
$ cpf --generate
|
56
|
+
417.524.931-17
|
57
|
+
|
58
|
+
$ cpf --generate --strip
|
59
|
+
76001454809
|
60
|
+
|
61
|
+
$ echo 76001454809 | cpf -f
|
62
|
+
760.014.548-09
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Commit your changes (`git commit -am "Added some feature"`)
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
70
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/cnpj
ADDED
data/bin/cpf
ADDED
data/cpf_cnpj.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/cpf_cnpj/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Nando Vieira"]
|
6
|
+
gem.email = ["fnando.vieira@gmail.com"]
|
7
|
+
gem.description = "Validate, generate and format CPF/CNPJ numbers. Include command-line tools."
|
8
|
+
gem.summary = gem.description
|
9
|
+
|
10
|
+
gem.files = `git ls-files`.split($\)
|
11
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.name = "cpf_cnpj"
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.version = CPF::VERSION
|
16
|
+
|
17
|
+
gem.add_development_dependency "rspec"
|
18
|
+
gem.add_development_dependency "pry"
|
19
|
+
gem.add_development_dependency "awesome_print"
|
20
|
+
end
|
data/lib/cnpj.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
class CNPJ
|
2
|
+
autoload :CLI, "cnpj/cli"
|
3
|
+
autoload :Formatter, "cnpj/formatter"
|
4
|
+
autoload :Generator, "cnpj/generator"
|
5
|
+
autoload :VerifierDigit, "cnpj/verifier_digit"
|
6
|
+
|
7
|
+
attr_reader :number
|
8
|
+
|
9
|
+
REGEX = /\A\d{2}\.\d{3}.\d{3}\/\d{4}-\d{2}\Z/
|
10
|
+
|
11
|
+
BLACKLIST = [
|
12
|
+
"00000000000000",
|
13
|
+
"11111111111111",
|
14
|
+
"22222222222222",
|
15
|
+
"33333333333333",
|
16
|
+
"44444444444444",
|
17
|
+
"55555555555555",
|
18
|
+
"66666666666666",
|
19
|
+
"77777777777777",
|
20
|
+
"88888888888888",
|
21
|
+
"99999999999999"
|
22
|
+
]
|
23
|
+
|
24
|
+
def self.valid?(number)
|
25
|
+
new(number).valid?
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.generate
|
29
|
+
Generator.generate
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(number)
|
33
|
+
@number = number.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def number=(number)
|
37
|
+
@stripped = nil
|
38
|
+
@formatted = nil
|
39
|
+
@numbers = nil
|
40
|
+
@number = number
|
41
|
+
end
|
42
|
+
|
43
|
+
def stripped
|
44
|
+
@stripped ||= Formatter.strip(number)
|
45
|
+
end
|
46
|
+
|
47
|
+
def formatted
|
48
|
+
@formatted ||= Formatter.format(number)
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid?
|
52
|
+
return unless stripped.size == 14
|
53
|
+
return if BLACKLIST.include?(stripped)
|
54
|
+
|
55
|
+
_numbers = numbers[0...12]
|
56
|
+
_numbers << VerifierDigit.generate(_numbers)
|
57
|
+
_numbers << VerifierDigit.generate(_numbers)
|
58
|
+
|
59
|
+
_numbers[-2, 2] == numbers[-2, 2]
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def numbers
|
64
|
+
@numbers ||= stripped.each_char.to_a.map(&:to_i)
|
65
|
+
end
|
66
|
+
end
|
data/lib/cnpj/cli.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
class CNPJ
|
2
|
+
class CLI
|
3
|
+
attr_accessor :arguments
|
4
|
+
attr_accessor :stdin
|
5
|
+
attr_accessor :stdout
|
6
|
+
attr_accessor :stderr
|
7
|
+
|
8
|
+
def initialize(arguments, stdin, stdout, stderr)
|
9
|
+
@arguments = arguments
|
10
|
+
@stdin = stdin
|
11
|
+
@stdout = stdout
|
12
|
+
@stderr = stderr
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
options = {}
|
17
|
+
|
18
|
+
opts.banner = "Usage: cnpj [options] [CNPJ number]"
|
19
|
+
opts.separator ""
|
20
|
+
opts.separator "Specific options:"
|
21
|
+
|
22
|
+
opts.on("-c", "--check", "Check if CNPJ is valid") do
|
23
|
+
options[:check] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on("-g", "--generate", "Generate a new CNPJ") do
|
27
|
+
options[:generate] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-f", "--format", "Format CNPJ with separators") do
|
31
|
+
options[:format] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-s", "--strip", "Remove CNPJ separators") do
|
35
|
+
options[:strip] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-v", "--version", "Show version") do
|
39
|
+
stdout << VERSION
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on_tail("-h", "--help", "Show help") do
|
44
|
+
help
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.parse!(arguments)
|
49
|
+
opts.permute!(arguments)
|
50
|
+
|
51
|
+
help and exit(1) if options.empty?
|
52
|
+
generate(options) if options[:generate]
|
53
|
+
|
54
|
+
cnpj = CNPJ.new(arguments.first || stdin.read)
|
55
|
+
validate(cnpj)
|
56
|
+
format(cnpj) if options[:format]
|
57
|
+
strip(cnpj) if options[:strip]
|
58
|
+
check(cnpj) if options[:check]
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate(cnpj)
|
62
|
+
return if cnpj.valid?
|
63
|
+
stderr << "Error: Invalid number\n"
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def check(cnpj)
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate(options)
|
72
|
+
cnpj = CNPJ.new(Generator.generate)
|
73
|
+
|
74
|
+
if options[:strip]
|
75
|
+
stdout << cnpj.stripped
|
76
|
+
else
|
77
|
+
stdout << cnpj.formatted
|
78
|
+
end
|
79
|
+
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
|
83
|
+
def format(cnpj)
|
84
|
+
stdout << cnpj.formatted
|
85
|
+
exit
|
86
|
+
end
|
87
|
+
|
88
|
+
def strip(cnpj)
|
89
|
+
stdout << cnpj.stripped
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
|
93
|
+
def help
|
94
|
+
stderr << opts.to_s
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def opts
|
99
|
+
@opts ||= OptionParser.new
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CNPJ
|
2
|
+
class VerifierDigit
|
3
|
+
def self.generate(numbers)
|
4
|
+
index = 2
|
5
|
+
|
6
|
+
sum = numbers.reverse.reduce(0) do |sum, number|
|
7
|
+
(sum + number * index).tap do
|
8
|
+
index = index == 9 ? 2 : index + 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
mod = sum % 11
|
13
|
+
mod < 2 ? 0 : 11 - mod
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/cpf.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class CPF
|
2
|
+
autoload :CLI, "cpf/cli"
|
3
|
+
autoload :Formatter, "cpf/formatter"
|
4
|
+
autoload :Generator, "cpf/generator"
|
5
|
+
autoload :VerifierDigit, "cpf/verifier_digit"
|
6
|
+
|
7
|
+
attr_reader :number
|
8
|
+
|
9
|
+
REGEX = /\A\d{3}\.\d{3}\.\d{3}-\d{2}\Z/
|
10
|
+
|
11
|
+
BLACKLIST = [
|
12
|
+
"00000000000",
|
13
|
+
"11111111111",
|
14
|
+
"22222222222",
|
15
|
+
"33333333333",
|
16
|
+
"44444444444",
|
17
|
+
"55555555555",
|
18
|
+
"66666666666",
|
19
|
+
"77777777777",
|
20
|
+
"88888888888",
|
21
|
+
"99999999999",
|
22
|
+
"12345678909"
|
23
|
+
]
|
24
|
+
|
25
|
+
def self.valid?(number)
|
26
|
+
new(number).valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.generate
|
30
|
+
Generator.generate
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(number)
|
34
|
+
@number = number.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def number=(number)
|
38
|
+
@stripped = nil
|
39
|
+
@formatted = nil
|
40
|
+
@numbers = nil
|
41
|
+
@number = number
|
42
|
+
end
|
43
|
+
|
44
|
+
def stripped
|
45
|
+
@stripped ||= Formatter.strip(number)
|
46
|
+
end
|
47
|
+
|
48
|
+
def formatted
|
49
|
+
@formatted ||= Formatter.format(number)
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid?
|
53
|
+
return unless stripped.size == 11
|
54
|
+
return if BLACKLIST.include?(stripped)
|
55
|
+
|
56
|
+
_numbers = numbers[0...9]
|
57
|
+
_numbers << VerifierDigit.generate(_numbers)
|
58
|
+
_numbers << VerifierDigit.generate(_numbers)
|
59
|
+
|
60
|
+
_numbers[-2, 2] == numbers[-2, 2]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def numbers
|
65
|
+
@numbers ||= stripped.each_char.to_a.map(&:to_i)
|
66
|
+
end
|
67
|
+
end
|
data/lib/cpf/cli.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
class CPF
|
2
|
+
class CLI
|
3
|
+
attr_accessor :arguments
|
4
|
+
attr_accessor :stdin
|
5
|
+
attr_accessor :stdout
|
6
|
+
attr_accessor :stderr
|
7
|
+
|
8
|
+
def initialize(arguments, stdin, stdout, stderr)
|
9
|
+
@arguments = arguments
|
10
|
+
@stdin = stdin
|
11
|
+
@stdout = stdout
|
12
|
+
@stderr = stderr
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
options = {}
|
17
|
+
|
18
|
+
opts.banner = "Usage: cpf [options] [CPF number]"
|
19
|
+
opts.separator ""
|
20
|
+
opts.separator "Specific options:"
|
21
|
+
|
22
|
+
opts.on("-c", "--check", "Check if CPF is valid") do
|
23
|
+
options[:check] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on("-g", "--generate", "Generate a new CPF") do
|
27
|
+
options[:generate] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-f", "--format", "Format CPF with separators") do
|
31
|
+
options[:format] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-s", "--strip", "Remove CPF separators") do
|
35
|
+
options[:strip] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-v", "--version", "Show version") do
|
39
|
+
stdout << VERSION
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on_tail("-h", "--help", "Show help") do
|
44
|
+
help
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.parse!(arguments)
|
49
|
+
opts.permute!(arguments)
|
50
|
+
|
51
|
+
help if options.empty?
|
52
|
+
generate(options) if options[:generate]
|
53
|
+
|
54
|
+
cpf = CPF.new(arguments.first || stdin.read)
|
55
|
+
|
56
|
+
validate(cpf)
|
57
|
+
format(cpf) if options[:format]
|
58
|
+
strip(cpf) if options[:strip]
|
59
|
+
check(cpf) if options[:check]
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate(cpf)
|
63
|
+
return if cpf.valid?
|
64
|
+
stderr << "Error: Invalid number\n"
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def check(cpf)
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
|
72
|
+
def generate(options)
|
73
|
+
cpf = CPF.new(Generator.generate)
|
74
|
+
|
75
|
+
if options[:strip]
|
76
|
+
stdout << cpf.stripped
|
77
|
+
else
|
78
|
+
stdout << cpf.formatted
|
79
|
+
end
|
80
|
+
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
|
84
|
+
def format(cpf)
|
85
|
+
stdout << cpf.formatted
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
|
89
|
+
def strip(cpf)
|
90
|
+
stdout << cpf.stripped
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
|
94
|
+
def help
|
95
|
+
stderr << opts.to_s
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
|
99
|
+
def opts
|
100
|
+
@opts ||= OptionParser.new
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CPF
|
2
|
+
class VerifierDigit
|
3
|
+
def self.generate(numbers)
|
4
|
+
modulus = numbers.size + 1
|
5
|
+
|
6
|
+
multiplied = numbers.map.with_index do |number, index|
|
7
|
+
number * (modulus - index)
|
8
|
+
end
|
9
|
+
|
10
|
+
mod = multiplied.reduce(:+) % 11
|
11
|
+
mod < 2 ? 0 : 11 - mod
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/cpf_cnpj.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CNPJ::CLI do
|
4
|
+
let(:stdout) { "" }
|
5
|
+
let(:stderr) { "" }
|
6
|
+
let(:stdin) { StringIO.new }
|
7
|
+
|
8
|
+
context "check" do
|
9
|
+
%w[-c --check].each do |switch|
|
10
|
+
it "checks if provided number is valid [using #{switch}]" do
|
11
|
+
capture_exit do
|
12
|
+
CNPJ::CLI.new([switch, "54550752000155"], stdin, stdout, stderr).start
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(stdout).to eql("")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "outputs error message if provided number is invalid [using #{switch}]" do
|
19
|
+
capture_exit(1) do
|
20
|
+
CNPJ::CLI.new([switch, "invalid"], stdin, stdout, stderr).start
|
21
|
+
end
|
22
|
+
|
23
|
+
expect(stderr).to include("Error: Invalid number")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "help" do
|
29
|
+
%w[-h --help].each do |switch|
|
30
|
+
it "outputs help [using #{switch}]" do
|
31
|
+
capture_exit(1) do
|
32
|
+
CNPJ::CLI.new([switch], stdin, stdout, stderr).start
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(stderr).to include("Usage: cnpj")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "outputs help on tail" do
|
40
|
+
capture_exit(1) do
|
41
|
+
CNPJ::CLI.new([], stdin, stdout, stderr).start
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(stderr).to include("Usage: cnpj")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "version" do
|
49
|
+
%w[-v --version].each do |switch|
|
50
|
+
it "outputs version [using #{switch}]" do
|
51
|
+
capture_exit do
|
52
|
+
CNPJ::CLI.new([switch], stdin, stdout, stderr).start
|
53
|
+
end
|
54
|
+
|
55
|
+
expect(stdout).to include(CNPJ::VERSION.to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "generate" do
|
61
|
+
%w[-g --generate].each do |switch|
|
62
|
+
it "generates number [using #{switch}]" do
|
63
|
+
capture_exit do
|
64
|
+
CNPJ::CLI.new([switch], stdin, stdout, stderr).start
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(stdout).to match(CNPJ::REGEX)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "generates stripped number" do
|
72
|
+
capture_exit do
|
73
|
+
CNPJ::CLI.new(["-gs"], stdin, stdout, stderr).start
|
74
|
+
end
|
75
|
+
|
76
|
+
expect(stdout).to match(/\A\d{14}\Z/)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "format" do
|
81
|
+
%w[-f --format].each do |switch|
|
82
|
+
it "formats argument [using #{switch}]" do
|
83
|
+
capture_exit do
|
84
|
+
CNPJ::CLI.new([switch, "54550752000155"], stdin, stdout, stderr).start
|
85
|
+
end
|
86
|
+
|
87
|
+
expect(stdout).to include("54.550.752/0001-55")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "formats argument using stdin" do
|
92
|
+
stdin = StringIO.new("54550752000155")
|
93
|
+
|
94
|
+
capture_exit do
|
95
|
+
CNPJ::CLI.new(["--format"], stdin, stdout, stderr).start
|
96
|
+
end
|
97
|
+
|
98
|
+
expect(stdout).to include("54.550.752/0001-55")
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:switch) { "--format" }
|
102
|
+
it_behaves_like "validation"
|
103
|
+
end
|
104
|
+
|
105
|
+
context "strip" do
|
106
|
+
%w[-s --strip].each do |switch|
|
107
|
+
it "strips argument [using #{switch}]" do
|
108
|
+
capture_exit do
|
109
|
+
CNPJ::CLI.new([switch, "54.550.752/0001-55"], stdin, stdout, stderr).start
|
110
|
+
end
|
111
|
+
|
112
|
+
expect(stdout).to include("54550752000155")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
let(:switch) { "--strip" }
|
117
|
+
it_behaves_like "validation"
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CNPJ::Formatter do
|
4
|
+
it "formats strings without separators" do
|
5
|
+
number = "12345678901234"
|
6
|
+
expect(CNPJ::Formatter.format(number)).to eql("12.345.678/9012-34")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "removes any non-numeric characters" do
|
10
|
+
number = "\n12$345[678/9012-34"
|
11
|
+
expect(CNPJ::Formatter.strip(number)).to eql("12345678901234")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CNPJ::Generator do
|
4
|
+
it "generates valid numbers" do
|
5
|
+
expect(CNPJ).to be_valid(CNPJ::Generator.generate)
|
6
|
+
expect(CNPJ).to be_valid(CNPJ::Generator.generate)
|
7
|
+
expect(CNPJ).to be_valid(CNPJ::Generator.generate)
|
8
|
+
expect(CNPJ).to be_valid(CNPJ::Generator.generate)
|
9
|
+
expect(CNPJ).to be_valid(CNPJ::Generator.generate)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "generates random numbers" do
|
13
|
+
expect(CNPJ::Generator.generate).not_to eql(CNPJ::Generator.generate)
|
14
|
+
end
|
15
|
+
end
|
data/spec/cnpj_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CNPJ do
|
4
|
+
it "blacklists common numbers" do
|
5
|
+
expect(CNPJ).not_to be_valid("11111111111111")
|
6
|
+
expect(CNPJ).not_to be_valid("22222222222222")
|
7
|
+
expect(CNPJ).not_to be_valid("33333333333333")
|
8
|
+
expect(CNPJ).not_to be_valid("44444444444444")
|
9
|
+
expect(CNPJ).not_to be_valid("55555555555555")
|
10
|
+
expect(CNPJ).not_to be_valid("66666666666666")
|
11
|
+
expect(CNPJ).not_to be_valid("77777777777777")
|
12
|
+
expect(CNPJ).not_to be_valid("88888888888888")
|
13
|
+
expect(CNPJ).not_to be_valid("99999999999999")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "rejects blank strings" do
|
17
|
+
expect(CNPJ).not_to be_valid("")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "rejects nil values" do
|
21
|
+
expect(CNPJ).not_to be_valid(nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "validates formatted strings" do
|
25
|
+
number = "54.550.752/0001-55"
|
26
|
+
expect(CNPJ).to be_valid(number)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "validates unformatted strings" do
|
30
|
+
number = "54550752000155"
|
31
|
+
expect(CNPJ).to be_valid(number)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "validates messed strings" do
|
35
|
+
number = "54550[752#0001..$55"
|
36
|
+
expect(CNPJ).to be_valid(number)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CPF::CLI do
|
4
|
+
let(:stdout) { "" }
|
5
|
+
let(:stderr) { "" }
|
6
|
+
let(:stdin) { StringIO.new }
|
7
|
+
|
8
|
+
context "check" do
|
9
|
+
%w[-c --check].each do |switch|
|
10
|
+
it "checks if provided number is valid [using #{switch}]" do
|
11
|
+
capture_exit do
|
12
|
+
CPF::CLI.new([switch, "77673736578"], stdin, stdout, stderr).start
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(stdout).to eql("")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "outputs error message if provided number is invalid [using #{switch}]" do
|
19
|
+
capture_exit(1) do
|
20
|
+
CPF::CLI.new([switch, "invalid"], stdin, stdout, stderr).start
|
21
|
+
end
|
22
|
+
|
23
|
+
expect(stderr).to include("Error: Invalid number")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "help" do
|
29
|
+
%w[-h --help].each do |switch|
|
30
|
+
it "outputs help [using #{switch}]" do
|
31
|
+
capture_exit(1) do
|
32
|
+
CPF::CLI.new([switch], stdin, stdout, stderr).start
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(stderr).to include("Usage: cpf")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "outputs help on tail" do
|
40
|
+
capture_exit(1) do
|
41
|
+
CPF::CLI.new([], stdin, stdout, stderr).start
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(stderr).to include("Usage: cpf")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "version" do
|
49
|
+
%w[-v --version].each do |switch|
|
50
|
+
it "outputs version [using #{switch}]" do
|
51
|
+
capture_exit do
|
52
|
+
CPF::CLI.new([switch], stdin, stdout, stderr).start
|
53
|
+
end
|
54
|
+
|
55
|
+
expect(stdout).to include(CPF::VERSION.to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "generate" do
|
61
|
+
%w[-g --generate].each do |switch|
|
62
|
+
it "generates number [using -#{switch}]" do
|
63
|
+
capture_exit do
|
64
|
+
CPF::CLI.new([switch], stdin, stdout, stderr).start
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(stdout).to match(CPF::REGEX)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "generates stripped number" do
|
72
|
+
capture_exit do
|
73
|
+
CPF::CLI.new(["-gs"], stdin, stdout, stderr).start
|
74
|
+
end
|
75
|
+
|
76
|
+
expect(stdout).to match(/\A\d{11}\Z/)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "format" do
|
81
|
+
%w[-f --format].each do |switch|
|
82
|
+
it "formats argument [using #{switch}]" do
|
83
|
+
capture_exit do
|
84
|
+
CPF::CLI.new([switch, "77673736578"], stdin, stdout, stderr).start
|
85
|
+
end
|
86
|
+
|
87
|
+
expect(stdout).to include("776.737.365-78")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "formats argument using stdin" do
|
92
|
+
stdin = StringIO.new("77673736578")
|
93
|
+
|
94
|
+
capture_exit do
|
95
|
+
CPF::CLI.new(["--format"], stdin, stdout, stderr).start
|
96
|
+
end
|
97
|
+
|
98
|
+
expect(stdout).to include("776.737.365-78")
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:switch) { "--format" }
|
102
|
+
it_behaves_like "validation"
|
103
|
+
end
|
104
|
+
|
105
|
+
context "strip" do
|
106
|
+
%w[-s --strip].each do |switch|
|
107
|
+
it "strips argument [using #{switch}]" do
|
108
|
+
capture_exit do
|
109
|
+
CPF::CLI.new([switch, "776.737.365-78"], stdin, stdout, stderr).start
|
110
|
+
end
|
111
|
+
|
112
|
+
expect(stdout).to include("77673736578")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
let(:switch) { "--strip" }
|
117
|
+
it_behaves_like "validation"
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CPF::Formatter do
|
4
|
+
it "formats strings without separators" do
|
5
|
+
number = "12345678909"
|
6
|
+
expect(CPF::Formatter.format(number)).to eql("123.456.789-09")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "removes any non-numeric characters" do
|
10
|
+
number = "\n12.-34567$8909"
|
11
|
+
expect(CPF::Formatter.strip(number)).to eql("12345678909")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CPF::Generator do
|
4
|
+
it "generates valid numbers" do
|
5
|
+
expect(CPF).to be_valid(CPF::Generator.generate)
|
6
|
+
expect(CPF).to be_valid(CPF::Generator.generate)
|
7
|
+
expect(CPF).to be_valid(CPF::Generator.generate)
|
8
|
+
expect(CPF).to be_valid(CPF::Generator.generate)
|
9
|
+
expect(CPF).to be_valid(CPF::Generator.generate)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "generates random numbers" do
|
13
|
+
expect(CPF::Generator.generate).not_to eql(CPF::Generator.generate)
|
14
|
+
end
|
15
|
+
end
|
data/spec/cpf_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CPF do
|
4
|
+
it "blacklists common numbers" do
|
5
|
+
expect(CPF).not_to be_valid("11111111111")
|
6
|
+
expect(CPF).not_to be_valid("22222222222")
|
7
|
+
expect(CPF).not_to be_valid("33333333333")
|
8
|
+
expect(CPF).not_to be_valid("44444444444")
|
9
|
+
expect(CPF).not_to be_valid("55555555555")
|
10
|
+
expect(CPF).not_to be_valid("66666666666")
|
11
|
+
expect(CPF).not_to be_valid("77777777777")
|
12
|
+
expect(CPF).not_to be_valid("88888888888")
|
13
|
+
expect(CPF).not_to be_valid("99999999999")
|
14
|
+
expect(CPF).not_to be_valid("12345678909")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "rejects blank strings" do
|
18
|
+
expect(CPF).not_to be_valid("")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "rejects nil values" do
|
22
|
+
expect(CPF).not_to be_valid(nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "validates formatted strings" do
|
26
|
+
number = "295.379.955-93"
|
27
|
+
expect(CPF).to be_valid(number)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "validates unformatted strings" do
|
31
|
+
number = "29537995593"
|
32
|
+
expect(CPF).to be_valid(number)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "validates messed strings" do
|
36
|
+
number = "295$379\n955...93"
|
37
|
+
expect(CPF).to be_valid(number)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns stripped number" do
|
41
|
+
cpf = CPF.new("295.379.955-93")
|
42
|
+
expect(cpf.stripped).to eql("29537995593")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "formats number" do
|
46
|
+
cpf = CPF.new("29537995593")
|
47
|
+
expect(cpf.formatted).to eql("295.379.955-93")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "generates number" do
|
51
|
+
CPF::Generator
|
52
|
+
.should_receive(:generate)
|
53
|
+
|
54
|
+
CPF.generate
|
55
|
+
end
|
56
|
+
|
57
|
+
context "memoization" do
|
58
|
+
let(:cpf) { CPF.new("29537995593") }
|
59
|
+
|
60
|
+
before do
|
61
|
+
cpf.number = "52139989171"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "invalidates stripped number" do
|
65
|
+
expect(cpf.stripped).to eql("52139989171")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "invalidates formatted number" do
|
69
|
+
expect(cpf.formatted).to eql("521.399.891-71")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module CaptureExit
|
2
|
+
def capture_exit(status = 0, &block)
|
3
|
+
yield
|
4
|
+
raise "Expected exit(#{status}); it didn't exit"
|
5
|
+
rescue SystemExit => error
|
6
|
+
raise "Expected exit(#{status}); got exit(#{error.status})" unless status == error.status
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec.configuration.include(CaptureExit)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
shared_examples_for "validation" do
|
2
|
+
it "fails when providing Invalid number" do
|
3
|
+
capture_exit(1) do
|
4
|
+
described_class.new([switch, "invalid"], stdin, stdout, stderr).start
|
5
|
+
end
|
6
|
+
|
7
|
+
expect(stderr).to include("Error: Invalid number")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "fails when not providing a number" do
|
11
|
+
capture_exit(1) do
|
12
|
+
described_class.new([switch], stdin, stdout, stderr).start
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(stderr).to include("Error: Invalid number")
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cpf_cnpj
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nando Vieira
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: pry
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: awesome_print
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Validate, generate and format CPF/CNPJ numbers. Include command-line
|
63
|
+
tools.
|
64
|
+
email:
|
65
|
+
- fnando.vieira@gmail.com
|
66
|
+
executables:
|
67
|
+
- cnpj
|
68
|
+
- cpf
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- .gitignore
|
73
|
+
- .rspec
|
74
|
+
- Gemfile
|
75
|
+
- LICENSE
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- bin/cnpj
|
79
|
+
- bin/cpf
|
80
|
+
- cpf_cnpj.gemspec
|
81
|
+
- lib/cnpj.rb
|
82
|
+
- lib/cnpj/cli.rb
|
83
|
+
- lib/cnpj/formatter.rb
|
84
|
+
- lib/cnpj/generator.rb
|
85
|
+
- lib/cnpj/verifier_digit.rb
|
86
|
+
- lib/cpf.rb
|
87
|
+
- lib/cpf/cli.rb
|
88
|
+
- lib/cpf/formatter.rb
|
89
|
+
- lib/cpf/generator.rb
|
90
|
+
- lib/cpf/verifier_digit.rb
|
91
|
+
- lib/cpf_cnpj.rb
|
92
|
+
- lib/cpf_cnpj/version.rb
|
93
|
+
- spec/cnpj/cli_spec.rb
|
94
|
+
- spec/cnpj/formatter_spec.rb
|
95
|
+
- spec/cnpj/generator_spec.rb
|
96
|
+
- spec/cnpj_spec.rb
|
97
|
+
- spec/cpf/cli_spec.rb
|
98
|
+
- spec/cpf/formatter_spec.rb
|
99
|
+
- spec/cpf/generator_spec.rb
|
100
|
+
- spec/cpf_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
- spec/support/capture_exit.rb
|
103
|
+
- spec/support/validation_shared.rb
|
104
|
+
homepage:
|
105
|
+
licenses: []
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.8.23
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Validate, generate and format CPF/CNPJ numbers. Include command-line tools.
|
128
|
+
test_files:
|
129
|
+
- spec/cnpj/cli_spec.rb
|
130
|
+
- spec/cnpj/formatter_spec.rb
|
131
|
+
- spec/cnpj/generator_spec.rb
|
132
|
+
- spec/cnpj_spec.rb
|
133
|
+
- spec/cpf/cli_spec.rb
|
134
|
+
- spec/cpf/formatter_spec.rb
|
135
|
+
- spec/cpf/generator_spec.rb
|
136
|
+
- spec/cpf_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
- spec/support/capture_exit.rb
|
139
|
+
- spec/support/validation_shared.rb
|