lib/offline_geocoder.rb
# 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