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

config[R]

Public Class Methods

new(opts = {}) click to toggle source
# 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

finest_latlng(data) click to toggle source

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
location() click to toggle source

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

build_url_query() click to toggle source
# 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
json_to_hash(json_str) click to toggle source
# File lib/gmaps_geocoding/api.rb, line 117
def json_to_hash(json_str)
  Oj.load(json_str)
end
retrieve_finest_location(data) click to toggle source

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
retrieve_geocoding_data() click to toggle source
# File lib/gmaps_geocoding/api.rb, line 112
def retrieve_geocoding_data
  data = build_url_query
  RestClient.get data[:url], params: data[:params]
end
xml_node_to_ruby(ox) click to toggle source

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
xml_to_hash(xml_str) click to toggle source
# 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