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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/HISTORY.md +4 -0
- data/Manifest.txt +43 -0
- data/README.md +85 -0
- data/Rakefile +44 -0
- data/lib/worlddb/deleter.rb +32 -0
- data/lib/worlddb/matcher.rb +143 -0
- data/lib/worlddb/models/city.rb +240 -0
- data/lib/worlddb/models/city_comp.rb +27 -0
- data/lib/worlddb/models/continent.rb +41 -0
- data/lib/worlddb/models/continent_comp.rb +24 -0
- data/lib/worlddb/models/country.rb +328 -0
- data/lib/worlddb/models/country_code.rb +41 -0
- data/lib/worlddb/models/country_comp.rb +35 -0
- data/lib/worlddb/models/forward.rb +57 -0
- data/lib/worlddb/models/lang.rb +18 -0
- data/lib/worlddb/models/lang_comp.rb +23 -0
- data/lib/worlddb/models/name.rb +13 -0
- data/lib/worlddb/models/place.rb +16 -0
- data/lib/worlddb/models/region.rb +176 -0
- data/lib/worlddb/models/region_comp.rb +26 -0
- data/lib/worlddb/models/tagdb/tag.rb +16 -0
- data/lib/worlddb/models/tagdb/tagging.rb +15 -0
- data/lib/worlddb/models/usage.rb +17 -0
- data/lib/worlddb/models.rb +200 -0
- data/lib/worlddb/patterns.rb +54 -0
- data/lib/worlddb/reader.rb +224 -0
- data/lib/worlddb/reader_file.rb +86 -0
- data/lib/worlddb/reader_zip.rb +160 -0
- data/lib/worlddb/readers/city.rb +81 -0
- data/lib/worlddb/readers/country.rb +78 -0
- data/lib/worlddb/readers/lang.rb +107 -0
- data/lib/worlddb/readers/region.rb +79 -0
- data/lib/worlddb/readers/usage.rb +98 -0
- data/lib/worlddb/schema.rb +202 -0
- data/lib/worlddb/stats.rb +31 -0
- data/lib/worlddb/version.rb +23 -0
- data/test/helper.rb +26 -0
- data/test/test_fixture_matchers.rb +112 -0
- data/test/test_model_city.rb +60 -0
- data/test/test_model_comp.rb +48 -0
- data/test/test_model_country.rb +53 -0
- data/test/test_model_region.rb +50 -0
- data/test/test_models.rb +35 -0
- 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
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
|
+
|