lib/ghtorrent/geolocator.rb
def geolocate(location: nil, wait: config(:geolocation_wait).to_i, from_cache: true)
      return EMPTY_LOCATION if location.nil? or location == ''
      location = location_filter(location)

      geo = []
      if from_cache
        geo = persister.find(:geo_cache, {'key' => location})
      end

      if geo.empty?

        if config(:geolocation_service) == 'gmaps'
          self.class.send :include, GHTorrent::Geolocator::GMaps
        elsif config(:geolocation_service) == 'bing'
          self.class.send :include, GHTorrent::Geolocator::Bing
        else
          self.class.send :include, GHTorrent::Geolocator::OSM
        end

        begin
          ts  = Time.now
          url = format_url(location)
          req = open(url)
          p   = JSON.parse(req.read)
          geo = parse_geolocation_result(location, p)

          info "Successful geolocation request. Location: #{location}"
        rescue StandardError => e
          warn "Failed geolocation request. Location: #{location}"
          geo       = EMPTY_LOCATION
          geo[:key] = location
        ensure
          in_db_geo = persister.find(:geo_cache, {'key' => location}).first

          if in_db_geo.nil?
            begin

              geo[:updated_at] = Time.now

              persister.store(:geo_cache, geo)
            rescue StandardError => e
              warn "Could not save location #{location} -> #{geo}: #{e.message}"
            end
          end

          info "Added location key '#{location}' -> #{geo[:status]}"
          taken    = Time.now.to_f - ts.to_f
          to_sleep = wait - taken
          sleep(to_sleep) if to_sleep > 0
        end
      else
        geo = geo[0]
        debug "Location with key '#{location}' exists"
      end

      geo
    end
def geolocate(location: nil, wait: config(:geolocation_wait).to_i, from_cache: true)
      return EMPTY_LOCATION if location.nil? or location == ''
      location = location_filter(location)

      geo = []
      if from_cache
        geo = persister.find(:geo_cache, {'key' => location})
      end

      if geo.empty?

        if config(:geolocation_service) == 'gmaps'
          self.class.send :include, GHTorrent::Geolocator::GMaps
        elsif config(:geolocation_service) == 'bing'
          self.class.send :include, GHTorrent::Geolocator::Bing
        else
          self.class.send :include, GHTorrent::Geolocator::OSM
        end

        begin
          ts  = Time.now
          url = format_url(location)
          req = open(url)
          p   = JSON.parse(req.read)
          geo = parse_geolocation_result(location, p)

          info "Successful geolocation request. Location: #{location}"
        rescue StandardError => e
          warn "Failed geolocation request. Location: #{location}"
          geo       = EMPTY_LOCATION
          geo[:key] = location
        ensure
          in_db_geo = persister.find(:geo_cache, {'key' => location}).first

          if in_db_geo.nil?
            begin

              geo[:updated_at] = Time.now

              persister.store(:geo_cache, geo)
            rescue StandardError => e
              warn "Could not save location #{location} -> #{geo}: #{e.message}"
            end
          end

          info "Added location key '#{location}' -> #{geo[:status]}"
          taken    = Time.now.to_f - ts.to_f
          to_sleep = wait - taken
          sleep(to_sleep) if to_sleep > 0
        end
      else
        geo = geo[0]
        debug "Location with key '#{location}' exists"
      end

      geo
    end
Given a location string, it returns a hash like the following:

 input: Larisa, Greece
 output:
 {
   :key          => "larisa",
   :long         => 22.41629981994629,
   :lat          => 39.61040115356445,
   :city         => "Larisa",
   :country      => "Greece",
   :state        => "Thessaly",
   :country_code => "gr",
   :status       => :ok
 }
 Uses aggressive caching