cpf_cnpj 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: de9eb28c1f452532ed8ac6d4f4de50a90dfbfcc3
4
- data.tar.gz: 245f841bb1134f3c196b9844a3aa2b2cd0dd2aff
3
+ metadata.gz: d13c9e2acfdc0d60eb9ffeb2c9008fdd6bad5d0f
4
+ data.tar.gz: bf59d4b1eb0c251086bc8d241b2811b61f7cefec
5
5
  SHA512:
6
- metadata.gz: 14b110b3d281159204b1615b7c5b382f209f34ceb2c5d5680468796d1f93424f60fd7c8f743a10a189581994dd14087f0c52b7699123d4acef65d8f062d846ff
7
- data.tar.gz: 5ba1e893019527388659e6141fef1685cc715641857192c68591af0165c891bca36915a6ac7ddb8f346a2e9f631f1bf3e0b2d7605d245aa6d75c2d0ffb14286f
6
+ metadata.gz: 778b36870ff6afc4ad0b4c5ba65aa148aef45ba8b8005c2e277808c5559d8e7b7ef4b8e06ff1036aef81b188ce765f5befea46901cbedf84e940a85d672755b2
7
+ data.tar.gz: c5a4bd47257e4afa53b44bbf514b17bb4c8b2b0726b8cb4157895f42184db1713201ace9c75550a0d566efb4bf65d9497479f1d134c678d5ffae36197177631b
data/.gitignore CHANGED
@@ -14,3 +14,4 @@ spec/reports
14
14
  test/tmp
15
15
  test/version_tmp
16
16
  tmp
17
+ Gemfile.lock
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ rvm:
5
+ - '2.1.8'
6
+ - '2.2.3'
7
+ - '2.3.0'
data/README.md CHANGED
@@ -1,9 +1,15 @@
1
1
  # CPF/CNPJ
2
2
 
3
+ [![Build Status](https://travis-ci.org/fnando/cpf_cnpj.svg)](https://travis-ci.org/fnando/cpf_cnpj)
4
+ [![Code Climate](https://codeclimate.com/github/fnando/cpf_cnpj/badges/gpa.svg)](https://codeclimate.com/github/fnando/cpf_cnpj)
5
+ [![Gem Version](https://badge.fury.io/rb/cpf_cnpj.svg)](http://badge.fury.io/rb/cpf_cnpj)
6
+
3
7
  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
8
 
5
9
  Just making my life easier when filling these damn numbers on internet bankings and government sites.
6
10
 
11
+ For ActiveModel/ActiveRecord validations, please check <https://github.com/fnando/validators>.
12
+
7
13
  ## Installation
8
14
 
9
15
  Add this line to your application's Gemfile:
@@ -24,16 +30,26 @@ Or install it yourself as:
24
30
 
25
31
  This library has the same API for both CNPJ/CPF, so only one of them is documented below.
26
32
 
27
- require "cpf_cnpj"
33
+ ```ruby
34
+ require "cpf_cnpj"
35
+
36
+ CPF.valid?(number) # Check if a CPF is valid
37
+ CPF.generate # Generate a random CPF number
38
+ CPF.generate(true) # Generate a formatted number
39
+
40
+ cpf = CPF.new(number)
41
+ cpf.formatted # Return formatted CPF (xxx.xxx.xxx-xx)
42
+ cpf.stripped # Return stripped CPF (xxxxxxxxxxx)
43
+ cpf.valid? # Check if CPF is valid
44
+ ```
45
+
46
+ #### Strict Validation
28
47
 
29
- CPF.valid?(number) # Check if a CPF is valid
30
- CPF.generate # Generate a random CPF number
31
- CPF.generate(true) # Generate a formatted number
48
+ By default, validations will strip any characters that aren't numbers. This means that `532#####820------857\n96` is considered a valid number. To perform a strict validation use `strict: true`.
32
49
 
33
- cpf = CPF.new(number)
34
- cpf.formatted # Return formatted CPF (xxx.xxx.xxx-xx)
35
- cpf.stripped # Return stripped CPF (xxxxxxxxxxx)
36
- cpf.valid? # Check if CPF is valid
50
+ ```ruby
51
+ CPF.valid?(number, strict: true)
52
+ ```
37
53
 
38
54
  ### Command-line
39
55
 
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
- #!/usr/bin/env rake
2
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ t.verbose = true
8
+ t.warning = false
9
+ end
10
+
11
+ task :default => :test
data/bin/cnpj CHANGED
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift "#{__dir__}/../lib"
2
3
  require "cpf_cnpj"
3
- CNPJ::CLI.new(ARGV, STDIN, STDOUT, STDERR).start
4
+ CpfCnpj::CLI.new(CNPJ, ARGV, STDIN, STDOUT, STDERR).start
data/bin/cpf CHANGED
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift "#{__dir__}/../lib"
2
3
  require "cpf_cnpj"
3
- CPF::CLI.new(ARGV, STDIN, STDOUT, STDERR).start
4
+ CpfCnpj::CLI.new(CPF, ARGV, STDIN, STDOUT, STDERR).start
@@ -14,6 +14,7 @@ Gem::Specification.new do |gem|
14
14
  gem.require_paths = ["lib"]
15
15
  gem.version = CPF::VERSION
16
16
 
17
- gem.add_development_dependency "rspec"
18
17
  gem.add_development_dependency "pry-meta"
18
+ gem.add_development_dependency "rake"
19
+ gem.add_development_dependency "minitest-utils"
19
20
  end
@@ -1,37 +1,40 @@
1
1
  class CNPJ
2
- require "cnpj/cli"
2
+ require "cpf_cnpj"
3
3
  require "cnpj/formatter"
4
- require "cnpj/generator"
5
4
  require "cnpj/verifier_digit"
6
5
 
7
6
  attr_reader :number
7
+ attr_reader :strict
8
8
 
9
9
  REGEX = /\A\d{2}\.\d{3}.\d{3}\/\d{4}-\d{2}\Z/
10
+ NUMBER_SIZE = 12
10
11
 
11
- BLACKLIST = [
12
- "00000000000000",
13
- "11111111111111",
14
- "22222222222222",
15
- "33333333333333",
16
- "44444444444444",
17
- "55555555555555",
18
- "66666666666666",
19
- "77777777777777",
20
- "88888888888888",
21
- "99999999999999"
22
- ]
12
+ BLACKLIST = %w[
13
+ 00000000000000
14
+ 11111111111111
15
+ 22222222222222
16
+ 33333333333333
17
+ 44444444444444
18
+ 55555555555555
19
+ 66666666666666
20
+ 77777777777777
21
+ 88888888888888
22
+ 9999999999999
23
+ ].freeze
23
24
 
24
- def self.valid?(number)
25
- new(number).valid?
25
+ def self.valid?(number, strict: false)
26
+ new(number, strict).valid?
26
27
  end
27
28
 
28
29
  def self.generate(formatted = false)
29
- cnpj = new(Generator.generate)
30
+ number = CpfCnpj::Generator.generate(NUMBER_SIZE, VerifierDigit)
31
+ cnpj = new(number)
30
32
  formatted ? cnpj.formatted : cnpj.stripped
31
33
  end
32
34
 
33
- def initialize(number)
35
+ def initialize(number, strict = false)
34
36
  @number = number.to_s
37
+ @strict = strict
35
38
  end
36
39
 
37
40
  def number=(number)
@@ -42,7 +45,7 @@ class CNPJ
42
45
  end
43
46
 
44
47
  def stripped
45
- @stripped ||= Formatter.strip(number)
48
+ @stripped ||= Formatter.strip(number, strict)
46
49
  end
47
50
 
48
51
  def formatted
@@ -53,14 +56,15 @@ class CNPJ
53
56
  return unless stripped.size == 14
54
57
  return if BLACKLIST.include?(stripped)
55
58
 
56
- _numbers = numbers[0...12]
57
- _numbers << VerifierDigit.generate(_numbers)
58
- _numbers << VerifierDigit.generate(_numbers)
59
+ digits = numbers[0...12]
60
+ digits << VerifierDigit.generate(digits)
61
+ digits << VerifierDigit.generate(digits)
59
62
 
60
- _numbers[-2, 2] == numbers[-2, 2]
63
+ digits[-2, 2] == numbers[-2, 2]
61
64
  end
62
65
 
63
66
  private
67
+
64
68
  def numbers
65
69
  @numbers ||= stripped.each_char.to_a.map(&:to_i)
66
70
  end
@@ -1,11 +1,14 @@
1
1
  class CNPJ
2
2
  class Formatter
3
+ STRICT_REGEX = /[\/.-]/
4
+ LOOSE_REGEX = /[^\d]/
5
+
3
6
  def self.format(number)
4
7
  strip(number).gsub(/\A(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})\Z/, "\\1.\\2.\\3/\\4-\\5")
5
8
  end
6
9
 
7
- def self.strip(number)
8
- number.to_s.gsub(/[^\d]/, "")
10
+ def self.strip(number, strict = false)
11
+ number.to_s.gsub(strict ? STRICT_REGEX : LOOSE_REGEX, "")
9
12
  end
10
13
  end
11
14
  end
data/lib/cpf.rb CHANGED
@@ -1,38 +1,41 @@
1
1
  class CPF
2
- require "cpf/cli"
2
+ require "cpf_cnpj"
3
3
  require "cpf/formatter"
4
- require "cpf/generator"
5
4
  require "cpf/verifier_digit"
6
5
 
7
6
  attr_reader :number
7
+ attr_reader :strict
8
8
 
9
9
  REGEX = /\A\d{3}\.\d{3}\.\d{3}-\d{2}\Z/
10
+ NUMBER_SIZE = 9
10
11
 
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
- ]
12
+ BLACKLIST = %w[
13
+ 00000000000
14
+ 11111111111
15
+ 22222222222
16
+ 33333333333
17
+ 44444444444
18
+ 55555555555
19
+ 66666666666
20
+ 77777777777
21
+ 88888888888
22
+ 99999999999
23
+ 12345678909
24
+ ].freeze
24
25
 
25
- def self.valid?(number)
26
- new(number).valid?
26
+ def self.valid?(number, strict: false)
27
+ new(number, strict).valid?
27
28
  end
28
29
 
29
30
  def self.generate(formatted = false)
30
- cpf = new(Generator.generate)
31
+ number = CpfCnpj::Generator.generate(NUMBER_SIZE, VerifierDigit)
32
+ cpf = new(number)
31
33
  formatted ? cpf.formatted : cpf.stripped
32
34
  end
33
35
 
34
- def initialize(number)
36
+ def initialize(number, strict = false)
35
37
  @number = number.to_s
38
+ @strict = strict
36
39
  end
37
40
 
38
41
  def number=(number)
@@ -43,25 +46,26 @@ class CPF
43
46
  end
44
47
 
45
48
  def stripped
46
- @stripped ||= Formatter.strip(number)
49
+ @stripped ||= Formatter.strip(number, strict)
47
50
  end
48
51
 
49
52
  def formatted
50
53
  @formatted ||= Formatter.format(number)
51
54
  end
52
55
 
53
- def valid?
56
+ def valid?(strict: false)
54
57
  return unless stripped.size == 11
55
58
  return if BLACKLIST.include?(stripped)
56
59
 
57
- _numbers = numbers[0...9]
58
- _numbers << VerifierDigit.generate(_numbers)
59
- _numbers << VerifierDigit.generate(_numbers)
60
+ digits = numbers[0...9]
61
+ digits << VerifierDigit.generate(digits)
62
+ digits << VerifierDigit.generate(digits)
60
63
 
61
- _numbers[-2, 2] == numbers[-2, 2]
64
+ digits[-2, 2] == numbers[-2, 2]
62
65
  end
63
66
 
64
67
  private
68
+
65
69
  def numbers
66
70
  @numbers ||= stripped.each_char.to_a.map(&:to_i)
67
71
  end
@@ -1,11 +1,14 @@
1
1
  class CPF
2
2
  class Formatter
3
+ STRICT_REGEX = /[.-]/
4
+ LOOSE_REGEX = /[^\d]/
5
+
3
6
  def self.format(number)
4
7
  strip(number).gsub(/\A(\d{3})(\d{3})(\d{3})(\d{2})\Z/, "\\1.\\2.\\3-\\4")
5
8
  end
6
9
 
7
- def self.strip(number)
8
- number.to_s.gsub(/[^\d]/, "")
10
+ def self.strip(number, strict = false)
11
+ number.to_s.gsub(strict ? STRICT_REGEX : LOOSE_REGEX, "")
9
12
  end
10
13
  end
11
14
  end
@@ -1,3 +1,6 @@
1
+ require "English"
1
2
  require "optparse"
3
+ require "cpf_cnpj/generator"
4
+ require "cpf_cnpj/cli"
2
5
  require "cpf"
3
6
  require "cnpj"
@@ -0,0 +1,109 @@
1
+ module CpfCnpj
2
+ class CLI
3
+ attr_reader :document_class, :arguments, :stdin, :stdout, :stderr
4
+
5
+ def initialize(document_class, arguments, stdin, stdout, stderr)
6
+ @document_class = document_class
7
+ @arguments = arguments
8
+ @stdin = stdin
9
+ @stdout = stdout
10
+ @stderr = stderr
11
+ end
12
+
13
+ def bin_name
14
+ document_name.downcase
15
+ end
16
+
17
+ def document_name
18
+ document_class.name
19
+ end
20
+
21
+ def start
22
+ options = {}
23
+
24
+ opts.banner = "Usage: #{bin_name} [options] [#{document_name} number]"
25
+ opts.separator ""
26
+ opts.separator "Specific options:"
27
+
28
+ opts.on("-c", "--check", "Check if #{document_name} is valid") do
29
+ options[:check] = true
30
+ end
31
+
32
+ opts.on("-g", "--generate", "Generate a new #{document_name}") do
33
+ options[:generate] = true
34
+ end
35
+
36
+ opts.on("-f", "--format", "Format #{document_name} with separators") do
37
+ options[:format] = true
38
+ end
39
+
40
+ opts.on("-s", "--strip", "Remove #{document_name} separators") do
41
+ options[:strip] = true
42
+ end
43
+
44
+ opts.on("-v", "--version", "Show version") do
45
+ stdout << VERSION
46
+ exit
47
+ end
48
+
49
+ opts.on_tail("-h", "--help", "Show help") do
50
+ help
51
+ exit
52
+ end
53
+
54
+ opts.parse!(arguments)
55
+ opts.permute!(arguments)
56
+
57
+ help if options.empty?
58
+ generate(options) if options[:generate]
59
+ input = stdin.tty? ? arguments.first : stdin.read
60
+ document = document_class.new(input)
61
+ validate(document)
62
+ format(document) if options[:format]
63
+ strip(document) if options[:strip]
64
+ check(document) if options[:check]
65
+ end
66
+
67
+ def validate(document)
68
+ return if document.valid?
69
+ stderr << "Error: Invalid number\n"
70
+ exit 1
71
+ end
72
+
73
+ # No-op method. CPF is always validated on CpfCnpj::CLI#start.
74
+ def check(_document)
75
+ exit
76
+ end
77
+
78
+ def generate(options)
79
+ document = document_class.new(document_class.generate)
80
+
81
+ if options[:strip]
82
+ stdout << document.stripped
83
+ else
84
+ stdout << document.formatted
85
+ end
86
+
87
+ exit
88
+ end
89
+
90
+ def format(document)
91
+ stdout << document.formatted
92
+ exit
93
+ end
94
+
95
+ def strip(document)
96
+ stdout << document.stripped
97
+ exit
98
+ end
99
+
100
+ def help
101
+ stderr << opts.to_s
102
+ exit 1
103
+ end
104
+
105
+ def opts
106
+ @opts ||= OptionParser.new
107
+ end
108
+ end
109
+ end