geocoder 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geocoder might be problematic. Click here for more details.

@@ -2,6 +2,13 @@
2
2
 
3
3
  Per-release changes to Geocoder.
4
4
 
5
+ == 1.0.3 (2011 Sep 17)
6
+
7
+ * Fix: rake assets:precompile (Rails 3.1) not working in some situations.
8
+ * Update Google API URL (thanks github.com/soorajb).
9
+ * Allow rescue from timeout with FreeGeoIP (thanks github.com/lukeledet).
10
+ * Fix: stop double-adjusting units when using kilometers (thanks github.com/hairyheron).
11
+
5
12
  == 1.0.2 (2011 June 25)
6
13
 
7
14
  * Add support for MongoMapper (thanks github.com/spagalloco).
@@ -77,9 +77,11 @@ Reverse geocoding is similar:
77
77
  reverse_geocoded_by :coordinates
78
78
  after_validation :reverse_geocode # auto-fetch address
79
79
 
80
+ Be sure to read <i>Latitude/Longitude Order</i> in the <i>Notes on MongoDB</i> section below on how to properly retrieve latitude/longitude coordinates from your objects.
81
+
80
82
  === MongoMapper
81
83
 
82
- MongoMapper is very similar to Mongoid, just be sure to include <tt>Geocoder::Model::Mongoid</tt>.
84
+ MongoMapper is very similar to Mongoid, just be sure to include <tt>Geocoder::Model::MongoMapper</tt>.
83
85
 
84
86
  === Bulk Geocoding
85
87
 
@@ -266,6 +268,7 @@ Languages:: ar, eu, bg, bn, ca, cs, da, de, el, en, en-AU, en-GB, es, eu, fa, fi
266
268
  Documentation:: http://code.google.com/apis/maps/documentation/geocoding/#JSON
267
269
  Terms of Service:: http://code.google.com/apis/maps/terms.html#section_10_12
268
270
  Limitations:: "You must not use or display the Content without a corresponding Google map, unless you are explicitly permitted to do so in the Maps APIs Documentation, or through written permission from Google." "You must not pre-fetch, cache, or store any Content, except that you may store: (i) limited amounts of Content for the purpose of improving the performance of your Maps API Implementation..."
271
+ Notes:: To use Google Premier set <tt>Geocoder::Configuration.lookup = :google_premier</tt> and <tt>Geocoder::Configuration.api_key = [key, client, channel]</tt>.
269
272
 
270
273
  ==== Yahoo (<tt>:yahoo</tt>)
271
274
 
@@ -424,6 +427,16 @@ Mongo document classes (Mongoid and MongoMapper) have a built-in +near+ scope, b
424
427
 
425
428
  Coordinates are generally printed and spoken as latitude, then logitude ([lat,lon]). Geocoder respects this convention and always expects method arguments to be given in [lat,lon] order. However, MongoDB requires that coordinates be stored in [lon,lat] order as per the GeoJSON spec (http://geojson.org/geojson-spec.html#positions), so internally they are stored "backwards." However, this does not affect order of arguments to methods when using Mongoid or MongoMapper.
426
429
 
430
+ To access an object's coordinates in the conventional order, use the <tt>to_coordinates</tt> instance method provided by Geocoder. For example:
431
+
432
+ obj.to_coordinates # => [37.7941013, -122.3951096] # [lat, lon]
433
+
434
+ Calling <tt>obj.coordinates</tt> directly returns the internal representation of the coordinates which, in the case of MongoDB, is probably the reverse of what you want:
435
+
436
+ obj.coordinates # => [-122.3951096, 37.7941013] # [lon, lat]
437
+
438
+ For consistency with the rest of Geocoder, always use the <tt>to_coordinates</tt> method instead.
439
+
427
440
 
428
441
  == Distance Queries in SQLite
429
442
 
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ end
10
10
 
11
11
  task :default => :test
12
12
 
13
- require 'rake/rdoctask'
13
+ require 'rdoc/task'
14
14
  Rake::RDocTask.new do |rdoc|
15
15
  rdoc.rdoc_dir = 'rdoc'
16
16
  rdoc.title = "Geocoder #{Geocoder::VERSION}"
@@ -56,7 +56,7 @@ module Geocoder
56
56
  # All street address lookups, default first.
57
57
  #
58
58
  def street_lookups
59
- [:google, :yahoo, :bing, :geocoder_ca, :yandex]
59
+ [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex]
60
60
  end
61
61
 
62
62
  ##
@@ -91,12 +91,8 @@ module Geocoder
91
91
  # Retrieve a Lookup object from the store.
92
92
  #
93
93
  def get_lookup(name)
94
- unless defined?(@lookups)
95
- @lookups = {}
96
- end
97
- unless @lookups.include?(name)
98
- @lookups[name] = spawn_lookup(name)
99
- end
94
+ @lookups = {} unless defined?(@lookups)
95
+ @lookups[name] = spawn_lookup(name) unless @lookups.include?(name)
100
96
  @lookups[name]
101
97
  end
102
98
 
@@ -108,9 +104,9 @@ module Geocoder
108
104
  name = name.to_s
109
105
  require "geocoder/lookups/#{name}"
110
106
  klass = name.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
111
- eval("Geocoder::Lookup::#{klass}.new")
107
+ Geocoder::Lookup.const_get(klass).new
112
108
  else
113
- valids = valid_lookups.map{ |l| ":#{l}" }.join(", ")
109
+ valids = valid_lookups.map(&:inspect).join(", ")
114
110
  raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
115
111
  "(#{name.inspect} is not one of: #{valids})."
116
112
  end
@@ -120,7 +116,7 @@ module Geocoder
120
116
  # Does the given value look like an IP address?
121
117
  #
122
118
  # Does not check for actual validity, just the appearance of four
123
- # dot-delimited 8-bit numbers.
119
+ # dot-delimited numbers.
124
120
  #
125
121
  def ip_address?(value)
126
122
  !!value.to_s.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
@@ -22,6 +22,7 @@ module Geocoder
22
22
  [:https_proxy, nil],
23
23
 
24
24
  # API key for geocoding service
25
+ # for Google Premier use a 3-element array: [key, client, channel]
25
26
  [:api_key, nil],
26
27
 
27
28
  # cache object (must respond to #[], #[]=, and #keys)
@@ -38,20 +39,20 @@ module Geocoder
38
39
  end
39
40
 
40
41
  # define getters and setters for all configuration settings
41
- self.options_and_defaults.each do |o,d|
42
- eval("def self.#{o}; @@#{o}; end")
43
- eval("def self.#{o}=(obj); @@#{o} = obj; end")
44
- end
42
+ self.options_and_defaults.each do |option, default|
43
+ class_eval(<<-END, __FILE__, __LINE__ + 1)
44
+
45
+ @@#{option} = default unless defined? @@#{option}
46
+
47
+ def self.#{option}
48
+ @@#{option}
49
+ end
45
50
 
46
- ##
47
- # Set all values to default.
48
- #
49
- def self.set_defaults
50
- self.options_and_defaults.each do |o,d|
51
- self.send("#{o}=", d)
52
- end
51
+ def self.#{option}=(obj)
52
+ @@#{option} = obj
53
+ end
54
+
55
+ END
53
56
  end
54
57
  end
55
58
  end
56
-
57
- Geocoder::Configuration.set_defaults
@@ -87,7 +87,7 @@ module Geocoder
87
87
  # Class of the result objects
88
88
  #
89
89
  def result_class
90
- eval("Geocoder::Result::#{self.class.to_s.split(":").last}")
90
+ Geocoder::Result.const_get(self.class.to_s.split(":").last)
91
91
  end
92
92
 
93
93
  ##
@@ -12,7 +12,7 @@ module Geocoder::Lookup
12
12
 
13
13
  def results(query, reverse = false)
14
14
  return [] unless doc = fetch_data(query, reverse)
15
-
15
+
16
16
  if doc['statusDescription'] == "OK"
17
17
  return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
18
18
  else
@@ -11,7 +11,8 @@ module Geocoder::Lookup
11
11
  return [reserved_result(query)] if loopback_address?(query)
12
12
  begin
13
13
  return (doc = fetch_data(query, reverse)) ? [doc] : []
14
- rescue StandardError # Freegeoip.net returns HTML on bad request
14
+ rescue StandardError => err # Freegeoip.net returns HTML on bad request
15
+ raise_error(err)
15
16
  return []
16
17
  end
17
18
  end
@@ -31,7 +31,7 @@ module Geocoder::Lookup
31
31
  :language => Geocoder::Configuration.language,
32
32
  :key => Geocoder::Configuration.api_key
33
33
  }
34
- "#{protocol}://maps.google.com/maps/api/geocode/json?" + hash_to_query(params)
34
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(params)
35
35
  end
36
36
  end
37
37
  end
@@ -0,0 +1,38 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'geocoder/lookups/google'
4
+ require 'geocoder/results/google_premier'
5
+
6
+ module Geocoder::Lookup
7
+ class GooglePremier < Google
8
+
9
+ private # ---------------------------------------------------------------
10
+
11
+ def query_url(query, reverse = false)
12
+ params = {
13
+ (reverse ? :latlng : :address) => query,
14
+ :sensor => 'false',
15
+ :language => Geocoder::Configuration.language,
16
+ :client => Geocoder::Configuration.api_key[1],
17
+ :channel => Geocoder::Configuration.api_key[2]
18
+ }.reject{ |key, value| value.nil? }
19
+ path = "/maps/api/geocode/json?#{hash_to_query(params)}"
20
+ "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}"
21
+ end
22
+
23
+ def sign(string)
24
+ raw_private_key = url_safe_base64_decode(Geocoder::Configuration.api_key[0])
25
+ digest = OpenSSL::Digest::Digest.new('sha1')
26
+ raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
27
+ url_safe_base64_encode(raw_signature)
28
+ end
29
+
30
+ def url_safe_base64_decode(base64_string)
31
+ Base64.decode64(base64_string.tr('-_', '+/'))
32
+ end
33
+
34
+ def url_safe_base64_encode(raw)
35
+ Base64.encode64(raw).tr('+/', '-_').strip
36
+ end
37
+ end
38
+ end
@@ -31,7 +31,7 @@ module Geocoder
31
31
  unless @geocoder_options
32
32
  @geocoder_options = {}
33
33
  require "geocoder/stores/#{geocoder_file_name}"
34
- include eval("Geocoder::Store::" + geocoder_module_name)
34
+ include Geocoder::Store.const_get(geocoder_module_name)
35
35
  end
36
36
  @geocoder_options.merge! options
37
37
  end
@@ -38,14 +38,14 @@ module Geocoder
38
38
  unless geocoder_initialized?
39
39
  @geocoder_options = {}
40
40
  require "geocoder/stores/#{geocoder_file_name}"
41
- include eval("Geocoder::Store::" + geocoder_module_name)
41
+ include Geocoder::Store.const_get(geocoder_module_name)
42
42
  end
43
43
  @geocoder_options.merge! options
44
44
  end
45
45
 
46
46
  def geocoder_initialized?
47
47
  begin
48
- included_modules.include? eval("Geocoder::Store::" + geocoder_module_name)
48
+ included_modules.include? Geocoder::Store.const_get(geocoder_module_name)
49
49
  rescue NameError
50
50
  false
51
51
  end
@@ -18,7 +18,7 @@ module Geocoder
18
18
 
19
19
  class Railtie
20
20
  def self.insert
21
- if defined?(::ActiveRecord)
21
+ if ENV['RAILS_GROUPS'].to_s != 'assets' and defined?(::ActiveRecord)
22
22
  ::ActiveRecord::Base.extend(Model::ActiveRecord)
23
23
  end
24
24
  end
@@ -4,7 +4,8 @@ module Geocoder::Result
4
4
  class Freegeoip < Base
5
5
 
6
6
  def address(format = :full)
7
- "#{city}#{', ' + state_code unless state_code == ''} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
7
+ s = state_code.to_s == "" ? "" : ", #{state_code}"
8
+ "#{city}#{s} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
8
9
  end
9
10
 
10
11
  def city
@@ -51,7 +51,7 @@ module Geocoder::Result
51
51
  end
52
52
 
53
53
 
54
- private # ----------------------------------------------------------------
54
+ private # ----------------------------------------------------------------
55
55
 
56
56
  def canadian_province_abbreviations
57
57
  %w[ON QC NS NB MB BC PE SK AB NL]
@@ -82,5 +82,9 @@ module Geocoder::Result
82
82
  def geometry
83
83
  @data['geometry']
84
84
  end
85
+
86
+ def precision
87
+ geometry['location_type'] if geometry
88
+ end
85
89
  end
86
90
  end
@@ -0,0 +1,6 @@
1
+ require 'geocoder/results/google'
2
+
3
+ module Geocoder::Result
4
+ class GooglePremier < Google
5
+ end
6
+ end
@@ -66,7 +66,6 @@ module Geocoder::Store
66
66
  # * +:exclude+ - an object to exclude (used by the +nearbys+ method)
67
67
  #
68
68
  def near_scope_options(latitude, longitude, radius = 20, options = {})
69
- radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km
70
69
  if connection.adapter_name.match /sqlite/i
71
70
  approx_near_scope_options(latitude, longitude, radius, options)
72
71
  else
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -9,4 +9,5 @@ class ConfigurationTest < Test::Unit::TestCase
9
9
  Geocoder.search "something dumb"
10
10
  end
11
11
  end
12
+
12
13
  end
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class CustomBlockTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_geocode_with_block_runs_block
11
7
  e = Event.new(*venue_params(:msg))
12
8
  coords = [40.750354, -73.993371]
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class ErrorHandlingTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_does_not_choke_on_timeout
11
7
  # keep test output clean: suppress timeout warning
12
8
  orig = $VERBOSE; $VERBOSE = nil
@@ -19,13 +15,23 @@ class ErrorHandlingTest < Test::Unit::TestCase
19
15
 
20
16
  def test_always_raise_timeout_error
21
17
  Geocoder::Configuration.always_raise = [TimeoutError]
22
- assert_raise(TimeoutError) { Geocoder.search("timeout") }
18
+ all_lookups.each do |l|
19
+ lookup = Geocoder.send(:get_lookup, l)
20
+ assert_raises TimeoutError do
21
+ lookup.send(:results, "timeout")
22
+ end
23
+ end
23
24
  Geocoder::Configuration.always_raise = []
24
25
  end
25
26
 
26
27
  def test_always_raise_socket_error
27
28
  Geocoder::Configuration.always_raise = [SocketError]
28
- assert_raise(SocketError) { Geocoder.search("socket_error") }
29
+ all_lookups.each do |l|
30
+ lookup = Geocoder.send(:get_lookup, l)
31
+ assert_raises SocketError do
32
+ lookup.send(:results, "socket_error")
33
+ end
34
+ end
29
35
  Geocoder::Configuration.always_raise = []
30
36
  end
31
37
  end
@@ -0,0 +1 @@
1
+ <html><title>404: Not Found</title><body>404: Not Found</body></html>
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class GeocoderTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_distance_to_returns_float
11
7
  v = Venue.new(*venue_params(:msg))
12
8
  v.latitude, v.longitude = [40.750354, -73.993371]
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class HttpsTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_uses_https_for_secure_query
11
7
  Geocoder::Configuration.use_https = true
12
8
  g = Geocoder::Lookup::Google.new
@@ -4,9 +4,9 @@ require 'test_helper'
4
4
  class LookupTest < Test::Unit::TestCase
5
5
 
6
6
  def test_search_returns_empty_array_when_no_results
7
- street_lookups.each do |l|
8
- Geocoder::Configuration.lookup = l
9
- assert_equal [], Geocoder.search("no results"),
7
+ all_lookups.each do |l|
8
+ lookup = Geocoder.send(:get_lookup, l)
9
+ assert_equal [], lookup.send(:results, "no results"),
10
10
  "Lookup #{l} does not return empty array when no results."
11
11
  end
12
12
  end
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class MethodAliasesTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_distance_from_is_alias_for_distance_to
11
7
  v = Venue.new(*venue_params(:msg))
12
8
  v.latitude, v.longitude = [40.750354, -73.993371]
@@ -7,10 +7,6 @@ require 'mongoid_test_helper'
7
7
 
8
8
  class MongoidTest < Test::Unit::TestCase
9
9
 
10
- def setup
11
- Geocoder::Configuration.set_defaults
12
- end
13
-
14
10
  def test_geocoded_check
15
11
  p = Place.new(*venue_params(:msg))
16
12
  p.location = [40.750354, -73.993371]
@@ -4,9 +4,9 @@ require 'test/unit'
4
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
6
 
7
- Mongoid.configure do |config|
7
+ Mongoid.configure do |config|
8
8
  config.logger = Logger.new($stderr, :debug)
9
- end
9
+ end
10
10
 
11
11
  ##
12
12
  # Geocoded model.
@@ -3,10 +3,6 @@ require 'test_helper'
3
3
 
4
4
  class ProxyTest < Test::Unit::TestCase
5
5
 
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
9
-
10
6
  def test_uses_proxy_when_specified
11
7
  Geocoder::Configuration.http_proxy = 'localhost'
12
8
  lookup = Geocoder::Lookup::Google.new
@@ -1,11 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'test_helper'
3
3
 
4
- class ServicesTest < Test::Unit::TestCase
5
-
6
- def setup
7
- Geocoder::Configuration.set_defaults
8
- end
4
+ class ServicesTest < Test::Unit::TestCase
9
5
 
10
6
 
11
7
  # --- Google ---
@@ -26,6 +22,28 @@ class ServicesTest < Test::Unit::TestCase
26
22
  assert_equal nil, result.city
27
23
  end
28
24
 
25
+ def test_google_precision
26
+ result = Geocoder.search("Madison Square Garden, New York, NY").first
27
+ assert_equal "ROOFTOP",
28
+ result.precision
29
+ end
30
+
31
+
32
+ # --- Google Premier ---
33
+
34
+ def test_google_premier_result_components
35
+ Geocoder::Configuration.lookup = :google_premier
36
+ result = Geocoder.search("Madison Square Garden, New York, NY").first
37
+ assert_equal "Manhattan",
38
+ result.address_components_of_type(:sublocality).first['long_name']
39
+ end
40
+
41
+ def test_google_premier_query_url
42
+ Geocoder::Configuration.api_key = ["deadbeef", "gme-test", "test-dev"]
43
+ assert_equal "http://maps.googleapis.com/maps/api/geocode/json?address=Madison+Square+Garden%2C+New+York%2C+NY&channel=test-dev&client=gme-test&language=en&sensor=false&signature=doJvJqX7YJzgV9rJ0DnVkTGZqTg=",
44
+ Geocoder::Lookup::GooglePremier.new.send(:query_url, "Madison Square Garden, New York, NY", false)
45
+ end
46
+
29
47
 
30
48
  # --- Yahoo ---
31
49
 
@@ -73,6 +73,9 @@ module Geocoder
73
73
  end
74
74
  end
75
75
 
76
+ class GooglePremier < Google
77
+ end
78
+
76
79
  class Yahoo < Base
77
80
  private #-----------------------------------------------------------------
78
81
  def fetch_raw_data(query, reverse = false)
@@ -122,7 +125,11 @@ module Geocoder
122
125
  def fetch_raw_data(query, reverse = false)
123
126
  raise TimeoutError if query == "timeout"
124
127
  raise SocketError if query == "socket_error"
125
- read_fixture "freegeoip_74_200_247_59.json"
128
+ file = case query
129
+ when "no results"; :no_results
130
+ else "74_200_247_59"
131
+ end
132
+ read_fixture "freegeoip_#{file}.json"
126
133
  end
127
134
  end
128
135
 
@@ -224,6 +231,12 @@ end
224
231
 
225
232
 
226
233
  class Test::Unit::TestCase
234
+
235
+ def teardown
236
+ Geocoder.send(:remove_const, :Configuration)
237
+ load "geocoder/configuration.rb"
238
+ end
239
+
227
240
  def venue_params(abbrev)
228
241
  {
229
242
  :msg => ["Madison Square Garden", "4 Penn Plaza, New York, NY"]
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: geocoder
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.0.2
5
+ version: 1.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alex Reisner
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-25 00:00:00 -04:00
13
+ date: 2011-09-17 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -40,6 +40,7 @@ files:
40
40
  - lib/geocoder/lookups/freegeoip.rb
41
41
  - lib/geocoder/lookups/geocoder_ca.rb
42
42
  - lib/geocoder/lookups/google.rb
43
+ - lib/geocoder/lookups/google_premier.rb
43
44
  - lib/geocoder/lookups/yahoo.rb
44
45
  - lib/geocoder/lookups/yandex.rb
45
46
  - lib/geocoder/models/active_record.rb
@@ -54,6 +55,7 @@ files:
54
55
  - lib/geocoder/results/freegeoip.rb
55
56
  - lib/geocoder/results/geocoder_ca.rb
56
57
  - lib/geocoder/results/google.rb
58
+ - lib/geocoder/results/google_premier.rb
57
59
  - lib/geocoder/results/yahoo.rb
58
60
  - lib/geocoder/results/yandex.rb
59
61
  - lib/geocoder/stores/active_record.rb
@@ -71,6 +73,7 @@ files:
71
73
  - test/fixtures/bing_no_results.json
72
74
  - test/fixtures/bing_reverse.json
73
75
  - test/fixtures/freegeoip_74_200_247_59.json
76
+ - test/fixtures/freegeoip_no_results.json
74
77
  - test/fixtures/geocoder_ca_madison_square_garden.json
75
78
  - test/fixtures/geocoder_ca_no_results.json
76
79
  - test/fixtures/geocoder_ca_reverse.json