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 ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/bin/cnpj ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require "cpf_cnpj"
3
+ CNPJ::CLI.new(ARGV, STDIN, STDOUT, STDERR).start
data/bin/cpf ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require "cpf_cnpj"
3
+ CPF::CLI.new(ARGV, STDIN, STDOUT, STDERR).start
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,11 @@
1
+ class CNPJ
2
+ class Formatter
3
+ def self.format(number)
4
+ strip(number).gsub(/\A(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})\Z/, "\\1.\\2.\\3/\\4-\\5")
5
+ end
6
+
7
+ def self.strip(number)
8
+ number.to_s.gsub(/[^\d]/, "")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class CNPJ
2
+ class Generator
3
+ NUMBERS = [*0..9].freeze
4
+
5
+ def self.generate
6
+ numbers = 12.times.map { NUMBERS.sample }
7
+ numbers << VerifierDigit.generate(numbers)
8
+ numbers << VerifierDigit.generate(numbers)
9
+ numbers.join("")
10
+ end
11
+ end
12
+ 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,11 @@
1
+ class CPF
2
+ class Formatter
3
+ def self.format(number)
4
+ strip(number).gsub(/\A(\d{3})(\d{3})(\d{3})(\d{2})\Z/, "\\1.\\2.\\3-\\4")
5
+ end
6
+
7
+ def self.strip(number)
8
+ number.to_s.gsub(/[^\d]/, "")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class CPF
2
+ class Generator
3
+ NUMBERS = [*0..9].freeze
4
+
5
+ def self.generate
6
+ numbers = 9.times.map { NUMBERS.sample }
7
+ numbers << VerifierDigit.generate(numbers)
8
+ numbers << VerifierDigit.generate(numbers)
9
+ numbers.join("")
10
+ end
11
+ end
12
+ 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,3 @@
1
+ require "optparse"
2
+ require "cpf"
3
+ require "cnpj"
@@ -0,0 +1,7 @@
1
+ class CPF
2
+ VERSION = "0.1.0"
3
+ end
4
+
5
+ class CNPJ
6
+ VERSION = "0.1.0"
7
+ end
@@ -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
@@ -0,0 +1,6 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+ Bundler.require
4
+
5
+ require "support/capture_exit"
6
+ require "support/validation_shared"
@@ -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