digit_checksum 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +98 -49
- data/examples/brazilian_cnpj.rb +4 -4
- data/examples/brazilian_cpf.rb +4 -4
- data/examples/h4ck.rb +7 -8
- data/lib/digit_checksum.rb +7 -0
- data/lib/digit_checksum/base_document.rb +149 -151
- data/lib/digit_checksum/delegators.rb +25 -0
- data/lib/digit_checksum/helpers.rb +33 -0
- data/lib/digit_checksum/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e098dcc7fc897c32eb09d70d394843796be0da2a
|
4
|
+
data.tar.gz: 6205b777875f7348ec6067b717b12151eb22000d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1029ae56d3961add0c57d6b9ccd4883457246bd504bf1a7c625fa1d57fb622d5dfd7f1ec2e2daaf6b3c26ded52889f8899cab89b2be82717aa70be2cce8b1ee
|
7
|
+
data.tar.gz: d6d87b10ab1bddc2e0bae2107123d6cc000b5a63f1f0a5c848709bb6ca9469fae3bab49592b26f41819c87a471635169f113a0e47c1a642839928433573bf4f8
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ One of the greatest abilitys of this library is allowing to check digit checksum
|
|
17
17
|
Add this line to your application's Gemfile:
|
18
18
|
|
19
19
|
```ruby
|
20
|
-
gem 'digit_checksum', '~> 0.2.
|
20
|
+
gem 'digit_checksum', '~> 0.2.3'
|
21
21
|
```
|
22
22
|
|
23
23
|
And then execute:
|
@@ -41,20 +41,18 @@ Don't you believe me? See for yourself an example:
|
|
41
41
|
require 'digit_checksum'
|
42
42
|
|
43
43
|
class CNPJ < DigitChecksum::BaseDocument
|
44
|
-
# weights masks that will be used to calculate each check digit
|
45
44
|
set_verify_digits_weights first: %w(5 4 3 2 9 8 7 6 5 4 3 2),
|
46
|
-
|
45
|
+
second: %w(6 5 4 3 2 9 8 7 6 5 4 3 2)
|
46
|
+
|
47
|
+
# MOD 11
|
48
|
+
set_division_modulo 11
|
47
49
|
|
48
50
|
# remove any non digit from document number
|
49
51
|
set_clear_number_regexp %r{[^(\d+)]}
|
50
52
|
|
51
|
-
# use modulo 11 as algorithm (can be any value)
|
52
|
-
set_division_factor_modulo 11
|
53
|
-
|
54
53
|
# match format such as: 99.999.999/9999-99 | 99-999-999/9999-99 | 99999999/999999 | 99999999999999
|
55
|
-
|
54
|
+
set_format_regexp %r{(\d{2})[-.]?(\d{3})[-.]?(\d{3})[\/]?(\d{4})[-.]?(\d{2})}
|
56
55
|
|
57
|
-
# mask utilized to prettify doc number
|
58
56
|
set_pretty_format_mask %(%s.%s.%s/%s-%s)
|
59
57
|
|
60
58
|
# numbers sampled to generate new document numbers
|
@@ -72,7 +70,7 @@ CNPJ.generate # "79.552.921/0786-55"
|
|
72
70
|
# without pretty formating
|
73
71
|
CNPJ.generate(false) # 85215313606778
|
74
72
|
|
75
|
-
# You can
|
73
|
+
# You can generate only random root numbers
|
76
74
|
root_numbers = CNPJ.generate_root_numbers
|
77
75
|
# => [3, 8, 9, 3, 2, 5, 9, 5, 0, 2, 6, 6]
|
78
76
|
|
@@ -81,7 +79,8 @@ CNPJ.calculate_verify_digits(root_numbers) # [6,7]
|
|
81
79
|
# To insert the verify digits in the CORRECT positions
|
82
80
|
# Remember: The correct position MAY NOT be the last positions
|
83
81
|
# So use `append_verify_digits` to handle this
|
84
|
-
|
82
|
+
|
83
|
+
CNPJ.pretty(CNPJ.append_verify_digits!(root_numbers))
|
85
84
|
=> "38.932.595/0266-67"
|
86
85
|
```
|
87
86
|
|
@@ -94,19 +93,13 @@ CNPJ.calculate_verify_digits("123.456.78/0001") # [9,5]
|
|
94
93
|
# invalid format
|
95
94
|
CNPJ.calculate_verify_digits("123.456.78/00001") # []
|
96
95
|
|
97
|
-
CNPJ.pretty(CNPJ.append_verify_digits("
|
96
|
+
CNPJ.pretty(CNPJ.append_verify_digits!("12.345.678/0001")) # "12.345.678/0001-95
|
98
97
|
|
99
98
|
document = "123.456.78/0001-95"
|
100
|
-
CNPJ.remove_verify_digits!(document)
|
101
|
-
#
|
102
|
-
document
|
103
|
-
# => 123456780001
|
104
|
-
CNPJ.pretty(CNPJ.append_verify_digits(document))
|
105
|
-
# => "12.345.678/0001-95"
|
99
|
+
CNPJ.remove_verify_digits!(document) => # [9,5]
|
100
|
+
document # => 123456780001
|
106
101
|
|
107
|
-
#
|
108
|
-
CNPJ.obtain_verify_digits_positions
|
109
|
-
# => [12, 13]
|
102
|
+
CNPJ.pretty(CNPJ.append_verify_digits!(document)) # => "12.345.678/0001-95"
|
110
103
|
|
111
104
|
```
|
112
105
|
|
@@ -115,12 +108,12 @@ CNPJ.obtain_verify_digits_positions
|
|
115
108
|
# convenience methods to check if document is valid
|
116
109
|
|
117
110
|
# invalid format
|
118
|
-
CNPJ.valid?("123.456.78/0001") # false
|
119
|
-
CNPJ.invalid?("123.456.78/0001") # true
|
111
|
+
CNPJ.valid?("123.456.78/0001") # => false
|
112
|
+
CNPJ.invalid?("123.456.78/0001") # => true
|
120
113
|
|
121
114
|
# valid format
|
122
|
-
CNPJ.valid?("123.456.78/0001-95") # true
|
123
|
-
CNPJ.valid?(12345678000195) # true
|
115
|
+
CNPJ.valid?("123.456.78/0001-95") # => true
|
116
|
+
CNPJ.valid?(12345678000195) # => true
|
124
117
|
|
125
118
|
```
|
126
119
|
|
@@ -129,20 +122,18 @@ CNPJ.valid?(12345678000195) # true
|
|
129
122
|
```ruby
|
130
123
|
|
131
124
|
# Get a array representation of document number
|
132
|
-
CNPJ.
|
125
|
+
CNPJ.normalize("123.456.78/0001-95")
|
133
126
|
# => [1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 1, 9, 5]
|
134
127
|
|
135
128
|
# also aliased as CNPJ.pretty_formatted(number) or CNPJ.formatted(number)
|
136
129
|
CNPJ.pretty("12345678000195") # "123.456.78/0001-95"
|
137
130
|
|
138
131
|
# also aliased as CNPJ.clear_number(number)
|
139
|
-
CNPJ.
|
140
|
-
# => "12345678000195"
|
132
|
+
CNPJ.strip("123.456.78/0001-95") # => "12345678000195"
|
141
133
|
```
|
142
134
|
|
143
135
|
See `examples/`for more detailed samples.
|
144
136
|
|
145
|
-
|
146
137
|
---
|
147
138
|
|
148
139
|
### Custom verify digits positions
|
@@ -152,48 +143,106 @@ to calculate check digits in any position in the middle of the document number,
|
|
152
143
|
|
153
144
|
```ruby
|
154
145
|
class MyDocument < DigitChecksum::BaseDocument
|
155
|
-
|
146
|
+
|
147
|
+
set_division_modulo 11
|
156
148
|
|
157
149
|
set_clear_number_regexp %r{[^(\d+)]}
|
158
150
|
|
159
|
-
|
151
|
+
set_root_digits_count 10
|
160
152
|
|
161
153
|
set_verify_digits_positions [8, 11]
|
162
154
|
|
163
155
|
set_verify_digits_weights first: %w(1 3 4 5 6 7 8 10),
|
164
156
|
last: %w(3 2 10 9 8 7 6 5 4 3 2)
|
165
157
|
|
166
|
-
|
158
|
+
set_format_regexp %r{(\d{3})[-.]?(\d{3})[-.]?(\d{3})[-.]?(\d{3})}
|
167
159
|
|
168
160
|
set_pretty_format_mask %(%s.%s.%s.%s)
|
169
161
|
|
170
162
|
set_generator_numbers (0..9).to_a
|
171
163
|
end
|
172
164
|
|
173
|
-
|
165
|
+
|
166
|
+
MyDocument.get_verify_digits_positions # [8, 11]
|
167
|
+
|
174
168
|
# document number without check digits
|
175
|
-
MyDocument.calculate_verify_digits("110.042.49.11")
|
176
|
-
|
177
|
-
document = MyDocument.append_verify_digits("110.042.49.11")
|
169
|
+
MyDocument.calculate_verify_digits("110.042.49.11") # => [1, 3]
|
170
|
+
|
171
|
+
document = MyDocument.append_verify_digits!("110.042.49.11")
|
178
172
|
# => "110042491113"
|
179
|
-
|
180
|
-
# => "110.042.491.113"
|
181
|
-
|
182
|
-
# => [1, 3]
|
183
|
-
|
184
|
-
# => "1100424911"
|
185
|
-
document = MyDocument.append_verify_digits(document)
|
173
|
+
|
174
|
+
MyDocument.pretty(document) # => "110.042.491.113"
|
175
|
+
|
176
|
+
MyDocument.remove_verify_digits!(document) # => [1, 3]
|
177
|
+
|
178
|
+
document # => "1100424911"
|
179
|
+
document = MyDocument.append_verify_digits!(document)
|
180
|
+
|
186
181
|
# => "110042491113"
|
187
|
-
MyDocument.pretty(document)
|
188
|
-
|
182
|
+
MyDocument.pretty(document) # => "110.042.491.113"
|
183
|
+
|
189
184
|
# document number with check digits in the right positions(8, 11)
|
190
|
-
MyDocument.valid?("110.042.491.113")
|
191
|
-
|
185
|
+
MyDocument.valid?("110.042.491.113") # => true
|
186
|
+
|
192
187
|
# document number with wrong check digits in the right positions
|
193
|
-
MyDocument.valid?("110.042.492.113")
|
194
|
-
|
195
|
-
MyDocument.pretty(MyDocument.append_verify_digits("110.042.49.11"))
|
188
|
+
MyDocument.valid?("110.042.492.113") # => false
|
189
|
+
|
190
|
+
MyDocument.pretty(MyDocument.append_verify_digits!("110.042.49.11"))
|
196
191
|
# => "110.042.491.113"
|
192
|
+
|
193
|
+
doc = MyDocument.generate # => "286.670.374.780"
|
194
|
+
|
195
|
+
MyDocument.valid?(doc) # =: true
|
196
|
+
```
|
197
|
+
|
198
|
+
---
|
199
|
+
|
200
|
+
## PORO - Plain Old Ruby Objects API
|
201
|
+
|
202
|
+
All API demonstrated in this documentation (mostly class methods call) are **simple instance methods delegations to a Ruby object instance**, you can work directly with objects in this way:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
object = CNPJ.new("53.091.177/2847-09")
|
206
|
+
|
207
|
+
object.valid? # true
|
208
|
+
|
209
|
+
# Try to get verify digits without calculating
|
210
|
+
# Just search in the right positions in number
|
211
|
+
object.current_verify_digits # [0, 9]
|
212
|
+
|
213
|
+
# Permanently remove verify digits from number
|
214
|
+
object.remove_verify_digits! # [0, 9]
|
215
|
+
|
216
|
+
# Try to get verify digits without calculating
|
217
|
+
object.current_verify_digits # []
|
218
|
+
|
219
|
+
object.number # object.to_s => "530911772847"
|
220
|
+
|
221
|
+
object.valid? # false
|
222
|
+
|
223
|
+
# Just calculate the verify digits, dont append to number
|
224
|
+
object.calculate_verify_digits # [0, 9]
|
225
|
+
|
226
|
+
# Use the `calculate_verify_digits` methods and append the digits in the RIGHT positions
|
227
|
+
object.append_verify_digits! # "53091177284709"
|
228
|
+
|
229
|
+
object.pretty # => "53.091.177/2847-09"
|
230
|
+
|
231
|
+
object.normalize
|
232
|
+
# => [5, 3, 0, 9, 1, 1, 7, 7, 2, 8, 4, 7, 0, 9]
|
233
|
+
|
234
|
+
object.strip # "53091177284709"
|
235
|
+
|
236
|
+
object.size # 14
|
237
|
+
|
238
|
+
object.root_digits_count # 12
|
239
|
+
|
240
|
+
object.verify_digits_count # 2
|
241
|
+
|
242
|
+
# root_digits_count + verify_digits_count
|
243
|
+
object.full_size # 14
|
244
|
+
|
245
|
+
object.verify_digits_positions # [12, 13]
|
197
246
|
```
|
198
247
|
|
199
248
|
---
|
data/examples/brazilian_cnpj.rb
CHANGED
@@ -3,13 +3,13 @@ class CNPJ < DigitChecksum::BaseDocument
|
|
3
3
|
second: %w(6 5 4 3 2 9 8 7 6 5 4 3 2)
|
4
4
|
|
5
5
|
# MOD 11
|
6
|
-
|
6
|
+
set_division_modulo 11
|
7
7
|
|
8
8
|
# remove any non digit from document number
|
9
9
|
set_clear_number_regexp %r{[^(\d+)]}
|
10
10
|
|
11
11
|
# match format such as: 99.999.999/9999-99 | 99-999-999/9999-99 | 99999999/999999 | 99999999999999
|
12
|
-
|
12
|
+
set_format_regexp %r{(\d{2})[-.]?(\d{3})[-.]?(\d{3})[\/]?(\d{4})[-.]?(\d{2})}
|
13
13
|
|
14
14
|
set_pretty_format_mask %(%s.%s.%s/%s-%s)
|
15
15
|
|
@@ -25,5 +25,5 @@ CNPJ.valid?(69739073000104) # true
|
|
25
25
|
CNPJ.valid?("38.485.271/0001-57") # true
|
26
26
|
|
27
27
|
CNPJ.calculate_verify_digits("423.819.53/0001") # [9,7]
|
28
|
-
CNPJ.
|
29
|
-
CNPJ.
|
28
|
+
CNPJ.pretty("69739073000104") # "69.739.073/0001-04"
|
29
|
+
CNPJ.strip("38.485.271/0001-57") # 38485271000157
|
data/examples/brazilian_cpf.rb
CHANGED
@@ -3,13 +3,13 @@ class CPF < DigitChecksum::BaseDocument
|
|
3
3
|
second: %w(11 10 9 8 7 6 5 4 3 2)
|
4
4
|
|
5
5
|
# MOD 11
|
6
|
-
|
6
|
+
set_division_modulo 11
|
7
7
|
|
8
8
|
# remove any non digit from document number
|
9
9
|
set_clear_number_regexp %r{[^(\d+)]}
|
10
10
|
|
11
11
|
# match format such as: 999.999.999-99 | 999-999-999-99 | 99999999999
|
12
|
-
|
12
|
+
set_format_regexp %r{(\d{3})[-.]?(\d{3})[-.]?(\d{3})[-.]?(\d{2})}
|
13
13
|
|
14
14
|
set_pretty_format_mask %(%s.%s.%s-%s)
|
15
15
|
|
@@ -25,5 +25,5 @@ CPF.valid?(31777259185) # true
|
|
25
25
|
CPF.valid?("315.844.227-26") # true
|
26
26
|
|
27
27
|
CPF.calculate_verify_digits("315.844.227") # [2, 6]
|
28
|
-
CPF.
|
29
|
-
CPF.
|
28
|
+
CPF.pretty("31777259185") # "315.844.227-26"
|
29
|
+
CPF.strip("315.844.227-26") # 31584422726
|
data/examples/h4ck.rb
CHANGED
@@ -12,7 +12,7 @@ class H4ck < DigitChecksum::BaseDocument
|
|
12
12
|
|
13
13
|
PROGRAMMINGS_LANGUAGES.default = 'Unknown'
|
14
14
|
|
15
|
-
|
15
|
+
set_division_modulo 11
|
16
16
|
|
17
17
|
set_verify_digits_weights first: %w(17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2),
|
18
18
|
second: %w(18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2),
|
@@ -23,7 +23,7 @@ class H4ck < DigitChecksum::BaseDocument
|
|
23
23
|
|
24
24
|
# 0101&&1111(0x01)||[16]<07>!29
|
25
25
|
# Ex: 0101&&1111(0x01)||[16]<07>!29-110
|
26
|
-
|
26
|
+
set_format_regexp %r{(\d{4})(\d{4})\(?[0x]?(\d{2})\)?\|?\|?\[?(\d{2})\]?\<?(\d{2})\>?\!?(\d{2})\-?(\d{3})}
|
27
27
|
|
28
28
|
# XXXX&&XXXX(0xZZ)||[YY]<MM>!DD-VVV;
|
29
29
|
set_pretty_format_mask %(%s&&%s(0x%s)||[%s]<%s>!%s-%s;)
|
@@ -31,9 +31,8 @@ class H4ck < DigitChecksum::BaseDocument
|
|
31
31
|
# numbers sampled to generate new document numbers
|
32
32
|
set_generator_numbers (0..9).to_a
|
33
33
|
|
34
|
-
def
|
35
|
-
|
36
|
-
languange_identifier = document_number[8..9].join
|
34
|
+
def favorite_language
|
35
|
+
languange_identifier = normalize[8..9].join
|
37
36
|
|
38
37
|
PROGRAMMINGS_LANGUAGES[languange_identifier]
|
39
38
|
end
|
@@ -45,11 +44,11 @@ invalid_doc_number = "0101&&1111(0x01)||[16]<07>!29-841"
|
|
45
44
|
|
46
45
|
H4ck.generate
|
47
46
|
H4ck.valid?(H4ck.generate)
|
48
|
-
H4ck.
|
47
|
+
H4ck.strip(root_doc_number) # "0101111101160729"
|
49
48
|
H4ck.calculate_verify_digits(root_doc_number) # [8,4,0]
|
50
49
|
H4ck.valid?(root_doc_number) # false
|
51
50
|
H4ck.valid?(valid_doc_number) # true
|
52
51
|
H4ck.valid?(invalid_doc_number) # false
|
53
52
|
|
54
|
-
H4ck.
|
55
|
-
H4ck.
|
53
|
+
H4ck.new(valid_doc_number).favorite_language # C#
|
54
|
+
H4ck.new("0101&&1111(0x04)||[16]<07>!29-840").favorite_language # Python
|
data/lib/digit_checksum.rb
CHANGED
@@ -1,219 +1,217 @@
|
|
1
1
|
module DigitChecksum
|
2
2
|
class BaseDocument
|
3
3
|
|
4
|
-
|
5
|
-
:root_documents_digits_count,
|
4
|
+
CLASS_METHODS = [
|
6
5
|
:verify_digits_positions,
|
7
6
|
:digits_ignore_positions,
|
8
|
-
:division_factor_modulo,
|
9
7
|
:verify_digits_weights,
|
10
8
|
:clear_number_regexp,
|
11
|
-
:
|
9
|
+
:root_digits_count,
|
12
10
|
:pretty_format_mask,
|
13
11
|
:generator_numbers,
|
14
|
-
:
|
12
|
+
:division_modulo,
|
13
|
+
:document_length,
|
14
|
+
:format_regexp
|
15
15
|
]
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
formatted ? pretty_formatted(document_number) : document_number
|
17
|
+
CLASS_METHODS.each do |const_name|
|
18
|
+
define_singleton_method "get_#{const_name}" do
|
19
|
+
self.const_get(const_name.to_s.upcase)
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
verify_digits = calculate_verify_digits(document_number)
|
27
|
-
|
28
|
-
obtain_verify_digits_positions.each_with_index {|position, index|
|
29
|
-
document_number.insert(position + index, verify_digits.shift)
|
30
|
-
}
|
31
|
-
|
32
|
-
normalize_number_to_s(document_number.compact)
|
22
|
+
define_singleton_method "set_#{const_name}" do |value|
|
23
|
+
self.const_set(const_name.to_s.upcase, value).freeze
|
33
24
|
end
|
34
25
|
|
35
|
-
|
36
|
-
|
26
|
+
define_method "get_#{const_name}" do
|
27
|
+
self.class.const_get(const_name.to_s.upcase)
|
37
28
|
end
|
29
|
+
end
|
38
30
|
|
39
|
-
|
40
|
-
# remove all non digits and return an string to be matched with mask
|
41
|
-
normalized_document = normalize_number_to_s(document_number)
|
31
|
+
attr_accessor :number
|
42
32
|
|
43
|
-
|
44
|
-
|
33
|
+
def initialize(number)
|
34
|
+
@number = stripped(number)
|
35
|
+
end
|
45
36
|
|
46
|
-
|
47
|
-
|
37
|
+
def valid?
|
38
|
+
# if document is empty or dont match the exact size, it's invalid
|
39
|
+
return false if (empty? || !valid_length?)
|
48
40
|
|
49
|
-
|
50
|
-
|
41
|
+
# match current verify digits with calculate through modulo operation
|
42
|
+
current_verify_digits == calculate_verify_digits
|
43
|
+
end
|
51
44
|
|
52
|
-
|
53
|
-
|
45
|
+
def invalid?
|
46
|
+
!valid?
|
47
|
+
end
|
54
48
|
|
55
|
-
|
56
|
-
|
49
|
+
def empty?
|
50
|
+
@number.nil? || @number.empty?
|
51
|
+
end
|
57
52
|
|
58
|
-
|
59
|
-
|
53
|
+
def valid_length?
|
54
|
+
size == full_size
|
55
|
+
end
|
60
56
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
57
|
+
def full_size
|
58
|
+
(root_digits_count + verify_digits_count)
|
59
|
+
end
|
65
60
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# when value its not set
|
70
|
-
rescue NameError => e
|
71
|
-
default_verify_digits_position
|
72
|
-
end
|
73
|
-
end
|
61
|
+
def size
|
62
|
+
normalize.length
|
63
|
+
end
|
74
64
|
|
75
|
-
|
76
|
-
verify_digits_count.times.map {|i| root_document_digits_count + i }
|
77
|
-
end
|
65
|
+
alias :length :size
|
78
66
|
|
79
|
-
|
80
|
-
|
81
|
-
|
67
|
+
def current_verify_digits
|
68
|
+
remove_verify_digits(@number.dup)
|
69
|
+
end
|
82
70
|
|
83
|
-
|
84
|
-
|
71
|
+
def calculate_verify_digits
|
72
|
+
number = without_verify_digits(@number)
|
73
|
+
digits = []
|
74
|
+
digits_positions = verify_digits_positions.dup
|
85
75
|
|
86
|
-
|
87
|
-
division_modulo = get_division_factor_modulo
|
88
|
-
digits_positions = obtain_verify_digits_positions.dup
|
89
|
-
digits = []
|
76
|
+
return [] unless number.size == root_digits_count
|
90
77
|
|
91
|
-
|
92
|
-
|
93
|
-
current_document = root_document_number(document_number, mask)
|
94
|
-
verify_digit = calculate_verify_digit(current_document, mask, division_modulo)
|
78
|
+
get_verify_digits_weights.each_with_index do |data, index|
|
79
|
+
position, weights = *data
|
95
80
|
|
96
|
-
|
97
|
-
|
81
|
+
current_number = normalized(number, weights.size)
|
82
|
+
verify_digit = calculate_verify_digit(current_number, weights)
|
98
83
|
|
99
|
-
|
100
|
-
|
101
|
-
end
|
84
|
+
# just update ref to calculate next digit
|
85
|
+
number.insert((digits_positions.shift + index), verify_digit)
|
102
86
|
|
103
|
-
digits
|
87
|
+
digits << verify_digit
|
104
88
|
end
|
105
89
|
|
106
|
-
|
107
|
-
|
90
|
+
digits
|
91
|
+
end
|
108
92
|
|
109
|
-
|
110
|
-
|
93
|
+
def remove_verify_digits!
|
94
|
+
remove_verify_digits(@number)
|
95
|
+
end
|
111
96
|
|
112
|
-
|
113
|
-
|
114
|
-
end
|
97
|
+
def append_verify_digits!
|
98
|
+
digits = calculate_verify_digits
|
115
99
|
|
116
|
-
|
117
|
-
|
100
|
+
if (!valid_length? && digits != current_verify_digits)
|
101
|
+
@number = normalize
|
118
102
|
|
119
|
-
|
103
|
+
verify_digits_positions.each_with_index.flat_map {|position, index|
|
104
|
+
# position + index
|
105
|
+
@number.insert(position, digits.shift)
|
106
|
+
}
|
120
107
|
end
|
121
108
|
|
122
|
-
|
123
|
-
|
124
|
-
end
|
109
|
+
@number = stripped(@number)
|
110
|
+
end
|
125
111
|
|
126
|
-
|
127
|
-
|
128
|
-
|
112
|
+
def normalize
|
113
|
+
normalized(@number)
|
114
|
+
end
|
115
|
+
|
116
|
+
def pretty
|
117
|
+
numbers = @number.to_s.scan(get_format_regexp).flatten
|
118
|
+
numbers.empty? ? '' : (get_pretty_format_mask % numbers)
|
119
|
+
end
|
129
120
|
|
130
|
-
|
131
|
-
|
121
|
+
def strip
|
122
|
+
stripped(@number)
|
123
|
+
end
|
132
124
|
|
133
|
-
|
125
|
+
def to_s
|
126
|
+
@number
|
127
|
+
end
|
134
128
|
|
135
|
-
|
129
|
+
def verify_digits_count
|
130
|
+
get_verify_digits_weights.size
|
131
|
+
end
|
136
132
|
|
137
|
-
|
138
|
-
|
133
|
+
def root_digits_count
|
134
|
+
self.class.root_digits_count
|
135
|
+
end
|
139
136
|
|
140
|
-
|
137
|
+
def verify_digits_positions
|
138
|
+
begin
|
139
|
+
get_verify_digits_positions
|
140
|
+
# when value its not set
|
141
|
+
rescue NameError => e
|
142
|
+
default_verify_digits_position
|
141
143
|
end
|
144
|
+
end
|
142
145
|
|
143
|
-
|
144
|
-
|
146
|
+
alias :as_array :normalize
|
147
|
+
alias :clear :strip
|
148
|
+
alias :formatted :pretty
|
145
149
|
|
146
|
-
|
147
|
-
|
150
|
+
private
|
151
|
+
def stripped(number)
|
152
|
+
number.to_s.gsub(get_clear_number_regexp, '')
|
153
|
+
end
|
148
154
|
|
149
|
-
|
150
|
-
|
151
|
-
quotient = (sum / division_factor)
|
155
|
+
def normalized(number, length = nil)
|
156
|
+
number = stripped(number).split(//).map(&:to_i)
|
152
157
|
|
153
|
-
|
158
|
+
length.nil? ? number : number[0, length]
|
159
|
+
end
|
154
160
|
|
155
|
-
|
156
|
-
|
161
|
+
def remove_verify_digits(number)
|
162
|
+
return [] unless number.size == full_size
|
157
163
|
|
158
|
-
|
159
|
-
(
|
160
|
-
|
164
|
+
verify_digits_positions.each_with_index.flat_map {|position, index|
|
165
|
+
number.slice!(position - index, 1)
|
166
|
+
}.map(&:to_i)
|
167
|
+
end
|
161
168
|
|
162
|
-
|
163
|
-
|
169
|
+
def without_verify_digits(number)
|
170
|
+
number = normalized(number)
|
164
171
|
|
165
|
-
|
166
|
-
end
|
172
|
+
return number unless number.size == full_size
|
167
173
|
|
168
|
-
|
169
|
-
|
174
|
+
remove_verify_digits(number) and number
|
175
|
+
end
|
170
176
|
|
171
|
-
|
172
|
-
|
177
|
+
def default_verify_digits_position
|
178
|
+
verify_digits_count.times.map {|i| root_digits_count + i }
|
179
|
+
end
|
173
180
|
|
174
|
-
|
175
|
-
|
181
|
+
def calculate_verify_digit(number, weights)
|
182
|
+
data = calculate_digits_data(number, weights)
|
176
183
|
|
177
|
-
|
178
|
-
|
179
|
-
end
|
184
|
+
calc_verify_digit(data[:rest])
|
185
|
+
end
|
180
186
|
|
181
|
-
|
182
|
-
|
183
|
-
|
187
|
+
def calculate_digits_data(number, weights)
|
188
|
+
sum = reduce_digits_weights(number, weights)
|
189
|
+
quotient = (sum / get_division_modulo)
|
190
|
+
rest = calculate_rest(sum, quotient)
|
184
191
|
|
185
|
-
|
186
|
-
|
187
|
-
get_root_documents_digits_count
|
188
|
-
rescue NameError => e
|
189
|
-
first_verify_mask.size
|
190
|
-
end
|
191
|
-
end
|
192
|
+
{ sum: sum, quotient: quotient, rest: rest }
|
193
|
+
end
|
192
194
|
|
193
|
-
|
194
|
-
|
195
|
-
end
|
195
|
+
def reduce_digits_weights(number, weights)
|
196
|
+
number = normalized(number)
|
196
197
|
|
197
|
-
|
198
|
-
|
199
|
-
|
198
|
+
number.each_with_index.map {|n,i|
|
199
|
+
n.to_i * weights[i].to_i
|
200
|
+
}.reduce(:+).to_f
|
201
|
+
end
|
200
202
|
|
201
|
-
|
202
|
-
|
203
|
-
alias :clear_number :clear_document_number
|
204
|
-
alias :stripped :clear_document_number
|
205
|
-
alias :formatted :pretty_formatted
|
206
|
-
alias :pretty :pretty_formatted
|
207
|
-
|
208
|
-
CONSTANTS_MAP.each do |const_name|
|
209
|
-
define_method "get_#{const_name}" do
|
210
|
-
self.const_get(const_name.to_s.upcase)
|
211
|
-
end
|
212
|
-
|
213
|
-
define_method "set_#{const_name}" do |value|
|
214
|
-
self.const_set(const_name.to_s.upcase, value)
|
215
|
-
end
|
216
|
-
end
|
203
|
+
def calculate_rest(sum, quotient)
|
204
|
+
(sum % get_division_modulo)
|
217
205
|
end
|
206
|
+
|
207
|
+
def calc_verify_digit(quotient_rest)
|
208
|
+
rest = (get_division_modulo - quotient_rest).to_i
|
209
|
+
|
210
|
+
# if rest has two digits(checkdigit must be a single digit), force 0
|
211
|
+
return 0 if rest >= 10
|
212
|
+
|
213
|
+
rest
|
214
|
+
end
|
215
|
+
|
218
216
|
end
|
219
217
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DigitChecksum
|
2
|
+
class BaseDocument
|
3
|
+
|
4
|
+
CLASS_METHODS_DELEGATES = [
|
5
|
+
:valid?,
|
6
|
+
:invalid?,
|
7
|
+
:pretty,
|
8
|
+
:strip,
|
9
|
+
:normalize,
|
10
|
+
:as_array,
|
11
|
+
:formatted,
|
12
|
+
:clear,
|
13
|
+
:remove_verify_digits!,
|
14
|
+
:append_verify_digits!,
|
15
|
+
:calculate_verify_digits,
|
16
|
+
:valid_length?
|
17
|
+
]
|
18
|
+
|
19
|
+
CLASS_METHODS_DELEGATES.each do |method_name|
|
20
|
+
define_singleton_method method_name do |number|
|
21
|
+
new(number).public_send(method_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DigitChecksum
|
2
|
+
module Helpers
|
3
|
+
def generate(pretty = true)
|
4
|
+
number = new(generate_root_numbers)
|
5
|
+
number.append_verify_digits!
|
6
|
+
|
7
|
+
pretty ? number.pretty : number.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def generate_root_numbers
|
11
|
+
root_digits_count.times.map { get_generator_numbers.sample }
|
12
|
+
end
|
13
|
+
|
14
|
+
def root_digits_count
|
15
|
+
begin
|
16
|
+
get_root_digits_count
|
17
|
+
rescue NameError => e
|
18
|
+
first_verify_mask = get_verify_digits_weights.values[0]
|
19
|
+
first_verify_mask.size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def root_number(number, mask = nil)
|
24
|
+
mask ||= get_verify_digits_weights.values[0]
|
25
|
+
|
26
|
+
new(number).normalize.slice(0, mask.size)
|
27
|
+
end
|
28
|
+
|
29
|
+
def root_number_to_s(number, mask = nil)
|
30
|
+
root_number(number, mask).join
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: digit_checksum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafael Fidelis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -90,6 +90,8 @@ files:
|
|
90
90
|
- examples/h4ck.rb
|
91
91
|
- lib/digit_checksum.rb
|
92
92
|
- lib/digit_checksum/base_document.rb
|
93
|
+
- lib/digit_checksum/delegators.rb
|
94
|
+
- lib/digit_checksum/helpers.rb
|
93
95
|
- lib/digit_checksum/version.rb
|
94
96
|
homepage: https://github.com/fidelisrafael/digit_checksum
|
95
97
|
licenses:
|