forked from alexreisner/geocoder
/
geocoder.rb
172 lines (152 loc) · 4.74 KB
/
geocoder.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
require "geocoder/configuration"
require "geocoder/calculations"
require "geocoder/cache"
require "geocoder/request"
require "geocoder/models/active_record"
require "geocoder/models/mongoid"
module Geocoder
extend self
##
# Search for information about an address or a set of coordinates.
#
def search(query, *args)
# convert coordinates as separate arguments to an array
if query.is_a?(Numeric) and args.first.is_a?(Numeric)
warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the search method, please pass an array: [#{query},#{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
query = [query, args.first]
end
if blank_query?(query)
results = []
else
results = lookup(query).search(query)
end
results.instance_eval do
def warn_search_deprecation(attr)
warn "DEPRECATION WARNING: Geocoder.search now returns an array of Geocoder::Result objects. " +
"Calling '%s' directly on the returned array will cause an exception in Geocoder v1.0." % attr
end
def coordinates; warn_search_deprecation('coordinates'); first.coordinates if first; end
def latitude; warn_search_deprecation('latitude'); first.latitude if first; end
def longitude; warn_search_deprecation('longitude'); first.longitude if first; end
def address; warn_search_deprecation('address'); first.address if first; end
def city; warn_search_deprecation('city'); first.city if first; end
def country; warn_search_deprecation('country'); first.country if first; end
def country_code; warn_search_deprecation('country_code'); first.country_code if first; end
end
return results
end
##
# Look up the coordinates of the given street or IP address.
#
def coordinates(address)
if (results = search(address)).size > 0
results.first.coordinates
end
end
##
# Look up the address of the given coordinates ([lat,lon])
# or IP address (string).
#
def address(query, *args)
if lon = args.first
warn "DEPRECATION WARNING: Instead of passing latitude/longitude as separate arguments to the address method, please pass an array: [#{query},#{args.first}]. The old argument format will not be supported in Geocoder v.1.0."
query = [query, lon]
end
if (results = search(query)).size > 0
results.first.address
end
end
##
# The working Cache object, or +nil+ if none configured.
#
def cache
if @cache.nil? and store = Configuration.cache
@cache = Cache.new(store, Configuration.cache_prefix)
end
@cache
end
##
# Array of valid Lookup names.
#
def valid_lookups
street_lookups + ip_lookups
end
##
# All street address lookups, default first.
#
def street_lookups
[:google, :yahoo, :geocoder_ca, :yandex]
end
##
# All IP address lookups, default first.
#
def ip_lookups
[:freegeoip]
end
def version
File.read("VERSION")
end
# exception classes
class Error < StandardError; end
class ConfigurationError < Error; end
private # -----------------------------------------------------------------
##
# Get a Lookup object (which communicates with the remote geocoding API).
# Takes a search query and returns an IP or street address Lookup
# depending on the query contents.
#
def lookup(query)
if ip_address?(query)
get_lookup(ip_lookups.first)
else
get_lookup(Configuration.lookup || street_lookups.first)
end
end
##
# Retrieve a Lookup object from the store.
#
def get_lookup(name)
unless defined?(@lookups)
@lookups = {}
end
unless @lookups.include?(name)
@lookups[name] = spawn_lookup(name)
end
@lookups[name]
end
##
# Spawn a Lookup of the given name.
#
def spawn_lookup(name)
if valid_lookups.include?(name)
name = name.to_s
require "geocoder/lookups/#{name}"
klass = name.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
eval("Geocoder::Lookup::#{klass}.new")
else
valids = valid_lookups.map{ |l| ":#{l}" }.join(", ")
raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
"(#{name.inspect} is not one of: #{valids})."
end
end
##
# Does the given value look like an IP address?
#
# Does not check for actual validity, just the appearance of four
# dot-delimited 8-bit numbers.
#
def ip_address?(value)
!!value.to_s.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
end
##
# Is the given search query blank? (ie, should we not bother searching?)
#
def blank_query?(value)
!!value.to_s.match(/^\s*$/)
end
end
# load Railtie if Rails exists
if defined?(Rails)
require "geocoder/railtie"
Geocoder::Railtie.insert
end