bw-geocoder 1.2.5
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.
- data/.gitignore +6 -0
- data/.travis.yml +31 -0
- data/CHANGELOG.md +377 -0
- data/LICENSE +20 -0
- data/README.md +1041 -0
- data/Rakefile +25 -0
- data/bin/geocode +5 -0
- data/examples/autoexpire_cache_dalli.rb +62 -0
- data/examples/autoexpire_cache_redis.rb +28 -0
- data/examples/cache_bypass.rb +48 -0
- data/gemfiles/Gemfile.mongoid-2.4.x +16 -0
- data/lib/generators/geocoder/config/config_generator.rb +14 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +21 -0
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
- data/lib/geocoder/cache.rb +90 -0
- data/lib/geocoder/calculations.rb +428 -0
- data/lib/geocoder/cli.rb +121 -0
- data/lib/geocoder/configuration.rb +124 -0
- data/lib/geocoder/configuration_hash.rb +11 -0
- data/lib/geocoder/exceptions.rb +21 -0
- data/lib/geocoder/ip_address.rb +21 -0
- data/lib/geocoder/lookup.rb +100 -0
- data/lib/geocoder/lookups/baidu.rb +55 -0
- data/lib/geocoder/lookups/baidu_ip.rb +54 -0
- data/lib/geocoder/lookups/base.rb +302 -0
- data/lib/geocoder/lookups/bing.rb +59 -0
- data/lib/geocoder/lookups/dstk.rb +20 -0
- data/lib/geocoder/lookups/esri.rb +48 -0
- data/lib/geocoder/lookups/freegeoip.rb +47 -0
- data/lib/geocoder/lookups/geocoder_ca.rb +54 -0
- data/lib/geocoder/lookups/geocoder_us.rb +39 -0
- data/lib/geocoder/lookups/geocodio.rb +42 -0
- data/lib/geocoder/lookups/google.rb +67 -0
- data/lib/geocoder/lookups/google_places_details.rb +50 -0
- data/lib/geocoder/lookups/google_premier.rb +47 -0
- data/lib/geocoder/lookups/here.rb +62 -0
- data/lib/geocoder/lookups/ip_address_labs.rb +43 -0
- data/lib/geocoder/lookups/mapquest.rb +60 -0
- data/lib/geocoder/lookups/maxmind.rb +90 -0
- data/lib/geocoder/lookups/maxmind_local.rb +58 -0
- data/lib/geocoder/lookups/nominatim.rb +52 -0
- data/lib/geocoder/lookups/okf.rb +43 -0
- data/lib/geocoder/lookups/opencagedata.rb +58 -0
- data/lib/geocoder/lookups/ovi.rb +62 -0
- data/lib/geocoder/lookups/pointpin.rb +68 -0
- data/lib/geocoder/lookups/smarty_streets.rb +45 -0
- data/lib/geocoder/lookups/telize.rb +40 -0
- data/lib/geocoder/lookups/test.rb +44 -0
- data/lib/geocoder/lookups/yahoo.rb +88 -0
- data/lib/geocoder/lookups/yandex.rb +54 -0
- data/lib/geocoder/models/active_record.rb +50 -0
- data/lib/geocoder/models/base.rb +39 -0
- data/lib/geocoder/models/mongo_base.rb +64 -0
- data/lib/geocoder/models/mongo_mapper.rb +26 -0
- data/lib/geocoder/models/mongoid.rb +32 -0
- data/lib/geocoder/query.rb +111 -0
- data/lib/geocoder/railtie.rb +26 -0
- data/lib/geocoder/request.rb +25 -0
- data/lib/geocoder/results/baidu.rb +79 -0
- data/lib/geocoder/results/baidu_ip.rb +62 -0
- data/lib/geocoder/results/base.rb +67 -0
- data/lib/geocoder/results/bing.rb +48 -0
- data/lib/geocoder/results/dstk.rb +6 -0
- data/lib/geocoder/results/esri.rb +51 -0
- data/lib/geocoder/results/freegeoip.rb +45 -0
- data/lib/geocoder/results/geocoder_ca.rb +60 -0
- data/lib/geocoder/results/geocoder_us.rb +39 -0
- data/lib/geocoder/results/geocodio.rb +66 -0
- data/lib/geocoder/results/google.rb +124 -0
- data/lib/geocoder/results/google_places_details.rb +35 -0
- data/lib/geocoder/results/google_premier.rb +6 -0
- data/lib/geocoder/results/here.rb +62 -0
- data/lib/geocoder/results/ip_address_labs.rb +78 -0
- data/lib/geocoder/results/mapquest.rb +51 -0
- data/lib/geocoder/results/maxmind.rb +135 -0
- data/lib/geocoder/results/maxmind_local.rb +49 -0
- data/lib/geocoder/results/nominatim.rb +94 -0
- data/lib/geocoder/results/okf.rb +106 -0
- data/lib/geocoder/results/opencagedata.rb +82 -0
- data/lib/geocoder/results/ovi.rb +62 -0
- data/lib/geocoder/results/pointpin.rb +44 -0
- data/lib/geocoder/results/smarty_streets.rb +106 -0
- data/lib/geocoder/results/telize.rb +45 -0
- data/lib/geocoder/results/test.rb +33 -0
- data/lib/geocoder/results/yahoo.rb +55 -0
- data/lib/geocoder/results/yandex.rb +84 -0
- data/lib/geocoder/sql.rb +107 -0
- data/lib/geocoder/stores/active_record.rb +278 -0
- data/lib/geocoder/stores/base.rb +127 -0
- data/lib/geocoder/stores/mongo_base.rb +89 -0
- data/lib/geocoder/stores/mongo_mapper.rb +13 -0
- data/lib/geocoder/stores/mongoid.rb +13 -0
- data/lib/geocoder/version.rb +3 -0
- data/lib/geocoder.rb +47 -0
- data/lib/hash_recursive_merge.rb +74 -0
- data/lib/maxmind_database.rb +109 -0
- data/lib/oauth_util.rb +112 -0
- data/lib/tasks/geocoder.rake +29 -0
- data/lib/tasks/maxmind.rake +73 -0
- data/test/fixtures/baidu_invalid_key +1 -0
- data/test/fixtures/baidu_ip_202_198_16_3 +19 -0
- data/test/fixtures/baidu_ip_invalid_key +1 -0
- data/test/fixtures/baidu_ip_no_results +1 -0
- data/test/fixtures/baidu_no_results +1 -0
- data/test/fixtures/baidu_reverse +1 -0
- data/test/fixtures/baidu_shanghai_pearl_tower +12 -0
- data/test/fixtures/bing_invalid_key +1 -0
- data/test/fixtures/bing_madison_square_garden +40 -0
- data/test/fixtures/bing_no_results +16 -0
- data/test/fixtures/bing_reverse +42 -0
- data/test/fixtures/cloudmade_invalid_key +1 -0
- data/test/fixtures/cloudmade_madison_square_garden +1 -0
- data/test/fixtures/cloudmade_no_results +1 -0
- data/test/fixtures/esri_madison_square_garden +59 -0
- data/test/fixtures/esri_no_results +8 -0
- data/test/fixtures/esri_reverse +21 -0
- data/test/fixtures/freegeoip_74_200_247_59 +12 -0
- data/test/fixtures/freegeoip_no_results +1 -0
- data/test/fixtures/geocoder_ca_madison_square_garden +1 -0
- data/test/fixtures/geocoder_ca_no_results +1 -0
- data/test/fixtures/geocoder_ca_reverse +34 -0
- data/test/fixtures/geocoder_us_madison_square_garden +1 -0
- data/test/fixtures/geocoder_us_no_results +1 -0
- data/test/fixtures/geocodio_1101_pennsylvania_ave +1 -0
- data/test/fixtures/geocodio_bad_api_key +3 -0
- data/test/fixtures/geocodio_invalid +4 -0
- data/test/fixtures/geocodio_no_results +1 -0
- data/test/fixtures/geocodio_over_query_limit +4 -0
- data/test/fixtures/google_garbage +456 -0
- data/test/fixtures/google_madison_square_garden +57 -0
- data/test/fixtures/google_no_city_data +44 -0
- data/test/fixtures/google_no_locality +51 -0
- data/test/fixtures/google_no_results +4 -0
- data/test/fixtures/google_over_limit +4 -0
- data/test/fixtures/google_places_details_invalid_request +4 -0
- data/test/fixtures/google_places_details_madison_square_garden +120 -0
- data/test/fixtures/google_places_details_no_results +4 -0
- data/test/fixtures/google_places_details_no_reviews +60 -0
- data/test/fixtures/google_places_details_no_types +66 -0
- data/test/fixtures/here_madison_square_garden +72 -0
- data/test/fixtures/here_no_results +8 -0
- data/test/fixtures/mapquest_error +16 -0
- data/test/fixtures/mapquest_invalid_api_key +16 -0
- data/test/fixtures/mapquest_invalid_request +16 -0
- data/test/fixtures/mapquest_madison_square_garden +52 -0
- data/test/fixtures/mapquest_no_results +16 -0
- data/test/fixtures/maxmind_24_24_24_21 +1 -0
- data/test/fixtures/maxmind_24_24_24_22 +1 -0
- data/test/fixtures/maxmind_24_24_24_23 +1 -0
- data/test/fixtures/maxmind_24_24_24_24 +1 -0
- data/test/fixtures/maxmind_74_200_247_59 +1 -0
- data/test/fixtures/maxmind_invalid_key +1 -0
- data/test/fixtures/maxmind_no_results +1 -0
- data/test/fixtures/nominatim_madison_square_garden +150 -0
- data/test/fixtures/nominatim_no_results +1 -0
- data/test/fixtures/nominatim_over_limit +1 -0
- data/test/fixtures/okf_kirstinmaki +67 -0
- data/test/fixtures/okf_no_results +4 -0
- data/test/fixtures/opencagedata_invalid_api_key +25 -0
- data/test/fixtures/opencagedata_invalid_request +26 -0
- data/test/fixtures/opencagedata_madison_square_garden +73 -0
- data/test/fixtures/opencagedata_no_results +29 -0
- data/test/fixtures/opencagedata_over_limit +31 -0
- data/test/fixtures/ovi_madison_square_garden +72 -0
- data/test/fixtures/ovi_no_results +8 -0
- data/test/fixtures/pointpin_10_10_10_10 +1 -0
- data/test/fixtures/pointpin_555_555_555_555 +1 -0
- data/test/fixtures/pointpin_80_111_555_555 +1 -0
- data/test/fixtures/pointpin_no_results +1 -0
- data/test/fixtures/smarty_streets_11211 +1 -0
- data/test/fixtures/smarty_streets_madison_square_garden +47 -0
- data/test/fixtures/smarty_streets_no_results +1 -0
- data/test/fixtures/telize_10_10_10_10 +1 -0
- data/test/fixtures/telize_555_555_555_555 +4 -0
- data/test/fixtures/telize_74_200_247_59 +1 -0
- data/test/fixtures/telize_no_results +1 -0
- data/test/fixtures/yahoo_error +1 -0
- data/test/fixtures/yahoo_invalid_key +2 -0
- data/test/fixtures/yahoo_madison_square_garden +52 -0
- data/test/fixtures/yahoo_no_results +10 -0
- data/test/fixtures/yahoo_over_limit +2 -0
- data/test/fixtures/yandex_canada_rue_dupuis_14 +446 -0
- data/test/fixtures/yandex_invalid_key +1 -0
- data/test/fixtures/yandex_kremlin +48 -0
- data/test/fixtures/yandex_new_york +1 -0
- data/test/fixtures/yandex_no_city_and_town +112 -0
- data/test/fixtures/yandex_no_results +16 -0
- data/test/integration/http_client_test.rb +31 -0
- data/test/mongoid_test_helper.rb +43 -0
- data/test/test_helper.rb +386 -0
- data/test/unit/active_record_test.rb +16 -0
- data/test/unit/cache_test.rb +37 -0
- data/test/unit/calculations_test.rb +220 -0
- data/test/unit/configuration_test.rb +55 -0
- data/test/unit/error_handling_test.rb +56 -0
- data/test/unit/geocoder_test.rb +78 -0
- data/test/unit/https_test.rb +17 -0
- data/test/unit/ip_address_test.rb +27 -0
- data/test/unit/lookup_test.rb +153 -0
- data/test/unit/lookups/bing_test.rb +68 -0
- data/test/unit/lookups/dstk_test.rb +26 -0
- data/test/unit/lookups/esri_test.rb +48 -0
- data/test/unit/lookups/freegeoip_test.rb +27 -0
- data/test/unit/lookups/geocoder_ca_test.rb +17 -0
- data/test/unit/lookups/geocodio_test.rb +55 -0
- data/test/unit/lookups/google_places_details_test.rb +122 -0
- data/test/unit/lookups/google_premier_test.rb +22 -0
- data/test/unit/lookups/google_test.rb +84 -0
- data/test/unit/lookups/mapquest_test.rb +60 -0
- data/test/unit/lookups/maxmind_local_test.rb +28 -0
- data/test/unit/lookups/maxmind_test.rb +63 -0
- data/test/unit/lookups/nominatim_test.rb +31 -0
- data/test/unit/lookups/okf_test.rb +38 -0
- data/test/unit/lookups/opencagedata_test.rb +64 -0
- data/test/unit/lookups/pointpin_test.rb +30 -0
- data/test/unit/lookups/smarty_streets_test.rb +71 -0
- data/test/unit/lookups/telize_test.rb +36 -0
- data/test/unit/lookups/yahoo_test.rb +35 -0
- data/test/unit/method_aliases_test.rb +26 -0
- data/test/unit/model_test.rb +38 -0
- data/test/unit/mongoid_test.rb +47 -0
- data/test/unit/near_test.rb +87 -0
- data/test/unit/oauth_util_test.rb +31 -0
- data/test/unit/proxy_test.rb +37 -0
- data/test/unit/query_test.rb +52 -0
- data/test/unit/rake_task_test.rb +21 -0
- data/test/unit/request_test.rb +35 -0
- data/test/unit/result_test.rb +72 -0
- data/test/unit/test_mode_test.rb +70 -0
- metadata +281 -0
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
Rake::TestTask.new(:test) do |test|
|
6
|
+
test.libs << 'lib' << 'test'
|
7
|
+
test.pattern = 'test/unit/**/*_test.rb'
|
8
|
+
test.verbose = true
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::TestTask.new(:integration) do |test|
|
12
|
+
test.libs << 'lib' << 'test'
|
13
|
+
test.pattern = 'test/integration/*_test.rb'
|
14
|
+
test.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:test]
|
18
|
+
|
19
|
+
require 'rdoc/task'
|
20
|
+
Rake::RDocTask.new do |rdoc|
|
21
|
+
rdoc.rdoc_dir = 'rdoc'
|
22
|
+
rdoc.title = "Geocoder #{Geocoder::VERSION}"
|
23
|
+
rdoc.rdoc_files.include('*.rdoc')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
data/bin/geocode
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# This class implements a cache with simple delegation to the the Dalli Memcached client
|
2
|
+
# https://github.com/mperham/dalli
|
3
|
+
#
|
4
|
+
# A TTL is set on initialization
|
5
|
+
|
6
|
+
class AutoexpireCacheDalli
|
7
|
+
def initialize(store, ttl = 86400)
|
8
|
+
@store = store
|
9
|
+
@keys = 'GeocoderDalliClientKeys'
|
10
|
+
@ttl = ttl
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](url)
|
14
|
+
res = @store.get(url)
|
15
|
+
res = YAML::load(res) if res.present?
|
16
|
+
res
|
17
|
+
end
|
18
|
+
|
19
|
+
def []=(url, value)
|
20
|
+
if value.nil?
|
21
|
+
del(url)
|
22
|
+
else
|
23
|
+
key_cache_add(url) if @store.add(url, YAML::dump(value), @ttl)
|
24
|
+
end
|
25
|
+
value
|
26
|
+
end
|
27
|
+
|
28
|
+
def keys
|
29
|
+
key_cache
|
30
|
+
end
|
31
|
+
|
32
|
+
def del(url)
|
33
|
+
key_cache_delete(url) if @store.delete(url)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def key_cache
|
39
|
+
the_keys = @store.get(@keys)
|
40
|
+
if the_keys.nil?
|
41
|
+
@store.add(@keys, YAML::dump([]))
|
42
|
+
[]
|
43
|
+
else
|
44
|
+
YAML::load(the_keys)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def key_cache_add(key)
|
49
|
+
@store.replace(@keys, YAML::dump(key_cache << key))
|
50
|
+
end
|
51
|
+
|
52
|
+
def key_cache_delete(key)
|
53
|
+
tmp = key_cache
|
54
|
+
tmp.delete(key)
|
55
|
+
@store.replace(@keys, YAML::dump(tmp))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Here Dalli is set up as on Heroku using the Memcachier gem.
|
60
|
+
# https://devcenter.heroku.com/articles/memcachier#ruby
|
61
|
+
# On other setups you might have to specify your Memcached server in Dalli::Client.new
|
62
|
+
Geocoder.configure(:cache => AutoexpireCacheDalli.new(Dalli::Client.new))
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This class implements a cache with simple delegation to the Redis store, but
|
2
|
+
# when it creates a key/value pair, it also sends an EXPIRE command with a TTL.
|
3
|
+
# It should be fairly simple to do the same thing with Memcached.
|
4
|
+
class AutoexpireCacheRedis
|
5
|
+
def initialize(store, ttl = 86400)
|
6
|
+
@store = store
|
7
|
+
@ttl = ttl
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](url)
|
11
|
+
@store.[](url)
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(url, value)
|
15
|
+
@store.[]=(url, value)
|
16
|
+
@store.expire(url, @ttl)
|
17
|
+
end
|
18
|
+
|
19
|
+
def keys
|
20
|
+
@store.keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def del(url)
|
24
|
+
@store.del(url)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Geocoder.configure(:cache => AutoexpireCacheRedis.new(Redis.new))
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# This class allows you to configure how Geocoder should treat errors that occur when
|
2
|
+
# the cache is not available.
|
3
|
+
# Configure it like this
|
4
|
+
# config/initializers/geocoder.rb
|
5
|
+
# Geocoder.configure(
|
6
|
+
# :cache => Geocoder::CacheBypass.new(Redis.new)
|
7
|
+
# )
|
8
|
+
#
|
9
|
+
# Depending on the value of @bypass this will either
|
10
|
+
# raise the exception (true) or swallow it and pretend the cache did not return a hit (false)
|
11
|
+
#
|
12
|
+
class Geocoder::CacheBypass
|
13
|
+
def initialize(target, bypass = true)
|
14
|
+
@target = target
|
15
|
+
@bypass = bypass
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
with_bypass { @target[key] }
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, value)
|
24
|
+
with_bypass(value) { @target[key] = value }
|
25
|
+
end
|
26
|
+
|
27
|
+
def keys
|
28
|
+
with_bypass([]) { @target.keys }
|
29
|
+
end
|
30
|
+
|
31
|
+
def del(key)
|
32
|
+
with_bypass { @target.del(key) }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def with_bypass(return_value_if_exception = nil, &block)
|
38
|
+
begin
|
39
|
+
yield
|
40
|
+
rescue
|
41
|
+
if @bypass
|
42
|
+
return_value_if_exception
|
43
|
+
else
|
44
|
+
raise # reraise original exception
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec :path => '..'
|
4
|
+
|
5
|
+
group :development, :test do
|
6
|
+
gem 'rake'
|
7
|
+
gem 'mongoid', '2.4.11'
|
8
|
+
gem 'bson_ext', :platforms => :ruby
|
9
|
+
gem 'geoip'
|
10
|
+
|
11
|
+
gem 'rails'
|
12
|
+
|
13
|
+
platforms :jruby do
|
14
|
+
gem 'jruby-openssl'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
class ConfigGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
|
7
|
+
desc "This generator creates an initializer file at config/initializers, " +
|
8
|
+
"with the default configuration options for Geocoder."
|
9
|
+
def add_initializer
|
10
|
+
template "initializer.rb", "config/initializers/geocoder.rb"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Geocoder.configure(
|
2
|
+
# geocoding options
|
3
|
+
# :timeout => 3, # geocoding service timeout (secs)
|
4
|
+
# :lookup => :google, # name of geocoding service (symbol)
|
5
|
+
# :language => :en, # ISO-639 language code
|
6
|
+
# :use_https => false, # use HTTPS for lookup requests? (if supported)
|
7
|
+
# :http_proxy => nil, # HTTP proxy server (user:pass@host:port)
|
8
|
+
# :https_proxy => nil, # HTTPS proxy server (user:pass@host:port)
|
9
|
+
# :api_key => nil, # API key for geocoding service
|
10
|
+
# :cache => nil, # cache object (must respond to #[], #[]=, and #keys)
|
11
|
+
# :cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
|
12
|
+
|
13
|
+
# exceptions that should not be rescued by default
|
14
|
+
# (if you want to implement custom error handling);
|
15
|
+
# supports SocketError and TimeoutError
|
16
|
+
# :always_raise => [],
|
17
|
+
|
18
|
+
# calculation options
|
19
|
+
# :units => :mi, # :km for kilometers or :mi for miles
|
20
|
+
# :distances => :linear # :spherical or :linear
|
21
|
+
)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
module Generators
|
5
|
+
module Maxmind
|
6
|
+
class GeoliteCityGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
10
|
+
|
11
|
+
def copy_migration_files
|
12
|
+
migration_template "migration/geolite_city.rb", "db/migrate/geocoder_maxmind_geolite_city.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define the next_migration_number method (necessary for the
|
16
|
+
# migration_template method to work)
|
17
|
+
def self.next_migration_number(dirname)
|
18
|
+
if ActiveRecord::Base.timestamped_migrations
|
19
|
+
sleep 1 # make sure each time we get a different timestamp
|
20
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
21
|
+
else
|
22
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
module Generators
|
5
|
+
module Maxmind
|
6
|
+
class GeoliteCountryGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
10
|
+
|
11
|
+
def copy_migration_files
|
12
|
+
migration_template "migration/geolite_country.rb", "db/migrate/geocoder_maxmind_geolite_country.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define the next_migration_number method (necessary for the
|
16
|
+
# migration_template method to work)
|
17
|
+
def self.next_migration_number(dirname)
|
18
|
+
if ActiveRecord::Base.timestamped_migrations
|
19
|
+
sleep 1 # make sure each time we get a different timestamp
|
20
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
21
|
+
else
|
22
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class GeocoderMaxmindGeoliteCity < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :maxmind_geolite_city_blocks, id: false do |t|
|
4
|
+
t.column :start_ip_num, :bigint, null: false
|
5
|
+
t.column :end_ip_num, :bigint, null: false
|
6
|
+
t.column :loc_id, :bigint, null: false
|
7
|
+
end
|
8
|
+
add_index :maxmind_geolite_city_blocks, :loc_id
|
9
|
+
add_index :maxmind_geolite_city_blocks, :start_ip_num, unique: true
|
10
|
+
add_index :maxmind_geolite_city_blocks, [:end_ip_num, :start_ip_num], unique: true, name: 'index_maxmind_geolite_city_blocks_on_end_ip_num_range'
|
11
|
+
|
12
|
+
create_table :maxmind_geolite_city_location, id: false do |t|
|
13
|
+
t.column :loc_id, :bigint, null: false
|
14
|
+
t.string :country, null: false
|
15
|
+
t.string :region, null: false
|
16
|
+
t.string :city
|
17
|
+
t.string :postal_code, null: false
|
18
|
+
t.float :latitude
|
19
|
+
t.float :longitude
|
20
|
+
t.integer :metro_code
|
21
|
+
t.integer :area_code
|
22
|
+
end
|
23
|
+
add_index :maxmind_geolite_city_location, :loc_id, unique: true
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down
|
27
|
+
drop_table :maxmind_geolite_city_location
|
28
|
+
drop_table :maxmind_geolite_city_blocks
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class GeocoderMaxmindGeoliteCountry < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :maxmind_geolite_country, id: false do |t|
|
4
|
+
t.column :start_ip, :string
|
5
|
+
t.column :end_ip, :string
|
6
|
+
t.column :start_ip_num, :bigint, null: false
|
7
|
+
t.column :end_ip_num, :bigint, null: false
|
8
|
+
t.column :country_code, :string, null: false
|
9
|
+
t.column :country, :string, null: false
|
10
|
+
end
|
11
|
+
add_index :maxmind_geolite_country, :start_ip_num, unique: true
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
drop_table :maxmind_geolite_country
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Geocoder
|
2
|
+
class Cache
|
3
|
+
|
4
|
+
def initialize(store, prefix)
|
5
|
+
@store = store
|
6
|
+
@prefix = prefix
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Read from the Cache.
|
11
|
+
#
|
12
|
+
def [](url)
|
13
|
+
interpret case
|
14
|
+
when store.respond_to?(:[])
|
15
|
+
store[key_for(url)]
|
16
|
+
when store.respond_to?(:get)
|
17
|
+
store.get key_for(url)
|
18
|
+
when store.respond_to?(:read)
|
19
|
+
store.read key_for(url)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Write to the Cache.
|
25
|
+
#
|
26
|
+
def []=(url, value)
|
27
|
+
case
|
28
|
+
when store.respond_to?(:[]=)
|
29
|
+
store[key_for(url)] = value
|
30
|
+
when store.respond_to?(:set)
|
31
|
+
store.set key_for(url), value
|
32
|
+
when store.respond_to?(:write)
|
33
|
+
store.write key_for(url), value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Delete cache entry for given URL,
|
39
|
+
# or pass <tt>:all</tt> to clear all URLs.
|
40
|
+
#
|
41
|
+
def expire(url)
|
42
|
+
if url == :all
|
43
|
+
urls.each{ |u| expire(u) }
|
44
|
+
else
|
45
|
+
expire_single_url(url)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
private # ----------------------------------------------------------------
|
51
|
+
|
52
|
+
def prefix; @prefix; end
|
53
|
+
def store; @store; end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Cache key for a given URL.
|
57
|
+
#
|
58
|
+
def key_for(url)
|
59
|
+
[prefix, url].join
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Array of keys with the currently configured prefix
|
64
|
+
# that have non-nil values.
|
65
|
+
#
|
66
|
+
def keys
|
67
|
+
store.keys.select{ |k| k.match(/^#{prefix}/) and interpret(store[k]) }
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Array of cached URLs.
|
72
|
+
#
|
73
|
+
def urls
|
74
|
+
keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Clean up value before returning. Namely, convert empty string to nil.
|
79
|
+
# (Some key/value stores return empty string instead of nil.)
|
80
|
+
#
|
81
|
+
def interpret(value)
|
82
|
+
value == "" ? nil : value
|
83
|
+
end
|
84
|
+
|
85
|
+
def expire_single_url(url)
|
86
|
+
key = key_for(url)
|
87
|
+
store.respond_to?(:del) ? store.del(key) : store.delete(key)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|