geocoder 0.9.10 → 0.9.11
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.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- data/.gitignore +1 -0
 - data/CHANGELOG.rdoc +10 -0
 - data/LICENSE +1 -1
 - data/README.rdoc +118 -31
 - data/VERSION +1 -1
 - data/lib/geocoder.rb +56 -14
 - data/lib/geocoder/cache.rb +70 -0
 - data/lib/geocoder/calculations.rb +162 -22
 - data/lib/geocoder/configuration.rb +46 -9
 - data/lib/geocoder/lookups/base.rb +40 -9
 - data/lib/geocoder/lookups/freegeoip.rb +4 -6
 - data/lib/geocoder/lookups/geocoder_ca.rb +44 -0
 - data/lib/geocoder/lookups/google.rb +8 -5
 - data/lib/geocoder/lookups/yahoo.rb +6 -4
 - data/lib/geocoder/orms/active_record.rb +85 -39
 - data/lib/geocoder/orms/active_record_legacy.rb +8 -4
 - data/lib/geocoder/orms/base.rb +24 -21
 - data/lib/geocoder/request.rb +1 -1
 - data/lib/geocoder/results/base.rb +0 -14
 - data/lib/geocoder/results/geocoder_ca.rb +58 -0
 - data/lib/geocoder/results/google.rb +16 -4
 - data/test/fixtures/geocoder_ca_madison_square_garden.json +1 -0
 - data/test/fixtures/geocoder_ca_no_results.json +1 -0
 - data/test/fixtures/geocoder_ca_reverse.json +34 -0
 - data/test/fixtures/google_no_locality.json +51 -0
 - data/test/geocoder_test.rb +220 -64
 - data/test/test_helper.rb +48 -9
 - metadata +15 -14
 
| 
         @@ -6,10 +6,10 @@ module Geocoder::Lookup 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                private # ---------------------------------------------------------------
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                def  
     | 
| 
       10 
     | 
    
         
            -
                  doc = fetch_data(query, reverse)
         
     | 
| 
      
 9 
     | 
    
         
            +
                def results(query, reverse = false)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  return [] unless doc = fetch_data(query, reverse)
         
     | 
| 
       11 
11 
     | 
    
         
             
                  case doc['status']; when "OK" # OK status implies >0 results
         
     | 
| 
       12 
     | 
    
         
            -
                    doc['results'] 
     | 
| 
      
 12 
     | 
    
         
            +
                    return doc['results']
         
     | 
| 
       13 
13 
     | 
    
         
             
                  when "OVER_QUERY_LIMIT"
         
     | 
| 
       14 
14 
     | 
    
         
             
                    warn "Google Geocoding API error: over query limit."
         
     | 
| 
       15 
15 
     | 
    
         
             
                  when "REQUEST_DENIED"
         
     | 
| 
         @@ -17,14 +17,17 @@ module Geocoder::Lookup 
     | 
|
| 
       17 
17 
     | 
    
         
             
                  when "INVALID_REQUEST"
         
     | 
| 
       18 
18 
     | 
    
         
             
                    warn "Google Geocoding API error: invalid request."
         
     | 
| 
       19 
19 
     | 
    
         
             
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  return []
         
     | 
| 
       20 
21 
     | 
    
         
             
                end
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
       22 
23 
     | 
    
         
             
                def query_url(query, reverse = false)
         
     | 
| 
       23 
24 
     | 
    
         
             
                  params = {
         
     | 
| 
       24 
25 
     | 
    
         
             
                    (reverse ? :latlng : :address) => query,
         
     | 
| 
       25 
     | 
    
         
            -
                    :sensor => "false"
         
     | 
| 
      
 26 
     | 
    
         
            +
                    :sensor => "false",
         
     | 
| 
      
 27 
     | 
    
         
            +
                    :language => Geocoder::Configuration.language,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    :key => Geocoder::Configuration.api_key
         
     | 
| 
       26 
29 
     | 
    
         
             
                  }
         
     | 
| 
       27 
     | 
    
         
            -
                  " 
     | 
| 
      
 30 
     | 
    
         
            +
                  "#{protocol}://maps.google.com/maps/api/geocode/json?" + hash_to_query(params)
         
     | 
| 
       28 
31 
     | 
    
         
             
                end
         
     | 
| 
       29 
32 
     | 
    
         
             
              end
         
     | 
| 
       30 
33 
     | 
    
         
             
            end
         
     | 
| 
         @@ -6,12 +6,13 @@ module Geocoder::Lookup 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                private # ---------------------------------------------------------------
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                def  
     | 
| 
       10 
     | 
    
         
            -
                  doc = fetch_data(query, reverse)
         
     | 
| 
      
 9 
     | 
    
         
            +
                def results(query, reverse = false)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  return [] unless doc = fetch_data(query, reverse)
         
     | 
| 
       11 
11 
     | 
    
         
             
                  if doc = doc['ResultSet'] and doc['Error'] == 0
         
     | 
| 
       12 
     | 
    
         
            -
                    doc[' 
     | 
| 
      
 12 
     | 
    
         
            +
                    return doc['Found'] > 0 ? doc['Results'] : []
         
     | 
| 
       13 
13 
     | 
    
         
             
                  else
         
     | 
| 
       14 
14 
     | 
    
         
             
                    warn "Yahoo Geocoding API error: #{doc['Error']} (#{doc['ErrorMessage']})."
         
     | 
| 
      
 15 
     | 
    
         
            +
                    return []
         
     | 
| 
       15 
16 
     | 
    
         
             
                  end
         
     | 
| 
       16 
17 
     | 
    
         
             
                end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
         @@ -20,7 +21,8 @@ module Geocoder::Lookup 
     | 
|
| 
       20 
21 
     | 
    
         
             
                    :location =>  query,
         
     | 
| 
       21 
22 
     | 
    
         
             
                    :flags => "JXTSR",
         
     | 
| 
       22 
23 
     | 
    
         
             
                    :gflags => "AC#{'R' if reverse}",
         
     | 
| 
       23 
     | 
    
         
            -
                    : 
     | 
| 
      
 24 
     | 
    
         
            +
                    :locale => "#{Geocoder::Configuration.language}_US",
         
     | 
| 
      
 25 
     | 
    
         
            +
                    :appid => Geocoder::Configuration.api_key
         
     | 
| 
       24 
26 
     | 
    
         
             
                  }
         
     | 
| 
       25 
27 
     | 
    
         
             
                  "http://where.yahooapis.com/geocode?" + hash_to_query(params)
         
     | 
| 
       26 
28 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,9 +27,11 @@ module Geocoder::Orm 
     | 
|
| 
       27 
27 
     | 
    
         
             
                        "OR #{geocoder_options[:longitude]} IS NULL"}}
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                    ##
         
     | 
| 
       30 
     | 
    
         
            -
                    # Find all objects within a radius  
     | 
| 
       31 
     | 
    
         
            -
                    #  
     | 
| 
       32 
     | 
    
         
            -
                    #  
     | 
| 
      
 30 
     | 
    
         
            +
                    # Find all objects within a radius of the given location.
         
     | 
| 
      
 31 
     | 
    
         
            +
                    # Location may be either a string to geocode or an array of
         
     | 
| 
      
 32 
     | 
    
         
            +
                    # coordinates (<tt>[lat,lon]</tt>). Also takes an options hash
         
     | 
| 
      
 33 
     | 
    
         
            +
                    # (see Geocoder::Orm::ActiveRecord::ClassMethods.near_scope_options
         
     | 
| 
      
 34 
     | 
    
         
            +
                    # for details).
         
     | 
| 
       33 
35 
     | 
    
         
             
                    #
         
     | 
| 
       34 
36 
     | 
    
         
             
                    scope :near, lambda{ |location, *args|
         
     | 
| 
       35 
37 
     | 
    
         
             
                      latitude, longitude = location.is_a?(Array) ?
         
     | 
| 
         @@ -53,16 +55,22 @@ module Geocoder::Orm 
     | 
|
| 
       53 
55 
     | 
    
         
             
                  # records within a radius (in miles) of the given point.
         
     | 
| 
       54 
56 
     | 
    
         
             
                  # Options hash may include:
         
     | 
| 
       55 
57 
     | 
    
         
             
                  #
         
     | 
| 
       56 
     | 
    
         
            -
                  #  
     | 
| 
       57 
     | 
    
         
            -
                  #  
     | 
| 
       58 
     | 
    
         
            -
                  # 
     | 
| 
       59 
     | 
    
         
            -
                  # + 
     | 
| 
       60 
     | 
    
         
            -
                  #  
     | 
| 
       61 
     | 
    
         
            -
                  #  
     | 
| 
      
 58 
     | 
    
         
            +
                  # * +:units+   - <tt>:mi</tt> (default) or <tt>:km</tt>; to be used
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   for interpreting radius as well as the +distance+ attribute which
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   is added to each found nearby object
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # * +:bearing+ - <tt>:linear</tt> (default) or <tt>:spherical</tt>;
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #   the method to be used for calculating the bearing (direction)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #   between the given point and each found nearby point;
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   set to false for no bearing calculation
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # * +:select+  - string with the SELECT SQL fragment (e.g. “id, name”)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # * +:order+   - column(s) for ORDER BY SQL clause
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # * +:limit+   - number of records to return (for LIMIT SQL clause)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # * +:offset+  - number of records to skip (for OFFSET SQL clause)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # * +:exclude+ - an object to exclude (used by the +nearbys+ method)
         
     | 
| 
       62 
70 
     | 
    
         
             
                  #
         
     | 
| 
       63 
71 
     | 
    
         
             
                  def near_scope_options(latitude, longitude, radius = 20, options = {})
         
     | 
| 
       64 
72 
     | 
    
         
             
                    radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km
         
     | 
| 
       65 
     | 
    
         
            -
                    if  
     | 
| 
      
 73 
     | 
    
         
            +
                    if connection.adapter_name.match /sqlite/i
         
     | 
| 
       66 
74 
     | 
    
         
             
                      approx_near_scope_options(latitude, longitude, radius, options)
         
     | 
| 
       67 
75 
     | 
    
         
             
                    else
         
     | 
| 
       68 
76 
     | 
    
         
             
                      full_near_scope_options(latitude, longitude, radius, options)
         
     | 
| 
         @@ -74,23 +82,50 @@ module Geocoder::Orm 
     | 
|
| 
       74 
82 
     | 
    
         | 
| 
       75 
83 
     | 
    
         
             
                  ##
         
     | 
| 
       76 
84 
     | 
    
         
             
                  # Scope options hash for use with a database that supports POWER(),
         
     | 
| 
       77 
     | 
    
         
            -
                  # SQRT(), PI(), and trigonometric functions  
     | 
| 
      
 85 
     | 
    
         
            +
                  # SQRT(), PI(), and trigonometric functions SIN(), COS(), ASIN(),
         
     | 
| 
      
 86 
     | 
    
         
            +
                  # ATAN2(), DEGREES(), and RADIANS().
         
     | 
| 
       78 
87 
     | 
    
         
             
                  #
         
     | 
| 
       79 
     | 
    
         
            -
                  #  
     | 
| 
      
 88 
     | 
    
         
            +
                  # Distance calculations based on the excellent tutorial at:
         
     | 
| 
       80 
89 
     | 
    
         
             
                  # http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
         
     | 
| 
       81 
90 
     | 
    
         
             
                  #
         
     | 
| 
      
 91 
     | 
    
         
            +
                  # Bearing calculation based on:
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # http://www.beginningspatial.com/calculating_bearing_one_point_another
         
     | 
| 
      
 93 
     | 
    
         
            +
                  #
         
     | 
| 
       82 
94 
     | 
    
         
             
                  def full_near_scope_options(latitude, longitude, radius, options)
         
     | 
| 
       83 
95 
     | 
    
         
             
                    lat_attr = geocoder_options[:latitude]
         
     | 
| 
       84 
96 
     | 
    
         
             
                    lon_attr = geocoder_options[:longitude]
         
     | 
| 
       85 
     | 
    
         
            -
                     
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                      " 
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
      
 97 
     | 
    
         
            +
                    options[:bearing] = :linear unless options.include?(:bearing)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    bearing = case options[:bearing]
         
     | 
| 
      
 99 
     | 
    
         
            +
                    when :linear
         
     | 
| 
      
 100 
     | 
    
         
            +
                      "CAST(" +
         
     | 
| 
      
 101 
     | 
    
         
            +
                        "DEGREES(ATAN2( " +
         
     | 
| 
      
 102 
     | 
    
         
            +
                          "RADIANS(#{lon_attr} - #{longitude}), " +
         
     | 
| 
      
 103 
     | 
    
         
            +
                          "RADIANS(#{lat_attr} - #{latitude})" +
         
     | 
| 
      
 104 
     | 
    
         
            +
                        ")) + 360 " +
         
     | 
| 
      
 105 
     | 
    
         
            +
                      "AS decimal) % 360"
         
     | 
| 
      
 106 
     | 
    
         
            +
                    when :spherical
         
     | 
| 
      
 107 
     | 
    
         
            +
                      "CAST(" +
         
     | 
| 
      
 108 
     | 
    
         
            +
                        "DEGREES(ATAN2( " +
         
     | 
| 
      
 109 
     | 
    
         
            +
                          "SIN(RADIANS(#{lon_attr} - #{longitude})) * " +
         
     | 
| 
      
 110 
     | 
    
         
            +
                          "COS(RADIANS(#{lat_attr})), (" +
         
     | 
| 
      
 111 
     | 
    
         
            +
                            "COS(RADIANS(#{latitude})) * SIN(RADIANS(#{lat_attr}))" +
         
     | 
| 
      
 112 
     | 
    
         
            +
                          ") - (" +
         
     | 
| 
      
 113 
     | 
    
         
            +
                            "SIN(RADIANS(#{latitude})) * COS(RADIANS(#{lat_attr})) * " +
         
     | 
| 
      
 114 
     | 
    
         
            +
                            "COS(RADIANS(#{lon_attr} - #{longitude}))" +
         
     | 
| 
      
 115 
     | 
    
         
            +
                          ")" +
         
     | 
| 
      
 116 
     | 
    
         
            +
                        ")) + 360 " +
         
     | 
| 
      
 117 
     | 
    
         
            +
                      "AS decimal) % 360"
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
      
 119 
     | 
    
         
            +
                    earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    distance = "#{earth} * 2 * ASIN(SQRT(" +
         
     | 
| 
      
 121 
     | 
    
         
            +
                      "POWER(SIN((#{latitude} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
         
     | 
| 
      
 122 
     | 
    
         
            +
                      "COS(#{latitude} * PI() / 180) * COS(#{lat_attr} * PI() / 180) * " +
         
     | 
| 
      
 123 
     | 
    
         
            +
                      "POWER(SIN((#{longitude} - #{lon_attr}) * PI() / 180 / 2), 2) ))"
         
     | 
| 
       91 
124 
     | 
    
         
             
                    options[:order] ||= "#{distance} ASC"
         
     | 
| 
       92 
125 
     | 
    
         
             
                    default_near_scope_options(latitude, longitude, radius, options).merge(
         
     | 
| 
       93 
     | 
    
         
            -
                      :select => "#{options[:select] || '*'},  
     | 
| 
      
 126 
     | 
    
         
            +
                      :select => "#{options[:select] || '*'}, " +
         
     | 
| 
      
 127 
     | 
    
         
            +
                        "#{distance} AS distance" +
         
     | 
| 
      
 128 
     | 
    
         
            +
                        (bearing ? ", #{bearing} AS bearing" : ""),
         
     | 
| 
       94 
129 
     | 
    
         
             
                      :having => "#{distance} <= #{radius}"
         
     | 
| 
       95 
130 
     | 
    
         
             
                    )
         
     | 
| 
       96 
131 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -101,9 +136,33 @@ module Geocoder::Orm 
     | 
|
| 
       101 
136 
     | 
    
         
             
                  # rather than a circle, so results are very approximate (will include
         
     | 
| 
       102 
137 
     | 
    
         
             
                  # objects outside the given radius).
         
     | 
| 
       103 
138 
     | 
    
         
             
                  #
         
     | 
| 
      
 139 
     | 
    
         
            +
                  # Distance and bearing calculations are *extremely inaccurate*. They
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # only exist for interface consistency--not intended for production!
         
     | 
| 
      
 141 
     | 
    
         
            +
                  #
         
     | 
| 
       104 
142 
     | 
    
         
             
                  def approx_near_scope_options(latitude, longitude, radius, options)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    lat_attr = geocoder_options[:latitude]
         
     | 
| 
      
 144 
     | 
    
         
            +
                    lon_attr = geocoder_options[:longitude]
         
     | 
| 
      
 145 
     | 
    
         
            +
                    options[:bearing] = :linear unless options.include?(:bearing)
         
     | 
| 
      
 146 
     | 
    
         
            +
                    if options[:bearing]
         
     | 
| 
      
 147 
     | 
    
         
            +
                      bearing = "CASE " +
         
     | 
| 
      
 148 
     | 
    
         
            +
                        "WHEN (#{lat_attr} >= #{latitude} AND #{lon_attr} >= #{longitude}) THEN  45.0 " +
         
     | 
| 
      
 149 
     | 
    
         
            +
                        "WHEN (#{lat_attr} <  #{latitude} AND #{lon_attr} >= #{longitude}) THEN 135.0 " +
         
     | 
| 
      
 150 
     | 
    
         
            +
                        "WHEN (#{lat_attr} <  #{latitude} AND #{lon_attr} <  #{longitude}) THEN 225.0 " +
         
     | 
| 
      
 151 
     | 
    
         
            +
                        "WHEN (#{lat_attr} >= #{latitude} AND #{lon_attr} <  #{longitude}) THEN 315.0 " +
         
     | 
| 
      
 152 
     | 
    
         
            +
                      "END"
         
     | 
| 
      
 153 
     | 
    
         
            +
                    else
         
     | 
| 
      
 154 
     | 
    
         
            +
                      bearing = false
         
     | 
| 
      
 155 
     | 
    
         
            +
                    end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                    distance = "(#{dy} * ABS(#{lat_attr} - #{latitude}) / 2) + " +
         
     | 
| 
      
 161 
     | 
    
         
            +
                      "(#{dx} * ABS(#{lon_attr} - #{longitude}) / 2)"
         
     | 
| 
       105 
162 
     | 
    
         
             
                    default_near_scope_options(latitude, longitude, radius, options).merge(
         
     | 
| 
       106 
     | 
    
         
            -
                      :select => options[:select] ||  
     | 
| 
      
 163 
     | 
    
         
            +
                      :select => "#{options[:select] || '*'}, " +
         
     | 
| 
      
 164 
     | 
    
         
            +
                        "#{distance} AS distance" +
         
     | 
| 
      
 165 
     | 
    
         
            +
                        (bearing ? ", #{bearing} AS bearing" : "")
         
     | 
| 
       107 
166 
     | 
    
         
             
                    )
         
     | 
| 
       108 
167 
     | 
    
         
             
                  end
         
     | 
| 
       109 
168 
     | 
    
         | 
| 
         @@ -113,9 +172,10 @@ module Geocoder::Orm 
     | 
|
| 
       113 
172 
     | 
    
         
             
                  def default_near_scope_options(latitude, longitude, radius, options)
         
     | 
| 
       114 
173 
     | 
    
         
             
                    lat_attr = geocoder_options[:latitude]
         
     | 
| 
       115 
174 
     | 
    
         
             
                    lon_attr = geocoder_options[:longitude]
         
     | 
| 
      
 175 
     | 
    
         
            +
                    b = Geocoder::Calculations.bounding_box(latitude, longitude, radius, options)
         
     | 
| 
       116 
176 
     | 
    
         
             
                    conditions = \
         
     | 
| 
       117 
177 
     | 
    
         
             
                      ["#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
         
     | 
| 
       118 
     | 
    
         
            -
                       
     | 
| 
      
 178 
     | 
    
         
            +
                      [b[0], b[2], b[1], b[3]]
         
     | 
| 
       119 
179 
     | 
    
         
             
                    if obj = options[:exclude]
         
     | 
| 
       120 
180 
     | 
    
         
             
                      conditions[0] << " AND #{table_name}.id != ?"
         
     | 
| 
       121 
181 
     | 
    
         
             
                      conditions << obj.id
         
     | 
| 
         @@ -128,22 +188,6 @@ module Geocoder::Orm 
     | 
|
| 
       128 
188 
     | 
    
         
             
                      :conditions => conditions
         
     | 
| 
       129 
189 
     | 
    
         
             
                    }
         
     | 
| 
       130 
190 
     | 
    
         
             
                  end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
                  ##
         
     | 
| 
       133 
     | 
    
         
            -
                  # Get the rough high/low lat/long bounds for a geographic point and
         
     | 
| 
       134 
     | 
    
         
            -
                  # radius. Returns an array: <tt>[lat_lo, lat_hi, lon_lo, lon_hi]</tt>.
         
     | 
| 
       135 
     | 
    
         
            -
                  # Used to constrain search to a (radius x radius) square.
         
     | 
| 
       136 
     | 
    
         
            -
                  #
         
     | 
| 
       137 
     | 
    
         
            -
                  def coordinate_bounds(latitude, longitude, radius)
         
     | 
| 
       138 
     | 
    
         
            -
                    radius = radius.to_f
         
     | 
| 
       139 
     | 
    
         
            -
                    factor = (Math::cos(latitude * Math::PI / 180.0) * 69.0).abs
         
     | 
| 
       140 
     | 
    
         
            -
                    [
         
     | 
| 
       141 
     | 
    
         
            -
                      latitude  - (radius / 69.0),
         
     | 
| 
       142 
     | 
    
         
            -
                      latitude  + (radius / 69.0),
         
     | 
| 
       143 
     | 
    
         
            -
                      longitude - (radius / factor),
         
     | 
| 
       144 
     | 
    
         
            -
                      longitude + (radius / factor)
         
     | 
| 
       145 
     | 
    
         
            -
                    ]
         
     | 
| 
       146 
     | 
    
         
            -
                  end
         
     | 
| 
       147 
191 
     | 
    
         
             
                end
         
     | 
| 
       148 
192 
     | 
    
         | 
| 
       149 
193 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -151,7 +195,8 @@ module Geocoder::Orm 
     | 
|
| 
       151 
195 
     | 
    
         
             
                # (or other as specified in +geocoded_by+). Returns coordinates (array).
         
     | 
| 
       152 
196 
     | 
    
         
             
                #
         
     | 
| 
       153 
197 
     | 
    
         
             
                def geocode
         
     | 
| 
       154 
     | 
    
         
            -
                  do_lookup(false) do |o, 
     | 
| 
      
 198 
     | 
    
         
            +
                  do_lookup(false) do |o,rs|
         
     | 
| 
      
 199 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       155 
200 
     | 
    
         
             
                    unless r.latitude.nil? or r.longitude.nil?
         
     | 
| 
       156 
201 
     | 
    
         
             
                      o.send :write_attribute, self.class.geocoder_options[:latitude],  r.latitude
         
     | 
| 
       157 
202 
     | 
    
         
             
                      o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude
         
     | 
| 
         @@ -167,7 +212,8 @@ module Geocoder::Orm 
     | 
|
| 
       167 
212 
     | 
    
         
             
                # in +reverse_geocoded_by+). Returns address (string).
         
     | 
| 
       168 
213 
     | 
    
         
             
                #
         
     | 
| 
       169 
214 
     | 
    
         
             
                def reverse_geocode
         
     | 
| 
       170 
     | 
    
         
            -
                  do_lookup(true) do |o, 
     | 
| 
      
 215 
     | 
    
         
            +
                  do_lookup(true) do |o,rs|
         
     | 
| 
      
 216 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       171 
217 
     | 
    
         
             
                    unless r.address.nil?
         
     | 
| 
       172 
218 
     | 
    
         
             
                      o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
         
     | 
| 
       173 
219 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -7,7 +7,8 @@ module Geocoder::Orm::ActiveRecord 
     | 
|
| 
       7 
7 
     | 
    
         
             
                def fetch_coordinates!
         
     | 
| 
       8 
8 
     | 
    
         
             
                  warn "DEPRECATION WARNING: The 'fetch_coordinates!' method is deprecated and will be removed in geocoder v1.0. " +
         
     | 
| 
       9 
9 
     | 
    
         
             
                    "Please use 'geocode' instead and then save your objects manually."
         
     | 
| 
       10 
     | 
    
         
            -
                  do_lookup(false) do |o, 
     | 
| 
      
 10 
     | 
    
         
            +
                  do_lookup(false) do |o,rs|
         
     | 
| 
      
 11 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       11 
12 
     | 
    
         
             
                    unless r.latitude.nil? or r.longitude.nil?
         
     | 
| 
       12 
13 
     | 
    
         
             
                      o.send :update_attribute, self.class.geocoder_options[:latitude],  r.latitude
         
     | 
| 
       13 
14 
     | 
    
         
             
                      o.send :update_attribute, self.class.geocoder_options[:longitude], r.longitude
         
     | 
| 
         @@ -19,7 +20,8 @@ module Geocoder::Orm::ActiveRecord 
     | 
|
| 
       19 
20 
     | 
    
         
             
                def fetch_coordinates(*args)
         
     | 
| 
       20 
21 
     | 
    
         
             
                  warn "DEPRECATION WARNING: The 'fetch_coordinates' method will cease taking " +
         
     | 
| 
       21 
22 
     | 
    
         
             
                    "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0
         
     | 
| 
       22 
     | 
    
         
            -
                  do_lookup(false) do |o, 
     | 
| 
      
 23 
     | 
    
         
            +
                  do_lookup(false) do |o,rs|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       23 
25 
     | 
    
         
             
                    unless r.latitude.nil? or r.longitude.nil?
         
     | 
| 
       24 
26 
     | 
    
         
             
                      method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute"
         
     | 
| 
       25 
27 
     | 
    
         
             
                      o.send method, self.class.geocoder_options[:latitude],  r.latitude
         
     | 
| 
         @@ -35,7 +37,8 @@ module Geocoder::Orm::ActiveRecord 
     | 
|
| 
       35 
37 
     | 
    
         
             
                def fetch_address!
         
     | 
| 
       36 
38 
     | 
    
         
             
                  warn "DEPRECATION WARNING: The 'fetch_address!' method is deprecated and will be removed in geocoder v1.0. " +
         
     | 
| 
       37 
39 
     | 
    
         
             
                    "Please use 'reverse_geocode' instead and then save your objects manually."
         
     | 
| 
       38 
     | 
    
         
            -
                  do_lookup(true) do |o, 
     | 
| 
      
 40 
     | 
    
         
            +
                  do_lookup(true) do |o,rs|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       39 
42 
     | 
    
         
             
                    unless r.address.nil?
         
     | 
| 
       40 
43 
     | 
    
         
             
                      o.send :update_attribute, self.class.geocoder_options[:fetched_address], r.address
         
     | 
| 
       41 
44 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -46,7 +49,8 @@ module Geocoder::Orm::ActiveRecord 
     | 
|
| 
       46 
49 
     | 
    
         
             
                def fetch_address(*args)
         
     | 
| 
       47 
50 
     | 
    
         
             
                  warn "DEPRECATION WARNING: The 'fetch_address' method will cease taking " +
         
     | 
| 
       48 
51 
     | 
    
         
             
                    "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0
         
     | 
| 
       49 
     | 
    
         
            -
                  do_lookup(true) do |o, 
     | 
| 
      
 52 
     | 
    
         
            +
                  do_lookup(true) do |o,rs|
         
     | 
| 
      
 53 
     | 
    
         
            +
                    r = rs.first
         
     | 
| 
       50 
54 
     | 
    
         
             
                    unless r.latitude.nil? or r.longitude.nil?
         
     | 
| 
       51 
55 
     | 
    
         
             
                      method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute"
         
     | 
| 
       52 
56 
     | 
    
         
             
                      o.send method, self.class.geocoder_options[:fetched_address], r.address
         
     | 
    
        data/lib/geocoder/orms/base.rb
    CHANGED
    
    | 
         @@ -6,7 +6,14 @@ module Geocoder 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  # Is this object geocoded? (Does it have latitude and longitude?)
         
     | 
| 
       7 
7 
     | 
    
         
             
                  #
         
     | 
| 
       8 
8 
     | 
    
         
             
                  def geocoded?
         
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
      
 9 
     | 
    
         
            +
                    to_coordinates.compact.size > 0
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # Coordinates [lat,lon] of the object.
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def to_coordinates
         
     | 
| 
      
 16 
     | 
    
         
            +
                    [:latitude, :longitude].map{ |i| send self.class.geocoder_options[i] }
         
     | 
| 
       10 
17 
     | 
    
         
             
                  end
         
     | 
| 
       11 
18 
     | 
    
         | 
| 
       12 
19 
     | 
    
         
             
                  ##
         
     | 
| 
         @@ -16,20 +23,24 @@ module Geocoder 
     | 
|
| 
       16 
23 
     | 
    
         
             
                  #
         
     | 
| 
       17 
24 
     | 
    
         
             
                  def distance_to(lat, lon, units = :mi)
         
     | 
| 
       18 
25 
     | 
    
         
             
                    return nil unless geocoded?
         
     | 
| 
       19 
     | 
    
         
            -
                    mylat,mylon =  
     | 
| 
      
 26 
     | 
    
         
            +
                    mylat,mylon = to_coordinates
         
     | 
| 
       20 
27 
     | 
    
         
             
                    Geocoder::Calculations.distance_between(mylat, mylon, lat, lon, :units => units)
         
     | 
| 
       21 
28 
     | 
    
         
             
                  end
         
     | 
| 
       22 
29 
     | 
    
         | 
| 
       23 
30 
     | 
    
         
             
                  alias_method :distance_from, :distance_to
         
     | 
| 
       24 
31 
     | 
    
         | 
| 
       25 
32 
     | 
    
         
             
                  ##
         
     | 
| 
       26 
     | 
    
         
            -
                  # Get nearby geocoded objects. 
     | 
| 
       27 
     | 
    
         
            -
                  #  
     | 
| 
      
 33 
     | 
    
         
            +
                  # Get nearby geocoded objects.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # Takes the same options hash as the near class method (scope).
         
     | 
| 
       28 
35 
     | 
    
         
             
                  #
         
     | 
| 
       29 
     | 
    
         
            -
                  def nearbys(radius = 20,  
     | 
| 
      
 36 
     | 
    
         
            +
                  def nearbys(radius = 20, options = {})
         
     | 
| 
       30 
37 
     | 
    
         
             
                    return [] unless geocoded?
         
     | 
| 
       31 
     | 
    
         
            -
                    options 
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 38 
     | 
    
         
            +
                    if options.is_a?(Symbol)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      options = {:units => options}
         
     | 
| 
      
 40 
     | 
    
         
            +
                      warn "DEPRECATION WARNING: The units argument to the nearbys method has been replaced with an options hash (same options hash as the near scope). You should instead call: obj.nearbys(#{radius}, :units => #{options[:units]}). The old syntax will not be supported in Geocoder v1.0."
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    options.merge!(:exclude => self)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    self.class.near(to_coordinates, radius, options)
         
     | 
| 
       33 
44 
     | 
    
         
             
                  end
         
     | 
| 
       34 
45 
     | 
    
         | 
| 
       35 
46 
     | 
    
         
             
                  ##
         
     | 
| 
         @@ -53,10 +64,10 @@ module Geocoder 
     | 
|
| 
       53 
64 
     | 
    
         | 
| 
       54 
65 
     | 
    
         
             
                  ##
         
     | 
| 
       55 
66 
     | 
    
         
             
                  # Look up geographic data based on object attributes (configured in
         
     | 
| 
       56 
     | 
    
         
            -
                  # geocoded_by or reverse_geocoded_by) and handle the  
     | 
| 
      
 67 
     | 
    
         
            +
                  # geocoded_by or reverse_geocoded_by) and handle the results with the
         
     | 
| 
       57 
68 
     | 
    
         
             
                  # block (given to geocoded_by or reverse_geocoded_by). The block is
         
     | 
| 
       58 
     | 
    
         
            -
                  # given two-arguments: the object being geocoded and  
     | 
| 
       59 
     | 
    
         
            -
                  # Geocoder::Result  
     | 
| 
      
 69 
     | 
    
         
            +
                  # given two-arguments: the object being geocoded and an array of
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # Geocoder::Result objects).
         
     | 
| 
       60 
71 
     | 
    
         
             
                  #
         
     | 
| 
       61 
72 
     | 
    
         
             
                  def do_lookup(reverse = false)
         
     | 
| 
       62 
73 
     | 
    
         
             
                    options = self.class.geocoder_options
         
     | 
| 
         @@ -69,28 +80,20 @@ module Geocoder 
     | 
|
| 
       69 
80 
     | 
    
         
             
                    end
         
     | 
| 
       70 
81 
     | 
    
         
             
                    args.map!{ |a| send(options[a]) }
         
     | 
| 
       71 
82 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
                    if  
     | 
| 
      
 83 
     | 
    
         
            +
                    if (results = Geocoder.search(*args)).size > 0
         
     | 
| 
       73 
84 
     | 
    
         | 
| 
       74 
85 
     | 
    
         
             
                      # execute custom block, if specified in configuration
         
     | 
| 
       75 
86 
     | 
    
         
             
                      block_key = reverse ? :reverse_block : :geocode_block
         
     | 
| 
       76 
87 
     | 
    
         
             
                      if custom_block = options[block_key]
         
     | 
| 
       77 
     | 
    
         
            -
                        custom_block.call(self,  
     | 
| 
      
 88 
     | 
    
         
            +
                        custom_block.call(self, results)
         
     | 
| 
       78 
89 
     | 
    
         | 
| 
       79 
90 
     | 
    
         
             
                      # else execute block passed directly to this method,
         
     | 
| 
       80 
91 
     | 
    
         
             
                      # which generally performs the "auto-assigns"
         
     | 
| 
       81 
92 
     | 
    
         
             
                      elsif block_given?
         
     | 
| 
       82 
     | 
    
         
            -
                        yield(self,  
     | 
| 
      
 93 
     | 
    
         
            +
                        yield(self, results)
         
     | 
| 
       83 
94 
     | 
    
         
             
                      end
         
     | 
| 
       84 
95 
     | 
    
         
             
                    end
         
     | 
| 
       85 
96 
     | 
    
         
             
                  end
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                  ##
         
     | 
| 
       88 
     | 
    
         
            -
                  # Read the coordinates [lat,lon] of the object.
         
     | 
| 
       89 
     | 
    
         
            -
                  # Looks at user config to determine attributes.
         
     | 
| 
       90 
     | 
    
         
            -
                  #
         
     | 
| 
       91 
     | 
    
         
            -
                  def read_coordinates
         
     | 
| 
       92 
     | 
    
         
            -
                    [:latitude, :longitude].map{ |i| send self.class.geocoder_options[i] }
         
     | 
| 
       93 
     | 
    
         
            -
                  end
         
     | 
| 
       94 
97 
     | 
    
         
             
                end
         
     | 
| 
       95 
98 
     | 
    
         
             
              end
         
     | 
| 
       96 
99 
     | 
    
         
             
            end
         
     | 
    
        data/lib/geocoder/request.rb
    CHANGED
    
    
| 
         @@ -39,20 +39,6 @@ module Geocoder 
     | 
|
| 
       39 
39 
     | 
    
         
             
                  def country_code
         
     | 
| 
       40 
40 
     | 
    
         
             
                    fail
         
     | 
| 
       41 
41 
     | 
    
         
             
                  end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  def [](i)
         
     | 
| 
       44 
     | 
    
         
            -
                    if i == 0
         
     | 
| 
       45 
     | 
    
         
            -
                      warn "DEPRECATION WARNING: You called '[0]' on a Geocoder::Result object. Geocoder.search(...) now returns a single result instead of an array so this is no longer necessary. This warning will be removed and an error will result in geocoder 1.0."
         
     | 
| 
       46 
     | 
    
         
            -
                    elsif i.is_a?(Fixnum)
         
     | 
| 
       47 
     | 
    
         
            -
                      warn "DEPRECATION WARNING: You tried to access a Geocoder result but Geocoder.search(...) now returns a single result instead of an array. This warning will be removed and an error will result in geocoder 1.0."
         
     | 
| 
       48 
     | 
    
         
            -
                    end
         
     | 
| 
       49 
     | 
    
         
            -
                    self
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  def first
         
     | 
| 
       53 
     | 
    
         
            -
                    warn "DEPRECATION WARNING: You called '.first' on a Geocoder::Result object. Geocoder.search(...) now returns a single result instead of an array so this is no longer necessary. This warning will be removed and an error will result in geocoder 1.0."
         
     | 
| 
       54 
     | 
    
         
            -
                    self
         
     | 
| 
       55 
     | 
    
         
            -
                  end
         
     | 
| 
       56 
42 
     | 
    
         
             
                end
         
     | 
| 
       57 
43 
     | 
    
         
             
              end
         
     | 
| 
       58 
44 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'geocoder/results/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geocoder::Result
         
     | 
| 
      
 4 
     | 
    
         
            +
              class GeocoderCa < Base
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def coordinates
         
     | 
| 
      
 7 
     | 
    
         
            +
                  [@data['latt'].to_f, @data['longt'].to_f]
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def address(format = :full)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  "#{street_address}, #{city}, #{state} #{postal_code}, #{country}"
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def street_address
         
     | 
| 
      
 15 
     | 
    
         
            +
                  "#{@data['stnumber']} #{@data['staddress']}"
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def city
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @data['city']
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def state
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @data['prov']
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                alias_method :province, :state
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def postal_code
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @data['postal']
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def country
         
     | 
| 
      
 33 
     | 
    
         
            +
                  country_code == 'CA' ? 'Canada' : 'United States'
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def country_code
         
     | 
| 
      
 37 
     | 
    
         
            +
                  prov = @data['prov']
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return nil if prov.nil? || prov == ""
         
     | 
| 
      
 39 
     | 
    
         
            +
                  canadian_province_abbreviations.include?(@data['prov']) ? "CA" : "US"
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def canadian_province_abbreviations
         
     | 
| 
      
 43 
     | 
    
         
            +
                  %w[ON QC NS NB MB BC PE SK AB NL]
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def self.response_attributes
         
     | 
| 
      
 47 
     | 
    
         
            +
                  %w[latt longt inlatt inlongt betweenRoad1 betweenRoad2 distance
         
     | 
| 
      
 48 
     | 
    
         
            +
                    stnumber staddress city prov postal
         
     | 
| 
      
 49 
     | 
    
         
            +
                    NearRoad NearRoadDistance intersection major_intersection]
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                response_attributes.each do |a|
         
     | 
| 
      
 53 
     | 
    
         
            +
                  define_method a do
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @data[a]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     |