andre-geokit 1.1.0 → 1.2.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.
- data/Manifest.txt +2 -3
- data/README.markdown +90 -11
- data/lib/geokit.rb +3 -3
- data/lib/{geocoders.rb → geokit/geocoders.rb} +79 -9
- data/lib/{mappable.rb → geokit/mappable.rb} +2 -2
- metadata +3 -5
- data/History.txt +0 -5
data/Manifest.txt
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
.loadpath
|
2
2
|
.project
|
3
|
-
History.txt
|
4
3
|
Manifest.txt
|
5
4
|
README.markdown
|
6
5
|
Rakefile
|
7
6
|
geokit.gemspec
|
8
|
-
lib/geocoders.rb
|
7
|
+
lib/geokit/geocoders.rb
|
9
8
|
lib/geokit.rb
|
10
|
-
lib/mappable.rb
|
9
|
+
lib/geokit/mappable.rb
|
11
10
|
test/test_base_geocoder.rb
|
12
11
|
test/test_bounds.rb
|
13
12
|
test/test_ca_geocoder.rb
|
data/README.markdown
CHANGED
@@ -8,13 +8,10 @@ The Geokit gem provides the following:
|
|
8
8
|
|
9
9
|
* Distance calculations between two points on the earth. Calculate the distance in miles or KM, with all the trigonometry abstracted away by GeoKit.
|
10
10
|
* Geocoding from multiple providers. It currently supports Google, Yahoo, Geocoder.us, and Geocoder.ca geocoders, and it provides a uniform response structure from all of them. It also provides a fail-over mechanism, in case your input fails to geocode in one service.
|
11
|
+
* Rectangular bounds calculations: is a point within a given rectangular bounds?
|
12
|
+
* Heading and midpoint calculations
|
11
13
|
|
12
|
-
Combine this with gem with the geokit-rails plugin to get location-based finders for your Rails app. Plugins for other web frameworks and ORMs will provide similar functionality.
|
13
|
-
|
14
|
-
|
15
|
-
## FEATURES/PROBLEMS:
|
16
|
-
|
17
|
-
* none currently
|
14
|
+
Combine this with gem with the [geokit-rails plugin](http://github.com/andre/geokit-rails/tree/master) to get location-based finders for your Rails app. Plugins for other web frameworks and ORMs will provide similar functionality.
|
18
15
|
|
19
16
|
## SYNOPSIS:
|
20
17
|
|
@@ -30,21 +27,103 @@ Combine this with gem with the geokit-rails plugin to get location-based finders
|
|
30
27
|
=> 1.21120007413626
|
31
28
|
irb> a.heading_to(b)
|
32
29
|
=> 244.959832435678
|
30
|
+
irb(main):006:0> c=a.midpoint_to(b) # what's halfway from a to b?
|
31
|
+
irb> c.ll
|
32
|
+
=> "37.7899239257175,-122.406153503469"
|
33
|
+
irb(main):008:0> d=c.endpoint(90,10) # what's 10 miles to the east of c?
|
34
|
+
irb> d.ll
|
35
|
+
=> "37.7897825005142,-122.223214776155"
|
33
36
|
|
34
|
-
|
35
|
-
## REQUIREMENTS:
|
36
|
-
|
37
|
+
FYI, that `.ll` method means "latitude longitude".
|
37
38
|
|
38
39
|
## INSTALL:
|
39
40
|
|
40
41
|
* gem sources -a http://gems.github.com
|
41
|
-
* sudo gem install
|
42
|
+
* sudo gem install andre-geokit-gem
|
43
|
+
|
44
|
+
## Configuration
|
45
|
+
|
46
|
+
If you're using this gem by itself, here's how to set configurations:
|
47
|
+
|
48
|
+
# These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
|
49
|
+
Geokit::default_units = :miles
|
50
|
+
Geokit::default_formula = :sphere
|
51
|
+
|
52
|
+
# This is the timeout value in seconds to be used for calls to the geocoder web
|
53
|
+
# services. For no timeout at all, comment out the setting. The timeout unit
|
54
|
+
# is in seconds.
|
55
|
+
Geokit::Geocoders::timeout = 3
|
56
|
+
|
57
|
+
# These settings are used if web service calls must be routed through a proxy.
|
58
|
+
# These setting can be nil if not needed, otherwise, addr and port must be
|
59
|
+
# filled in at a minimum. If the proxy requires authentication, the username
|
60
|
+
# and password can be provided as well.
|
61
|
+
Geokit::Geocoders::proxy_addr = nil
|
62
|
+
Geokit::Geocoders::proxy_port = nil
|
63
|
+
Geokit::Geocoders::proxy_user = nil
|
64
|
+
Geokit::Geocoders::proxy_pass = nil
|
65
|
+
|
66
|
+
# This is your yahoo application key for the Yahoo Geocoder.
|
67
|
+
# See http://developer.yahoo.com/faq/index.html#appid
|
68
|
+
# and http://developer.yahoo.com/maps/rest/V1/geocode.html
|
69
|
+
Geokit::Geocoders::yahoo = 'REPLACE_WITH_YOUR_YAHOO_KEY'
|
70
|
+
|
71
|
+
# This is your Google Maps geocoder key.
|
72
|
+
# See http://www.google.com/apis/maps/signup.html
|
73
|
+
# and http://www.google.com/apis/maps/documentation/#Geocoding_Examples
|
74
|
+
Geokit::Geocoders::google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
|
75
|
+
|
76
|
+
# This is your username and password for geocoder.us.
|
77
|
+
# To use the free service, the value can be set to nil or false. For
|
78
|
+
# usage tied to an account, the value should be set to username:password.
|
79
|
+
# See http://geocoder.us
|
80
|
+
# and http://geocoder.us/user/signup
|
81
|
+
Geokit::Geocoders::geocoder_us = false
|
82
|
+
|
83
|
+
# This is your authorization key for geocoder.ca.
|
84
|
+
# To use the free service, the value can be set to nil or false. For
|
85
|
+
# usage tied to an account, set the value to the key obtained from
|
86
|
+
# Geocoder.ca.
|
87
|
+
# See http://geocoder.ca
|
88
|
+
# and http://geocoder.ca/?register=1
|
89
|
+
Geokit::Geocoders::geocoder_ca = false
|
90
|
+
|
91
|
+
# This is the order in which the geocoders are called in a failover scenario
|
92
|
+
# If you only want to use a single geocoder, put a single symbol in the array.
|
93
|
+
# Valid symbols are :google, :yahoo, :us, and :ca.
|
94
|
+
# Be aware that there are Terms of Use restrictions on how you can use the
|
95
|
+
# various geocoders. Make sure you read up on relevant Terms of Use for each
|
96
|
+
# geocoder you are going to use.
|
97
|
+
Geokit::Geocoders::provider_order = [:google,:us]
|
98
|
+
|
99
|
+
If you're using this gem with the [geokit-rails plugin](http://github.com/andre/geokit-rails/tree/master), a template with these settings gets placed in your app's config/initializers directory.
|
100
|
+
|
101
|
+
## NOTES ON WHAT'S WHERE
|
102
|
+
|
103
|
+
mappable.rb contains the Mappable module, which provides basic
|
104
|
+
distance calculation methods, i.e., calculating the distance
|
105
|
+
between two points.
|
106
|
+
|
107
|
+
mappable.rb also contains LatLng, GeoLoc, and Bounds.
|
108
|
+
LatLng is a simple container for latitude and longitude, but
|
109
|
+
it's made more powerful by mixing in the above-mentioned Mappable
|
110
|
+
module -- therefore, you can calculate easily the distance between two
|
111
|
+
LatLng ojbects with `distance = first.distance_to(other)`
|
112
|
+
|
113
|
+
GeoLoc (also in mappable.rb) represents an address or location which
|
114
|
+
has been geocoded. You can get the city, zipcode, street address, etc.
|
115
|
+
from a GeoLoc object. GeoLoc extends LatLng, so you also get lat/lng
|
116
|
+
AND the Mappable modeule goodness for free.
|
117
|
+
|
118
|
+
geocoders.rb contains all the geocoder implemenations. All the gercoders
|
119
|
+
inherit from a common base (class Geocoder) and implement the private method
|
120
|
+
do_geocode.
|
42
121
|
|
43
122
|
## LICENSE:
|
44
123
|
|
45
124
|
(The MIT License)
|
46
125
|
|
47
|
-
Copyright (c) 2007-
|
126
|
+
Copyright (c) 2007-2009 Andre Lewis and Bill Eisenhauer
|
48
127
|
|
49
128
|
Permission is hereby granted, free of charge, to any person obtaining
|
50
129
|
a copy of this software and associated documentation files (the
|
data/lib/geokit.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Geokit
|
2
|
-
VERSION = '1.
|
2
|
+
VERSION = '1.2.0'
|
3
3
|
# These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
|
4
4
|
@@default_units = :miles
|
5
5
|
@@default_formula = :sphere
|
@@ -21,8 +21,8 @@ module Geokit
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
require 'geocoders'
|
25
|
-
require 'mappable'
|
24
|
+
require 'geokit/geocoders'
|
25
|
+
require 'geokit/mappable'
|
26
26
|
|
27
27
|
# make old-style module name "GeoKit" equivilent to new-style "Geokit"
|
28
28
|
module GeoKit
|
@@ -59,11 +59,12 @@ module Geokit
|
|
59
59
|
@@google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
|
60
60
|
@@geocoder_us = false
|
61
61
|
@@geocoder_ca = false
|
62
|
+
@@geonames = false
|
62
63
|
@@provider_order = [:google,:us]
|
63
64
|
@@logger=Logger.new(STDOUT)
|
64
65
|
@@logger.level=Logger::INFO
|
65
66
|
|
66
|
-
[:yahoo, :google, :geocoder_us, :geocoder_ca, :provider_order, :timeout,
|
67
|
+
[:yahoo, :google, :geocoder_us, :geocoder_ca, :geonames, :provider_order, :timeout,
|
67
68
|
:proxy_addr, :proxy_port, :proxy_user, :proxy_pass,:logger].each do |sym|
|
68
69
|
class_eval <<-EOS, __FILE__, __LINE__
|
69
70
|
def self.#{sym}
|
@@ -111,9 +112,16 @@ module Geokit
|
|
111
112
|
private
|
112
113
|
|
113
114
|
# Wraps the geocoder call around a proxy if necessary.
|
114
|
-
def self.do_get(url)
|
115
|
-
|
116
|
-
|
115
|
+
def self.do_get(url)
|
116
|
+
uri = URI.parse(url)
|
117
|
+
req = Net::HTTP::Get.new(url)
|
118
|
+
req.basic_auth(uri.user, uri.password) if uri.userinfo
|
119
|
+
res = Net::HTTP::Proxy(GeoKit::Geocoders::proxy_addr,
|
120
|
+
GeoKit::Geocoders::proxy_port,
|
121
|
+
GeoKit::Geocoders::proxy_user,
|
122
|
+
GeoKit::Geocoders::proxy_pass).start(uri.host, uri.port) { |http| http.request(req) }
|
123
|
+
|
124
|
+
return res
|
117
125
|
end
|
118
126
|
|
119
127
|
# Adds subclass' geocode method making it conveniently available through
|
@@ -280,19 +288,32 @@ module Geokit
|
|
280
288
|
class UsGeocoder < Geocoder
|
281
289
|
|
282
290
|
private
|
283
|
-
|
284
|
-
# For now, the geocoder_method will only geocode full addresses -- not zips or cities in isolation
|
285
291
|
def self.do_geocode(address)
|
286
292
|
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
287
|
-
|
293
|
+
|
294
|
+
query = (address_str =~ /^\d{5}(?:-\d{4})?$/ ? "zip" : "address") + "=#{Geokit::Inflector::url_escape(address_str)}"
|
295
|
+
url = if GeoKit::Geocoders::geocoder_us
|
296
|
+
"http://#{GeoKit::Geocoders::geocoder_us}@geocoder.us/member/service/csv/geocode"
|
297
|
+
else
|
298
|
+
"http://geocoder.us/service/csv/geocode"
|
299
|
+
end
|
300
|
+
|
301
|
+
url = "#{url}?#{query}"
|
288
302
|
res = self.call_geocoder_service(url)
|
303
|
+
|
289
304
|
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
290
305
|
data = res.body
|
291
306
|
logger.debug "Geocoder.us geocoding. Address: #{address}. Result: #{data}"
|
292
307
|
array = data.chomp.split(',')
|
293
|
-
|
294
|
-
if array.length ==
|
308
|
+
|
309
|
+
if array.length == 5
|
295
310
|
res=GeoLoc.new
|
311
|
+
res.lat,res.lng,res.city,res.state,res.zip=array
|
312
|
+
res.country_code='US'
|
313
|
+
res.success=true
|
314
|
+
return res
|
315
|
+
elsif array.length == 6
|
316
|
+
res=GeoLoc.new
|
296
317
|
res.lat,res.lng,res.street_address,res.city,res.state,res.zip=array
|
297
318
|
res.country_code='US'
|
298
319
|
res.success=true
|
@@ -304,6 +325,7 @@ module Geokit
|
|
304
325
|
rescue
|
305
326
|
logger.error "Caught an error during geocoder.us geocoding call: "+$!
|
306
327
|
return GeoLoc.new
|
328
|
+
|
307
329
|
end
|
308
330
|
end
|
309
331
|
|
@@ -350,6 +372,54 @@ module Geokit
|
|
350
372
|
return GeoLoc.new
|
351
373
|
end
|
352
374
|
end
|
375
|
+
|
376
|
+
class GeonamesGeocoder < Geocoder
|
377
|
+
|
378
|
+
private
|
379
|
+
|
380
|
+
# Template method which does the geocode lookup.
|
381
|
+
def self.do_geocode(address)
|
382
|
+
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
383
|
+
# geonames need a space seperated search string
|
384
|
+
address_str.gsub!(/,/, " ")
|
385
|
+
params = "/postalCodeSearch?placename=#{Geokit::Inflector::url_escape(address_str)}&maxRows=10"
|
386
|
+
|
387
|
+
if(GeoKit::Geocoders::geonames)
|
388
|
+
url = "http://ws.geonames.net#{params}&username=#{GeoKit::Geocoders::geonames}"
|
389
|
+
else
|
390
|
+
url = "http://ws.geonames.org#{params}"
|
391
|
+
end
|
392
|
+
|
393
|
+
res = self.call_geocoder_service(url)
|
394
|
+
|
395
|
+
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
396
|
+
|
397
|
+
xml=res.body
|
398
|
+
logger.debug "Geonames geocoding. Address: #{address}. Result: #{xml}"
|
399
|
+
doc=REXML::Document.new(xml)
|
400
|
+
|
401
|
+
if(doc.elements['//geonames/totalResultsCount'].text.to_i > 0)
|
402
|
+
res=GeoLoc.new
|
403
|
+
|
404
|
+
# only take the first result
|
405
|
+
res.lat=doc.elements['//code/lat'].text if doc.elements['//code/lat']
|
406
|
+
res.lng=doc.elements['//code/lng'].text if doc.elements['//code/lng']
|
407
|
+
res.country_code=doc.elements['//code/countryCode'].text if doc.elements['//code/countryCode']
|
408
|
+
res.provider='genomes'
|
409
|
+
res.city=doc.elements['//code/name'].text if doc.elements['//code/name']
|
410
|
+
res.state=doc.elements['//code/adminName1'].text if doc.elements['//code/adminName1']
|
411
|
+
res.zip=doc.elements['//code/postalcode'].text if doc.elements['//code/postalcode']
|
412
|
+
res.success=true
|
413
|
+
return res
|
414
|
+
else
|
415
|
+
logger.info "Geonames was unable to geocode address: "+address
|
416
|
+
return GeoLoc.new
|
417
|
+
end
|
418
|
+
|
419
|
+
rescue
|
420
|
+
logger.error "Caught an error during Geonames geocoding call: "+$!
|
421
|
+
end
|
422
|
+
end
|
353
423
|
|
354
424
|
# Provides methods to geocode with a variety of geocoding service providers, plus failover
|
355
425
|
# among providers in the order you configure.
|
@@ -353,7 +353,7 @@ module Geokit
|
|
353
353
|
|
354
354
|
# provide sw and ne to instantiate a new Bounds instance
|
355
355
|
def initialize(sw,ne)
|
356
|
-
raise
|
356
|
+
raise ArgumentError if !(sw.is_a?(Geokit::LatLng) && ne.is_a?(Geokit::LatLng))
|
357
357
|
@sw,@ne=sw,ne
|
358
358
|
end
|
359
359
|
|
@@ -410,7 +410,7 @@ module Geokit
|
|
410
410
|
Geokit::Bounds.new(sw,ne)
|
411
411
|
end
|
412
412
|
|
413
|
-
# Takes two main combinations of
|
413
|
+
# Takes two main combinations of arguments to create a bounds:
|
414
414
|
# point,point (this is the only one which takes two arguments
|
415
415
|
# [point,point]
|
416
416
|
# . . . where a point is anything LatLng#normalize can handle (which is quite a lot)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: andre-geokit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andre Lewis and Bill Eisenhauer
|
@@ -29,17 +29,15 @@ executables: []
|
|
29
29
|
extensions: []
|
30
30
|
|
31
31
|
extra_rdoc_files:
|
32
|
-
- History.txt
|
33
32
|
- Manifest.txt
|
34
33
|
- README.markdown
|
35
34
|
files:
|
36
|
-
- History.txt
|
37
35
|
- Manifest.txt
|
38
36
|
- README.markdown
|
39
37
|
- Rakefile
|
40
|
-
- lib/geocoders.rb
|
38
|
+
- lib/geokit/geocoders.rb
|
41
39
|
- lib/geokit.rb
|
42
|
-
- lib/mappable.rb
|
40
|
+
- lib/geokit/mappable.rb
|
43
41
|
- test/test_base_geocoder.rb
|
44
42
|
- test/test_bounds.rb
|
45
43
|
- test/test_ca_geocoder.rb
|