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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +31 -13
  3. data/README.md +7 -7
  4. data/Rakefile +1 -1
  5. data/lib/worlddb/deleter.rb +6 -1
  6. data/lib/worlddb/helpers/value_helper.rb +117 -0
  7. data/lib/worlddb/matcher.rb +99 -135
  8. data/lib/worlddb/matcher_adm.rb +82 -0
  9. data/lib/worlddb/models/city.rb +30 -208
  10. data/lib/worlddb/models/city_base.rb +220 -0
  11. data/lib/worlddb/models/continent.rb +9 -0
  12. data/lib/worlddb/models/country.rb +21 -4
  13. data/lib/worlddb/models/forward.rb +25 -9
  14. data/lib/worlddb/models/lang.rb +6 -0
  15. data/lib/worlddb/models/place.rb +1 -1
  16. data/lib/worlddb/models/state.rb +83 -0
  17. data/lib/worlddb/models/{region.rb → state_base.rb} +52 -36
  18. data/lib/worlddb/models/tagdb/tag.rb +1 -1
  19. data/lib/worlddb/models.rb +11 -8
  20. data/lib/worlddb/patterns.rb +4 -4
  21. data/lib/worlddb/reader.rb +68 -39
  22. data/lib/worlddb/reader_file.rb +36 -3
  23. data/lib/worlddb/reader_zip.rb +33 -3
  24. data/lib/worlddb/readers/base.rb +149 -0
  25. data/lib/worlddb/readers/city.rb +2 -65
  26. data/lib/worlddb/readers/country.rb +2 -63
  27. data/lib/worlddb/readers/lang.rb +3 -68
  28. data/lib/worlddb/readers/state.rb +61 -0
  29. data/lib/worlddb/readers/state_tree.rb +118 -0
  30. data/lib/worlddb/readers/usage.rb +2 -65
  31. data/lib/worlddb/schema.rb +142 -43
  32. data/lib/worlddb/stats.rb +7 -4
  33. data/lib/worlddb/tree_reader.rb +97 -0
  34. data/lib/worlddb/version.rb +2 -2
  35. data/test/adm/test_fixture_matcher_adm2.rb +73 -0
  36. data/test/{test_fixture_matcher_adm3.rb → adm/test_fixture_matcher_adm3.rb} +6 -6
  37. data/test/adm/test_fixture_matcher_tree.rb +52 -0
  38. data/test/{test_read_adm.rb → adm/test_read_adm.rb} +13 -20
  39. data/test/adm/test_read_tree.rb +63 -0
  40. data/test/data/at-austria/2--n-niederoesterreich/counties.txt +6 -4
  41. data/test/data/at-austria/orte.txt +23 -0
  42. data/test/data/at-austria/setups/tree.txt +9 -0
  43. data/test/data/de-deutschland/3--by-bayern/4--oberfranken/counties.txt +14 -13
  44. data/test/data/de-deutschland/3--by-bayern/4--oberfranken/orte.txt +104 -0
  45. data/test/data/de-deutschland/3--by-bayern/4--oberfranken/orte_ii.txt +17 -0
  46. data/test/data/de-deutschland/3--by-bayern/{districts.txt → parts.txt} +1 -1
  47. data/test/data/de-deutschland/orte.txt +12 -0
  48. data/test/data/de-deutschland/setups/adm.txt +1 -1
  49. data/test/data/de-deutschland/setups/tree.txt +9 -0
  50. data/test/helper.rb +8 -1
  51. data/test/test_fixture_matchers.rb +9 -10
  52. data/test/test_fixture_matchers_ii.rb +20 -19
  53. data/test/test_model_city.rb +26 -9
  54. data/test/{test_model_comp.rb → test_model_compat.rb} +15 -13
  55. data/test/test_model_country.rb +1 -1
  56. data/test/test_model_state.rb +54 -0
  57. data/test/test_model_states_at.rb +111 -0
  58. data/test/test_model_states_de.rb +147 -0
  59. data/test/test_models.rb +10 -3
  60. data/test/test_parse_city.rb +70 -0
  61. data/test/test_parse_country.rb +56 -0
  62. data/test/test_parse_state.rb +46 -0
  63. data/test/test_state_tree_reader_at.rb +54 -0
  64. data/test/test_state_tree_reader_de.rb +71 -0
  65. data/test/test_tree_reader.rb +39 -0
  66. metadata +50 -22
  67. data/lib/worlddb/models/city_compat.rb +0 -27
  68. data/lib/worlddb/models/continent_compat.rb +0 -24
  69. data/lib/worlddb/models/country_compat.rb +0 -35
  70. data/lib/worlddb/models/lang_compat.rb +0 -23
  71. data/lib/worlddb/models/region_compat.rb +0 -26
  72. data/lib/worlddb/readers/region.rb +0 -79
  73. data/test/test_fixture_matcher_adm2.rb +0 -62
  74. data/test/test_model_region.rb +0 -50
@@ -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 :place, class_name: 'Place', foreign_key: 'place_id'
28
- belongs_to :country, class_name: 'Country', foreign_key: 'country_id'
29
- belongs_to :region, class_name: 'Region', foreign_key: 'region_id'
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
- before_create :on_create
55
- before_update :on_update
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
- ### fix/todo: make sure city records won't overlap (e.g. using metro n city flag at the same time; use separate records)
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
- validates :key, format: { with: /#{CITY_KEY_PATTERN}/, message: CITY_KEY_PATTERN_MESSAGE }
84
- validates :code, format: { with: /#{CITY_CODE_PATTERN}/, message: CITY_CODE_PATTERN_MESSAGE }, allow_nil: true
85
-
86
-
87
- scope :by_key, ->{ order( 'key asc' ) } # order by key (a-z)
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
- def all_names( opts={} )
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
- def self.create_or_update_from_values( values, more_attribs={} )
109
- ## key & title & country required
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
- attribs, more_values = find_key_n_title( values )
112
- attribs = attribs.merge( more_attribs )
41
+ has_many :cities, class_name: 'City', foreign_key: 'metro_id'
113
42
 
114
- ## check for optional values
115
- City.create_or_update_from_attribs( attribs, more_values )
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
- titles.each do |title|
123
- values = [title]
124
- City.create_or_update_from_values( values, more_attribs )
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.is_region?, self.is_address?, is_taglist? etc.
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 :regions, class_name: 'Region', foreign_key: 'country_id'
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: 'Region', foregin_key: 'region_id'
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 < ActiveRecord::Base ; end
19
- class Place < ActiveRecord::Base ; end
20
- class Continent < ActiveRecord::Base ; end
21
- class Country < ActiveRecord::Base ; end
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 Lang < ActiveRecord::Base ; end
26
- class Usage < ActiveRecord::Base ; end
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
- Region = WorldDb::Model::Region
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
@@ -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
@@ -6,7 +6,7 @@ module WorldDb
6
6
  class Place < ActiveRecord::Base
7
7
 
8
8
  ## todo: depending on type
9
- ## has_one continent, country, region, city etc.
9
+ ## has_one continent, country, state, city etc.
10
10
 
11
11
  end # class Place
12
12