itax_code 2.0.0 → 2.0.2

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.
@@ -14,8 +14,6 @@ module ItaxCode
14
14
  #
15
15
  # @return [String] The encoded tax code
16
16
  class Encoder
17
- MissingDataError = Class.new(StandardError)
18
-
19
17
  # @param [Hash] data The user attributes
20
18
  # @param [Utils] utils
21
19
  #
@@ -25,6 +23,8 @@ module ItaxCode
25
23
  # @option data [String, Date] :birthdate The user birthdate
26
24
  # @option data [String] :birthplace The user birthplace
27
25
  def initialize(data = {}, utils = Utils.new)
26
+ @utils = utils
27
+
28
28
  @surname = data[:surname]
29
29
  @name = data[:name]
30
30
  @gender = data[:gender]&.upcase
@@ -33,7 +33,6 @@ module ItaxCode
33
33
  validate_data_presence!
34
34
 
35
35
  @birthdate = parse_birthdate!
36
- @utils = utils
37
36
  end
38
37
 
39
38
  # Computes the tax code from its components.
@@ -81,8 +80,8 @@ module ItaxCode
81
80
  place_slug = utils.slugged(birthplace)
82
81
  place_item = src.find { |i| place_slug == utils.slugged(i[lookup_key]) }
83
82
 
84
- code = place_item.try(:[], "code")
85
- return code if code.present?
83
+ code = place_item&.[]("code")
84
+ return code if utils.present?(code)
86
85
  raise MissingDataError, "no code found for #{birthplace}" if stop
87
86
 
88
87
  encode_birthplace(utils.countries, stop: true)
@@ -90,7 +89,7 @@ module ItaxCode
90
89
 
91
90
  def validate_data_presence!
92
91
  instance_variables.each do |ivar|
93
- next if instance_variable_get(ivar).present?
92
+ next if utils.present?(instance_variable_get(ivar))
94
93
 
95
94
  raise MissingDataError, "missing #{ivar} value"
96
95
  end
@@ -99,7 +98,7 @@ module ItaxCode
99
98
  def parse_birthdate!
100
99
  Date.parse(birthdate)
101
100
  rescue StandardError
102
- raise ArgumentError, "#{birthdate} is not a valid date"
101
+ raise InvalidBirthdateError, "#{birthdate} is not a valid date"
103
102
  end
104
103
  end
105
104
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ItaxCode
4
+ Error = Class.new(StandardError)
5
+
6
+ class Encoder
7
+ Error = Class.new(Error)
8
+
9
+ InvalidBirthdateError = Class.new(Error)
10
+ MissingDataError = Class.new(Error)
11
+ end
12
+
13
+ class Parser
14
+ Error = Class.new(Error)
15
+
16
+ InvalidControlInternalNumberError = Class.new(Error)
17
+ InvalidTaxCodeError = Class.new(Error)
18
+ NoTaxCodeError = Class.new(Error)
19
+ end
20
+ end
@@ -11,11 +11,6 @@ module ItaxCode
11
11
  #
12
12
  # @return [Hash] The parsed tax code
13
13
  class Parser
14
- Error = Class.new(StandardError)
15
- NoTaxCodeError = Class.new(Error)
16
- InvalidControlInternalNumberError = Class.new(Error)
17
- InvalidTaxCodeError = Class.new(Error)
18
-
19
14
  LENGTH = 16
20
15
 
21
16
  # @param [String] tax_code
@@ -24,7 +19,7 @@ module ItaxCode
24
19
  @tax_code = tax_code&.upcase
25
20
  @utils = utils
26
21
 
27
- raise NoTaxCodeError if @tax_code.blank?
22
+ raise NoTaxCodeError if @utils.blank?(@tax_code)
28
23
  raise InvalidTaxCodeError if @tax_code.length != LENGTH
29
24
  raise InvalidControlInternalNumberError if raw[:cin] != @utils.encode_cin(@tax_code)
30
25
  end
@@ -61,7 +56,7 @@ module ItaxCode
61
56
  end
62
57
 
63
58
  def raw_matches
64
- @raw_matches ||= tax_code.scan(utils.regex).flatten
59
+ @raw_matches ||= tax_code.scan(utils.tax_code_sections_regex).flatten
65
60
  end
66
61
 
67
62
  def gender
@@ -73,8 +68,9 @@ module ItaxCode
73
68
  # value could be wrong. E.g. a person born on 1920 would have birthdate_year = 20 meaning
74
69
  # that both 1920 and 2020 could be valid born years.
75
70
  def year
76
- val = (Date.today.year.to_s[0..1] + utils.omocodia_decode(raw[:birthdate_year])).to_i
77
- val > Date.today.year ? val - 100 : val
71
+ current_year = Date.today.year
72
+ val = (current_year.to_s[0..1] + utils.omocodia_decode(raw[:birthdate_year])).to_i
73
+ val > current_year ? val - 100 : val
78
74
  end
79
75
 
80
76
  def month
@@ -96,7 +92,7 @@ module ItaxCode
96
92
  if place.nil?
97
93
  birthplace(utils.countries, stop: true) unless stop
98
94
  else
99
- place.to_h.deep_symbolize_keys
95
+ place.to_h.transform_keys(&:to_sym)
100
96
  end
101
97
  end
102
98
 
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ItaxCode
4
+ # https://github.com/ruby-i18n/i18n/blob/master/lib/i18n/backend/transliterator.rb
5
+ class Transliterator
6
+ DEFAULT_REPLACEMENT_CHAR = "?"
7
+
8
+ def transliterate(string, replacement = nil)
9
+ replacement ||= DEFAULT_REPLACEMENT_CHAR
10
+ string.gsub(/[^\x00-\x7f]/u) { |char| approximations[char] || replacement }
11
+ end
12
+
13
+ private
14
+
15
+ def approximations
16
+ @approximations ||= {
17
+ "À" => "A",
18
+ "Á" => "A",
19
+ "Â" => "A",
20
+ "Ã" => "A",
21
+ "Ä" => "A",
22
+ "Å" => "A",
23
+ "Æ" => "AE",
24
+ "Ç" => "C",
25
+ "È" => "E",
26
+ "É" => "E",
27
+ "Ê" => "E",
28
+ "Ë" => "E",
29
+ "Ì" => "I",
30
+ "Í" => "I",
31
+ "Î" => "I",
32
+ "Ï" => "I",
33
+ "Ð" => "D",
34
+ "Ñ" => "N",
35
+ "Ò" => "O",
36
+ "Ó" => "O",
37
+ "Ô" => "O",
38
+ "Õ" => "O",
39
+ "Ö" => "O",
40
+ "×" => "x",
41
+ "Ø" => "O",
42
+ "Ù" => "U",
43
+ "Ú" => "U",
44
+ "Û" => "U",
45
+ "Ü" => "U",
46
+ "Ý" => "Y",
47
+ "Þ" => "Th",
48
+ "ß" => "ss",
49
+ "ẞ" => "SS",
50
+ "à" => "a",
51
+ "á" => "a",
52
+ "â" => "a",
53
+ "ã" => "a",
54
+ "ä" => "a",
55
+ "å" => "a",
56
+ "æ" => "ae",
57
+ "ç" => "c",
58
+ "è" => "e",
59
+ "é" => "e",
60
+ "ê" => "e",
61
+ "ë" => "e",
62
+ "ì" => "i",
63
+ "í" => "i",
64
+ "î" => "i",
65
+ "ï" => "i",
66
+ "ð" => "d",
67
+ "ñ" => "n",
68
+ "ò" => "o",
69
+ "ó" => "o",
70
+ "ô" => "o",
71
+ "õ" => "o",
72
+ "ö" => "o",
73
+ "ø" => "o",
74
+ "ù" => "u",
75
+ "ú" => "u",
76
+ "û" => "u",
77
+ "ü" => "u",
78
+ "ý" => "y",
79
+ "þ" => "th",
80
+ "ÿ" => "y",
81
+ "Ā" => "A",
82
+ "ā" => "a",
83
+ "Ă" => "A",
84
+ "ă" => "a",
85
+ "Ą" => "A",
86
+ "ą" => "a",
87
+ "Ć" => "C",
88
+ "ć" => "c",
89
+ "Ĉ" => "C",
90
+ "ĉ" => "c",
91
+ "Ċ" => "C",
92
+ "ċ" => "c",
93
+ "Č" => "C",
94
+ "č" => "c",
95
+ "Ď" => "D",
96
+ "ď" => "d",
97
+ "Đ" => "D",
98
+ "đ" => "d",
99
+ "Ē" => "E",
100
+ "ē" => "e",
101
+ "Ĕ" => "E",
102
+ "ĕ" => "e",
103
+ "Ė" => "E",
104
+ "ė" => "e",
105
+ "Ę" => "E",
106
+ "ę" => "e",
107
+ "Ě" => "E",
108
+ "ě" => "e",
109
+ "Ĝ" => "G",
110
+ "ĝ" => "g",
111
+ "Ğ" => "G",
112
+ "ğ" => "g",
113
+ "Ġ" => "G",
114
+ "ġ" => "g",
115
+ "Ģ" => "G",
116
+ "ģ" => "g",
117
+ "Ĥ" => "H",
118
+ "ĥ" => "h",
119
+ "Ħ" => "H",
120
+ "ħ" => "h",
121
+ "Ĩ" => "I",
122
+ "ĩ" => "i",
123
+ "Ī" => "I",
124
+ "ī" => "i",
125
+ "Ĭ" => "I",
126
+ "ĭ" => "i",
127
+ "Į" => "I",
128
+ "į" => "i",
129
+ "İ" => "I",
130
+ "ı" => "i",
131
+ "IJ" => "IJ",
132
+ "ij" => "ij",
133
+ "Ĵ" => "J",
134
+ "ĵ" => "j",
135
+ "Ķ" => "K",
136
+ "ķ" => "k",
137
+ "ĸ" => "k",
138
+ "Ĺ" => "L",
139
+ "ĺ" => "l",
140
+ "Ļ" => "L",
141
+ "ļ" => "l",
142
+ "Ľ" => "L",
143
+ "ľ" => "l",
144
+ "Ŀ" => "L",
145
+ "ŀ" => "l",
146
+ "Ł" => "L",
147
+ "ł" => "l",
148
+ "Ń" => "N",
149
+ "ń" => "n",
150
+ "Ņ" => "N",
151
+ "ņ" => "n",
152
+ "Ň" => "N",
153
+ "ň" => "n",
154
+ "ʼn" => "'n",
155
+ "Ŋ" => "NG",
156
+ "ŋ" => "ng",
157
+ "Ō" => "O",
158
+ "ō" => "o",
159
+ "Ŏ" => "O",
160
+ "ŏ" => "o",
161
+ "Ő" => "O",
162
+ "ő" => "o",
163
+ "Œ" => "OE",
164
+ "œ" => "oe",
165
+ "Ŕ" => "R",
166
+ "ŕ" => "r",
167
+ "Ŗ" => "R",
168
+ "ŗ" => "r",
169
+ "Ř" => "R",
170
+ "ř" => "r",
171
+ "Ś" => "S",
172
+ "ś" => "s",
173
+ "Ŝ" => "S",
174
+ "ŝ" => "s",
175
+ "Ş" => "S",
176
+ "ş" => "s",
177
+ "Š" => "S",
178
+ "š" => "s",
179
+ "Ţ" => "T",
180
+ "ţ" => "t",
181
+ "Ť" => "T",
182
+ "ť" => "t",
183
+ "Ŧ" => "T",
184
+ "ŧ" => "t",
185
+ "Ũ" => "U",
186
+ "ũ" => "u",
187
+ "Ū" => "U",
188
+ "ū" => "u",
189
+ "Ŭ" => "U",
190
+ "ŭ" => "u",
191
+ "Ů" => "U",
192
+ "ů" => "u",
193
+ "Ű" => "U",
194
+ "ű" => "u",
195
+ "Ų" => "U",
196
+ "ų" => "u",
197
+ "Ŵ" => "W",
198
+ "ŵ" => "w",
199
+ "Ŷ" => "Y",
200
+ "ŷ" => "y",
201
+ "Ÿ" => "Y",
202
+ "Ź" => "Z",
203
+ "ź" => "z",
204
+ "Ż" => "Z",
205
+ "ż" => "z",
206
+ "Ž" => "Z",
207
+ "ž" => "z"
208
+ }
209
+ end
210
+ end
211
+ end
@@ -1,20 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "csv"
4
+ require "itax_code/transliterator"
4
5
 
5
6
  module ItaxCode
6
7
  class Utils
7
- def regex
8
+ def blank?(obj)
9
+ obj.respond_to?(:empty?) ? !!obj.empty? : !obj
10
+ end
11
+
12
+ def present?(obj)
13
+ !blank?(obj)
14
+ end
15
+
16
+ def slugged(string)
17
+ transliterated = transliterate(string.downcase.strip)
18
+ transliterated.gsub(/[^\w-]+/, "-").gsub(/-{2,}/, "-").gsub(/^-+|-+$/, "")
19
+ end
20
+
21
+ def transliterate(string)
22
+ return string if string.ascii_only?
23
+
24
+ transliterator = Transliterator.new
25
+ transliterator.transliterate(string.unicode_normalize(:nfc))
26
+ end
27
+
28
+ def tax_code_sections_regex
8
29
  /^([A-Z]{3})([A-Z]{3})
9
30
  (([A-Z\d]{2})([ABCDEHLMPRST]{1})([A-Z\d]{2}))
10
31
  ([A-Z]{1}[A-Z\d]{3})
11
32
  ([A-Z]{1})$/x
12
33
  end
13
34
 
14
- def slugged(str, separator = "-")
15
- str.gsub(/\s*@\s*/, " at ").gsub(/\s*&\s*/, " and ").parameterize(separator: separator)
16
- end
17
-
18
35
  def months
19
36
  %w[A B C D E H L M P R S T]
20
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ItaxCode
4
- VERSION = "2.0.0"
4
+ VERSION = "2.0.2"
5
5
  end
data/lib/itax_code.rb CHANGED
@@ -1,15 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/all"
4
-
5
3
  require "itax_code/version"
6
4
  require "itax_code/utils"
7
5
  require "itax_code/encoder"
8
6
  require "itax_code/parser"
7
+ require "itax_code/error"
9
8
 
10
9
  module ItaxCode
11
- Error = Class.new(StandardError)
12
-
13
10
  class << self
14
11
  # Encodes the user tax code.
15
12
  #
data/rakelib/cities.rake CHANGED
@@ -16,7 +16,7 @@ namespace :cities do
16
16
  output_string = CSV.generate do |csv|
17
17
  csv << %w[code province name created_on deleted_on]
18
18
 
19
- CSV.foreach(tempfile.path, headers: true) do |row|
19
+ CSV.foreach(tempfile.path, encoding: "bom|utf-8", headers: true) do |row|
20
20
  csv << [
21
21
  row["CODCATASTALE"],
22
22
  row["SIGLAPROVINCIA"],
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itax_code
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Rossi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-01 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
11
+ date: 2023-11-04 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description:
28
14
  email:
29
15
  - mttrss5@gmail.com
@@ -37,7 +23,6 @@ files:
37
23
  - ".github/workflows/test.yml"
38
24
  - ".gitignore"
39
25
  - ".rubocop.yml"
40
- - ".travis.yml"
41
26
  - CHANGELOG.md
42
27
  - CODE_OF_CONDUCT.md
43
28
  - Gemfile
@@ -51,8 +36,10 @@ files:
51
36
  - lib/itax_code/data/cities.csv
52
37
  - lib/itax_code/data/countries.csv
53
38
  - lib/itax_code/encoder.rb
39
+ - lib/itax_code/error.rb
54
40
  - lib/itax_code/omocode.rb
55
41
  - lib/itax_code/parser.rb
42
+ - lib/itax_code/transliterator.rb
56
43
  - lib/itax_code/utils.rb
57
44
  - lib/itax_code/version.rb
58
45
  - rakelib/cities.rake
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.0
6
- before_install: gem install bundler -v 2.1.4