worlddb-models 2.1.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/HISTORY.md +4 -0
  4. data/Manifest.txt +43 -0
  5. data/README.md +85 -0
  6. data/Rakefile +44 -0
  7. data/lib/worlddb/deleter.rb +32 -0
  8. data/lib/worlddb/matcher.rb +143 -0
  9. data/lib/worlddb/models/city.rb +240 -0
  10. data/lib/worlddb/models/city_comp.rb +27 -0
  11. data/lib/worlddb/models/continent.rb +41 -0
  12. data/lib/worlddb/models/continent_comp.rb +24 -0
  13. data/lib/worlddb/models/country.rb +328 -0
  14. data/lib/worlddb/models/country_code.rb +41 -0
  15. data/lib/worlddb/models/country_comp.rb +35 -0
  16. data/lib/worlddb/models/forward.rb +57 -0
  17. data/lib/worlddb/models/lang.rb +18 -0
  18. data/lib/worlddb/models/lang_comp.rb +23 -0
  19. data/lib/worlddb/models/name.rb +13 -0
  20. data/lib/worlddb/models/place.rb +16 -0
  21. data/lib/worlddb/models/region.rb +176 -0
  22. data/lib/worlddb/models/region_comp.rb +26 -0
  23. data/lib/worlddb/models/tagdb/tag.rb +16 -0
  24. data/lib/worlddb/models/tagdb/tagging.rb +15 -0
  25. data/lib/worlddb/models/usage.rb +17 -0
  26. data/lib/worlddb/models.rb +200 -0
  27. data/lib/worlddb/patterns.rb +54 -0
  28. data/lib/worlddb/reader.rb +224 -0
  29. data/lib/worlddb/reader_file.rb +86 -0
  30. data/lib/worlddb/reader_zip.rb +160 -0
  31. data/lib/worlddb/readers/city.rb +81 -0
  32. data/lib/worlddb/readers/country.rb +78 -0
  33. data/lib/worlddb/readers/lang.rb +107 -0
  34. data/lib/worlddb/readers/region.rb +79 -0
  35. data/lib/worlddb/readers/usage.rb +98 -0
  36. data/lib/worlddb/schema.rb +202 -0
  37. data/lib/worlddb/stats.rb +31 -0
  38. data/lib/worlddb/version.rb +23 -0
  39. data/test/helper.rb +26 -0
  40. data/test/test_fixture_matchers.rb +112 -0
  41. data/test/test_model_city.rb +60 -0
  42. data/test/test_model_comp.rb +48 -0
  43. data/test/test_model_country.rb +53 -0
  44. data/test/test_model_region.rb +50 -0
  45. data/test/test_models.rb +35 -0
  46. metadata +252 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a6f4e2c609b98e4e47364d364685e82cdb315ab7
4
+ data.tar.gz: 9329d22376b1a85b186780ff0db0884de86f85af
5
+ SHA512:
6
+ metadata.gz: ac729c3828ed5e4ffd2c54cf3e700bb1f6f20e0be8fc670b2b7c524700e50ef2544aa0fd1838ca72a7d16581fbc0def39628afd9cdb02a6c1c27b92e0321b6bf
7
+ data.tar.gz: 3c8e225f39c7481fca92ec4395f2ef262c8c91bc7065e85f69e8662bbdc67c6d4883d4a1b5b3cf4866653106bc3182111666b62b66b2238da2c33a5bdc3d0a59
data/.gemtest ADDED
File without changes
data/HISTORY.md ADDED
@@ -0,0 +1,4 @@
1
+ ### 0.0.1 / 2012-11-05
2
+
3
+ * Everything is new. First release
4
+
data/Manifest.txt ADDED
@@ -0,0 +1,43 @@
1
+ HISTORY.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/worlddb/deleter.rb
6
+ lib/worlddb/matcher.rb
7
+ lib/worlddb/models.rb
8
+ lib/worlddb/models/city.rb
9
+ lib/worlddb/models/city_comp.rb
10
+ lib/worlddb/models/continent.rb
11
+ lib/worlddb/models/continent_comp.rb
12
+ lib/worlddb/models/country.rb
13
+ lib/worlddb/models/country_code.rb
14
+ lib/worlddb/models/country_comp.rb
15
+ lib/worlddb/models/forward.rb
16
+ lib/worlddb/models/lang.rb
17
+ lib/worlddb/models/lang_comp.rb
18
+ lib/worlddb/models/name.rb
19
+ lib/worlddb/models/place.rb
20
+ lib/worlddb/models/region.rb
21
+ lib/worlddb/models/region_comp.rb
22
+ lib/worlddb/models/tagdb/tag.rb
23
+ lib/worlddb/models/tagdb/tagging.rb
24
+ lib/worlddb/models/usage.rb
25
+ lib/worlddb/patterns.rb
26
+ lib/worlddb/reader.rb
27
+ lib/worlddb/reader_file.rb
28
+ lib/worlddb/reader_zip.rb
29
+ lib/worlddb/readers/city.rb
30
+ lib/worlddb/readers/country.rb
31
+ lib/worlddb/readers/lang.rb
32
+ lib/worlddb/readers/region.rb
33
+ lib/worlddb/readers/usage.rb
34
+ lib/worlddb/schema.rb
35
+ lib/worlddb/stats.rb
36
+ lib/worlddb/version.rb
37
+ test/helper.rb
38
+ test/test_fixture_matchers.rb
39
+ test/test_model_city.rb
40
+ test/test_model_comp.rb
41
+ test/test_model_country.rb
42
+ test/test_model_region.rb
43
+ test/test_models.rb
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # worlddb-models
2
+
3
+ worlddb-models gem - world.db schema & models for easy (re)use
4
+
5
+ * home :: [github.com/worlddb/world.db.models](https://github.com/worlddb/world.db.models)
6
+ * bugs :: [github.com/worlddb/world.db.models/issues](https://github.com/worlddb/world.db.models/issues)
7
+ * gem :: [rubygems.org/gems/worlddb-models](https://rubygems.org/gems/worlddb-models)
8
+ * rdoc :: [rubydoc.info/gems/worlddb-models](http://rubydoc.info/gems/worlddb-models)
9
+ * forum :: [groups.google.com/group/openmundi](https://groups.google.com/group/openmundi)
10
+
11
+
12
+ ## Usage Models
13
+
14
+ `Country` Model - Example:
15
+
16
+ at = Country.find_by! key: 'at'
17
+ at.name
18
+ # => 'Austria'
19
+ at.pop
20
+ # => 8_414_638
21
+ at.area
22
+ # => 83_871
23
+
24
+ at.regions.count
25
+ # => 9
26
+ at.regions
27
+ # => [ 'Wien', 'Niederösterreich', 'Oberösterreich', ... ]
28
+
29
+ at.cities.by_pop
30
+ # => [ 'Wien', 'Graz', 'Linz', 'Salzburg', 'Innsbruck' ... ]
31
+
32
+
33
+ `City` Model - Example:
34
+
35
+ c = City.find_by! key: 'wien'
36
+ c.name
37
+ # => 'Wien'
38
+ c.country.name
39
+ # => 'Austria'
40
+ c.country.continent.name
41
+ # => 'Europe'
42
+
43
+ la = City.find_by! key: 'losangeles'
44
+ la.name
45
+ # => 'Los Angeles'
46
+ la.region.name
47
+ # => 'California'
48
+ la.region.key
49
+ # => 'ca'
50
+ la.country.name
51
+ # => 'United States'
52
+ la.country.key
53
+ # => 'us'
54
+ la.country.continent.name
55
+ # => 'North America'
56
+
57
+
58
+ `Tag` Model - Example:
59
+
60
+ euro = Tag.find_by! key: 'euro'
61
+ euro.countries.count
62
+ # => 17
63
+ euro.countries
64
+ # => ['Austria, 'Belgium', 'Cyprus', ... ]
65
+
66
+ flanders = Tag.find_by! key: 'flanders'
67
+ flanders.regions.count
68
+ # => 5
69
+ flanders.regions
70
+ # => ['Antwerpen', 'Brabant Wallon', 'Limburg', 'Oost-Vlaanderen', 'West-Vlaanderen']
71
+ flanders.regions.first.country.name
72
+ # => 'Belgium'
73
+
74
+ and so on.
75
+
76
+
77
+ ## License
78
+
79
+ The `worlddb-models` scripts are dedicated to the public domain.
80
+ Use it as you please with no restrictions whatsoever.
81
+
82
+ ## Questions? Comments?
83
+
84
+ Send them along to the [Open Mundi (world.db) Database Forum/Mailing List](http://groups.google.com/group/openmundi).
85
+ Thanks!
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'hoe'
2
+ require './lib/worlddb/version.rb'
3
+
4
+
5
+ Hoe.spec 'worlddb-models' do
6
+
7
+ self.version = WorldDb::VERSION
8
+
9
+ self.summary = "worlddb - world.db schema & models for easy (re)use"
10
+ self.description = summary
11
+
12
+ self.urls = ['https://github.com/worlddb/world.db.models']
13
+
14
+ self.author = 'Gerald Bauer'
15
+ self.email = 'openmundi@googlegroups.com'
16
+
17
+ self.extra_deps = [
18
+ ['props'], # settings / prop(ertie)s / env / INI
19
+ ['logutils'], # logging
20
+ ['textutils', '>= 0.9.9'], # e.g. >= 0.6 && <= 1.0 ## will include logutils, props
21
+
22
+ ['tagutils'], # tags n categories for activerecord
23
+ ['activerecord-utils'],
24
+ ['props-activerecord'],
25
+ ['logutils-activerecord'],
26
+
27
+ ## 3rd party
28
+ ['rubyzip'], ## todo: pull in via textutils ??
29
+ ['activerecord'] # NB: will include activesupport,etc.
30
+ ]
31
+
32
+ # switch extension to .markdown for gihub formatting
33
+ # -- NB: auto-changed when included in manifest
34
+ self.readme_file = 'README.md'
35
+ self.history_file = 'HISTORY.md'
36
+
37
+
38
+ self.licenses = ['Public Domain']
39
+
40
+ self.spec_extras = {
41
+ required_ruby_version: '>= 1.9.2'
42
+ }
43
+
44
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module WorldDb
4
+
5
+ class Deleter
6
+
7
+ ## make models available in worlddb module by default with namespace
8
+ # e.g. lets you use City instead of Models::City
9
+ include WorldDb::Models
10
+
11
+ def run
12
+ # for now delete all tables
13
+
14
+ ## Tagging.delete_all # - use TagDb.delete!
15
+ ## Tag.delete_all
16
+
17
+ CountryCode.delete_all
18
+ Name.delete_all
19
+ Place.delete_all
20
+ City.delete_all
21
+ Region.delete_all
22
+ Country.delete_all
23
+ Continent.delete_all
24
+ Usage.delete_all
25
+ Lang.delete_all
26
+
27
+ # Prop.delete_all # - use ConfDb.delete!
28
+ end
29
+
30
+ end # class Deleter
31
+
32
+ end # module WorldDb
@@ -0,0 +1,143 @@
1
+ # encoding: UTF-8
2
+
3
+ module WorldDb
4
+
5
+ module Matcher
6
+
7
+ def match_xxx_for_country( name, xxx ) # xxx e.g. cities|regions|beers|breweries
8
+ # auto-add required country code (from folder structure)
9
+ # note: always let match_xxx_for_country_n_region go first
10
+
11
+ # note: allow /cities and /1--hokkaido--cities
12
+ xxx_pattern = "(?:#{xxx}|[0-9]+--[^\\/]+?--#{xxx})" # note: double escape \\ required for backslash
13
+
14
+ ##
15
+ ## todo: add $-anchor at the end of pattern - why? why not?? (will include .txt or .yaml??)
16
+
17
+ if name =~ /(?:^|\/)([a-z]{2,3})-[^\/]+\/#{xxx_pattern}/ || # (1)
18
+ name =~ /(?:^|\/)[0-9]+--([a-z]{2,3})-[^\/]+\/#{xxx_pattern}/ || # (2)
19
+ name =~ /(?:^|\/)([a-z]{2,3})\/#{xxx_pattern}/ || # (3)
20
+ name =~ /(?:^|\/)([a-z]{2,3})-[^\/]+\/[0-9]+--[^\/]+\/#{xxx_pattern}/ || # (4)
21
+ name =~ /(?:^|\/)([a-z]{2,3})-[^\/]+--#{xxx}/ # (5)
22
+
23
+ country_key = $1.dup
24
+ yield( country_key )
25
+ true # bingo - match found
26
+
27
+ ######
28
+ # (1) new style: e.g. /at-austria/beers or ^at-austria!/cities
29
+ #
30
+ # (2) new-new style e.g. /1--at-austria--central/cities
31
+ #
32
+ # (3) classic style: e.g. /at/beers (europe/at/cities)
33
+ #
34
+ # (4) new style w/ region w/o abbrev/code e.g. /ja-japon/1--hokkaido/cities
35
+ #
36
+ # (5) compact style (country part of filename):
37
+ # e.g. /at-austria--cities or /europe/at-austria--cities
38
+ else
39
+ false # no match found
40
+ end
41
+ end
42
+
43
+
44
+ def match_xxx_for_country_n_region( name, xxx ) # xxx e.g. wine|wineries
45
+
46
+ # auto-add required country n region code (from folder structure)
47
+
48
+ ## -- allow opt_folders after long regions (e.g. additional subregion/zone)
49
+ ## -- allow anything (prefixes) before -- for xxx
50
+ # e.g. at-austria!/1--n-niederoesterreich--eastern/wagram--wines
51
+ # at-austria!/1--n-niederoesterreich--eastern/wagram--wagram--wines
52
+
53
+ # note: allow /cities and /1--hokkaido--cities and /hokkaido--cities too
54
+ xxx_pattern = "(?:#{xxx}|[^\\/]+--#{xxx})" # note: double escape \\ required for backslash
55
+
56
+ ## allow optional folders -- TODO: add restriction ?? e.g. must be 4+ alphas ???
57
+ opt_folders_pattern = "(?:\/[^\/]+)*"
58
+ ## note: for now only (style #2) n (style #3) that is long region allow opt folders
59
+
60
+ if name =~ /(?:^|\/)([a-z]{2,3})-[^\/]+\/([a-z]{1,3})-[^\/]+\/#{xxx_pattern}/ || # (1)
61
+ name =~ /(?:^|\/)[0-9]+--([a-z]{2,3})-[^\/]+\/[0-9]+--([a-z]{1,3})-[^\/]+#{opt_folders_pattern}\/#{xxx_pattern}/ || # (2)
62
+ name =~ /(?:^|\/)([a-z]{2,3})-[^\/]+\/[0-9]+--([a-z]{1,3})-[^\/]+#{opt_folders_pattern}\/#{xxx_pattern}/ || # (3)
63
+ name =~ /(?:^|\/)[0-9]+--([a-z]{2,3})-[^\/]+\/([a-z]{1,3})-[^\/]+\/#{xxx_pattern}/ # (4)
64
+
65
+ #######
66
+ # nb: country must start name (^) or coming after / e.g. europe/at-austria/...
67
+ # (1)
68
+ # new style: e.g. /at-austria/w-wien/cities or
69
+ # ^at-austria!/w-wien/cities
70
+ # (2)
71
+ # new new style e.g. /1--at-austria--central/1--w-wien--eastern/cities
72
+ #
73
+ # (3)
74
+ # new new mixed style e.g. /at-austria/1--w-wien--eastern/cities
75
+ # "classic" country plus new new region
76
+ #
77
+ # (4)
78
+ # new new mixed style e.g. /1--at-austria--central/w-wien/cities
79
+ # new new country plus "classic" region
80
+
81
+ country_key = $1.dup
82
+ region_key = $2.dup
83
+ yield( country_key, region_key )
84
+ true # bingo - match found
85
+ else
86
+ false # no match found
87
+ end
88
+ end
89
+
90
+
91
+ def match_cities_for_country( name, &blk )
92
+ ## todo: check if there's a better (more ruby way) to pass along code block ??
93
+ ## e.g. try
94
+ ## match_xxx_for_country( name, 'cities') { |country_key| yield(country_key) }
95
+
96
+ match_xxx_for_country( name, 'cities', &blk )
97
+ end
98
+
99
+ def match_regions_for_country( name, &blk )
100
+ ## also try synonyms e.g. old regions (if not match for states)
101
+ found = match_xxx_for_country( name, 'states', &blk )
102
+ found = match_xxx_for_country( name, 'regions', &blk ) unless found
103
+ found
104
+ end
105
+
106
+ def match_regions_abbr_for_country( name, &blk ) # NB: . gets escaped for regex, that is, \.
107
+ ## also try synonyms e.g. old regions (if not match for states)
108
+ found = match_xxx_for_country( name, 'states\.abbr', &blk )
109
+ found = match_xxx_for_country( name, 'regions\.abbr', &blk ) unless found
110
+ found
111
+ end
112
+
113
+ def match_regions_iso_for_country( name, &blk ) # NB: . gets escaped for regex, that is, \.
114
+ ## also try synonyms e.g. old regions (if not match for states)
115
+ found = match_xxx_for_country( name, 'states\.iso', &blk )
116
+ found = match_xxx_for_country( name, 'regions\.iso', &blk ) unless found
117
+ found
118
+ end
119
+
120
+ def match_regions_nuts_for_country( name, &blk ) # NB: . gets escaped for regex, that is, \.
121
+ ## also try synonyms e.g. old regions (if not match for states)
122
+ found = match_xxx_for_country( name, 'states\.nuts', &blk )
123
+ found = match_xxx_for_country( name, 'regions\.nuts', &blk ) unless found
124
+ found
125
+ end
126
+
127
+
128
+ def match_countries_for_continent( name )
129
+ if name =~ /^([a-z][a-z\-_]+[a-z])\/countries/ # e.g. africa/countries or america/countries
130
+ ### NB: continent changed to regions (e.g. middle-east, caribbean, north-america, etc.)
131
+ ## auto-add continent (from folder structure) as tag
132
+ ## fix: allow dash/hyphen/minus in tag
133
+ continent = $1.dup
134
+ yield( continent )
135
+ true
136
+ else
137
+ false # no match found
138
+ end
139
+ end
140
+
141
+ end # module Matcher
142
+
143
+ end # module WorldDb
@@ -0,0 +1,240 @@
1
+ # encoding: utf-8
2
+
3
+ module WorldDb
4
+ module Model
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
+
24
+
25
+ self.table_name = 'cities'
26
+
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
53
+
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
66
+
67
+ 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
80
+ end
81
+
82
+
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)
92
+
93
+
94
+ def all_names( opts={} )
95
+ ### fix:
96
+ ## allow to passing in sep or separator e.g. | or other
97
+
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
+
107
+
108
+ def self.create_or_update_from_values( values, more_attribs={} )
109
+ ## key & title & country required
110
+
111
+ attribs, more_values = find_key_n_title( values )
112
+ attribs = attribs.merge( more_attribs )
113
+
114
+ ## check for optional values
115
+ City.create_or_update_from_attribs( attribs, more_values )
116
+ end
117
+
118
+
119
+ def self.create_or_update_from_titles( titles, more_attribs = {} )
120
+ # ary of titles e.g. ['Wien', 'Graz'] etc.
121
+
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
127
+
128
+
129
+
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
+
239
+ end # module Model
240
+ end # module WorldDb
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module WorldDb
4
+ module Model
5
+
6
+ #############################################################
7
+ # collect depreciated or methods for future removal here
8
+ # - keep for now for commpatibility (for old code)
9
+
10
+ class City
11
+
12
+ def title() name; end
13
+ def title=(value) self.name = value; end
14
+
15
+ scope :by_title, ->{ order( 'name asc' ) } # order by title (a-z)
16
+
17
+
18
+ def synonyms() alt_names; end
19
+ def synonyms=(value) self.alt_names = value; end
20
+
21
+ def title_w_synonyms( opts={} ) all_names( opts ); end # depreciated: use all_names instead
22
+
23
+ end # class Cities
24
+
25
+ end # module Model
26
+ end # module WorldDb
27
+
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module WorldDb
4
+ module Model
5
+
6
+ class Continent < ActiveRecord::Base
7
+
8
+ belongs_to :place, class_name: 'Place', foreign_key: 'place_id'
9
+ has_many :countries
10
+
11
+ # NB: allow dots in keys e.g. concacaf.naf etc.
12
+
13
+ before_create :on_create
14
+ before_update :on_update
15
+
16
+ def on_create
17
+ place_rec = Place.create!( name: name, kind: place_kind )
18
+ self.place_id = place_rec.id
19
+
20
+ self.slug = TextUtils.slugify( name ) if slug.blank?
21
+ end
22
+
23
+ def on_update
24
+ ## fix/todo: check - if name or kind changed - only update if changed ?? why? why not??
25
+ place.update_attributes!( name: name, kind: place_kind )
26
+
27
+ ## check if name changed -- possible?
28
+ ## update slug too??
29
+ end
30
+
31
+ def place_kind # use place_kind_of_code ??
32
+ 'CONT'
33
+ end
34
+
35
+
36
+ end # class Continent
37
+
38
+
39
+ end # module Model
40
+ end # module WorldDb
41
+