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.
@@ -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
@@ -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-2008 Andre Lewis and Bill Eisenhauer
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
@@ -1,5 +1,5 @@
1
1
  module Geokit
2
- VERSION = '1.0.0'
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
- return Net::HTTP::Proxy(Geokit::Geocoders::proxy_addr, Geokit::Geocoders::proxy_port,
116
- Geokit::Geocoders::proxy_user, Geokit::Geocoders::proxy_pass).get_response(URI.parse(url))
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
- url = "http://"+(Geokit::Geocoders::geocoder_us || '')+"geocoder.us/service/csv/geocode?address=#{Geokit::Inflector::url_escape(address_str)}"
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 == 6
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 ArguementError if !(sw.is_a?(Geokit::LatLng) && ne.is_a?(Geokit::LatLng))
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 arguements to create a bounds:
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.1.0
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
@@ -1,5 +0,0 @@
1
- === 1.0.0 / 2008-11-30
2
-
3
- * Extracted geocoding and mappable functionality and tests from original GeoKit Rails plugin.
4
-
5
-