geo_rb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '028b35e41da078d2419f0b7a9400fbd98c84c5d06c021ad9c0d8eb5b642b321a'
4
+ data.tar.gz: 5cefbfc862f9b3063e879e7427a41c51913330ddc73294d9299940fbe5f6ac24
5
+ SHA512:
6
+ metadata.gz: 739a39e6937c42157b810f34fd32bf93c56c16db5a2e6e6359e7ed68b3469113353f007b21f70c06265132f7c79594ae1628bf51c60563980357c32460507e59
7
+ data.tar.gz: 6064574fdfac9cd8c2638a467e13a181d7c6fd03222d96048f4264c2a39fca01d2bb3d812c0fb9b0a63c5e231976364e561be8a04a008dc6cc30af8ceb6a2388
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ .DS_Store
2
+ .idea
3
+ .ruby-version
4
+ .tool-versions
5
+ gemfiles/*.lock
6
+ *.gem
7
+ *.rbc
8
+ .bundle
9
+ .config
10
+ .yardoc
11
+ Gemfile.lock
12
+ InstalledFiles
13
+ _yardoc
14
+ coverage
15
+ doc/
16
+ lib/bundler/man
17
+ pkg
18
+ rdoc
19
+ spec/reports
20
+ test/tmp
21
+ test/version_tmp
22
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper --color
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.0.1 (April 15, 2021)
2
+
3
+ - Initial commit
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2021 Victor Rodriguez
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # geo_rb
2
+
3
+ [![Gem Version](http://img.shields.io/gem/v/geo_rb.svg)][gem]
4
+ [![Code Climate](https://codeclimate.com/github/kucho/geo_rb.svg)][codeclimate]
5
+
6
+ geo_rb makes it easy for Ruby developers to locate the coordinates of addresses, cities, countries, and landmarks across the globe using third-party geocoders.
7
+
8
+ It is heavily inspired by [geopy](https://github.com/geopy/geopy).
9
+
10
+ ## Install
11
+
12
+ gem install geo_rb
13
+
14
+ ## Usage
15
+
16
+ ### Address lookup
17
+ ```ruby
18
+ plaza = GeoRb::Location.lookup("Plaza San Martin, Lima, Peru")
19
+ palacio = GeoRb::Location.lookup("Palacio de Justicia, Lima, Peru")
20
+ plaza.distance_to(palacio).km # => 0.6649563608870949
21
+ palacio.distance_to(plaza).km # => 0.6649563608870949
22
+ ```
data/geo_rb.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "geo_rb/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "geo_rb"
7
+ spec.required_ruby_version = ">= 2.4.0"
8
+ spec.homepage = "https://github.com/kucho/geo_rb"
9
+ spec.version = GeoRb::VERSION
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.summary = "Client for geolocation services"
12
+ spec.description = "geo_rb makes it easy for Ruby developers to locate the coordinates of addresses, cities, countries, and landmarks across the globe using third-party geocoders and other data sources"
13
+ spec.authors = ["Victor Rodriguez"]
14
+ spec.email = "victor.rodriguez.guriz@gmail.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.metadata = {
21
+ "source_code_uri" => "https://github.com/kucho/geo_rb",
22
+ "changelog_uri" => "https://github.com/kucho/geo_rb/blob/master/CHANGELOG.md"
23
+ }
24
+
25
+ spec.add_runtime_dependency("geographiclib", "~> 0.0.2")
26
+
27
+ spec.add_development_dependency("bundler", "~> 2.2")
28
+ spec.add_development_dependency("standardrb", "~> 1.0")
29
+ spec.add_development_dependency("rspec", "~> 3.10")
30
+ end
data/lib/geo_rb.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "logger"
2
+
3
+ module GeoRb
4
+ autoload :Distance, "geo_rb/distance"
5
+ autoload :GeoCoders, "geo_rb/geo_coders"
6
+ autoload :Location, "geo_rb/location"
7
+ autoload :Point, "geo_rb/point"
8
+
9
+ def self.logger
10
+ @@logger ||= defined?(Rails) ? Rails.logger : Logger.new($stdout)
11
+ end
12
+
13
+ def self.logger=(logger)
14
+ @@logger = logger
15
+ end
16
+ end
@@ -0,0 +1,73 @@
1
+ require "geographiclib"
2
+
3
+ module GeoRb
4
+ class Distance
5
+ EARTH_RADIUS = 6_371.0088
6
+
7
+ attr_reader :kilometers
8
+ alias_method :km, :kilometers
9
+
10
+ def initialize(*locations)
11
+ @kilometers = case locations.size
12
+ when 1
13
+ Float(locations.first) if locations.size == 1
14
+ else
15
+ locations.each_cons(2).reduce(0) do |distance, pair|
16
+ a, b = sanitize_location(pair.first), sanitize_location(pair.last)
17
+ distance + measure(a, b)
18
+ end
19
+ end
20
+ end
21
+
22
+ def ensure_same_altitude(a, b)
23
+ raise LatitudeMismatch if (a.altitude - b.altitude).abs > 1e-6
24
+ end
25
+
26
+ def measure(a, b)
27
+ ensure_same_altitude(a, b)
28
+ r = GeographicLib::Geodesic::WGS84.inverse(a.latitude, a.longitude, b.latitude, b.longitude)
29
+ r[:s12] / 1_000
30
+ end
31
+
32
+ private
33
+
34
+ def sanitize_location(location)
35
+ case location
36
+ when Location, Point
37
+ location
38
+ when Array
39
+ case location.size
40
+ when 2..3
41
+ Point.new(*location.map(&:to_f))
42
+ else
43
+ raise CoordsError
44
+ end
45
+ when String
46
+ points = location.split(",")
47
+ raise CoordsError unless [2, 3].include?(points.size)
48
+
49
+ Point.new(*points.map(&:to_f))
50
+ else
51
+ raise LocationError
52
+ end
53
+ end
54
+ end
55
+
56
+ class LatitudeMismatch < ArgumentError
57
+ def message
58
+ "Calculating distance between points with different altitudes is not supported"
59
+ end
60
+ end
61
+
62
+ class LocationError < ArgumentError
63
+ def message
64
+ "Invalid locations"
65
+ end
66
+ end
67
+
68
+ class CoordsError < ArgumentError
69
+ def message
70
+ "In order to calculate the distance between points it is necessary to have at least latitude and longitude"
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,6 @@
1
+ module GeoRb
2
+ module GeoCoders
3
+ autoload :Base, "geo_rb/geo_coders/base"
4
+ autoload :Nominatim, "geo_rb/geo_coders/nominatim"
5
+ end
6
+ end
@@ -0,0 +1,28 @@
1
+ require "json"
2
+ require "net/http"
3
+
4
+ module GeoRb
5
+ module GeoCoders
6
+ class Base
7
+ def call(url, post_process_proc = nil)
8
+ GeoRb.logger.debug data = parse_payload(fetch_data(URI(url)))
9
+ post_process_proc ? post_process_proc.call(data) : data
10
+ end
11
+
12
+ private
13
+
14
+ def fetch_data(url)
15
+ response = Net::HTTP.get(url)
16
+ JSON.parse(response).map { |result| result.transform_keys(&:to_sym) }
17
+ end
18
+
19
+ def format_bounding_box(a, b)
20
+ lat1 = [a.latitude, b.latitude].min
21
+ lon1 = [a.longitude, b.longitude].min
22
+ lat2 = [a.longitude, b.latitude].max
23
+ lon2 = [a.longitude, b.longitude].max
24
+ [lat1, lon1, lat2, lon2].join(",")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,85 @@
1
+ module GeoRb
2
+ module GeoCoders
3
+ class Nominatim < Base
4
+ DEFAULT_NOMINATIM_DOMAIN = "https://nominatim.openstreetmap.org".freeze
5
+ API_PATHS = {
6
+ search: "/search",
7
+ reverse: "/reverse"
8
+ }.freeze
9
+ STRUCTURED_QUERY_PARAMS = %w[street city county state country postalcode].freeze
10
+
11
+ # @param [String | Hash] query: query can be a string or a hash for a structured query
12
+ # whose keys are one of: `street`, `city`, `county`, `state`,
13
+ # `country`, `postalcode`. For more information, see Nominatim's
14
+ # documentation for `structured requests`:
15
+ # https://nominatim.org/release-docs/develop/api/Search
16
+ # @param [Boolean] detailed: Include a breakdown of the address into elements
17
+ # @param [Boolean] exactly_one: Return one result or a list of results, if available.
18
+ #
19
+ # @param [ nil | Integer] limit: Maximum amount of results to return from Nominatim.
20
+ # Unless exactly_one is set to False, limit will always be 1.
21
+ #
22
+ # @param [Array] country_codes: Limit search results to a specific country (or a list of countries).
23
+ # A country_code should be the ISO 3166-1alpha2 code,
24
+ # e.g. ``gb`` for the United Kingdom, ``de`` for Germany, etc.
25
+ #
26
+ # @param [ nil | Array] viewbox: refer this area to find search results. Requires an array of Pointer.
27
+ # By default this is treated as a hint, if you want to restrict results
28
+ # to this area, specify ``bounded=True`` as well.
29
+ # @param [Boolean] bounded: Restrict the results to only items contained within the bounding ``viewbox``.
30
+ def geocode(query, detailed: false, language: nil, country_codes: [], viewbox: nil, exactly_one: true, limit: nil, bounded: false)
31
+ params = case query
32
+ when Hash
33
+ query.slice(STRUCTURED_QUERY_PARAMS)
34
+ else
35
+ {'q': query}
36
+ end
37
+
38
+ if exactly_one
39
+ params[:limit] = 1
40
+ elsif limit.nil?
41
+ raise "Limit cannot be less than 1" if limit < 1
42
+ params[:limit] = limit
43
+ end
44
+
45
+ params[:bounded] = 1 if bounded
46
+ params[:addressdetails] = 1 if detailed
47
+ params[:countrycodes] = country_codes.join(",") unless country_codes.empty?
48
+ params[:format] = "json"
49
+ params[:"accept-language"] = language if language
50
+ params[:viewbox] = format_bounding_box(viewbox[0], viewbox[1]) if viewbox
51
+
52
+ url = build_url(:search, params)
53
+ GeoRb.logger.debug url
54
+ proc = ->(data) { data.first } if exactly_one
55
+ call(url, proc)
56
+ end
57
+
58
+ private
59
+
60
+ def parse_payload(data)
61
+ data.map do |result|
62
+ result[:latitude] = Float(result.delete(:lat))
63
+ result[:longitude] = Float(result.delete(:lon))
64
+
65
+ params = {
66
+ address: result[:display_name],
67
+ raw: result,
68
+ point: Point.new(result[:latitude], result[:longitude])
69
+ }.compact
70
+
71
+ Location.new(**params)
72
+ end
73
+ end
74
+
75
+ def api(path)
76
+ DEFAULT_NOMINATIM_DOMAIN + API_PATHS[path]
77
+ end
78
+
79
+ def build_url(path, params)
80
+ params = URI.encode_www_form(params.to_a)
81
+ "#{api(path)}?#{params}"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,32 @@
1
+ require "forwardable"
2
+
3
+ module GeoRb
4
+ # Contains a parsed geocoder response. Can be iterated over as
5
+ # ``(location<String>, (latitude<float>, longitude<Float))``.
6
+ # Or one can access the properties ``address``, ``latitude``,
7
+ # ``longitude``, or ``raw``. The last
8
+ # is a dictionary of the geocoder's response for this item.
9
+ class Location
10
+ extend Forwardable
11
+ def_delegators :point, :latitude, :longitude, :altitude
12
+ attr_reader :address, :point, :raw
13
+
14
+ def self.lookup(text, adapter: GeoRb::GeoCoders::Nominatim, **options)
15
+ adapter.new.geocode(text, **options)
16
+ end
17
+
18
+ def initialize(address:, raw:, point: Point)
19
+ @address = address
20
+ @point = point
21
+ @raw = raw
22
+ end
23
+
24
+ def distance_to(location)
25
+ Distance.new(self, location)
26
+ end
27
+
28
+ def to_h
29
+ {address: address}.merge(point.to_h)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,42 @@
1
+ module GeoRb
2
+ class Point
3
+ attr_reader :latitude, :longitude, :altitude
4
+
5
+ def initialize(latitude = 0.0, longitude = 0.0, altitude = 0.0)
6
+ @latitude, @longitude, @altitude = normalize_coordinates(latitude, longitude, altitude)
7
+ end
8
+
9
+ def to_h
10
+ instance_variables.map do |var|
11
+ [var[1..].to_sym, instance_variable_get(var)]
12
+ end.to_h
13
+ end
14
+
15
+ private
16
+
17
+ # Normalize angle `x` to be within `[-limit; limit)` range.
18
+ def normalize_angle(x, limit)
19
+ double_limit = limit * 2.0
20
+ modulo = x % double_limit
21
+ return modulo + double_limit if modulo < -limit
22
+ return modulo - double_limit if modulo >= limit
23
+
24
+ modulo
25
+ end
26
+
27
+ def normalize_coordinates(latitude, longitude, altitude)
28
+ latitude = Float(latitude)
29
+ longitude = Float(longitude)
30
+ altitude = Float(altitude)
31
+
32
+ unless [latitude, longitude, altitude].all?(&:finite?)
33
+ raise "Point coordinates must be finite. #{latitude}, #{longitude} #{altitude} has been passed as coordinates."
34
+ end
35
+
36
+ raise "Latitude must be in the [-90; 90] range." if latitude.abs > 90
37
+
38
+ longitude = normalize_angle(longitude, 180.0) if longitude.abs > 180
39
+ [latitude, longitude, altitude]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module GeoRb
2
+ VERSION = Gem::Version.new("0.0.1")
3
+ end
@@ -0,0 +1,34 @@
1
+ describe GeoRb::Distance do
2
+ subject { described_class.new(*locations).km }
3
+ let(:north_pole) { GeoRb::Point.new(90, 0) }
4
+ let(:south_pole) { GeoRb::Point.new(-90, 0) }
5
+ let(:earth_radius) { described_class::EARTH_RADIUS }
6
+ let(:earth_circumference) { 2 * Math::PI * earth_radius }
7
+
8
+ describe "#measure" do
9
+ context "when points are the same" do
10
+ let(:locations) { %w[0,0 0,0] }
11
+
12
+ it { is_expected.to eq 0 }
13
+ end
14
+
15
+ context "when distinct points" do
16
+ let(:locations) { %w[0,0 0,1] }
17
+
18
+ it { is_expected.to_not eq 0 }
19
+ end
20
+
21
+ context "when across antimeridian" do
22
+ let(:nines) { 1 - 1e-30 } # 0.(9)
23
+ let(:locations) { [[0, -179 - nines], [0, 179 + nines]] }
24
+
25
+ it { is_expected.to eq 0 }
26
+ end
27
+
28
+ context "when trip between poles" do
29
+ let(:locations) { [north_pole, south_pole] }
30
+
31
+ it { should be_within(12).of(earth_circumference / 2) }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ describe GeoRb::GeoCoders::Nominatim do
2
+ subject { client.geocode(query, **optional_params).to_h }
3
+ let(:raw_response) { client.geocode(query, **optional_params).raw }
4
+ let(:optional_params) { {} }
5
+ let(:client) { described_class.new }
6
+
7
+ describe "#geocode" do
8
+ describe "only query" do
9
+ context "with no optional params" do
10
+ let(:query) { "435 north michigan ave, chicago il 60611 usa" }
11
+ let(:expected_result) { {latitude: 41.89037385, longitude: -87.62367299422614, altitude: 0} }
12
+
13
+ it { is_expected.to include(expected_result) }
14
+ end
15
+
16
+ context "when query is CJK" do
17
+ let(:query) { "故宫 北京" }
18
+ let(:expected_result) { {latitude: 39.91727565, longitude: 116.39076940577283, altitude: 0} }
19
+
20
+ it { is_expected.to include(expected_result) }
21
+ end
22
+ end
23
+
24
+ describe "with viewbox" do
25
+ let(:points) do
26
+ [
27
+ GeoRb::Point.new(56.588456, 84.719353),
28
+ GeoRb::Point.new(56.437293, 85.296822)
29
+ ]
30
+ end
31
+ let(:query) { "строитель томск" }
32
+
33
+ context "when not bounded" do
34
+ let(:optional_params) { {viewbox: points} }
35
+ let(:expected_result) { {latitude: 56.4129459, longitude: 84.84783106981399} }
36
+
37
+ it { is_expected.to include(expected_result) }
38
+ end
39
+
40
+ context "when bounded" do
41
+ let(:optional_params) { {viewbox: points, bounded: true} }
42
+
43
+ it { is_expected.to eq({}) }
44
+ end
45
+ end
46
+
47
+ describe "with language" do
48
+ let(:query) { "Mohrenstrasse Berlin" }
49
+ let(:optional_params) { {language: "es", detailed: true} }
50
+ let(:expected_result) { {"country" => "Alemania"} }
51
+
52
+ it { expect(raw_response[:address]).to include(expected_result) }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,8 @@
1
+ require "rspec"
2
+ require "geo_rb"
3
+
4
+ RSpec.configure do |config|
5
+ config.expect_with :rspec do |c|
6
+ c.syntax = :expect # disables `should`
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geo_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Victor Rodriguez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: geographiclib
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: standardrb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.10'
69
+ description: geo_rb makes it easy for Ruby developers to locate the coordinates of
70
+ addresses, cities, countries, and landmarks across the globe using third-party geocoders
71
+ and other data sources
72
+ email: victor.rodriguez.guriz@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - CHANGELOG.md
80
+ - Gemfile
81
+ - LICENSE
82
+ - README.md
83
+ - geo_rb.gemspec
84
+ - lib/geo_rb.rb
85
+ - lib/geo_rb/distance.rb
86
+ - lib/geo_rb/geo_coders.rb
87
+ - lib/geo_rb/geo_coders/base.rb
88
+ - lib/geo_rb/geo_coders/nominatim.rb
89
+ - lib/geo_rb/location.rb
90
+ - lib/geo_rb/point.rb
91
+ - lib/geo_rb/version.rb
92
+ - spec/geo_rb/distance_spec.rb
93
+ - spec/geo_rb/geo_coders/nominatim_spec.rb
94
+ - spec/spec_helper.rb
95
+ homepage: https://github.com/kucho/geo_rb
96
+ licenses:
97
+ - MIT
98
+ metadata:
99
+ source_code_uri: https://github.com/kucho/geo_rb
100
+ changelog_uri: https://github.com/kucho/geo_rb/blob/master/CHANGELOG.md
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 2.4.0
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubygems_version: 3.2.3
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Client for geolocation services
120
+ test_files:
121
+ - spec/geo_rb/distance_spec.rb
122
+ - spec/geo_rb/geo_coders/nominatim_spec.rb
123
+ - spec/spec_helper.rb