geo_rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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