Add Google Map of voters
[selectricity-live] / vendor / plugins / ym4r_gm / lib / gm_plugin / geocoding.rb
1 require 'open-uri'\r
2 require 'rexml/document'\r
3 \r
4 module Ym4r\r
5   module GmPlugin\r
6     module Geocoding\r
7 \r
8       GEO_SUCCESS = 200\r
9       GEO_MISSING_ADDRESS = 601\r
10       GEO_UNKNOWN_ADDRESS = 602\r
11       GEO_UNAVAILABLE_ADDRESS = 603\r
12       GEO_BAD_KEY = 610\r
13       GEO_TOO_MANY_QUERIES = 620\r
14       GEO_SERVER_ERROR = 500\r
15       \r
16       #Gets placemarks by querying the Google Maps Geocoding service with the +request+ string. Options can either an explicity GMaps API key (<tt>:key</tt>) or a host, (<tt>:host</tt>). \r
17       def self.get(request,options = {})\r
18         api_key = ApiKey.get(options)\r
19         output =  options[:output] || "kml"\r
20         url = "http://maps.google.com/maps/geo?q=#{URI.encode(request)}&key=#{api_key}&output=#{output}"\r
21 \r
22         res = open(url).read\r
23 \r
24         case output.to_sym\r
25           when :json\r
26           res = eval(res.gsub(":","=>")) #!!!EVAL EVAL EVAL EVAL!!! hopefully we can trust google...\r
27           placemarks = Placemarks.new(res['name'],res['Status']['code'])\r
28           if res['Placemark']\r
29             placemark = res['Placemark']\r
30    \r
31             placemark.each do |data|\r
32               \r
33               data_country = data['Country']['CountryNameCode'] rescue ""\r
34               data_administrative = data['Country']['AdministrativeArea']['AdministrativeAreaName'] rescue ""\r
35               data_sub_administrative = data['Country']['AdministrativeArea']['SubAdministrativeArea']['SubAdministrativeAreaName'] rescue ""\r
36               data_locality = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName'] rescue ""\r
37               data_dependent_locality = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['DependentLocalityName'] rescue ""\r
38               data_thoroughfare = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['Thoroughfare']['ThoroughfareName'] rescue ""\r
39               data_postal_code = data['Country']['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality']['Thoroughfare']['PostalCode']['PostalCodeNumber'] rescue ""\r
40               lon, lat = data['Point']['coordinates'][0,2]\r
41               data_accuracy = data['Accuracy']\r
42               unless data_accuracy.nil?\r
43                 data_accuracy = data_accuracy.to_i\r
44               end\r
45         \r
46               placemarks << Geocoding::Placemark.new(data['address'],\r
47                                                      data_country,\r
48                                                      data_administrative,\r
49                                                      data_sub_administrative,\r
50                                                      data_locality,\r
51                                                      data_dependent_locality,\r
52                                                      data_thoroughfare,\r
53                                                      data_postal_code,\r
54                                                      lon, lat, data_accuracy)\r
55                                                      \r
56             end\r
57           end\r
58           when :kml, :xml\r
59           \r
60           doc = REXML::Document.new(res) \r
61 \r
62           response = doc.elements['//Response']\r
63           placemarks = Placemarks.new(response.elements['name'].text,response.elements['Status/code'].text.to_i)\r
64           response.elements.each(".//Placemark") do |placemark|\r
65             data = placemark.elements\r
66             data_country = data['.//CountryNameCode']\r
67             data_administrative = data['.//AdministrativeAreaName']\r
68             data_sub_administrative = data['.//SubAdministrativeAreaName']\r
69             data_locality = data['.//LocalityName']\r
70             data_dependent_locality = data['.//DependentLocalityName']\r
71             data_thoroughfare = data['.//ThoroughfareName']\r
72             data_postal_code = data['.//PostalCodeNumber']\r
73             lon, lat = data['.//coordinates'].text.split(",")[0..1].collect {|l| l.to_f }\r
74             data_accuracy = data['.//*[local-name()="AddressDetails"]'].attributes['Accuracy']\r
75             unless data_accuracy.nil?\r
76                data_accuracy = data_accuracy.to_i\r
77              end\r
78             placemarks << Geocoding::Placemark.new(data['address'].text,\r
79                                                    data_country.nil? ? "" : data_country.text,\r
80                                                    data_administrative.nil? ? "" : data_administrative.text,\r
81                                                    data_sub_administrative.nil? ? "" : data_sub_administrative.text,\r
82                                                    data_locality.nil? ? "" : data_locality.text,\r
83                                                    data_dependent_locality.nil? ? "" : data_dependent_locality.text,\r
84                                                    data_thoroughfare.nil? ? "" : data_thoroughfare.text,\r
85                                                    data_postal_code.nil? ? "" : data_postal_code.text,\r
86                                                    lon, lat, data_accuracy )\r
87           end\r
88         end\r
89                 \r
90         placemarks\r
91       end\r
92 \r
93       #Group of placemarks returned by the Geocoding service. If the result is valid the +status+ attribute should be equal to <tt>Geocoding::GE0_SUCCESS</tt>\r
94       class Placemarks < Array\r
95         attr_accessor :name,:status\r
96 \r
97         def initialize(name,status)\r
98           super(0)\r
99           @name = name\r
100           @status = status\r
101         end\r
102       end\r
103 \r
104       #A result from the Geocoding service.\r
105       class Placemark < Struct.new(:address,:country_code,:administrative_area,:sub_administrative_area,:locality,:dependent_locality,:thoroughfare,:postal_code,:longitude,:latitude,:accuracy)\r
106         def lonlat\r
107           [longitude,latitude]\r
108         end\r
109 \r
110         def latlon\r
111           [latitude,longitude]\r
112         end\r
113       end\r
114     end\r
115   end\r
116 end\r

Benjamin Mako Hill || Want to submit a patch?