address_geocoder 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 +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.rdoc +72 -0
- data/Rakefile +4 -0
- data/address_geocoder.gemspec +26 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/countries.yaml +1000 -0
- data/lib/address_geocoder.rb +11 -0
- data/lib/address_geocoder/client.rb +180 -0
- data/lib/address_geocoder/error.rb +31 -0
- data/lib/address_geocoder/parser.rb +24 -0
- data/lib/address_geocoder/requester.rb +52 -0
- data/lib/address_geocoder/url_generator.rb +43 -0
- data/lib/address_geocoder/version.rb +3 -0
- data/lib/maps_api.rb +7 -0
- data/lib/maps_api/google.rb +9 -0
- data/lib/maps_api/google/client.rb +19 -0
- data/lib/maps_api/google/parser.rb +121 -0
- data/lib/maps_api/google/requester.rb +70 -0
- data/lib/maps_api/google/url_generator.rb +94 -0
- metadata +88 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'address_geocoder/requester'
|
2
|
+
require 'maps_api/google/url_generator'
|
3
|
+
require 'maps_api/google/parser'
|
4
|
+
|
5
|
+
module MapsApi
|
6
|
+
module Google
|
7
|
+
# Class for making requests to Google Maps API
|
8
|
+
class Requester < ::AddressGeocoder::Requester
|
9
|
+
# Make a call to Google Maps' Geocoding API
|
10
|
+
# @return (see AddressGeocoder::Requester#make_call)
|
11
|
+
def make_call
|
12
|
+
@url_generator = UrlGenerator.new(address: @address.dup,
|
13
|
+
api_key: @api_key,
|
14
|
+
language: @language)
|
15
|
+
@url_generator.levels.each do |level_of_search|
|
16
|
+
@url_generator.level = level_of_search
|
17
|
+
call
|
18
|
+
break if success?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Determines whether the request to Google Maps' Geocoding API was a
|
23
|
+
# success
|
24
|
+
# @return (see AddressGeocoder::Requester#success?)
|
25
|
+
def success?
|
26
|
+
return false unless @result['status'] == 'OK'
|
27
|
+
return false unless @result['results'][0]['address_components'].length > 1
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check if the certainty level of the response
|
32
|
+
# @note certainty is determined in two ways: first, by ensuring that the
|
33
|
+
# country was not the only field returned and that it was the correct
|
34
|
+
# country; second, that the city, state, and postal code were all
|
35
|
+
# present in the response if they were included in the level of call.
|
36
|
+
def certain?
|
37
|
+
level = @url_generator.level
|
38
|
+
if @parser.just_country?(@result) ||
|
39
|
+
@parser.not_correct_country?(@result)
|
40
|
+
false
|
41
|
+
elsif @parser.city_present?(level) || @parser.state_present?(level) ||
|
42
|
+
@parser.pc_present?(level)
|
43
|
+
false
|
44
|
+
else
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a compacted, flattened array of different address responses.
|
50
|
+
# @return (see AddressGeocoder::Requester#array_result)
|
51
|
+
def array_result
|
52
|
+
[@result['results']].flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def call
|
58
|
+
attempts = 0
|
59
|
+
begin
|
60
|
+
@result = HTTParty.get(@url_generator.generate_url)
|
61
|
+
rescue
|
62
|
+
sleep(0.5)
|
63
|
+
attempts += 1
|
64
|
+
retry if attempts <= 5
|
65
|
+
connection_error('Could not connect to GoogleAPI')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'address_geocoder/url_generator'
|
2
|
+
|
3
|
+
module MapsApi
|
4
|
+
module Google
|
5
|
+
# Class for generatoring URLs to call Google Maps API
|
6
|
+
class UrlGenerator < ::AddressGeocoder::UrlGenerator
|
7
|
+
# Google's attribute names for our address variables
|
8
|
+
GOOGLE_TITLES = {
|
9
|
+
country: 'country',
|
10
|
+
postal_code: 'postal_code',
|
11
|
+
city: 'locality',
|
12
|
+
state: 'administrative_area'
|
13
|
+
}.freeze
|
14
|
+
# The URL of Google Maps' Geocoding API
|
15
|
+
URL = 'https://maps.googleapis.com/maps/api/geocode/json?'.freeze
|
16
|
+
# Google accepted language codes
|
17
|
+
# @see https://developers.google.com/maps/faq#languagesupport
|
18
|
+
LANGUAGES = ['zh-CN', 'ja', 'es', 'ko', 'ru', 'de', 'fr'].freeze
|
19
|
+
# The call levels to cycle through
|
20
|
+
CYCLE = { base: [1, 5], no_street: [2, 6], no_city: [3, 7],
|
21
|
+
no_state: [4] }.freeze
|
22
|
+
|
23
|
+
# @!attribute level
|
24
|
+
# @return [Integer] the level at which to generate the URL
|
25
|
+
attr_accessor :level
|
26
|
+
|
27
|
+
def initialize(args = {})
|
28
|
+
@level = args[:level]
|
29
|
+
super args
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generates a URL with which to call Google Maps' Geocoding API
|
33
|
+
# @return (see AddressGeocoder::UrlGenerator#generate_url)
|
34
|
+
def generate_url
|
35
|
+
params = prune_address.map { |key, value| add(key, value) }
|
36
|
+
params = params.join.tr('\=', ':').chop
|
37
|
+
|
38
|
+
if ([1, 5] & [@level]).any?
|
39
|
+
street = hash_to_query('address' => @street) + '&'
|
40
|
+
end
|
41
|
+
|
42
|
+
params << "&key=#{@api_key}" unless @api_key.empty?
|
43
|
+
|
44
|
+
language = "&language=#{@language}" if LANGUAGES.include? @language
|
45
|
+
|
46
|
+
"#{URL}#{street}components=#{params}#{language}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generates layers of calls to make, starting with a base layer that calls
|
50
|
+
# all valid fields, and removing a layer each call
|
51
|
+
# @return [Array<Integer>] a list of calls to determine what values are
|
52
|
+
# used in the call to Google Maps' API
|
53
|
+
def levels
|
54
|
+
levels = []
|
55
|
+
# Assign base levels unless no street
|
56
|
+
levels += CYCLE[:base] if @address[:street]
|
57
|
+
# Assign levels that don't use street if valid city
|
58
|
+
levels += CYCLE[:no_street] if @address[:city]
|
59
|
+
# Assign levels that don't use street,city if valid state
|
60
|
+
levels += CYCLE[:no_city] if @address[:state]
|
61
|
+
if @address[:postal_code]
|
62
|
+
# Assign the level that doesn't use street,city,state
|
63
|
+
levels += CYCLE[:no_state]
|
64
|
+
else
|
65
|
+
# Remove all levels that included postal code
|
66
|
+
levels -= [5, 6, 7]
|
67
|
+
end
|
68
|
+
levels.sort
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Removes attributes from the address that don't fit with the level
|
74
|
+
# @return [Hash] an address object to add to the call
|
75
|
+
def prune_address
|
76
|
+
address = (@address.select { |_k, v| v }).to_h
|
77
|
+
address[:country] = address[:country][:alpha2]
|
78
|
+
@street = address.delete(:street)
|
79
|
+
|
80
|
+
address.delete(:postal_code) if @level > 4
|
81
|
+
address.delete(:city) if ([3, 4, 7] & [@level]).any?
|
82
|
+
address.delete(:state) if @level == 4
|
83
|
+
address
|
84
|
+
end
|
85
|
+
|
86
|
+
# Parses a key and value from a hash into a query
|
87
|
+
# @return [String] a query to be used in the URL
|
88
|
+
def add(key, value)
|
89
|
+
str = hash_to_query(GOOGLE_TITLES[key] => value)
|
90
|
+
"#{str}|"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: address_geocoder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carson Long
|
8
|
+
- Wing Leung Choi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-05-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.13.7
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.13.7
|
28
|
+
description: Calls and parses various maps APIs for accurate address validation and
|
29
|
+
geocoding
|
30
|
+
email:
|
31
|
+
- ctlong.970@gmail.com
|
32
|
+
- wingleungchoi@gmail.com
|
33
|
+
executables:
|
34
|
+
- console
|
35
|
+
- setup
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- ".gitignore"
|
40
|
+
- ".travis.yml"
|
41
|
+
- CODE_OF_CONDUCT.md
|
42
|
+
- Gemfile
|
43
|
+
- LICENSE
|
44
|
+
- README.rdoc
|
45
|
+
- Rakefile
|
46
|
+
- address_geocoder.gemspec
|
47
|
+
- bin/console
|
48
|
+
- bin/setup
|
49
|
+
- countries.yaml
|
50
|
+
- lib/address_geocoder.rb
|
51
|
+
- lib/address_geocoder/client.rb
|
52
|
+
- lib/address_geocoder/error.rb
|
53
|
+
- lib/address_geocoder/parser.rb
|
54
|
+
- lib/address_geocoder/requester.rb
|
55
|
+
- lib/address_geocoder/url_generator.rb
|
56
|
+
- lib/address_geocoder/version.rb
|
57
|
+
- lib/maps_api.rb
|
58
|
+
- lib/maps_api/google.rb
|
59
|
+
- lib/maps_api/google/client.rb
|
60
|
+
- lib/maps_api/google/parser.rb
|
61
|
+
- lib/maps_api/google/requester.rb
|
62
|
+
- lib/maps_api/google/url_generator.rb
|
63
|
+
homepage: https://github.com/ctlong/address_geocoder
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message: Happy mapping!
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.4.5.1
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Address validation and geocoding
|
87
|
+
test_files: []
|
88
|
+
has_rdoc:
|