worlddb-models 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +31 -13
- data/README.md +7 -7
- data/Rakefile +1 -1
- data/lib/worlddb/deleter.rb +6 -1
- data/lib/worlddb/helpers/value_helper.rb +117 -0
- data/lib/worlddb/matcher.rb +99 -135
- data/lib/worlddb/matcher_adm.rb +82 -0
- data/lib/worlddb/models/city.rb +30 -208
- data/lib/worlddb/models/city_base.rb +220 -0
- data/lib/worlddb/models/continent.rb +9 -0
- data/lib/worlddb/models/country.rb +21 -4
- data/lib/worlddb/models/forward.rb +25 -9
- data/lib/worlddb/models/lang.rb +6 -0
- data/lib/worlddb/models/place.rb +1 -1
- data/lib/worlddb/models/state.rb +83 -0
- data/lib/worlddb/models/{region.rb → state_base.rb} +52 -36
- data/lib/worlddb/models/tagdb/tag.rb +1 -1
- data/lib/worlddb/models.rb +11 -8
- data/lib/worlddb/patterns.rb +4 -4
- data/lib/worlddb/reader.rb +68 -39
- data/lib/worlddb/reader_file.rb +36 -3
- data/lib/worlddb/reader_zip.rb +33 -3
- data/lib/worlddb/readers/base.rb +149 -0
- data/lib/worlddb/readers/city.rb +2 -65
- data/lib/worlddb/readers/country.rb +2 -63
- data/lib/worlddb/readers/lang.rb +3 -68
- data/lib/worlddb/readers/state.rb +61 -0
- data/lib/worlddb/readers/state_tree.rb +118 -0
- data/lib/worlddb/readers/usage.rb +2 -65
- data/lib/worlddb/schema.rb +142 -43
- data/lib/worlddb/stats.rb +7 -4
- data/lib/worlddb/tree_reader.rb +97 -0
- data/lib/worlddb/version.rb +2 -2
- data/test/adm/test_fixture_matcher_adm2.rb +73 -0
- data/test/{test_fixture_matcher_adm3.rb → adm/test_fixture_matcher_adm3.rb} +6 -6
- data/test/adm/test_fixture_matcher_tree.rb +52 -0
- data/test/{test_read_adm.rb → adm/test_read_adm.rb} +13 -20
- data/test/adm/test_read_tree.rb +63 -0
- data/test/data/at-austria/2--n-niederoesterreich/counties.txt +6 -4
- data/test/data/at-austria/orte.txt +23 -0
- data/test/data/at-austria/setups/tree.txt +9 -0
- data/test/data/de-deutschland/3--by-bayern/4--oberfranken/counties.txt +14 -13
- data/test/data/de-deutschland/3--by-bayern/4--oberfranken/orte.txt +104 -0
- data/test/data/de-deutschland/3--by-bayern/4--oberfranken/orte_ii.txt +17 -0
- data/test/data/de-deutschland/3--by-bayern/{districts.txt → parts.txt} +1 -1
- data/test/data/de-deutschland/orte.txt +12 -0
- data/test/data/de-deutschland/setups/adm.txt +1 -1
- data/test/data/de-deutschland/setups/tree.txt +9 -0
- data/test/helper.rb +8 -1
- data/test/test_fixture_matchers.rb +9 -10
- data/test/test_fixture_matchers_ii.rb +20 -19
- data/test/test_model_city.rb +26 -9
- data/test/{test_model_comp.rb → test_model_compat.rb} +15 -13
- data/test/test_model_country.rb +1 -1
- data/test/test_model_state.rb +54 -0
- data/test/test_model_states_at.rb +111 -0
- data/test/test_model_states_de.rb +147 -0
- data/test/test_models.rb +10 -3
- data/test/test_parse_city.rb +70 -0
- data/test/test_parse_country.rb +56 -0
- data/test/test_parse_state.rb +46 -0
- data/test/test_state_tree_reader_at.rb +54 -0
- data/test/test_state_tree_reader_de.rb +71 -0
- data/test/test_tree_reader.rb +39 -0
- metadata +50 -22
- data/lib/worlddb/models/city_compat.rb +0 -27
- data/lib/worlddb/models/continent_compat.rb +0 -24
- data/lib/worlddb/models/country_compat.rb +0 -35
- data/lib/worlddb/models/lang_compat.rb +0 -23
- data/lib/worlddb/models/region_compat.rb +0 -26
- data/lib/worlddb/readers/region.rb +0 -79
- data/test/test_fixture_matcher_adm2.rb +0 -62
- data/test/test_model_region.rb +0 -50
data/lib/worlddb/models/city.rb
CHANGED
@@ -3,238 +3,60 @@
|
|
3
3
|
module WorldDb
|
4
4
|
module Model
|
5
5
|
|
6
|
-
###
|
7
|
-
## Todo:
|
8
|
-
## use four classes instead of one ?
|
9
|
-
# e.g. Use class class Metro n class City n class District n class CityBase ?? - why? why not?
|
10
|
-
#
|
11
|
-
# find a better name for CityBase ??
|
12
|
-
# Locality ??
|
13
|
-
# or CityCore or CityStd or CityAll or CityGeneric
|
14
|
-
# or CityLike or CityTable or CityTbl or ???
|
15
|
-
|
16
|
-
class City < ActiveRecord::Base
|
17
|
-
|
18
|
-
extend TextUtils::TagHelper # will add self.find_tags, self.find_tags_in_attribs!, etc.
|
19
|
-
|
20
|
-
# NB: use extend - is_<type>? become class methods e.g. self.is_<type>? for use in
|
21
|
-
# self.create_or_update_from_values
|
22
|
-
extend TextUtils::ValueHelper # e.g. self.is_year?, self.is_region?, self.is_address?, self.is_taglist? etc.
|
23
6
|
|
7
|
+
class City < CityBase
|
24
8
|
|
25
9
|
self.table_name = 'cities'
|
26
10
|
|
27
|
-
belongs_to :
|
28
|
-
belongs_to :
|
29
|
-
belongs_to :
|
30
|
-
|
31
|
-
## self referencing hierachy within cities e.g. m|metro > c|city > d|district
|
32
|
-
|
33
|
-
## fix: use condition check for m|d|c flag?? why? why not? (NB: flags are NOT exclusive e.g. possible metro|city)
|
34
|
-
|
35
|
-
## (1) metro - level up
|
36
|
-
has_many :cities, class_name: 'City', foreign_key: 'city_id'
|
37
|
-
|
38
|
-
## (2) city
|
39
|
-
belongs_to :metro, class_name: 'City', foreign_key: 'city_id' ## for now alias for parent - use parent?
|
40
|
-
has_many :districts, class_name: 'City', foreign_key: 'city_id' ## for now alias for cities - use cities?
|
41
|
-
|
42
|
-
## (3) district - level down
|
43
|
-
belongs_to :city, class_name: 'City', foreign_key: 'city_id' ## for now alias for parent - use parent?
|
44
|
-
|
45
|
-
has_many_tags
|
46
|
-
|
47
|
-
###
|
48
|
-
# NB: use is_ for flags to avoid conflict w/ assocs (e.g. metro?, city? etc.)
|
49
|
-
|
50
|
-
def is_metro?() m? == true; end
|
51
|
-
def is_city?() c? == true; end
|
52
|
-
def is_district?() d? == true; end
|
11
|
+
belongs_to :country, class_name: 'Country', foreign_key: 'country_id'
|
12
|
+
belongs_to :state, class_name: 'State', foreign_key: 'state_id'
|
13
|
+
belongs_to :muni, class_name: 'Muni', foreign_key: 'muni_id'
|
53
14
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def on_create
|
58
|
-
place_rec = Place.create!( name: name, kind: place_kind )
|
59
|
-
self.place_id = place_rec.id
|
60
|
-
end
|
61
|
-
|
62
|
-
def on_update
|
63
|
-
## fix/todo: check - if name or kind changed - only update if changed ?? why? why not??
|
64
|
-
place.update_attributes!( name: name, kind: place_kind )
|
65
|
-
end
|
15
|
+
belongs_to :metro, class_name: 'Metro', foreign_key: 'metro_id'
|
16
|
+
has_many :districts, class_name: 'District', foreign_key: 'city_id'
|
66
17
|
|
67
18
|
def place_kind # use place_kind_of_code ??
|
68
|
-
|
69
|
-
#//////////////////////////////////
|
70
|
-
#// fix: add nested record syntax e.g. city w/ metro population
|
71
|
-
#// use (metro: 4444) e.g. must start with (<nested_type>: props) !!! or similar
|
72
|
-
#//
|
73
|
-
if is_metro?
|
74
|
-
'MTRO'
|
75
|
-
elsif is_district?
|
76
|
-
'DIST'
|
77
|
-
else
|
78
|
-
'CITY'
|
79
|
-
end
|
19
|
+
'CITY'
|
80
20
|
end
|
81
21
|
|
22
|
+
def self.create_or_update_from_titles( titles, more_attribs = {} )
|
23
|
+
# ary of titles e.g. ['Wien', 'Graz'] etc.
|
82
24
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
scope :by_name, ->{ order( 'name asc' ) } # order by title (a-z)
|
89
|
-
scope :by_pop, ->{ order( 'pop desc' ) } # order by pop(ulation)
|
90
|
-
scope :by_popm, ->{ order( 'popm desc' ) } # order by pop(ulation) metropolitan area
|
91
|
-
scope :by_area, ->{ order( 'area desc' ) } # order by area (in square km)
|
25
|
+
titles.each do |title|
|
26
|
+
values = [title]
|
27
|
+
City.create_or_update_from_values( values, more_attribs )
|
28
|
+
end # each city
|
29
|
+
end # method create_or_update_from_titles
|
92
30
|
|
93
31
|
|
94
|
-
|
95
|
-
### fix:
|
96
|
-
## allow to passing in sep or separator e.g. | or other
|
32
|
+
end # class City
|
97
33
|
|
98
|
-
return name if alt_names.blank?
|
99
|
-
|
100
|
-
buf = ''
|
101
|
-
buf << name
|
102
|
-
buf << ' | '
|
103
|
-
buf << alt_names.split('|').join(' | ')
|
104
|
-
buf
|
105
|
-
end
|
106
34
|
|
35
|
+
class Metro < CityBase
|
107
36
|
|
108
|
-
|
109
|
-
|
37
|
+
belongs_to :country, class_name: 'Country', foreign_key: 'country_id'
|
38
|
+
## note: metro might be part of more than one (two,three) states (thus, cannot belong_to state)
|
39
|
+
## collect (all) states from cities??
|
110
40
|
|
111
|
-
|
112
|
-
attribs = attribs.merge( more_attribs )
|
41
|
+
has_many :cities, class_name: 'City', foreign_key: 'metro_id'
|
113
42
|
|
114
|
-
|
115
|
-
|
43
|
+
def place_kind # use place_kind_of_code ??
|
44
|
+
'MTRO'
|
116
45
|
end
|
117
46
|
|
47
|
+
end # class Metro
|
118
48
|
|
119
|
-
def self.create_or_update_from_titles( titles, more_attribs = {} )
|
120
|
-
# ary of titles e.g. ['Wien', 'Graz'] etc.
|
121
49
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end # each city
|
126
|
-
end # method create_or_update_from_titles
|
50
|
+
class District < CityBase
|
51
|
+
|
52
|
+
belongs_to :city, class_name: 'City', foreign_key: 'city_id'
|
127
53
|
|
54
|
+
def place_kind # use place_kind_of_code ??
|
55
|
+
'DIST'
|
56
|
+
end
|
128
57
|
|
58
|
+
end # class District
|
129
59
|
|
130
|
-
def self.create_or_update_from_attribs( new_attributes, values, opts={} )
|
131
|
-
# attribs -> key/value pairs e.g. hash
|
132
|
-
# values -> ary of string values/strings (key not yet known; might be starting of value e.g. city:wien)
|
133
|
-
|
134
|
-
## opts e.g. :skip_tags true|false
|
135
|
-
|
136
|
-
## fix: add/configure logger for ActiveRecord!!!
|
137
|
-
logger = LogKernel::Logger.root
|
138
|
-
|
139
|
-
value_numbers = []
|
140
|
-
value_tag_keys = []
|
141
|
-
|
142
|
-
### check for "default" tags - that is, if present new_attributes[:tags] remove from hash
|
143
|
-
value_tag_keys += find_tags_in_attribs!( new_attributes )
|
144
|
-
|
145
|
-
new_attributes[ :c ] = true # assume city type by default (use metro,district to change in fixture)
|
146
|
-
|
147
|
-
## check for optional values
|
148
|
-
|
149
|
-
values.each_with_index do |value,index|
|
150
|
-
if match_region_for_country( value, new_attributes[:country_id] ) do |region|
|
151
|
-
new_attributes[ :region_id ] = region.id
|
152
|
-
end
|
153
|
-
elsif match_country( value ) do |country|
|
154
|
-
new_attributes[ :country_id ] = country.id
|
155
|
-
end
|
156
|
-
elsif match_metro( value ) do |city|
|
157
|
-
new_attributes[ :city_id ] = city.id
|
158
|
-
end
|
159
|
-
elsif match_metro_pop( value ) do |num| # m:
|
160
|
-
new_attributes[ :popm ] = num
|
161
|
-
new_attributes[ :m ] = true # auto-mark city as m|metro too
|
162
|
-
end
|
163
|
-
elsif match_metro_flag( value ) do |_| # metro(politan area)
|
164
|
-
new_attributes[ :c ] = false # turn off default c|city flag; make it m|metro only
|
165
|
-
new_attributes[ :m ] = true
|
166
|
-
end
|
167
|
-
elsif match_city( value ) do |city| # parent city for district
|
168
|
-
new_attributes[ :city_id ] = city.id
|
169
|
-
new_attributes[ :c ] = false # turn off default c|city flag; make it d|district only
|
170
|
-
new_attributes[ :d ] = true
|
171
|
-
end
|
172
|
-
elsif match_km_squared( value ) do |num| # allow numbers like 453 km²
|
173
|
-
value_numbers << num
|
174
|
-
end
|
175
|
-
elsif match_number( value ) do |num| # numeric (nb: can use any _ or spaces inside digits e.g. 1_000_000 or 1 000 000)
|
176
|
-
value_numbers << num
|
177
|
-
end
|
178
|
-
elsif value =~ /#{CITY_CODE_PATTERN}/ ## assume three-letter code
|
179
|
-
new_attributes[ :code ] = value
|
180
|
-
elsif (values.size==(index+1)) && is_taglist?( value ) # tags must be last entry
|
181
|
-
logger.debug " found tags: >>#{value}<<"
|
182
|
-
value_tag_keys += find_tags( value )
|
183
|
-
else
|
184
|
-
# issue warning: unknown type for value
|
185
|
-
logger.warn "unknown type for value >#{value}<"
|
186
|
-
end
|
187
|
-
end # each value
|
188
|
-
|
189
|
-
if value_numbers.size > 0
|
190
|
-
new_attributes[ :pop ] = value_numbers[0] # assume first number is pop for cities
|
191
|
-
new_attributes[ :area ] = value_numbers[1]
|
192
|
-
end
|
193
|
-
|
194
|
-
rec = City.find_by_key( new_attributes[ :key ] )
|
195
|
-
|
196
|
-
if rec.present?
|
197
|
-
logger.debug "update City #{rec.id}-#{rec.key}:"
|
198
|
-
else
|
199
|
-
logger.debug "create City:"
|
200
|
-
rec = City.new
|
201
|
-
end
|
202
|
-
|
203
|
-
logger.debug new_attributes.to_json
|
204
|
-
|
205
|
-
rec.update_attributes!( new_attributes )
|
206
|
-
|
207
|
-
##################
|
208
|
-
## add taggings
|
209
|
-
|
210
|
-
## todo/fix: reuse - move add taggings into method etc.
|
211
|
-
|
212
|
-
if value_tag_keys.size > 0
|
213
|
-
|
214
|
-
if opts[:skip_tags].present?
|
215
|
-
logger.debug " skipping add taggings (flag skip_tag)"
|
216
|
-
else
|
217
|
-
value_tag_keys.uniq! # remove duplicates
|
218
|
-
logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."
|
219
|
-
|
220
|
-
### fix/todo: check tag_ids and only update diff (add/remove ids)
|
221
|
-
|
222
|
-
value_tag_keys.each do |key|
|
223
|
-
tag = Tag.find_by_key( key )
|
224
|
-
if tag.nil? # create tag if it doesn't exit
|
225
|
-
logger.debug " creating tag >#{key}<"
|
226
|
-
tag = Tag.create!( key: key )
|
227
|
-
end
|
228
|
-
rec.tags << tag
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
rec
|
234
|
-
end # method create_or_update_from_values
|
235
|
-
|
236
|
-
|
237
|
-
end # class Cities
|
238
60
|
|
239
61
|
end # module Model
|
240
62
|
end # module WorldDb
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WorldDb
|
4
|
+
module Model
|
5
|
+
|
6
|
+
|
7
|
+
class CityBase < ActiveRecord::Base
|
8
|
+
|
9
|
+
self.abstract_class = true
|
10
|
+
|
11
|
+
extend TextUtils::TagHelper # will add self.find_tags, self.find_tags_in_attribs!, etc.
|
12
|
+
|
13
|
+
# NB: use extend - is_<type>? become class methods e.g. self.is_<type>? for use in
|
14
|
+
# self.create_or_update_from_values
|
15
|
+
extend TextUtils::ValueHelper # e.g. self.is_year?, self.is_address?, self.is_taglist? etc.
|
16
|
+
|
17
|
+
belongs_to :place, class_name: 'Place', foreign_key: 'place_id'
|
18
|
+
|
19
|
+
has_many_tags
|
20
|
+
|
21
|
+
## begin compat
|
22
|
+
def title() name; end
|
23
|
+
def title=(value) self.name = value; end
|
24
|
+
|
25
|
+
def synonyms() alt_names; end
|
26
|
+
def synonyms=(value) self.alt_names = value; end
|
27
|
+
## end
|
28
|
+
|
29
|
+
before_create :on_create
|
30
|
+
before_update :on_update
|
31
|
+
|
32
|
+
def on_create
|
33
|
+
place_rec = Place.create!( name: name, kind: place_kind )
|
34
|
+
self.place_id = place_rec.id
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_update
|
38
|
+
## fix/todo: check - if name or kind changed - only update if changed ?? why? why not??
|
39
|
+
place.update_attributes!( name: name, kind: place_kind )
|
40
|
+
end
|
41
|
+
|
42
|
+
validates :key, format: { with: /#{CITY_KEY_PATTERN}/, message: CITY_KEY_PATTERN_MESSAGE }
|
43
|
+
validates :code, format: { with: /#{CITY_CODE_PATTERN}/, message: CITY_CODE_PATTERN_MESSAGE }, allow_nil: true
|
44
|
+
|
45
|
+
|
46
|
+
scope :by_key, ->{ order( 'key asc' ) } # order by key (a-z)
|
47
|
+
scope :by_name, ->{ order( 'name asc' ) } # order by title (a-z)
|
48
|
+
scope :by_pop, ->{ order( 'pop desc' ) } # order by pop(ulation)
|
49
|
+
scope :by_area, ->{ order( 'area desc' ) } # order by area (in square km)
|
50
|
+
|
51
|
+
|
52
|
+
def all_names( opts={} )
|
53
|
+
### fix:
|
54
|
+
## allow to passing in sep or separator e.g. | or other
|
55
|
+
|
56
|
+
return name if alt_names.blank?
|
57
|
+
|
58
|
+
buf = ''
|
59
|
+
buf << name
|
60
|
+
buf << ' | '
|
61
|
+
buf << alt_names.split('|').join(' | ')
|
62
|
+
buf
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
def self.parse( *args )
|
68
|
+
## remove (extract) attribs hash (if last arg is a hash n present)
|
69
|
+
more_attribs = args.last.is_a?(Hash) ? args.pop : {} ## extract_options!
|
70
|
+
values = args
|
71
|
+
|
72
|
+
self.create_or_update_from_values( values, more_attribs )
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def self.create_or_update_from_values( values, more_attribs={} )
|
77
|
+
## key & title & country required
|
78
|
+
|
79
|
+
attribs, more_values = find_key_n_title( values )
|
80
|
+
attribs = attribs.merge( more_attribs )
|
81
|
+
|
82
|
+
## check for optional values
|
83
|
+
self.create_or_update_from_attribs( attribs, more_values )
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.create_or_update_from_attribs( new_attributes, values, opts={} )
|
87
|
+
# attribs -> key/value pairs e.g. hash
|
88
|
+
# values -> ary of string values/strings (key not yet known; might be starting of value e.g. city:wien)
|
89
|
+
|
90
|
+
## opts e.g. :skip_tags true|false
|
91
|
+
|
92
|
+
## fix: add/configure logger for ActiveRecord!!!
|
93
|
+
logger = LogKernel::Logger.root
|
94
|
+
|
95
|
+
value_numbers = []
|
96
|
+
value_tag_keys = []
|
97
|
+
|
98
|
+
### check for "default" tags - that is, if present new_attributes[:tags] remove from hash
|
99
|
+
value_tag_keys += find_tags_in_attribs!( new_attributes )
|
100
|
+
|
101
|
+
city_class = City # assume city type by default (use metro,district to change in fixture)
|
102
|
+
new_attributes_metro = {}
|
103
|
+
|
104
|
+
## check for optional values
|
105
|
+
|
106
|
+
values.each_with_index do |value,index|
|
107
|
+
if match_state_for_country( value, new_attributes[:country_id] ) do |state|
|
108
|
+
new_attributes[ :state_id ] = state.id
|
109
|
+
end
|
110
|
+
elsif match_country( value ) do |country|
|
111
|
+
new_attributes[ :country_id ] = country.id
|
112
|
+
end
|
113
|
+
elsif match_metro( value ) do |metro|
|
114
|
+
new_attributes[ :metro_id ] = metro.id
|
115
|
+
end
|
116
|
+
elsif match_metro_pop( value ) do |num| # e.g m: 1 444 444
|
117
|
+
new_attributes_metro[ :pop ] = num # note: gets added to **metro** attributes; triggers auto-added metro record
|
118
|
+
end
|
119
|
+
elsif match_metro_flag( value ) do |_| # metro(politan area)
|
120
|
+
city_class = Metro # turn off default c|city flag; make it m|metro only
|
121
|
+
end
|
122
|
+
elsif match_city( value ) do |city| # parent city for district
|
123
|
+
new_attributes[ :city_id ] = city.id
|
124
|
+
city_class = District # turn off default c|city flag; make it d|district only
|
125
|
+
end
|
126
|
+
elsif match_km_squared( value ) do |num| # allow numbers like 453 km²
|
127
|
+
value_numbers << num
|
128
|
+
end
|
129
|
+
elsif match_number( value ) do |num| # numeric (nb: can use any _ or spaces inside digits e.g. 1_000_000 or 1 000 000)
|
130
|
+
value_numbers << num
|
131
|
+
end
|
132
|
+
elsif value =~ /#{CITY_CODE_PATTERN}/ ## assume three-letter code
|
133
|
+
new_attributes[ :code ] = value
|
134
|
+
elsif (values.size==(index+1)) && is_taglist?( value ) # tags must be last entry
|
135
|
+
logger.debug " found tags: >>#{value}<<"
|
136
|
+
value_tag_keys += find_tags( value )
|
137
|
+
else
|
138
|
+
# issue warning: unknown type for value
|
139
|
+
logger.warn "unknown type for value >#{value}<"
|
140
|
+
end
|
141
|
+
end # each value
|
142
|
+
|
143
|
+
if value_numbers.size > 0
|
144
|
+
new_attributes[ :pop ] = value_numbers[0] # assume first number is pop for cities
|
145
|
+
new_attributes[ :area ] = value_numbers[1]
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
#######
|
150
|
+
## auto add metro if used M:/m: shortcut
|
151
|
+
if new_attributes_metro.empty? == false
|
152
|
+
new_attributes_metro[:key] = new_attributes[:key]
|
153
|
+
## todo/fix: use title or name?
|
154
|
+
new_attributes_metro[:name] = new_attributes[:name] || new_attributes[:title]
|
155
|
+
new_attributes_metro[:country_id] = new_attributes[:country_id]
|
156
|
+
|
157
|
+
metro_rec = Metro.find_by_key( new_attributes_metro[ :key ] )
|
158
|
+
|
159
|
+
if metro_rec.present?
|
160
|
+
logger.debug "(auto-)update Metro #{metro_rec.id}-#{metro_rec.key}:"
|
161
|
+
else
|
162
|
+
logger.debug "(auto-)create Metro:"
|
163
|
+
metro_rec = Metro.new
|
164
|
+
end
|
165
|
+
|
166
|
+
logger.debug new_attributes_metro.to_json
|
167
|
+
|
168
|
+
metro_rec.update_attributes!( new_attributes_metro )
|
169
|
+
new_attributes[:metro_id] = metro_rec.id
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
rec = city_class.find_by_key( new_attributes[ :key ] )
|
174
|
+
|
175
|
+
if rec.present?
|
176
|
+
logger.debug "update #{city_class.name} #{rec.id}-#{rec.key}:"
|
177
|
+
else
|
178
|
+
logger.debug "create #{city_class.name}:"
|
179
|
+
rec = city_class.new
|
180
|
+
end
|
181
|
+
|
182
|
+
logger.debug new_attributes.to_json
|
183
|
+
|
184
|
+
rec.update_attributes!( new_attributes )
|
185
|
+
|
186
|
+
|
187
|
+
##################
|
188
|
+
## add taggings
|
189
|
+
|
190
|
+
## todo/fix: reuse - move add taggings into method etc.
|
191
|
+
|
192
|
+
if value_tag_keys.size > 0
|
193
|
+
|
194
|
+
if opts[:skip_tags].present?
|
195
|
+
logger.debug " skipping add taggings (flag skip_tag)"
|
196
|
+
else
|
197
|
+
value_tag_keys.uniq! # remove duplicates
|
198
|
+
logger.debug " adding #{value_tag_keys.size} taggings: >>#{value_tag_keys.join('|')}<<..."
|
199
|
+
|
200
|
+
### fix/todo: check tag_ids and only update diff (add/remove ids)
|
201
|
+
|
202
|
+
value_tag_keys.each do |key|
|
203
|
+
tag = Tag.find_by_key( key )
|
204
|
+
if tag.nil? # create tag if it doesn't exit
|
205
|
+
logger.debug " creating tag >#{key}<"
|
206
|
+
tag = Tag.create!( key: key )
|
207
|
+
end
|
208
|
+
rec.tags << tag
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
rec
|
214
|
+
end # method create_or_update_from_values
|
215
|
+
|
216
|
+
|
217
|
+
end # class Cities
|
218
|
+
|
219
|
+
end # module Model
|
220
|
+
end # module WorldDb
|
@@ -8,6 +8,15 @@ class Continent < ActiveRecord::Base
|
|
8
8
|
belongs_to :place, class_name: 'Place', foreign_key: 'place_id'
|
9
9
|
has_many :countries
|
10
10
|
|
11
|
+
## begin compat
|
12
|
+
def title() name; end
|
13
|
+
def title=(value) self.name = value; end
|
14
|
+
|
15
|
+
def synonyms() alt_names; end
|
16
|
+
def synonyms=(value) self.alt_names = value; end
|
17
|
+
## end
|
18
|
+
|
19
|
+
|
11
20
|
# NB: allow dots in keys e.g. concacaf.naf etc.
|
12
21
|
|
13
22
|
before_create :on_create
|
@@ -12,7 +12,7 @@ class Country < ActiveRecord::Base
|
|
12
12
|
|
13
13
|
# NB: use extend - is_<type>? become class methods e.g. self.is_<type>? for use in
|
14
14
|
# self.create_or_update_from_values
|
15
|
-
extend TextUtils::ValueHelper # e.g. self.is_year?, self.
|
15
|
+
extend TextUtils::ValueHelper # e.g. self.is_year?, self.is_address?, is_taglist? etc.
|
16
16
|
|
17
17
|
|
18
18
|
self.table_name = 'countries'
|
@@ -23,14 +23,14 @@ class Country < ActiveRecord::Base
|
|
23
23
|
has_many :usages
|
24
24
|
has_many :langs, :through => :usages # lang(uage)s through usages (that is, countries_langs) join table
|
25
25
|
|
26
|
-
has_many :
|
26
|
+
has_many :states, class_name: 'State', foreign_key: 'country_id'
|
27
27
|
has_many :cities, class_name: 'City', foreign_key: 'country_id'
|
28
|
-
|
28
|
+
|
29
29
|
## self referencing hierachy within countries e.g. EU > GB > EN
|
30
30
|
belongs_to :parent, class_name: 'Country', foreign_key: 'country_id'
|
31
31
|
has_many :countries, class_name: 'Country', foreign_key: 'country_id'
|
32
32
|
### recursive self-reference - use node??
|
33
|
-
## has_many :nodes, class_name: '
|
33
|
+
## has_many :nodes, class_name: 'State', foregin_key: 'state_id'
|
34
34
|
|
35
35
|
|
36
36
|
has_many_tags
|
@@ -38,6 +38,14 @@ class Country < ActiveRecord::Base
|
|
38
38
|
validates :key, format: { with: /#{COUNTRY_KEY_PATTERN}/, message: COUNTRY_KEY_PATTERN_MESSAGE }
|
39
39
|
validates :code, format: { with: /#{COUNTRY_CODE_PATTERN}/, message: COUNTRY_CODE_PATTERN_MESSAGE }
|
40
40
|
|
41
|
+
## begin compat
|
42
|
+
def title() name; end
|
43
|
+
def title=(value) self.name = value; end
|
44
|
+
|
45
|
+
def synonyms() alt_names; end
|
46
|
+
def synonyms=(value) self.alt_names = value; end
|
47
|
+
## end
|
48
|
+
|
41
49
|
|
42
50
|
scope :by_key, ->{ order( 'key asc' ) } # order by key (a-z)
|
43
51
|
scope :by_name, ->{ order( 'name asc' ) } # order by name (a-z)
|
@@ -167,6 +175,15 @@ class Country < ActiveRecord::Base
|
|
167
175
|
end
|
168
176
|
|
169
177
|
|
178
|
+
|
179
|
+
def self.parse( *args )
|
180
|
+
## remove (extract) attribs hash (if last arg is a hash n present)
|
181
|
+
more_attribs = args.last.is_a?(Hash) ? args.pop : {} ## extract_options!
|
182
|
+
values = args
|
183
|
+
|
184
|
+
self.create_or_update_from_values( values, more_attribs )
|
185
|
+
end
|
186
|
+
|
170
187
|
def self.create_or_update_from_values( values, more_attribs={} )
|
171
188
|
|
172
189
|
## key & title
|
@@ -15,15 +15,24 @@ Tagging = TagDb::Model::Tagging
|
|
15
15
|
Tag = TagDb::Model::Tag
|
16
16
|
|
17
17
|
|
18
|
-
class Name
|
19
|
-
class Place
|
20
|
-
class Continent
|
21
|
-
class Country
|
22
|
-
class Region < ActiveRecord::Base ; end
|
23
|
-
class City < ActiveRecord::Base ; end
|
18
|
+
class Name < ActiveRecord::Base ; end
|
19
|
+
class Place < ActiveRecord::Base ; end
|
20
|
+
class Continent < ActiveRecord::Base ; end
|
21
|
+
class Country < ActiveRecord::Base ; end
|
24
22
|
|
25
|
-
class
|
26
|
-
class
|
23
|
+
class CityBase < ActiveRecord::Base ; end
|
24
|
+
class Metro < CityBase ; end
|
25
|
+
class City < CityBase ; end
|
26
|
+
class District < CityBase ; end
|
27
|
+
|
28
|
+
class StateBase < ActiveRecord::Base ; end
|
29
|
+
class State < StateBase ; end ## ADM1
|
30
|
+
class Part < StateBase ; end ## x /ADM2
|
31
|
+
class County < StateBase ; end ## ADM2/ADM3
|
32
|
+
class Muni < StateBase ; end ## ADM3/ADM4
|
33
|
+
|
34
|
+
class Lang < ActiveRecord::Base ; end
|
35
|
+
class Usage < ActiveRecord::Base ; end
|
27
36
|
|
28
37
|
class CountryCode < ActiveRecord::Base ; end
|
29
38
|
|
@@ -45,8 +54,15 @@ Name = WorldDb::Model::Name
|
|
45
54
|
Place = WorldDb::Model::Place
|
46
55
|
Continent = WorldDb::Model::Continent
|
47
56
|
Country = WorldDb::Model::Country
|
48
|
-
|
57
|
+
|
58
|
+
State = WorldDb::Model::State ## ADM1
|
59
|
+
Part = WorldDb::Model::Part ## x /ADM2
|
60
|
+
County = WorldDb::Model::County ## ADM2/ADM3
|
61
|
+
Muni = WorldDb::Model::Muni ## ADM3/ADM4
|
62
|
+
|
63
|
+
Metro = WorldDb::Model::Metro
|
49
64
|
City = WorldDb::Model::City
|
65
|
+
District = WorldDb::Model::District
|
50
66
|
|
51
67
|
Lang = WorldDb::Model::Lang
|
52
68
|
Usage = WorldDb::Model::Usage
|
data/lib/worlddb/models/lang.rb
CHANGED
@@ -11,6 +11,12 @@ class Lang < ActiveRecord::Base
|
|
11
11
|
|
12
12
|
validates :key, format: { with: /#{LANG_KEY_PATTERN}/, message: LANG_KEY_PATTERN_MESSAGE }
|
13
13
|
|
14
|
+
## begin compat
|
15
|
+
def title() name; end
|
16
|
+
def title=(value) self.name = value; end
|
17
|
+
## end
|
18
|
+
|
19
|
+
|
14
20
|
end # class Lang
|
15
21
|
|
16
22
|
end # module Model
|