class GmapsGeocoding::Api
Google Maps Geocoding Service abstraction class
@example
opts = {address: 'Tour Eiffel, Paris, IDF, France', output: 'json'} api = GmapsGeocoding::Api.new(opts)
Attributes
Public Class Methods
# File lib/gmaps_geocoding/api.rb, line 19 def initialize(opts = {}) @logger = opts.delete(:logger) unless @logger @logger = Logger.new(STDERR) do |l| l.progname = 'gmaps_geocoding' l.level = $DEBUG ? Logger::DEBUG : Logger::INFO end end @config = GmapsGeocoding::Config.new(opts) Oj.default_options = Oj.default_options.merge(bigdecimal_load: :float, float_precision: 7) end
Public Instance Methods
Get the best latlng for an address based on Google Maps Geocoder “location_type”
location_type stores additional data about the specified location. The following values are currently supported:
google.maps.GeocoderLocationType.ROOFTOP indicates that the returned result reflects a precise geocode. google.maps.GeocoderLocationType.RANGE_INTERPOLATED indicates that the returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address. google.maps.GeocoderLocationType.GEOMETRIC_CENTER indicates that the returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region). google.maps.GeocoderLocationType.APPROXIMATE indicates that the returned result is approximate.
@example
# json output example opts = {address: 'Tour Eiffel, Paris, IDF, France', output: 'json'} api = GmapsGeocoding::Api.new(opts) data = api.location if data.include?('status') && data['status'].eql?('OK') # or more simple : if data.include?('results') return finest_latlng(data['results']) # output : [2.291018, 48.857269] end
@param data [Array] The json#results or xml#result array from {#location} method @return [Array] array contains latitude and longitude of the location rubocop:disable Metrics/AbcSize
# File lib/gmaps_geocoding/api.rb, line 79 def finest_latlng(data) result = retrieve_finest_location(data) return [result['ROOFTOP'][:lng], result['ROOFTOP'][:lat]] if result.include?('ROOFTOP') return [result['RANGE_INTERPOLATED'][:lng], result['RANGE_INTERPOLATED'][:lat]] if result.include?('RANGE_INTERPOLATED') return [result['GEOMETRIC_CENTER'][:lng], result['GEOMETRIC_CENTER'][:lat]] if result.include?('GEOMETRIC_CENTER') [result['APPROXIMATE'][:lng], result['APPROXIMATE'][:lat]] rescue [0.0, 0.0].freeze end
Return a Ruby Hash object of the Google Maps Geocoding Service response
{developers.google.com/maps/documentation/geocoding/ Google Maps Geocoding Service documentation}.
@example
# json output example opts = {address: 'Tour Eiffel, Paris, IDF, France', output: 'json'} api = GmapsGeocoding::Api.new(opts) result = api.location # xml output example opts = {address: 'Tour Eiffel, Paris, IDF, France', output: 'xml'} api = GmapsGeocoding::Api.new(opts) result = api.location
# File lib/gmaps_geocoding/api.rb, line 45 def location raise 'Invalid configuration parameters check the Google Geocoding API documentation' unless @config.valid? rest_client = retrieve_geocoding_data case @config.json_format? when true json_to_hash(rest_client) else xml_to_hash(rest_client) end rescue => e @logger.error e nil end
Private Instance Methods
# File lib/gmaps_geocoding/api.rb, line 103 def build_url_query query_params = {} VALID_QUERY_PARAMS.each do |k| val = @config.send(k) query_params[k] = val if val end { url: "#{@config.url}/#{@config.output}", params: query_params }.freeze end
# File lib/gmaps_geocoding/api.rb, line 117 def json_to_hash(json_str) Oj.load(json_str) end
rubocop:enable Metrics/AbcSize
# File lib/gmaps_geocoding/api.rb, line 92 def retrieve_finest_location(data) result = {} tmp_data = data tmp_data = [tmp_data] unless tmp_data.is_a?(Array) tmp_data.each do |d| result[d['geometry']['location_type']] = { lng: d['geometry']['location']['lng'].to_f, lat: d['geometry']['location']['lat'].to_f } end result end
# File lib/gmaps_geocoding/api.rb, line 112 def retrieve_geocoding_data data = build_url_query RestClient.get data[:url], params: data[:params] end
rubocop:disable Metrics/AbcSize rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/CyclomaticComplexity
# File lib/gmaps_geocoding/api.rb, line 134 def xml_node_to_ruby(ox) return unless ox.respond_to?(:nodes) result = {} ox.nodes.each do |d| next unless d.respond_to?(:nodes) if d.nodes[0].is_a?(Ox::Element) if result.include?(d.value) result[d.value] = [result[d.value]] unless result[d.value].is_a?(Array) result[d.value] << xml_node_to_ruby(d) else result[d.value] = xml_node_to_ruby(d) end elsif result.include?(d.value) result[d.value] = [result[d.value]] unless result[d.value].is_a?(Array) result[d.value] << d.nodes[0] else result[d.value] = d.nodes[0] end end result end
# File lib/gmaps_geocoding/api.rb, line 121 def xml_to_hash(xml_str) xml = Ox.parse(xml_str) r = xml_node_to_ruby(xml) if r.include?('GeocodeResponse') r['GeocodeResponse'] else { status: 'UNKNOWN_ERROR' } end end