municipitaly2 2.0.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.
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # Define data structure for a Municipality
5
+ class Municipality
6
+ extend Forwardable
7
+ include DataCaller
8
+ include RegionDelegator
9
+ include ZoneDelegator
10
+
11
+ def initialize(province_istat:, name:, name_alt:, partial_istat:,
12
+ cadastrial_code:, postal_codes:, population:,
13
+ area:, latitude:, longitude:) # :nodoc:
14
+ @province_istat = province_istat
15
+ @name = name
16
+ @name_alt = name_alt
17
+ @partial_istat = partial_istat
18
+ @cadastrial_code = cadastrial_code
19
+ @postal_codes = postal_codes.split
20
+ @population = population.to_i
21
+ @area = area.to_f
22
+ @latitude = latitude.to_f
23
+ @longitude = longitude.to_f
24
+ end
25
+
26
+ # <b>istat code</b> relative to parent province (String)
27
+ attr_reader :province_istat
28
+
29
+ # <b>name</b> of municipality (String)
30
+ attr_reader :name
31
+
32
+ # <b>alternative name</b> of municipality (String)
33
+ attr_reader :name_alt
34
+
35
+ attr_reader :partial_istat # :nodoc:
36
+
37
+ # <b>cadastrial code</b> of municipality (String)
38
+ attr_reader :cadastrial_code
39
+
40
+ # an Array of one or more postal code (as String)
41
+ attr_reader :postal_codes
42
+
43
+ # total <b>population</b> of municipality (Integer)
44
+ attr_reader :population
45
+
46
+ # total <b>area</b> of municipality (Float)
47
+ attr_reader :area
48
+
49
+ # total <b>population</b> of municipality (Float)
50
+ attr_reader :latitude
51
+
52
+ # total <b>population</b> of municipality (Float)
53
+ attr_reader :longitude
54
+
55
+ def_delegator :province, :acronym, :province_acronym
56
+ def_delegator :province, :name, :province_name
57
+ def_delegator :province, :region_istat, :region_istat
58
+
59
+ # returns an array of all +Municipitaly2::Municipality+ objects.
60
+ def self.all
61
+ data.municipalities
62
+ end
63
+
64
+ # returns <b>istat code</b> for current municipality.
65
+ def istat
66
+ province_istat + partial_istat
67
+ end
68
+
69
+ def name_full
70
+ name_alt.nil? ? name : "#{name}/#{name_alt}"
71
+ end
72
+
73
+ # returns +Municipitaly2::Province+ object for current municipality.
74
+ def province
75
+ @province ||= Search.province_from_istat(province_istat)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # Define data structure for a Province
5
+ class Province
6
+ extend Forwardable
7
+ include DataCaller
8
+ include RegionDelegator
9
+ include ZoneDelegator
10
+
11
+ def initialize(region_istat:, name:, istat:, acronym:)
12
+ @region_istat = region_istat
13
+ @name = name
14
+ @istat = istat
15
+ @acronym = acronym
16
+ end
17
+
18
+ attr_reader :region_istat, :name, :istat, :acronym
19
+
20
+ # returns an array of all +Municipitaly2::Province+ objects.
21
+ def self.all
22
+ data.provinces
23
+ end
24
+
25
+ # returns an array of all +Municipitaly2::Municipality+ objects belongs
26
+ # to current province.
27
+ def municipalities
28
+ @municipalities ||= Search.municipalities_from_province_istat(istat)
29
+ end
30
+
31
+ # returns ISO 3166-2 code for current province.
32
+ def iso3166_2
33
+ "IT-#{acronym}"
34
+ end
35
+
36
+ alias iso3166 iso3166_2
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # Define data structure for a Region
5
+ class Region
6
+ include DataCaller
7
+ include ZoneDelegator
8
+
9
+ def initialize(zone_code:, name:, istat:, partial_iso3166:)
10
+ @zone_code = zone_code
11
+ @name = name
12
+ @istat = istat
13
+ @partial_iso3166 = partial_iso3166
14
+ end
15
+
16
+ attr_reader :zone_code, :name, :istat, :partial_iso3166
17
+
18
+ # returns an array of all +Municipitaly2::Region+ objects.
19
+ def self.all
20
+ data.regions
21
+ end
22
+
23
+ # returns an array of all +Municipitaly2::Province+ objects belongs
24
+ # to current region.
25
+ def provinces
26
+ @provinces ||= Search.provinces_from_region_istat(istat)
27
+ end
28
+
29
+ # returns an array of all +Municipitaly2::Municipality+ objects belongs
30
+ # to current region.
31
+ def municipalities
32
+ @municipalities ||= Search.municipalities_from_region_istat(istat)
33
+ end
34
+
35
+ # returns ISO 3166-2 code for current province.
36
+ def iso3166_2
37
+ "IT-#{partial_iso3166}"
38
+ end
39
+
40
+ alias iso3166 iso3166_2
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # shared module to delegate Region istance and its methods
5
+ module RegionDelegator
6
+ extend Forwardable
7
+
8
+ def_delegator :region, :name, :region_name
9
+ def_delegator :region, :zone_code, :zone_code
10
+
11
+ def region
12
+ @region ||= Search.region_from_istat(region_istat)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,233 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # +Municipitaly2::Search+ class implement different search methods.
5
+ #
6
+ # You <b>must use</b> shortcut <b>class methods</b> that invoke private
7
+ # instance methods having same method name, for example:
8
+ #
9
+ # Search.municipalities_from_postal_code('36040')
10
+ #
11
+ # invoke to:
12
+ #
13
+ # Search.new('36040').municipalities_from_postal_code
14
+ #
15
+ class Search
16
+ include DataCaller
17
+
18
+ CLASS_METHODS = %i[zone_from_code region_from_istat regions_from_zone_code
19
+ province_from_name province_from_istat
20
+ province_from_acronym provinces_from_region_istat
21
+ provinces_from_zone_code municipalities_from_name
22
+ municipality_from_cadastrial municipality_from_istat
23
+ municipalities_from_postal_code
24
+ municipalities_from_province_istat
25
+ municipalities_from_region_istat
26
+ municipalities_from_zone_code].freeze # :nodoc:
27
+
28
+ CLASS_METHODS.each do |method|
29
+ define_singleton_method method do |message, opts = {}|
30
+ Search.new(message, opts).send(method)
31
+ end
32
+ end # :nodoc:
33
+
34
+ attr_accessor :term, :opts # :nodoc:
35
+
36
+ def initialize(term, opts = {}) # :nodoc:
37
+ @term = term.to_s.strip
38
+ @opts = opts
39
+ end
40
+
41
+ protected
42
+
43
+ # returns a +Municipitaly2::Zone+ object from a <b>zone code</b> term
44
+ #
45
+ # example usage:
46
+ # zone = Search.zone_from_code('4')
47
+ def zone_from_code # :doc:
48
+ data.zones.find do |z|
49
+ z.code == term
50
+ end
51
+ end
52
+
53
+ # returns a +Municipitaly2::Region+ object from a <b>region istat</b> term
54
+ #
55
+ # example usage:
56
+ # region = Search.region_from_istat('15')
57
+ def region_from_istat # :doc:
58
+ data.regions.find do |r|
59
+ r.istat == term
60
+ end
61
+ end
62
+
63
+ # returns an array of +Municipitaly2::Region+ objects from a <b>zone
64
+ # code</b> term
65
+ #
66
+ # example usage:
67
+ # regions = Search.regions_from_zone_code('3')
68
+ def regions_from_zone_code # :doc:
69
+ data.regions.select do |r|
70
+ r.zone_code == term
71
+ end
72
+ end
73
+
74
+ # returns a +Municipitaly2::Province+ object from a <b>province name</b>
75
+ # term
76
+ #
77
+ # example usage:
78
+ # province = Search.province_from_name('Paler')
79
+ def province_from_name # :doc:
80
+ term_set = Municipitaly2.sanitize_term(term)
81
+ return nil if term_set.size < 3
82
+
83
+ data.provinces.find do |p|
84
+ name_set = Municipitaly2.sanitize_term(p.name)
85
+ name_set =~ Regexp.new(term_set)
86
+ end
87
+ end
88
+
89
+ # returns a +Municipitaly2::Province+ object from a <b>province istat</b>
90
+ # term
91
+ #
92
+ # example usage:
93
+ # province = Search.province_from_istat('061')
94
+ def province_from_istat # :doc:
95
+ data.provinces.find do |p|
96
+ p.istat == term
97
+ end
98
+ end
99
+
100
+ # returns a +Municipitaly2::Province+ object from a <b>province acronym</b>
101
+ # term
102
+ #
103
+ # example usage:
104
+ # province = Search.province_from_acronym('MI')
105
+ def province_from_acronym # :doc:
106
+ data.provinces.find do |p|
107
+ p.acronym == term
108
+ end
109
+ end
110
+
111
+ # returns an array of +Municipitaly2::Province+ objects from a <b>region
112
+ # istat</b> term
113
+ #
114
+ # example usage:
115
+ # provinces = Search.provinces_from_region_istat('05')
116
+ def provinces_from_region_istat # :doc:
117
+ data.provinces.select do |p|
118
+ p.region_istat == term
119
+ end
120
+ end
121
+
122
+ # returns an array of +Municipitaly2::Province+ objects from a <b>zone
123
+ # code</b> term
124
+ #
125
+ # example usage:
126
+ # provinces = Search.provinces_from_zone_code('5')
127
+ def provinces_from_zone_code # :doc:
128
+ region_istats = regions_from_zone_code.map(&:istat)
129
+ data.provinces.select do |p|
130
+ region_istats.include? p.region_istat
131
+ end
132
+ end
133
+
134
+ # returns an array of +Municipitaly2::Municipality+ objects from a
135
+ # <b>municipality name</b> term.
136
+ # Term can be a partial string and is case insensitive.
137
+ # The optional parameter +greedy+ [boolean] permit to serch exact term
138
+ # name (if false) or partial word (true by default).
139
+ #
140
+ # example usage:
141
+ # municipalities = Search.municipalities_from_name('monte')
142
+ # municipalities = Search.municipalities_from_name('monte', greedy: false)
143
+ def municipalities_from_name # :doc:
144
+ greedy = opts.fetch(:greedy, true)
145
+ term_set = Municipitaly2.sanitize_term(term)
146
+
147
+ return [] if term_set.size < 3
148
+
149
+ regexp = if greedy
150
+ Regexp.new(term_set, true)
151
+ else
152
+ Regexp.new("^#{term_set}$", true)
153
+ end
154
+ data.municipalities.select do |m|
155
+ Municipitaly2.sanitize_term(m.name) =~ regexp || (m.name_alt && Municipitaly2.sanitize_term(m.name_alt) =~ regexp)
156
+ end
157
+ end
158
+
159
+ # returns a +Municipitaly2::Municipality+ object from a <b>cadastrial
160
+ # code</b> term
161
+ #
162
+ # example usage:
163
+ # municipality = Search.municipality_from_cadastrial('D791')
164
+ def municipality_from_cadastrial # :doc:
165
+ data.municipalities.find do |m|
166
+ m.cadastrial_code == term.upcase
167
+ end
168
+ end
169
+
170
+ # returns a +Municipitaly2::Municipality+ object from a <b>municipality
171
+ # istat</b> term
172
+ #
173
+ # example usage:
174
+ # municipality = Search.municipality_from_istat('066032')
175
+ def municipality_from_istat # :doc:
176
+ province_istat = term.slice!(0...3)
177
+ partial_istat = term
178
+ data.municipalities.find do |m|
179
+ m.province_istat == province_istat && m.partial_istat == partial_istat
180
+ end
181
+ end
182
+
183
+ # returns an array of +Municipitaly2::Municipality+ objects from a
184
+ # <b>postal code</b> term.
185
+ #
186
+ # example usage:
187
+ # municipalities = Search.municipalities_from_postal_code('00163')
188
+ def municipalities_from_postal_code # :doc:
189
+ data.municipalities.select do |m|
190
+ m.postal_codes.include? term
191
+ end
192
+ end
193
+
194
+ # returns an array of +Municipitaly2::Municipality+ objects from a
195
+ # <b>province istat</b> term.
196
+ #
197
+ # example usage:
198
+ # municipalities = Search.municipalities_from_province_istat('090')
199
+ def municipalities_from_province_istat # :doc:
200
+ data.municipalities.select do |m|
201
+ m.province_istat == term
202
+ end
203
+ end
204
+
205
+ # returns an array of +Municipitaly2::Municipality+ objects from a
206
+ # <b>region istat</b> term.
207
+ #
208
+ # example usage:
209
+ # municipalities = Search.municipalities_from_region_istat('13')
210
+ def municipalities_from_region_istat # :doc:
211
+ province_istats = provinces_from_region_istat.map(&:istat)
212
+ municipalities_from_province_istats(province_istats)
213
+ end
214
+
215
+ # returns an array of +Municipitaly2::Municipality+ objects from a
216
+ # <b>zone code</b> term.
217
+ #
218
+ # example usage:
219
+ # municipalities = Search.municipalities_from_zone_code('3')
220
+ def municipalities_from_zone_code # :doc:
221
+ province_istats = provinces_from_zone_code.map(&:istat)
222
+ municipalities_from_province_istats(province_istats)
223
+ end
224
+
225
+ private
226
+
227
+ def municipalities_from_province_istats(istats)
228
+ data.municipalities.select do |m|
229
+ istats.include? m.province_istat
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # :nodoc:
5
+ VERSION = '2.0.0'
6
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # Define data structure for a Zone
5
+ class Zone
6
+ include DataCaller
7
+
8
+ def initialize(name:, code:)
9
+ @name = name
10
+ @code = code
11
+ end
12
+
13
+ attr_reader :name, :code
14
+
15
+ # returns an array of all +Municipitaly2::Zone+ objects.
16
+ def self.all
17
+ data.zones
18
+ end
19
+
20
+ # returns an array of all +Municipitaly2::Region+ objects belongs to
21
+ # current zone.
22
+ def regions
23
+ Search.regions_from_zone_code(code)
24
+ end
25
+
26
+ # returns an array of all +Municipitaly2::Province+ objects belongs
27
+ # to current zone.
28
+ def provinces
29
+ @provinces ||= Search.provinces_from_zone_code(code)
30
+ end
31
+
32
+ # returns an array of all +Municipitaly2::Municipality+ objects belongs
33
+ # to current zone.
34
+ def municipalities
35
+ @municipalities ||= Search.municipalities_from_zone_code(code)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Municipitaly2
4
+ # shared module to delegate Zone istance and its methods
5
+ module ZoneDelegator
6
+ extend Forwardable
7
+
8
+ def_delegator :zone, :name, :zone_name
9
+
10
+ def zone
11
+ @zone ||= Search.zone_from_code(zone_code)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+ require 'forwardable'
5
+
6
+ require_relative 'municipitaly2/version'
7
+ require_relative 'municipitaly2/data'
8
+ require_relative 'municipitaly2/zone_delegator'
9
+ require_relative 'municipitaly2/region_delegator'
10
+ require_relative 'municipitaly2/data_caller'
11
+ require_relative 'municipitaly2/zone'
12
+ require_relative 'municipitaly2/region'
13
+ require_relative 'municipitaly2/province'
14
+ require_relative 'municipitaly2/municipality'
15
+ require_relative 'municipitaly2/search'
16
+
17
+ # top level namespace
18
+ module Municipitaly2
19
+ # :nodoc:
20
+
21
+ # returns a sanitized term removing everything except letters to make
22
+ # matches less prone to errors (case insensitive and accent insensitive)
23
+ #
24
+ # example usage:
25
+ # sanitized_term = Search.sanitize_term('Forlì Cesena')
26
+ def self.sanitize_term(term) # :doc:
27
+ term.strip.downcase.tr('àâçèéêìòôù', 'aaceeeioou').gsub(/[^a-z]/, '')
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'municipitaly2/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'municipitaly2'
9
+ spec.version = Municipitaly2::VERSION
10
+ spec.authors = %w[yupswing NatyDev]
11
+ spec.email = ['me@simonecingano.it', 'natydev@aol.com']
12
+
13
+ spec.summary = 'Municipitaly2'
14
+ spec.description = 'Codes (postal, istat, cadastrian, ...) about Italian ' \
15
+ 'subdivisions and municipalities in Italy [city, cities]'
16
+ spec.homepage = 'https://github.com/yupswing/municipitaly2'
17
+ spec.license = 'MIT'
18
+ spec.metadata = {
19
+ # 'documentation_uri' => 'https://www.rubydoc.info/github/natydev/municipitaly/master',
20
+ 'rubygems_mfa_required' => 'true'
21
+ }
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0")
27
+ .reject { |f| f.match(%r{^(test|spec|features|tools)/}) }
28
+ end
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.required_ruby_version = '>= 3.0.0'
34
+
35
+ spec.add_development_dependency 'bundler', '~> 2.5.11'
36
+ spec.add_development_dependency 'rake', '~> 13.2.1'
37
+ spec.add_development_dependency 'rspec', '~> 3.13'
38
+ spec.add_development_dependency 'rubocop', '~> 1.64.1'
39
+ spec.add_development_dependency 'simplecov', '~> 0.22.0'
40
+ end