locode 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +4 -0
- data/CONTRIBUTERS +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +66 -0
- data/Rakefile +18 -0
- data/data/README.md +29 -0
- data/data/locode_data_update.rb +86 -0
- data/data/yaml/dump.yml +984613 -0
- data/lib/locode.rb +119 -0
- data/lib/locode/location.rb +507 -0
- data/lib/locode/version.rb +6 -0
- data/locode.gemspec +26 -0
- data/test/lib/location_test.rb +84 -0
- data/test/lib/version_test.rb +7 -0
- data/test/locode_test.rb +102 -0
- data/test/test_helper.rb +4 -0
- metadata +122 -0
data/lib/locode.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'yaml'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
require_relative 'locode/version'
|
6
|
+
require_relative 'locode/location'
|
7
|
+
|
8
|
+
module Locode
|
9
|
+
|
10
|
+
def self.load_data
|
11
|
+
YAML.load(File.read(File.expand_path('../../data/yaml/dump.yml', __FILE__)))
|
12
|
+
end
|
13
|
+
private_class_method :load_data
|
14
|
+
|
15
|
+
ALL_LOCATIONS = load_data
|
16
|
+
private_constant :ALL_LOCATIONS
|
17
|
+
|
18
|
+
def self.seaports(limit = ALL_LOCATIONS.size)
|
19
|
+
ALL_LOCATIONS.select { |location| location.seaport? }.take(limit)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.rail_terminals(limit = ALL_LOCATIONS.size)
|
23
|
+
ALL_LOCATIONS.select { |location| location.rail_terminal? }.take(limit)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.road_terminals(limit = ALL_LOCATIONS.size)
|
27
|
+
ALL_LOCATIONS.select { |location| location.road_terminal? }.take(limit)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.airport(limit = ALL_LOCATIONS.size)
|
31
|
+
ALL_LOCATIONS.select { |location| location.airport? }.take(limit)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.postal_exchange_offices(limit = ALL_LOCATIONS.size)
|
35
|
+
ALL_LOCATIONS.select { |location| location.postal_exchange_office? }.take(limit)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.inland_clearance_depots(limit = ALL_LOCATIONS.size)
|
39
|
+
ALL_LOCATIONS.select { |location| location.inland_clearance_depot? }.take(limit)
|
40
|
+
end
|
41
|
+
|
42
|
+
# the spec says these are currently just oil platforms
|
43
|
+
def self.fixed_transport_functions(limit = ALL_LOCATIONS.size)
|
44
|
+
ALL_LOCATIONS.select { |location| location.fixed_transport_functions? }.take(limit)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.border_crossing_functions(limit = ALL_LOCATIONS.size)
|
48
|
+
ALL_LOCATIONS.select { |location| location.border_crossing? }.take(limit)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Find Locations that partially match the Search String.
|
52
|
+
# This means you can search by just the country code or a
|
53
|
+
# whole LOCODE.
|
54
|
+
#
|
55
|
+
# search_string - The string that will be used in the LOCODE search.
|
56
|
+
#
|
57
|
+
# Examples
|
58
|
+
#
|
59
|
+
# Locode.find_by_locode('US')
|
60
|
+
# #=> [<Locode::Location: 'US NYC'>,
|
61
|
+
# <Locode::Location: 'US LAX'>, ... ]
|
62
|
+
#
|
63
|
+
# Locode.find_by_locode('DE HAM')
|
64
|
+
# #=> [<Locode::Location: 'DE HAM'>]
|
65
|
+
#
|
66
|
+
# Locode.find_by_locode('foobar')
|
67
|
+
# #=> []
|
68
|
+
#
|
69
|
+
# Returns an Array of Location
|
70
|
+
def self.find_by_locode(search_string)
|
71
|
+
return [] unless search_string && search_string.is_a?(String)
|
72
|
+
ALL_LOCATIONS.select { |location| location.locode.start_with?(search_string.strip.upcase) }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Public: Find Locations whose full name or full name without diacritics
|
76
|
+
# matches the search string
|
77
|
+
#
|
78
|
+
# search_string - The string that will be used in the LOCODE search.
|
79
|
+
#
|
80
|
+
# Examples
|
81
|
+
#
|
82
|
+
# Locode.find_by_name('Göteborg')
|
83
|
+
# #=> [<Locode::Location: 'SE GOT'>]
|
84
|
+
#
|
85
|
+
# Locode.find_by_name('Gothenburg')
|
86
|
+
# #=> [<Locode::Location: 'SE GOT'>]
|
87
|
+
#
|
88
|
+
# Returns an Array of Location because the name might not be unique
|
89
|
+
def self.find_by_name(search_string)
|
90
|
+
return [] unless search_string && search_string.is_a?(String)
|
91
|
+
ALL_LOCATIONS.select do |location|
|
92
|
+
names = []
|
93
|
+
names << location.full_name if location.full_name
|
94
|
+
names << location.full_name_without_diacritics if location.full_name_without_diacritics
|
95
|
+
names += location.alternative_full_names
|
96
|
+
names += location.alternative_full_names_without_diacritics
|
97
|
+
names.map { |name| name.downcase }.any? { |name| name.start_with?(search_string.strip.downcase) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: Find locations for a specific country with a specific function
|
102
|
+
#
|
103
|
+
# country_code - ISO 3166 alpha-2 Country Code String to filter locations by country
|
104
|
+
# function - Integer or :B that specifies the function of the location
|
105
|
+
# limit - Integer to specify how many locations you want
|
106
|
+
#
|
107
|
+
# Examples
|
108
|
+
#
|
109
|
+
# Locode.find_by_country_and_function('BE', 1)
|
110
|
+
# #=> [<Locode::Location: 'BE ANR'>, ..]
|
111
|
+
#
|
112
|
+
# Returns an Array of Locations that satisfy the above conditions
|
113
|
+
def self.find_by_country_and_function(country_code, function, limit = ALL_LOCATIONS.size)
|
114
|
+
return [] unless country_code.to_s =~ /^[A-Z]{2}$/
|
115
|
+
return [] unless function.to_s =~ /^[1-7]{1}|:B{1}$/
|
116
|
+
|
117
|
+
ALL_LOCATIONS.select { |location| location.country_code == country_code && location.function_classifier.include?(function) }.take(limit)
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,507 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Locode
|
4
|
+
class Location
|
5
|
+
# Public: Initializes a new Location
|
6
|
+
#
|
7
|
+
# location_attributes - A Hash of the following structure
|
8
|
+
# {
|
9
|
+
# country_code: String | Symbol
|
10
|
+
# city_code: String | Symbol
|
11
|
+
# full_name: String
|
12
|
+
# full_name_without_diacritics: String
|
13
|
+
# subdivision: String | Symbol
|
14
|
+
# function_classifier: String | Array
|
15
|
+
# status: String | Symbol
|
16
|
+
# date: String
|
17
|
+
# iata_code: String | nil
|
18
|
+
# coordinates: String | nil
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# Examples
|
22
|
+
#
|
23
|
+
# Locode::Location.new
|
24
|
+
# #=> <Locode::Location: invalid location>
|
25
|
+
#
|
26
|
+
# location_attributes = {
|
27
|
+
# country_code: 'US',
|
28
|
+
# city_code: 'NYC',
|
29
|
+
# full_name: 'New York',
|
30
|
+
# full_name_without_diacritics: 'New York',
|
31
|
+
# subdivision: 'NY',
|
32
|
+
# function_classifier: '12345---',
|
33
|
+
# status: 'AI',
|
34
|
+
# date: '0401',
|
35
|
+
# iata_code: '',
|
36
|
+
# coordinates: '4042N 07400W'
|
37
|
+
# }
|
38
|
+
#
|
39
|
+
# Locode::Location.new(location_attributes)
|
40
|
+
# #=> <Locode::Location: 'US NYC'>
|
41
|
+
#
|
42
|
+
#
|
43
|
+
def initialize(location_attributes)
|
44
|
+
location_attributes.each do |k,v|
|
45
|
+
begin
|
46
|
+
send("#{k}=", v) if !v.nil?
|
47
|
+
rescue NoMethodError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Internal: Once we are done parsing the csv files we no longer want to allow
|
53
|
+
# changes to the alternative_full_names or
|
54
|
+
# alternative_full_names_without_diacritics.
|
55
|
+
#
|
56
|
+
# Returns nothing
|
57
|
+
def parsing_completed
|
58
|
+
private :alternative_full_names=,
|
59
|
+
:alternative_full_names_without_diacritics=,
|
60
|
+
:parsing_completed
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public: UN/LOCODE
|
64
|
+
#
|
65
|
+
# Examples
|
66
|
+
#
|
67
|
+
# Locode.find_by_locode('US NYC').first.locode
|
68
|
+
# #=> 'US NYC'
|
69
|
+
#
|
70
|
+
# Returns a String that represents the UN/LOCODE
|
71
|
+
def locode
|
72
|
+
"#{country_code.to_s} #{city_code.to_s}".strip
|
73
|
+
end
|
74
|
+
|
75
|
+
# Public: ISO 3166 alpha-2 Country Code
|
76
|
+
#
|
77
|
+
# Examples
|
78
|
+
#
|
79
|
+
# Locode.find_by_locode('US NYC').first.country_code
|
80
|
+
# #=> 'US'
|
81
|
+
#
|
82
|
+
# Returns a String containing the country code or an empty string.
|
83
|
+
def country_code
|
84
|
+
@country_code.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
# Public: Three letter code for a place
|
88
|
+
#
|
89
|
+
# Examples
|
90
|
+
#
|
91
|
+
# Locode.find_by_locode('US NYC').first.city_code
|
92
|
+
# #=> 'NYC'
|
93
|
+
#
|
94
|
+
# Returns a String containing the city code or an empty string.
|
95
|
+
def city_code
|
96
|
+
@city_code.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
# Public: The name of a location
|
100
|
+
#
|
101
|
+
# Examples
|
102
|
+
#
|
103
|
+
# Locode.find_by_locode('SE GOT').first.full_name
|
104
|
+
# #=> 'Göteborg'
|
105
|
+
#
|
106
|
+
# Returns a String containing the full name of the location or an
|
107
|
+
# empty string.
|
108
|
+
def full_name
|
109
|
+
@full_name
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: The alternative names of a location
|
113
|
+
#
|
114
|
+
# Examples
|
115
|
+
#
|
116
|
+
# Locode.find_by_locode('SE GOT').first.alternative_full_names
|
117
|
+
# #=> ['Gothenburg']
|
118
|
+
#
|
119
|
+
# Returns an Array of Strings containing the alternative full names of the
|
120
|
+
# location or an empty array.
|
121
|
+
def alternative_full_names
|
122
|
+
@alternative_full_names ||= []
|
123
|
+
end
|
124
|
+
|
125
|
+
# Internal: adds the alternative full name of a location to the list of alternatives
|
126
|
+
# This might not be coherent with the normal semantics of a setter
|
127
|
+
# but I think it is ok since it is just a private method.
|
128
|
+
#
|
129
|
+
# Returns nothing
|
130
|
+
def alternative_full_names=(alternative_full_name)
|
131
|
+
if alternative_full_name && alternative_full_name.is_a?(String)
|
132
|
+
@alternative_full_names ||= []
|
133
|
+
@alternative_full_names << alternative_full_name.strip
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Public: The name of the location, but all non-latin-base characters
|
138
|
+
# are converted.
|
139
|
+
#
|
140
|
+
# Examples
|
141
|
+
#
|
142
|
+
# Locode.find_by_locode('SE GOT').first.full_name_without_diacritics
|
143
|
+
# #=> 'Goteborg'
|
144
|
+
#
|
145
|
+
# Returns a String which contains the the full name without
|
146
|
+
# diacritics or an empty string
|
147
|
+
def full_name_without_diacritics
|
148
|
+
@full_name_without_diacritics
|
149
|
+
end
|
150
|
+
|
151
|
+
# Public: The alternative names of the location, but all non-latin-base
|
152
|
+
# characters are converted.
|
153
|
+
#
|
154
|
+
# Examples
|
155
|
+
#
|
156
|
+
# Locode.find_by_locode('SE GOT').first.alternative_full_names_without_diacritics
|
157
|
+
# #=> ['Gothenburg']
|
158
|
+
#
|
159
|
+
# Returns an Array of Strings containing the alternative full names without
|
160
|
+
# diacritics of the location or an empty array.
|
161
|
+
def alternative_full_names_without_diacritics
|
162
|
+
@alternative_full_names_without_diacritics ||= []
|
163
|
+
end
|
164
|
+
|
165
|
+
# Internal: adds the alternative full name without diacritics of the location
|
166
|
+
# to the list of alternatives.
|
167
|
+
# This might not be coherent with the normal semantics of a setter
|
168
|
+
# but I think it is ok since it is just a private method.
|
169
|
+
#
|
170
|
+
# Returns nothing
|
171
|
+
def alternative_full_names_without_diacritics=(alternative_full_name_without_diacritics)
|
172
|
+
if alternative_full_name_without_diacritics && alternative_full_name_without_diacritics.is_a?(String)
|
173
|
+
@alternative_full_names_without_diacritics ||= []
|
174
|
+
@alternative_full_names_without_diacritics << alternative_full_name_without_diacritics.strip
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Public: The ISO 1 to 3 character alphabetic and/or numeric code for the
|
179
|
+
# administrative division (state, province, department, etc.)
|
180
|
+
# of the country, as included in ISO 3166-2/1998. Only the
|
181
|
+
# latter part of the complete ISO 3166-2 code element (after
|
182
|
+
# the hyphen) is shown.
|
183
|
+
#
|
184
|
+
# Examples
|
185
|
+
#
|
186
|
+
# Locode.find_by_locode('US NYC').first.subdivision
|
187
|
+
# #=> 'NY'
|
188
|
+
#
|
189
|
+
# Locode.find_by_locode('SE GOT').first.subdivision
|
190
|
+
# #=> 'O'
|
191
|
+
#
|
192
|
+
# Returns a String representing the subdivision or an empty string
|
193
|
+
def subdivision
|
194
|
+
@subdivision
|
195
|
+
end
|
196
|
+
|
197
|
+
# Public: contains a 1-digit function classifier code for the location
|
198
|
+
#
|
199
|
+
# Examples
|
200
|
+
#
|
201
|
+
# Locode.find_by_locode('US NYC').first.function_classifier
|
202
|
+
# #=> [1, 2, 3, 4, 5]
|
203
|
+
#
|
204
|
+
# Returns an Array containing Integer or :B with the following
|
205
|
+
# meanings:
|
206
|
+
# 1 = seaport, any port with the possibility of transport via water
|
207
|
+
# 2 = rail terminal
|
208
|
+
# 3 = road terminal
|
209
|
+
# 4 = airport
|
210
|
+
# 5 = postal exchange office
|
211
|
+
# 6 = Inland Clearance Depot – ICD or "Dry Port"
|
212
|
+
# 7 = reserved for fixed transport functions (e.g. oil platform)
|
213
|
+
# :B = border crossing
|
214
|
+
def function_classifier
|
215
|
+
@function_classifier
|
216
|
+
end
|
217
|
+
|
218
|
+
# Public: Indicates the status of the entry by a 2-character code
|
219
|
+
#
|
220
|
+
# Examples
|
221
|
+
#
|
222
|
+
# Locode.find_by_locode('US NYC').first.status
|
223
|
+
# #=> :AI
|
224
|
+
#
|
225
|
+
# Returns a Symbol with the following meaning or nil
|
226
|
+
# :AA = Approved by competent national government agency
|
227
|
+
# :AC = Approved by Customs Authority
|
228
|
+
# :AF = Approved by national facilitation body
|
229
|
+
# :AI = Code adopted by international organisation (IATA or ECLAC)
|
230
|
+
# :AM = Approved by the UN/LOCODE Maintenance Agency
|
231
|
+
# :AS = Approved by national standardisation body
|
232
|
+
# :AQ = Entry approved, functions not verified
|
233
|
+
# :RL = Recognised location - Existence and representation of location name
|
234
|
+
# confirmed by check against nominated gazetteer or other
|
235
|
+
# reference work
|
236
|
+
# :RN = Request from credible national sources for locations in their own country
|
237
|
+
# :RQ = Request under consideration
|
238
|
+
# :RR = Request rejected
|
239
|
+
# :QQ = Original entry not verified since date indicated
|
240
|
+
# :UR = Entry included on user's request; not officially approved
|
241
|
+
# :XX = Entry that will be removed from the next issue of UN/LOCODE
|
242
|
+
#
|
243
|
+
def status
|
244
|
+
@status
|
245
|
+
end
|
246
|
+
|
247
|
+
# Public: The date the location was added or updated
|
248
|
+
#
|
249
|
+
# Examples
|
250
|
+
#
|
251
|
+
# Locode.find_by_locode('US NYC').first.date
|
252
|
+
# #=> '0401'
|
253
|
+
#
|
254
|
+
# Returns a String containing the date the location was added to the
|
255
|
+
# list of LOCODEs. The meaning of the date values is the following:
|
256
|
+
# '0207' equals July 2002, '9501' equals January 1995
|
257
|
+
def date
|
258
|
+
@date
|
259
|
+
end
|
260
|
+
|
261
|
+
# Public: The IATA code for the location if different from the second
|
262
|
+
# part of the UN/LOCODE. Else the second part of the UN/LOCODE.
|
263
|
+
#
|
264
|
+
# Examples
|
265
|
+
#
|
266
|
+
# Locode.find_by_locode('SE GOT').first.iata_code
|
267
|
+
# #=> 'XWL'
|
268
|
+
#
|
269
|
+
# Locode.find_by_locode('US NYC').first.iata_code
|
270
|
+
# #=> 'NYC'
|
271
|
+
#
|
272
|
+
# Returns a String which is the IATA code if it is different from
|
273
|
+
# the city code of the LOCODE. Else it returns the city
|
274
|
+
# code.
|
275
|
+
#
|
276
|
+
def iata_code
|
277
|
+
@iata_code
|
278
|
+
end
|
279
|
+
|
280
|
+
# Public: The coordinates of a location.
|
281
|
+
#
|
282
|
+
# Examples
|
283
|
+
#
|
284
|
+
# Locode.find_by_locode('SE GOT').first.coordinates
|
285
|
+
# #=> nil
|
286
|
+
#
|
287
|
+
# Locode.find_by_locode('SE GO2').first.coordinates
|
288
|
+
# #=> '5742N 01156E'
|
289
|
+
#
|
290
|
+
# Returns nil if no coordinates are associated with the Location
|
291
|
+
# otherwise it returns a String with the coordinates which
|
292
|
+
# represents these with two numbers and letters for the cardinal
|
293
|
+
# directions. The first followed by either N or S, the second by
|
294
|
+
# either E or W.
|
295
|
+
def coordinates
|
296
|
+
@coordinates
|
297
|
+
end
|
298
|
+
|
299
|
+
# Public: The String representation of the Location
|
300
|
+
#
|
301
|
+
# Examples
|
302
|
+
#
|
303
|
+
# Locode.find_by_locode('US NYC').first.to_s
|
304
|
+
# #=> <Locode::Location: 'US NYC'>
|
305
|
+
#
|
306
|
+
# Returns a String that represents the Location
|
307
|
+
def to_s
|
308
|
+
"<Locode::Location: '#{locode}'>"
|
309
|
+
end
|
310
|
+
|
311
|
+
# Public: The Hash representation of the Location
|
312
|
+
#
|
313
|
+
# Examples
|
314
|
+
#
|
315
|
+
# Locode.find_by_locode('BE ANR').first.to_h
|
316
|
+
# #=> {:country_code=>"BE", ... }
|
317
|
+
#
|
318
|
+
# Returns a Hash that represents the Location
|
319
|
+
def to_h
|
320
|
+
{
|
321
|
+
country_code: country_code,
|
322
|
+
city_code: city_code,
|
323
|
+
full_name: full_name,
|
324
|
+
full_name_without_diacritics: full_name_without_diacritics,
|
325
|
+
subdivision: subdivision,
|
326
|
+
function_classifier: function_classifier,
|
327
|
+
status: status,
|
328
|
+
date: date,
|
329
|
+
iata_code: iata_code,
|
330
|
+
coordinates: coordinates
|
331
|
+
}
|
332
|
+
end
|
333
|
+
|
334
|
+
# Public: The JSON representation of the Location
|
335
|
+
#
|
336
|
+
# Examples
|
337
|
+
#
|
338
|
+
# Locode.find_by_locode('US NYC').first.to_json
|
339
|
+
# #=> {"country_code":"US","city_code":"NYC", ...}
|
340
|
+
#
|
341
|
+
# Returns a JSON that represents the Location
|
342
|
+
def to_json
|
343
|
+
MultiJson.dump(self.to_h)
|
344
|
+
end
|
345
|
+
|
346
|
+
# Public: To check whether the Locations attributes are all
|
347
|
+
# initialized correctly.
|
348
|
+
#
|
349
|
+
# Examples
|
350
|
+
#
|
351
|
+
# Locode.find_by_locode('US NYC').first.valid?
|
352
|
+
# #=> true
|
353
|
+
#
|
354
|
+
# Locode::Location.new.valid?
|
355
|
+
# #=> false
|
356
|
+
#
|
357
|
+
# Returns true or false
|
358
|
+
def valid?
|
359
|
+
country_code && country_code.size == 2 && city_code && city_code.size == 3
|
360
|
+
end
|
361
|
+
|
362
|
+
private
|
363
|
+
|
364
|
+
# Internal: sets the ISO 3166 alpha-2 Country Code
|
365
|
+
#
|
366
|
+
# Returns nothing
|
367
|
+
def country_code=(country_code)
|
368
|
+
if country_code
|
369
|
+
if country_code.is_a?(String)
|
370
|
+
@country_code = country_code.strip.upcase.to_sym
|
371
|
+
elsif country_code.is_a?(Symbol)
|
372
|
+
@country_code = country_code.upcase
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Internal: sets the three letter code for a place
|
378
|
+
#
|
379
|
+
# Returns nothing
|
380
|
+
def city_code=(city_code)
|
381
|
+
if city_code
|
382
|
+
if city_code.is_a?(String)
|
383
|
+
@city_code = city_code.strip.upcase.to_sym
|
384
|
+
elsif city_code.is_a?(Symbol)
|
385
|
+
@city_code = city_code.upcase
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# Internal: sets the name of a location
|
391
|
+
#
|
392
|
+
# Returns nothing
|
393
|
+
def full_name=(full_name)
|
394
|
+
if full_name && full_name.is_a?(String)
|
395
|
+
@full_name = full_name.strip
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Internal: sets the full name without diacritics of the location
|
400
|
+
#
|
401
|
+
# Returns nothing
|
402
|
+
def full_name_without_diacritics=(full_name_without_diacritics)
|
403
|
+
if full_name_without_diacritics && full_name_without_diacritics.is_a?(String)
|
404
|
+
@full_name_without_diacritics = full_name_without_diacritics.strip
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# Internal: sets the ISO 1 to 3 character alphabetic and/or numeric code
|
409
|
+
#
|
410
|
+
# Returns nothing
|
411
|
+
def subdivision=(subdivision)
|
412
|
+
if subdivision && subdivision.is_a?(String)
|
413
|
+
@subdivision = subdivision.strip
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Internal: sets the 1-digit function classifier code for the location
|
418
|
+
#
|
419
|
+
# Returns nothing
|
420
|
+
def function_classifier=(function_classifier)
|
421
|
+
if function_classifier
|
422
|
+
if function_classifier.is_a?(String)
|
423
|
+
@function_classifier = function_classifier.strip.chars.select do |char|
|
424
|
+
char.to_i.between?(1, 7) || char.upcase.to_s == "B"
|
425
|
+
end.map do |char|
|
426
|
+
if char.to_i.between?(1, 7)
|
427
|
+
char.to_i
|
428
|
+
else
|
429
|
+
char.upcase.to_sym
|
430
|
+
end
|
431
|
+
end
|
432
|
+
elsif function_classifier.is_a?(Array)
|
433
|
+
@function_classifier = function_classifier.flatten
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
# Internal: sets the status indicator of the entry
|
439
|
+
#
|
440
|
+
# Returns nothing
|
441
|
+
def status=(status)
|
442
|
+
if status && (status.is_a?(String) || status.is_a?(Symbol))
|
443
|
+
@status = status.upcase.to_sym
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
# Internal: sets the date the location was added or updated
|
448
|
+
#
|
449
|
+
# Returns nothing
|
450
|
+
def date=(date)
|
451
|
+
if date && date.is_a?(String)
|
452
|
+
@date = date.strip
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
# Internal: sets the IATA code for the location
|
457
|
+
#
|
458
|
+
# Returns nothing
|
459
|
+
def iata_code=(iata_code)
|
460
|
+
if iata_code && iata_code.is_a?(String)
|
461
|
+
@iata_code = iata_code.strip
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# Internal: sets the coordinates of a location.
|
466
|
+
#
|
467
|
+
# Returns nothing
|
468
|
+
def coordinates=(coordinates)
|
469
|
+
if coordinates && coordinates.is_a?(String)
|
470
|
+
@coordinates = coordinates.strip
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
# Internal: Used to link name of a status and the status number
|
475
|
+
def self.functions_name_identifier
|
476
|
+
{
|
477
|
+
seaport: 1,
|
478
|
+
rail_terminal: 2,
|
479
|
+
road_terminal: 3,
|
480
|
+
airport: 4,
|
481
|
+
postal_exchange_office: 5,
|
482
|
+
inland_clearance_depot: 6,
|
483
|
+
fixed_transport_functions: 7,
|
484
|
+
border_crossing: :B
|
485
|
+
}
|
486
|
+
end
|
487
|
+
|
488
|
+
# Dynamically defines the following predicates:
|
489
|
+
#
|
490
|
+
# seaport?
|
491
|
+
# rail_terminal?
|
492
|
+
# road_terminal?
|
493
|
+
# airport?
|
494
|
+
# postal_exchange_office?
|
495
|
+
# inland_clearance_depot?
|
496
|
+
# fixed_transport_functions?
|
497
|
+
# border_crossing?
|
498
|
+
#
|
499
|
+
# Each returns: true | false
|
500
|
+
#
|
501
|
+
functions_name_identifier.each do |key, value|
|
502
|
+
define_method "#{key}?" do
|
503
|
+
function_classifier.include?(value)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|