sildur/offline_geocoder

View on GitHub
lib/offline_geocoder.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'offline_geocoder/version'
require 'csv'
require 'geokdtree'

class OfflineGeocoder
  CSV_PATH = File.expand_path('../og_cities1000.csv', __dir__)

  def initialize
    return if defined? @@cities

    @@cities = []
    @@tree = Geokdtree::Tree.new(2)
    @@table = []
    index = 0
    CSV.foreach(CSV_PATH, headers: true, header_converters: :symbol) do |row|
      as_hash = row.to_h
      as_hash[:lat] = as_hash[:lat].to_f
      as_hash[:lon] = as_hash[:lon].to_f
      @@tree.insert([row[:lat], row[:lon]], index)
      @@table << as_hash
      index += 1
    end
  end

  def search(query, lon = nil)
    lat, lon = lon.nil? ? [query[:lat], query[:lon]] : [query, lon]

    if lat && lon
      search_by_latlon(lat.to_f, lon.to_f)
    else
      search_by_attr(query)
    end
  end

  # Hide internal variables
  def inspect
    "#<#{self.class}:0x#{format('%<id>014x', id: (object_id << 1))}>"
  end

  private

  def search_by_latlon(lat, lon)
    @@table[@@tree.nearest([lat, lon]).data.to_i].to_h
  end

  def search_by_attr(query = {})
    @@table.select { |object| object >= query }.first
  end
end