digit_checksum 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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:
|