graticule 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/graticule.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  $:.unshift(File.dirname(__FILE__))
2
3
 
3
4
  require 'active_support'
data/lib/graticule/cli.rb CHANGED
@@ -1,11 +1,12 @@
1
+ # encoding: UTF-8
1
2
  require 'graticule'
2
3
  require 'optparse'
3
4
 
4
5
  module Graticule
5
-
6
+
6
7
  # A command line interface for geocoding. From the command line, run:
7
8
  #
8
- # geocode 49423
9
+ # geocode 49423
9
10
  #
10
11
  # Outputs:
11
12
  #
@@ -13,16 +14,16 @@ module Graticule
13
14
  # # latitude: 42.7654, longitude: -86.1085
14
15
  #
15
16
  # == Usage: geocode [options] location
16
- #
17
- # Options:
17
+ #
18
+ # Options:
18
19
  # -s, --service service Geocoding service
19
20
  # -a, --apikey apikey API key for the selected service
20
21
  # -h, --help Help
21
22
  class Cli
22
-
23
+
23
24
  def self.start(args, out = STDOUT)
24
25
  options = { :service => :yahoo, :api_key => 'YahooDemo' }
25
-
26
+
26
27
  OptionParser.new do |opts|
27
28
  opts.banner = "Usage: geocode [options] location"
28
29
  opts.separator ""
@@ -31,9 +32,9 @@ module Graticule
31
32
  opts.on("-s service", %w(yahoo google geocoder_us metacarta), "--service service", "Geocoding service") do |service|
32
33
  options[:service] = service
33
34
  end
34
-
35
+
35
36
  opts.on("-a apikey", "--apikey apikey", "API key for the selected service")
36
-
37
+
37
38
  opts.on_tail("-h", "--help", "Help") do
38
39
  puts opts
39
40
  exit
@@ -41,7 +42,7 @@ module Graticule
41
42
  end.parse! args
42
43
 
43
44
  options[:location] = args.join(" ")
44
-
45
+
45
46
  result = Graticule.service(options[:service]).new(*options[:api_key].split(',')).locate(options[:location])
46
47
  location = (result.is_a?(Array) ? result.first : result)
47
48
  if location
@@ -57,8 +58,8 @@ module Graticule
57
58
  Graticule::Error => error
58
59
  $stderr.puts error.message
59
60
  end
60
-
61
-
61
+
62
+
62
63
  end
63
64
  end
64
65
 
@@ -1,10 +1,11 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
  module RadiansAndDegrees
3
4
  # Convert from degrees to radians
4
5
  def to_radians
5
6
  ( self / 360.0 ) * Math::PI * 2
6
7
  end
7
-
8
+
8
9
  # Convert from radians to degrees
9
10
  def to_degrees
10
11
  ( self * 360.0 ) / Math::PI / 2
@@ -12,4 +13,4 @@ module Graticule
12
13
  end
13
14
  end
14
15
 
15
- Numeric.send :include, Graticule::RadiansAndDegrees
16
+ Numeric.send :include, Graticule::RadiansAndDegrees
@@ -1,6 +1,7 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
  module Distance
3
-
4
+
4
5
  EARTH_RADIUS = { :kilometers => 6378.135, :miles => 3963.1676 }
5
6
  # WGS-84 numbers
6
7
  EARTH_MAJOR_AXIS_RADIUS = { :kilometers => 6378.137, :miles => 3963.19059 }
@@ -9,7 +10,7 @@ module Graticule
9
10
  class DistanceFormula
10
11
  include Math
11
12
  extend Math
12
-
13
+
13
14
  def initialize
14
15
  raise NotImplementedError
15
16
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
  module Distance
3
4
  #
@@ -7,7 +8,7 @@ module Graticule
7
8
  # for distance formulas.
8
9
  #
9
10
  class Haversine < DistanceFormula
10
-
11
+
11
12
  # Calculate the distance between two Locations using the Haversine formula
12
13
  #
13
14
  # Graticule::Distance::Haversine.distance(
@@ -25,9 +26,9 @@ module Graticule
25
26
  latitude_delta = to_latitude - from_latitude
26
27
  longitude_delta = to_longitude - from_longitude
27
28
 
28
- a = sin(latitude_delta/2)**2 +
29
- cos(from_latitude) *
30
- cos(to_latitude) *
29
+ a = sin(latitude_delta/2)**2 +
30
+ cos(from_latitude) *
31
+ cos(to_latitude) *
31
32
  sin(longitude_delta/2)**2
32
33
 
33
34
  c = 2 * atan2(sqrt(a), sqrt(1-a))
@@ -37,4 +38,4 @@ module Graticule
37
38
 
38
39
  end
39
40
  end
40
- end
41
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
  module Distance
3
4
 
@@ -25,7 +26,7 @@ module Graticule
25
26
  Math.sin(from_latitude) *
26
27
  Math.sin(to_latitude) +
27
28
 
28
- Math.cos(from_latitude) *
29
+ Math.cos(from_latitude) *
29
30
  Math.cos(to_latitude) *
30
31
  Math.cos(to_longitude - from_longitude)
31
32
  ) * EARTH_RADIUS[units.to_sym]
@@ -46,7 +47,7 @@ module Graticule
46
47
  ) * #{Graticule::Distance::EARTH_RADIUS[options[:units].to_sym]})
47
48
  }.gsub("\n", '').squeeze(" ")
48
49
  end
49
-
50
+
50
51
  end
51
52
  end
52
- end
53
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
  module Distance
3
4
 
@@ -73,4 +74,4 @@ module Graticule
73
74
 
74
75
  end
75
76
  end
76
- end
77
+ end
@@ -1,7 +1,8 @@
1
+ # encoding: UTF-8
1
2
  require 'happymapper'
2
3
 
3
4
  module Graticule
4
-
5
+
5
6
  # Get a geocoder for the given service
6
7
  #
7
8
  # geocoder = Graticule.service(:google).new "api_key"
@@ -11,7 +12,7 @@ module Graticule
11
12
  def self.service(name)
12
13
  Geocoder.const_get name.to_s.camelize
13
14
  end
14
-
15
+
15
16
  # Base error class
16
17
  class Error < RuntimeError; end
17
18
  class CredentialsError < Error; end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'open-uri'
2
3
 
3
4
  module Graticule #:nodoc:
@@ -22,7 +23,7 @@ module Graticule #:nodoc:
22
23
  # perform URL customization, override +make_url+.
23
24
  #
24
25
  # class FakeGeocoder < Base
25
- #
26
+ #
26
27
  # def initialize(appid)
27
28
  # @appid = appid
28
29
  # @url = URI.parse 'http://example.com/test'
@@ -31,22 +32,22 @@ module Graticule #:nodoc:
31
32
  # def locate(query)
32
33
  # get :q => query
33
34
  # end
34
- #
35
+ #
35
36
  # private
36
- #
37
+ #
37
38
  # def check_error(xml)
38
39
  # raise Error, xml.elements['error'].text if xml.elements['error']
39
40
  # end
40
- #
41
+ #
41
42
  # def make_url(params)
42
43
  # params[:appid] = @appid
43
44
  # super params
44
45
  # end
45
- #
46
+ #
46
47
  # def parse_response(response)
47
48
  # # return Location
48
49
  # end
49
- #
50
+ #
50
51
  # end
51
52
  #
52
53
  class Base
@@ -55,9 +56,9 @@ module Graticule #:nodoc:
55
56
  def initialize
56
57
  raise NotImplementedError
57
58
  end
58
-
59
+
59
60
  private
60
-
61
+
61
62
  def location_from_params(params)
62
63
  case params
63
64
  when Location then params
@@ -95,7 +96,7 @@ module Graticule #:nodoc:
95
96
  url.query = escaped_params.join '&'
96
97
  return url
97
98
  end
98
-
99
+
99
100
  # Override to convert the response to something besides a String, which
100
101
  # will get passed to +check_error+ and +parse_response+.
101
102
  def prepare_response(response)
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
  # Bogus geocoder that can be used for test purposes
@@ -5,10 +6,10 @@ module Graticule #:nodoc:
5
6
  # A queue of canned responses
6
7
  class_attribute :responses
7
8
  self.responses = []
8
-
9
+
9
10
  # A default location to use if the responses queue is empty
10
- class_inheritable_accessor :default
11
-
11
+ class_attribute :default
12
+
12
13
  def locate(address)
13
14
  responses.shift || default || Location.new(:street => address)
14
15
  end
@@ -1,6 +1,7 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
-
4
+
4
5
  # freethepostcode.org (http://www.freethepostcode.org/) is a
5
6
  # free service to convert UK postcodes into geolocation data.
6
7
  #
@@ -17,13 +18,13 @@ module Graticule #:nodoc:
17
18
  def locate(postcode)
18
19
  get :postcode => postcode
19
20
  end
20
-
21
+
21
22
  private
22
23
 
23
24
  def prepare_response(response)
24
25
  response.split("\n")[1]
25
26
  end
26
-
27
+
27
28
  def parse_response(response)
28
29
  data = response.split
29
30
  Location.new(:latitude => data[0].to_f, :longitude => data[1].to_f, :precision => :unknown)
@@ -32,7 +33,7 @@ module Graticule #:nodoc:
32
33
  def check_error(response)
33
34
  raise AddressError, 'unknown address' if response.blank?
34
35
  end
35
-
36
+
36
37
  end
37
38
  end
38
39
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
 
@@ -12,9 +13,9 @@ module Graticule #:nodoc:
12
13
  def locate(address)
13
14
  get :locate => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
14
15
  end
15
-
16
+
16
17
  private
17
-
18
+
18
19
  class Response
19
20
  include HappyMapper
20
21
  tag 'geodata'
@@ -25,25 +26,25 @@ module Graticule #:nodoc:
25
26
  element :locality, String, :deep => true, :tag => 'city'
26
27
  element :postal_code, String, :tag => 'postal'
27
28
  element :region, String, :deep => true, :tag => 'prov'
28
-
29
+
29
30
  class Error
30
31
  include HappyMapper
31
32
  tag 'error'
32
33
  element :code, Integer
33
34
  element :description, String
34
35
  end
35
-
36
+
36
37
  has_one :error, Error
37
-
38
+
38
39
  def street
39
40
  [street_number, street_name].join(' ')
40
41
  end
41
42
  end
42
-
43
+
43
44
  def prepare_response(xml)
44
45
  Response.parse(xml, :single => true)
45
46
  end
46
-
47
+
47
48
  def parse_response(response) #:nodoc:
48
49
  Location.new(
49
50
  :latitude => response.latitude,
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
 
@@ -27,13 +28,13 @@ module Graticule #:nodoc:
27
28
  def locate(address)
28
29
  get :address => address.is_a?(String) ? address : location_from_params(address).to_s(:country => false)
29
30
  end
30
-
31
+
31
32
  private
32
33
  class Point
33
34
  include HappyMapper
34
35
  tag 'Point'
35
36
  namespace 'http://www.w3.org/2003/01/geo/wgs84_pos#'
36
-
37
+
37
38
  element :description, String, :namespace => 'http://purl.org/dc/elements/1.1/'
38
39
  element :longitude, Float, :tag => 'long'
39
40
  element :latitude, Float, :tag => 'lat'
@@ -1,30 +1,31 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
  class Geonames < Base
4
-
5
+
5
6
  def initialize
6
7
  @url = URI.parse 'http://ws.geonames.org/timezone'
7
8
  end
8
-
9
+
9
10
  def time_zone(location)
10
- get :formatted => 'true', :style => 'full', :lat => location.latitude, :lng => location.longitude
11
+ get :formatted => 'true', :style => 'full', :lat => location.latitude, :lng => location.longitude
11
12
  end
12
-
13
- private
13
+
14
+ private
14
15
  class Status
15
16
  include HappyMapper
16
17
  tag 'status'
17
18
  attribute :message, String
18
19
  attribute :value, String
19
20
  end
20
-
21
+
21
22
  class Response
22
23
  include HappyMapper
23
24
  tag 'geonames'
24
25
  element :timezoneId, String, :deep => true
25
26
  has_one :status, Status
26
27
  end
27
-
28
+
28
29
  def prepare_response(xml)
29
30
  Response.parse(xml, :single => true)
30
31
  end
@@ -32,7 +33,7 @@ module Graticule #:nodoc:
32
33
  def parse_response(response) #:nodoc:
33
34
  response.timezoneId
34
35
  end
35
-
36
+
36
37
  # Extracts and raises an error from +xml+, if any.
37
38
  def check_error(response) #:nodoc:
38
39
  if response && response.status
@@ -1,9 +1,10 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
-
4
+
4
5
  # First you need a Google Maps API key. You can register for one here:
5
6
  # http://www.google.com/apis/maps/signup.html
6
- #
7
+ #
7
8
  # gg = Graticule.service(:google).new(MAPS_API_KEY)
8
9
  # location = gg.locate '1600 Amphitheater Pkwy, Mountain View, CA'
9
10
  # p location.coordinates
@@ -11,7 +12,7 @@ module Graticule #:nodoc:
11
12
  #
12
13
  class Google < Base
13
14
  # http://www.google.com/apis/maps/documentation/#Geocoding_HTTP_Request
14
-
15
+
15
16
  # http://www.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy
16
17
  PRECISION = {
17
18
  0 => Precision::Unknown, # Unknown location.
@@ -44,15 +45,15 @@ module Graticule #:nodoc:
44
45
 
45
46
  attribute :accuracy, Integer, :tag => 'Accuracy'
46
47
  end
47
-
48
+
48
49
  class Placemark
49
50
  include HappyMapper
50
51
  tag 'Placemark'
51
52
  element :coordinates, String, :deep => true
52
53
  has_one :address, Address
53
-
54
+
54
55
  attr_reader :longitude, :latitude
55
-
56
+
56
57
  with_options :deep => true, :namespace => 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0' do |map|
57
58
  map.element :street, String, :tag => 'ThoroughfareName'
58
59
  map.element :locality, String, :tag => 'LocalityName'
@@ -60,27 +61,27 @@ module Graticule #:nodoc:
60
61
  map.element :postal_code, String, :tag => 'PostalCodeNumber'
61
62
  map.element :country, String, :tag => 'CountryNameCode'
62
63
  end
63
-
64
+
64
65
  def coordinates=(coordinates)
65
66
  @longitude, @latitude, _ = coordinates.split(',').map { |v| v.to_f }
66
67
  end
67
-
68
+
68
69
  def accuracy
69
70
  address.accuracy if address
70
71
  end
71
-
72
+
72
73
  def precision
73
74
  PRECISION[accuracy] || :unknown
74
75
  end
75
76
  end
76
-
77
+
77
78
  class Response
78
79
  include HappyMapper
79
80
  tag 'Response'
80
81
  element :code, Integer, :tag => 'code', :deep => true
81
82
  has_many :placemarks, Placemark
82
83
  end
83
-
84
+
84
85
  def prepare_response(xml)
85
86
  Response.parse(xml, :single => true)
86
87
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'yaml'
2
3
 
3
4
  module Graticule #:nodoc:
@@ -13,14 +14,14 @@ module Graticule #:nodoc:
13
14
  def locate(address)
14
15
  get :ip => address, :position => true
15
16
  end
16
-
17
+
17
18
  private
18
-
19
+
19
20
  def prepare_response(response)
20
21
  # add new line so YAML.load doesn't puke
21
22
  YAML.load(response + "\n")
22
23
  end
23
-
24
+
24
25
  def parse_response(response) #:nodoc:
25
26
  Location.new.tap do |location|
26
27
  location.latitude = response['Latitude']
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
 
@@ -5,20 +6,20 @@ module Graticule #:nodoc:
5
6
  #
6
7
  # See http://emad.fano.us/blog/?p=277
7
8
  class LocalSearchMaps < Base
8
-
9
+
9
10
  def initialize
10
11
  @url = URI.parse 'http://geo.localsearchmaps.com/'
11
12
  end
12
-
13
+
13
14
  # This web service will handle some addresses outside the US
14
15
  # if given more structured arguments than just a string address
15
16
  # So allow input as a hash for the different arguments (:city, :country, :zip)
16
17
  def locate(params)
17
18
  get params.is_a?(String) ? {:loc => params} : map_attributes(location_from_params(params))
18
19
  end
19
-
20
+
20
21
  private
21
-
22
+
22
23
  def map_attributes(location)
23
24
  mapping = {:street => :street, :locality => :city, :region => :state, :postal_code => :zip, :country => :country}
24
25
  mapping.keys.inject({}) do |result,attribute|
@@ -26,7 +27,7 @@ module Graticule #:nodoc:
26
27
  result
27
28
  end
28
29
  end
29
-
30
+
30
31
  def check_error(js)
31
32
  case js
32
33
  when nil
@@ -35,12 +36,12 @@ module Graticule #:nodoc:
35
36
  raise AddressError, 'Location not found'
36
37
  end
37
38
  end
38
-
39
+
39
40
  def parse_response(js)
40
41
  coordinates = js.match(/map.centerAndZoom\(new GPoint\((.+?), (.+?)\)/)
41
42
  Location.new(:longitude => coordinates[1].to_f, :latitude => coordinates[2].to_f)
42
43
  end
43
-
44
+
44
45
  end
45
46
  end
46
47
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
 
@@ -6,10 +7,10 @@ module Graticule #:nodoc:
6
7
  # http://developer.mapquest.com/Home/Register?_devAPISignup_WAR_devAPISignup_action=signup&_devAPISignup_WAR_devAPISignup_clientType=Developer
7
8
  #
8
9
  # mq = Graticule.service(:mapquest).new(CLIENT_ID, PASSWORD)
9
- # location = gg.locate('44 Allen Rd., Lovell, ME 04051')
10
+ # location = gg.locate('44 Allen Rd., Lovell, ME 04051')
10
11
  # [42.78942, -86.104424]
11
12
  #
12
- class Mapquest < Base
13
+ class Mapquest < Base
13
14
  # I would link to the documentation here, but there is none that will do anything but confuse you.
14
15
 
15
16
  PRECISION = {
@@ -48,7 +49,7 @@ module Graticule #:nodoc:
48
49
  url.query = URI.escape(query)
49
50
  url
50
51
  end
51
-
52
+
52
53
  class Address
53
54
  include HappyMapper
54
55
  tag 'GeoAddress'
@@ -60,18 +61,18 @@ module Graticule #:nodoc:
60
61
  element :postal_code, String, :tag => 'PostalCode'
61
62
  element :country, String, :tag => 'AdminArea1'
62
63
  element :result_code, String, :tag => 'ResultCode'
63
-
64
+
64
65
  def precision
65
66
  PRECISION[result_code.to_s[0,2]] || :unknown
66
67
  end
67
68
  end
68
-
69
+
69
70
  class Result
70
71
  include HappyMapper
71
72
  tag 'GeocodeResponse'
72
73
  has_many :addresses, Address, :deep => true
73
74
  end
74
-
75
+
75
76
  def prepare_response(xml)
76
77
  Result.parse(xml, :single => true)
77
78
  end
@@ -1,9 +1,10 @@
1
+ # encoding: UTF-8
1
2
  require 'timeout'
2
3
 
3
4
  module Graticule #:nodoc:
4
5
  module Geocoder #:nodoc:
5
6
  class Multi
6
-
7
+
7
8
  # The Multi geocoder allows you to use multiple geocoders in succession.
8
9
  #
9
10
  # geocoder = Graticule.service(:multi).new(
@@ -30,10 +31,10 @@ module Graticule #:nodoc:
30
31
  #
31
32
  def initialize(*geocoders, &acceptable)
32
33
  @options = {:timeout => 10, :async => false}.merge(geocoders.extract_options!)
33
- @acceptable = acceptable || lambda { true }
34
- @geocoders = geocoders.flatten
34
+ @acceptable = acceptable || Proc.new { true }
35
+ @geocoders = geocoders
35
36
  end
36
-
37
+
37
38
  def locate(address)
38
39
  @lookup = @options[:async] ? ParallelLookup.new : SerialLookup.new
39
40
  last_error = nil
@@ -53,16 +54,16 @@ module Graticule #:nodoc:
53
54
  end
54
55
  @lookup.result || raise(last_error || AddressError.new("Couldn't find '#{address}' with any of the services"))
55
56
  end
56
-
57
+
57
58
  class SerialLookup #:nodoc:
58
59
  def initialize
59
60
  @blocks = []
60
61
  end
61
-
62
+
62
63
  def perform(&block)
63
64
  @blocks << block
64
65
  end
65
-
66
+
66
67
  def result
67
68
  result = nil
68
69
  @blocks.detect do |block|
@@ -71,19 +72,19 @@ module Graticule #:nodoc:
71
72
  result
72
73
  end
73
74
  end
74
-
75
+
75
76
  class ParallelLookup #:nodoc:
76
77
  def initialize
77
78
  @threads = []
78
79
  @monitor = Monitor.new
79
80
  end
80
-
81
+
81
82
  def perform(&block)
82
83
  @threads << Thread.new do
83
84
  self.result = block.call
84
85
  end
85
86
  end
86
-
87
+
87
88
  def result=(result)
88
89
  if result
89
90
  @monitor.synchronize do
@@ -92,7 +93,7 @@ module Graticule #:nodoc:
92
93
  end
93
94
  end
94
95
  end
95
-
96
+
96
97
  def result
97
98
  @threads.each(&:join)
98
99
  @result
@@ -1,14 +1,15 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
4
 
4
5
  # Multimap geocoding API
5
-
6
+
6
7
  class Multimap < Base
7
-
8
+
8
9
  # This precision information is not complete.
9
10
  # More details should be implemented from:
10
11
  # http://www.multimap.com/share/documentation/clientzone/gqcodes.htm
11
-
12
+
12
13
  PRECISION = {
13
14
  6 => Precision::Country,
14
15
  5 => Precision::Region,
@@ -17,39 +18,39 @@ module Graticule #:nodoc:
17
18
  2 => Precision::Street,
18
19
  1 => Precision::Address
19
20
  }
20
-
21
+
21
22
  # Web services initializer.
22
23
  #
23
24
  # The +api_key+ is the Open API key that uniquely identifies your
24
25
  # application.
25
26
  #
26
27
  # See http://www.multimap.com/openapi/
27
-
28
+
28
29
  def initialize(api_key)
29
30
  @api_key = api_key
30
31
  @url = URI.parse "http://clients.multimap.com/API/geocode/1.2/#{@api_key}"
31
32
  end
32
-
33
+
33
34
  # Returns a location for an address in the form of a String, Hash or Location.
34
-
35
+
35
36
  def locate(address)
36
37
  location = address.is_a?(String) ? address : location_from_params(address)
37
38
  case location
38
39
  when String
39
40
  get :qs => location
40
41
  when Location
41
- get "street" => location.street,
42
- "region" => location.region,
43
- "city" => location.locality,
44
- "postalCode" => location.postal_code,
42
+ get "street" => location.street,
43
+ "region" => location.region,
44
+ "city" => location.locality,
45
+ "postalCode" => location.postal_code,
45
46
  "countryCode" => location.country
46
47
  end
47
48
  end
48
-
49
+
49
50
  class Address
50
51
  include HappyMapper
51
52
  tag 'Location'
52
-
53
+
53
54
  attribute :quality, Integer, :tag => 'geocodeQuality'
54
55
  element :street, String, :tag => 'Street', :deep => true
55
56
  element :locality, String, :tag => 'Area', :deep => true
@@ -58,23 +59,23 @@ module Graticule #:nodoc:
58
59
  element :country, String, :tag => 'CountryCode', :deep => true
59
60
  element :latitude, Float, :tag => 'Lat', :deep => true
60
61
  element :longitude, Float, :tag => 'Lon', :deep => true
61
-
62
+
62
63
  def precision
63
64
  PRECISION[quality] || :unknown
64
65
  end
65
66
  end
66
-
67
+
67
68
  class Result
68
69
  include HappyMapper
69
70
  tag 'Results'
70
71
  attribute :error, String, :tag => 'errorCode'
71
72
  has_many :addresses, Address
72
73
  end
73
-
74
+
74
75
  def prepare_response(xml)
75
76
  Result.parse(xml, :single => true)
76
77
  end
77
-
78
+
78
79
  def parse_response(result)
79
80
  addr = result.addresses.first
80
81
  Location.new(
@@ -88,11 +89,11 @@ module Graticule #:nodoc:
88
89
  :precision => addr.precision
89
90
  )
90
91
  end
91
-
92
+
92
93
  def check_error(result)
93
94
  raise Error, result.error unless result.error.blank?
94
95
  end
95
-
96
+
96
97
  end
97
98
  end
98
99
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'json'
2
3
 
3
4
  module Graticule
@@ -1,6 +1,7 @@
1
+ # encoding: UTF-8
1
2
  module Graticule #:nodoc:
2
3
  module Geocoder #:nodoc:
3
-
4
+
4
5
  # Yahoo geocoding API.
5
6
  #
6
7
  # http://developer.yahoo.com/maps/rest/V1/geocode.html
@@ -42,13 +43,13 @@ module Graticule #:nodoc:
42
43
  # yahoo pukes on line breaks
43
44
  get :location => location.gsub("\n", ', ')
44
45
  end
45
-
46
+
46
47
  private
47
-
48
+
48
49
  class Address
49
50
  include HappyMapper
50
51
  tag 'Result'
51
-
52
+
52
53
  attribute :precision, String
53
54
  attribute :warning, String
54
55
  element :latitude, Float, :tag => 'Latitude'
@@ -58,24 +59,24 @@ module Graticule #:nodoc:
58
59
  element :region, String, :tag => 'State'
59
60
  element :postal_code, String, :tag => 'Zip'
60
61
  element :country, String, :tag => 'Country'
61
-
62
+
62
63
  def precision
63
64
  PRECISION[@precision] || :unknown
64
65
  end
65
66
  end
66
-
67
+
67
68
  class Result
68
69
  include HappyMapper
69
70
  tag 'ResultSet'
70
71
  has_many :addresses, Address
71
72
  end
72
-
73
+
73
74
  class Error
74
75
  include HappyMapper
75
76
  tag 'Error'
76
77
  element :message, String, :tag => 'Message'
77
78
  end
78
-
79
+
79
80
  def parse_response(response) # :nodoc:
80
81
  addr = Result.parse(response, :single => true).addresses.first
81
82
  Location.new(
@@ -108,6 +109,6 @@ module Graticule #:nodoc:
108
109
  end
109
110
 
110
111
  end
111
-
112
+
112
113
  end
113
114
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
3
 
3
4
  # A geographic location
@@ -9,7 +10,7 @@ module Graticule
9
10
 
10
11
  def initialize(attrs = {})
11
12
  attrs.each do |key,value|
12
- self.send("#{key}=", value)
13
+ self.send("#{key}=", value.respond_to?(:force_encoding) ? value.force_encoding('UTF-8') : value)
13
14
  end
14
15
  self.precision ||= :unknown
15
16
  end
@@ -1,10 +1,11 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
-
3
+
3
4
  # Used to compare the precision of different geocoded locations
4
5
  class Precision
5
6
  include Comparable
6
7
  attr_reader :name
7
-
8
+
8
9
  NAMES = [
9
10
  :unknown,
10
11
  :country,
@@ -15,12 +16,12 @@ module Graticule
15
16
  :address,
16
17
  :premise
17
18
  ]
18
-
19
+
19
20
  def initialize(name)
20
21
  @name = name.to_sym
21
22
  raise ArgumentError, "#{name} is not a valid precision. Use one of #{NAMES.inspect}" unless NAMES.include?(@name)
22
23
  end
23
-
24
+
24
25
  Unknown = Precision.new(:unknown)
25
26
  Country = Precision.new(:country)
26
27
  Region = Precision.new(:region)
@@ -29,16 +30,16 @@ module Graticule
29
30
  Street = Precision.new(:street)
30
31
  Address = Precision.new(:address)
31
32
  Premise = Precision.new(:premise)
32
-
33
+
33
34
  def to_s
34
35
  @name.to_s
35
36
  end
36
-
37
+
37
38
  def <=>(other)
38
39
  other = Precision.new(other) unless other.is_a?(Precision)
39
40
  NAMES.index(self.name) <=> NAMES.index(other.name)
40
41
  end
41
-
42
+
42
43
  def ==(other)
43
44
  (self <=> other) == 0
44
45
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Graticule
2
- VERSION = '2.0.1' unless defined?(::Graticule::VERSION)
3
+ VERSION = '2.1.0' unless defined?(::Graticule::VERSION)
3
4
  end
metadata CHANGED
@@ -1,119 +1,92 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: graticule
3
- version: !ruby/object:Gem::Version
4
- hash: 13
5
- prerelease: false
6
- segments:
7
- - 2
8
- - 0
9
- - 1
10
- version: 2.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Brandon Keepers
14
9
  - Daniel Morrison
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2011-02-28 00:00:00 -05:00
20
- default_executable: geocode
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
23
- version_requirements: &id001 !ruby/object:Gem::Requirement
13
+ date: 2011-08-05 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ requirement: &70239866982580 !ruby/object:Gem::Requirement
24
18
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
32
- requirement: *id001
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
33
23
  type: :runtime
34
- name: activesupport
35
24
  prerelease: false
36
- - !ruby/object:Gem::Dependency
37
- version_requirements: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *70239866982580
26
+ - !ruby/object:Gem::Dependency
27
+ name: i18n
28
+ requirement: &70239866981940 !ruby/object:Gem::Requirement
38
29
  none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
46
- requirement: *id002
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
47
34
  type: :runtime
48
- name: i18n
49
35
  prerelease: false
50
- - !ruby/object:Gem::Dependency
51
- version_requirements: &id003 !ruby/object:Gem::Requirement
36
+ version_requirements: *70239866981940
37
+ - !ruby/object:Gem::Dependency
38
+ name: happymapper
39
+ requirement: &70239866981260 !ruby/object:Gem::Requirement
52
40
  none: false
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- hash: 19
57
- segments:
58
- - 0
59
- - 3
60
- - 0
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
61
44
  version: 0.3.0
62
- requirement: *id003
63
45
  type: :runtime
64
- name: happymapper
65
46
  prerelease: false
66
- - !ruby/object:Gem::Dependency
67
- version_requirements: &id004 !ruby/object:Gem::Requirement
47
+ version_requirements: *70239866981260
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ requirement: &70239866980440 !ruby/object:Gem::Requirement
68
51
  none: false
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
- version: "0"
76
- requirement: *id004
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
77
56
  type: :runtime
78
- name: json
79
57
  prerelease: false
80
- - !ruby/object:Gem::Dependency
81
- version_requirements: &id005 !ruby/object:Gem::Requirement
58
+ version_requirements: *70239866980440
59
+ - !ruby/object:Gem::Dependency
60
+ name: mocha
61
+ requirement: &70239866979600 !ruby/object:Gem::Requirement
82
62
  none: false
83
- requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- hash: 3
87
- segments:
88
- - 0
89
- version: "0"
90
- requirement: *id005
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
91
67
  type: :development
92
- name: mocha
93
68
  prerelease: false
94
- - !ruby/object:Gem::Dependency
95
- version_requirements: &id006 !ruby/object:Gem::Requirement
69
+ version_requirements: *70239866979600
70
+ - !ruby/object:Gem::Dependency
71
+ name: rcov
72
+ requirement: &70239866978740 !ruby/object:Gem::Requirement
96
73
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- hash: 3
101
- segments:
102
- - 0
103
- version: "0"
104
- requirement: *id006
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
105
78
  type: :development
106
- name: rcov
107
79
  prerelease: false
108
- description: Graticule is a geocoding API that provides a common interface to all the popular services, including Google, Yahoo, Geocoder.us, and MetaCarta.
80
+ version_requirements: *70239866978740
81
+ description: Graticule is a geocoding API that provides a common interface to all
82
+ the popular services, including Google, Yahoo, Geocoder.us, and MetaCarta.
109
83
  email: brandon@opensoul.org
110
- executables:
84
+ executables:
111
85
  - geocode
112
86
  extensions: []
113
-
114
- extra_rdoc_files:
87
+ extra_rdoc_files:
115
88
  - README.textile
116
- files:
89
+ files:
117
90
  - bin/geocode
118
91
  - lib/graticule/cli.rb
119
92
  - lib/graticule/core_ext.rb
@@ -143,42 +116,38 @@ files:
143
116
  - CHANGELOG.txt
144
117
  - LICENSE.txt
145
118
  - README.textile
146
- has_rdoc: true
147
119
  homepage: http://github.com/collectiveidea/graticule
148
120
  licenses: []
149
-
150
121
  post_install_message:
151
- rdoc_options:
122
+ rdoc_options:
152
123
  - --main
153
124
  - README.rdoc
154
125
  - --inline-source
155
126
  - --line-numbers
156
- require_paths:
127
+ require_paths:
157
128
  - lib
158
- required_ruby_version: !ruby/object:Gem::Requirement
129
+ required_ruby_version: !ruby/object:Gem::Requirement
159
130
  none: false
160
- requirements:
161
- - - ">="
162
- - !ruby/object:Gem::Version
163
- hash: 3
164
- segments:
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ segments:
165
136
  - 0
166
- version: "0"
167
- required_rubygems_version: !ruby/object:Gem::Requirement
137
+ hash: -334130965420677482
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
139
  none: false
169
- requirements:
170
- - - ">="
171
- - !ruby/object:Gem::Version
172
- hash: 3
173
- segments:
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ segments:
174
145
  - 0
175
- version: "0"
146
+ hash: -334130965420677482
176
147
  requirements: []
177
-
178
148
  rubyforge_project: graticule
179
- rubygems_version: 1.3.7
149
+ rubygems_version: 1.8.6
180
150
  signing_key:
181
151
  specification_version: 3
182
152
  summary: API for using all the popular geocoding services.
183
153
  test_files: []
184
-