geonames_client 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +4 -0
- data/.rvmrc +2 -0
- data/Gemfile +15 -0
- data/Guardfile +7 -0
- data/README.rdoc +0 -0
- data/Rakefile +6 -0
- data/geonames_client.gemspec +250 -0
- data/lib/geonames_client/_location.rb +68 -0
- data/lib/geonames_client/location.rb +123 -0
- data/lib/geonames_client/nearby_street.rb +29 -0
- data/lib/geonames_client/service.rb +96 -0
- data/lib/geonames_client/service_definition.rb +76 -0
- data/lib/geonames_client/version.rb +3 -0
- data/lib/geonames_client.rb +14 -0
- data/spec/data/geoname_response-headers.yml +16 -0
- data/spec/data/geoname_response-parsed_response.yml +153 -0
- data/spec/data/geoname_response-response.yml +196 -0
- data/spec/lib/geonames_client/location_spec.rb +221 -0
- data/spec/lib/geonames_client/nearby_street_spec.rb +28 -0
- data/spec/lib/geonames_client/service_definition_spec.rb +122 -0
- data/spec/lib/geonames_client/service_spec.rb +70 -0
- data/spec/spec_helper.rb +22 -0
- metadata +176 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
source "http://rubygems.org"
|
3
|
+
|
4
|
+
group :development, :test do
|
5
|
+
gem 'ruby-debug'
|
6
|
+
gem 'guard'
|
7
|
+
gem 'rb-fsevent'
|
8
|
+
gem 'growl'
|
9
|
+
gem 'guard-rspec'
|
10
|
+
gem 'guard-shell'
|
11
|
+
gem 'httparty'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Specify your gem's dependencies in geonames_client.gemspec
|
15
|
+
gemspec
|
data/Guardfile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
guard 'rspec', :version => 2, :all_on_start => true, :all_after_pass => false, :cli => '--color --format doc' do
|
4
|
+
watch( %r{^spec/.+_spec\.rb$} )
|
5
|
+
watch( %r{^lib/(.+)\.rb$} ) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
6
|
+
watch( 'spec/spec_helper.rb' ) { "spec" }
|
7
|
+
end
|
data/README.rdoc
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "geonames_client/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "geonames_client"
|
7
|
+
s.version = GeonamesClient::VERSION
|
8
|
+
s.authors = ["C. Jason Harrelson"]
|
9
|
+
s.email = ["jason@lookforwardenterprises.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{A client to consume the geonames web services.}
|
12
|
+
s.description = %q{A client to consume the geonames web services (www.geonames.org).}
|
13
|
+
|
14
|
+
s.rubyforge_project = "geonames_client"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
development_dependencies = {
|
22
|
+
%q<rake> => [">= 0.9.2"],
|
23
|
+
%q<rspec> => [">= 2.6.0"],
|
24
|
+
%q<httparty> => [">= 0.8.0"]
|
25
|
+
}
|
26
|
+
|
27
|
+
runtime_dependencies = {
|
28
|
+
%q<httparty> => [">= 0.8.0"]
|
29
|
+
}
|
30
|
+
|
31
|
+
if s.respond_to? :specification_version then
|
32
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
33
|
+
s.specification_version = 3
|
34
|
+
|
35
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
36
|
+
development_dependencies.each do |name, versions|
|
37
|
+
s.add_development_dependency( name, versions )
|
38
|
+
end
|
39
|
+
|
40
|
+
runtime_dependencies.each do |name, versions|
|
41
|
+
s.add_runtime_dependency( name, versions )
|
42
|
+
end
|
43
|
+
else
|
44
|
+
development_dependencies.each do |name, versions|
|
45
|
+
s.add_dependency( name, versions )
|
46
|
+
end
|
47
|
+
|
48
|
+
runtime_dependencies.each do |name, versions|
|
49
|
+
s.add_dependency( name, versions )
|
50
|
+
end
|
51
|
+
end
|
52
|
+
else
|
53
|
+
development_dependencies.each do |name, versions|
|
54
|
+
s.add_dependency( name, versions )
|
55
|
+
end
|
56
|
+
|
57
|
+
runtime_dependencies.each do |name, versions|
|
58
|
+
s.add_dependency( name, versions )
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
# -*- encoding: utf-8 -*-
|
63
|
+
$:.push File.expand_path("../lib", __FILE__)
|
64
|
+
require "geonames_client/version"
|
65
|
+
|
66
|
+
Gem::Specification.new do |s|
|
67
|
+
s.name = "geonames_client"
|
68
|
+
s.version = GeonamesClient::VERSION
|
69
|
+
s.authors = ["C. Jason Harrelson"]
|
70
|
+
s.email = ["jason@lookforwardenterprises.com"]
|
71
|
+
s.homepage = ""
|
72
|
+
s.summary = %q{A client to consume the geonames web services.}
|
73
|
+
s.description = %q{A client to consume the geonames web services (www.geonames.org).}
|
74
|
+
|
75
|
+
s.rubyforge_project = "geonames_client"
|
76
|
+
|
77
|
+
s.files = `git ls-files`.split("\n")
|
78
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
79
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
80
|
+
s.require_paths = ["lib"]
|
81
|
+
|
82
|
+
development_dependencies = {
|
83
|
+
%q<rake> => [">= 0.9.2" ],
|
84
|
+
%q<rspec> => [">= 2.6.0" ],
|
85
|
+
%q<ruby-debug> => [">= 0.10.4"],
|
86
|
+
%q<guard> => [">= 0.4.2" ],
|
87
|
+
%q<guard-rspec> => [">= 0.4.0" ],
|
88
|
+
}
|
89
|
+
|
90
|
+
runtime_dependencies = {
|
91
|
+
|
92
|
+
}
|
93
|
+
|
94
|
+
if s.respond_to? :specification_version then
|
95
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
96
|
+
s.specification_version = 3
|
97
|
+
|
98
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
99
|
+
development_dependencies.each do |name, versions|
|
100
|
+
s.add_development_dependency( name, versions )
|
101
|
+
end
|
102
|
+
|
103
|
+
runtime_dependencies.each do |name, versions|
|
104
|
+
s.add_runtime_dependency( name, versions )
|
105
|
+
end
|
106
|
+
else
|
107
|
+
development_dependencies.each do |name, versions|
|
108
|
+
s.add_dependency( name, versions )
|
109
|
+
end
|
110
|
+
|
111
|
+
runtime_dependencies.each do |name, versions|
|
112
|
+
s.add_dependency( name, versions )
|
113
|
+
end
|
114
|
+
end
|
115
|
+
else
|
116
|
+
development_dependencies.each do |name, versions|
|
117
|
+
s.add_dependency( name, versions )
|
118
|
+
end
|
119
|
+
|
120
|
+
runtime_dependencies.each do |name, versions|
|
121
|
+
s.add_dependency( name, versions )
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# -*- encoding: utf-8 -*-
|
126
|
+
$:.push File.expand_path("../lib", __FILE__)
|
127
|
+
require "geonames_client/version"
|
128
|
+
|
129
|
+
Gem::Specification.new do |s|
|
130
|
+
s.name = "geonames_client"
|
131
|
+
s.version = GeonamesClient::VERSION
|
132
|
+
s.authors = ["C. Jason Harrelson"]
|
133
|
+
s.email = ["jason@lookforwardenterprises.com"]
|
134
|
+
s.homepage = ""
|
135
|
+
s.summary = %q{A client to consume the geonames web services.}
|
136
|
+
s.description = %q{A client to consume the geonames web services (www.geonames.org).}
|
137
|
+
|
138
|
+
s.rubyforge_project = "geonames_client"
|
139
|
+
|
140
|
+
s.files = `git ls-files`.split("\n")
|
141
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
142
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
143
|
+
s.require_paths = ["lib"]
|
144
|
+
|
145
|
+
development_dependencies = {
|
146
|
+
%q<rake> => [">= 0.9.2" ],
|
147
|
+
%q<rspec> => [">= 2.6.0" ],
|
148
|
+
%q<ruby-debug> => [">= 0.10.4"],
|
149
|
+
%q<guard> => [">= 0.4.2" ],
|
150
|
+
%q<guard-rspec> => [">= 0.4.0" ],
|
151
|
+
}
|
152
|
+
|
153
|
+
runtime_dependencies = {
|
154
|
+
|
155
|
+
}
|
156
|
+
|
157
|
+
if s.respond_to? :specification_version then
|
158
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
159
|
+
s.specification_version = 3
|
160
|
+
|
161
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
162
|
+
development_dependencies.each do |name, versions|
|
163
|
+
s.add_development_dependency( name, versions )
|
164
|
+
end
|
165
|
+
|
166
|
+
runtime_dependencies.each do |name, versions|
|
167
|
+
s.add_runtime_dependency( name, versions )
|
168
|
+
end
|
169
|
+
else
|
170
|
+
development_dependencies.each do |name, versions|
|
171
|
+
s.add_dependency( name, versions )
|
172
|
+
end
|
173
|
+
|
174
|
+
runtime_dependencies.each do |name, versions|
|
175
|
+
s.add_dependency( name, versions )
|
176
|
+
end
|
177
|
+
end
|
178
|
+
else
|
179
|
+
development_dependencies.each do |name, versions|
|
180
|
+
s.add_dependency( name, versions )
|
181
|
+
end
|
182
|
+
|
183
|
+
runtime_dependencies.each do |name, versions|
|
184
|
+
s.add_dependency( name, versions )
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
# -*- encoding: utf-8 -*-
|
189
|
+
$:.push File.expand_path("../lib", __FILE__)
|
190
|
+
require "geonames_client/version"
|
191
|
+
|
192
|
+
Gem::Specification.new do |s|
|
193
|
+
s.name = "geonames_client"
|
194
|
+
s.version = GeonamesClient::VERSION
|
195
|
+
s.authors = ["C. Jason Harrelson"]
|
196
|
+
s.email = ["jason@lookforwardenterprises.com"]
|
197
|
+
s.homepage = ""
|
198
|
+
s.summary = %q{A client to consume the geonames web services.}
|
199
|
+
s.description = %q{A client to consume the geonames web services (www.geonames.org).}
|
200
|
+
|
201
|
+
s.rubyforge_project = "geonames_client"
|
202
|
+
|
203
|
+
s.files = `git ls-files`.split("\n")
|
204
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
205
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
206
|
+
s.require_paths = ["lib"]
|
207
|
+
|
208
|
+
development_dependencies = {
|
209
|
+
%q<rake> => [">= 0.9.2" ],
|
210
|
+
%q<rspec> => [">= 2.6.0" ],
|
211
|
+
%q<ruby-debug> => [">= 0.10.4"],
|
212
|
+
%q<guard> => [">= 0.4.2" ],
|
213
|
+
%q<guard-rspec> => [">= 0.4.0" ],
|
214
|
+
}
|
215
|
+
|
216
|
+
runtime_dependencies = {
|
217
|
+
|
218
|
+
}
|
219
|
+
|
220
|
+
if s.respond_to? :specification_version then
|
221
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
222
|
+
s.specification_version = 3
|
223
|
+
|
224
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
225
|
+
development_dependencies.each do |name, versions|
|
226
|
+
s.add_development_dependency( name, versions )
|
227
|
+
end
|
228
|
+
|
229
|
+
runtime_dependencies.each do |name, versions|
|
230
|
+
s.add_runtime_dependency( name, versions )
|
231
|
+
end
|
232
|
+
else
|
233
|
+
development_dependencies.each do |name, versions|
|
234
|
+
s.add_dependency( name, versions )
|
235
|
+
end
|
236
|
+
|
237
|
+
runtime_dependencies.each do |name, versions|
|
238
|
+
s.add_dependency( name, versions )
|
239
|
+
end
|
240
|
+
end
|
241
|
+
else
|
242
|
+
development_dependencies.each do |name, versions|
|
243
|
+
s.add_dependency( name, versions )
|
244
|
+
end
|
245
|
+
|
246
|
+
runtime_dependencies.each do |name, versions|
|
247
|
+
s.add_dependency( name, versions )
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Location
|
2
|
+
|
3
|
+
def self.deg2rad(deg)
|
4
|
+
(deg * Math::PI / 180)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.rad2deg(rad)
|
8
|
+
(rad * 180 / Math::PI)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.acos(rad)
|
12
|
+
Math.atan2(Math.sqrt(1 - rad**2), rad)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.distance_in_miles(loc1, loc2)
|
16
|
+
lat1 = loc1.latitude
|
17
|
+
lon1 = loc1.longitude
|
18
|
+
lat2 = loc2.latitude
|
19
|
+
lon2 = loc2.longitude
|
20
|
+
theta = lon1 - lon2
|
21
|
+
|
22
|
+
dist = Math.sin(self.deg2rad(lat1)) * Math.sin(deg2rad(lat2))
|
23
|
+
+ Math.cos(self.deg2rad(lat1)) * Math.cos(self.deg2rad(lat2)) * Math.cos(deg2rad(theta))
|
24
|
+
|
25
|
+
dist = self.rad2deg(self.acos(dist))
|
26
|
+
|
27
|
+
(dist * 60 * 1.1515).round #distance in miles
|
28
|
+
end
|
29
|
+
|
30
|
+
def miles_to(location)
|
31
|
+
Location.distance_in_miles(self, location)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.locationArea(location, miles)
|
35
|
+
radius = miles.to_f
|
36
|
+
latR = radius / ((6076 / 5280) * 60)
|
37
|
+
lonR = radius / (((Math.cos(location.latitude * Math::PI / 180) * 6076) / 5280) * 60)
|
38
|
+
|
39
|
+
{
|
40
|
+
:min_latitude => location.latitude - latR,
|
41
|
+
:min_longitude => location.longitude - lonR,
|
42
|
+
:max_latitude => location.latitude + latR,
|
43
|
+
:max_longitude => location.longitude + lonR
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.location_ids_in_range(location, miles)
|
48
|
+
la = Location.locationArea(location, miles)
|
49
|
+
Location.find(:all,
|
50
|
+
:select => Location.connection.quote_column_name( 'id' ),
|
51
|
+
:conditions => ["(#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'latitude'} <= ?) AND (#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'latitude'} >= ?) AND " +
|
52
|
+
"(#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'longitude'} >= ?) AND (#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'longitude'} <= ?)",
|
53
|
+
la[:max_latitude], la[:min_latitude], la[:min_longitude], la[:max_longitude]
|
54
|
+
]
|
55
|
+
).collect { |l| l.id }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.locations_in_range(location, miles)
|
59
|
+
la = Location.locationArea(location, miles)
|
60
|
+
Location.find(:all,
|
61
|
+
:conditions => ["(#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'latitude'} <= ?) AND (#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'latitude'} >= ?) AND " +
|
62
|
+
"(#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'longitude'} >= ?) AND (#{connection.quote_table_name 'locations'}.#{connection.quote_column_name 'longitude'} <= ?)",
|
63
|
+
la[:max_latitude], la[:min_latitude], la[:min_longitude], la[:max_longitude]
|
64
|
+
]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module GeonamesClient
|
2
|
+
# This class is not suitable for distances over a couple of miles. Due to the fact
|
3
|
+
# that spherical triginometry must be employed due to the curvature of the earth.
|
4
|
+
#
|
5
|
+
class Location
|
6
|
+
|
7
|
+
attr_reader :latitude_in_decimal_degrees, :longitude_in_decimal_degrees
|
8
|
+
|
9
|
+
def initialize( latitude_in_decimal_degrees,
|
10
|
+
longitude_in_decimal_degrees )
|
11
|
+
@latitude_in_decimal_degrees = latitude_in_decimal_degrees
|
12
|
+
@longitude_in_decimal_degrees = longitude_in_decimal_degrees
|
13
|
+
end
|
14
|
+
|
15
|
+
def bounding_box_locations_as_array( distance )
|
16
|
+
bounding_box_locations( distance ).map &:to_a
|
17
|
+
end
|
18
|
+
|
19
|
+
def bounding_box_locations_as_hash_like_array( distance )
|
20
|
+
[
|
21
|
+
:northeast,
|
22
|
+
:northwest,
|
23
|
+
:southwest,
|
24
|
+
:southeast
|
25
|
+
].zip( bounding_box_locations_as_array( distance ) )
|
26
|
+
end
|
27
|
+
|
28
|
+
def bounding_box_locations_as_hash( distance )
|
29
|
+
hash = {}
|
30
|
+
|
31
|
+
bounding_box_locations_as_hash_like_array( distance ).each do |direction, location|
|
32
|
+
hash[direction] = location
|
33
|
+
end
|
34
|
+
|
35
|
+
hash
|
36
|
+
end
|
37
|
+
|
38
|
+
def bounding_box_locations( distance )
|
39
|
+
%w(
|
40
|
+
northeast
|
41
|
+
northwest
|
42
|
+
southwest
|
43
|
+
southeast
|
44
|
+
).map do |direction|
|
45
|
+
send( "bounding_box_#{direction}_location", distance )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_a
|
50
|
+
[
|
51
|
+
latitude_in_decimal_degrees,
|
52
|
+
longitude_in_decimal_degrees
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
def ==( another_location )
|
57
|
+
return false unless another_location.is_a?( Location )
|
58
|
+
return false unless another_location.latitude_in_decimal_degrees == latitude_in_decimal_degrees
|
59
|
+
return false unless another_location.longitude_in_decimal_degrees == longitude_in_decimal_degrees
|
60
|
+
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
%w(
|
67
|
+
northeast
|
68
|
+
northwest
|
69
|
+
southwest
|
70
|
+
southeast
|
71
|
+
).each do |direction|
|
72
|
+
|
73
|
+
define_method "dx_#{direction}" do |distance|
|
74
|
+
rount_float( distance * Math.cos( send( "#{direction}_theta" ).degrees ), 2 )
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method "dy_#{direction}" do |distance|
|
78
|
+
rount_float( distance * Math.sin( send( "#{direction}_theta" ).degrees ), 2 )
|
79
|
+
end
|
80
|
+
|
81
|
+
define_method "delta_latitude_#{direction}" do |distance|
|
82
|
+
rount_float( send( "dy_#{direction}", distance ) / 110540.0, 6 )
|
83
|
+
end
|
84
|
+
|
85
|
+
define_method "delta_longitude_#{direction}" do |distance|
|
86
|
+
rount_float( send( "dx_#{direction}", distance ) / (111320.0 * Math.cos( latitude_in_decimal_degrees.degrees )), 6 )
|
87
|
+
end
|
88
|
+
|
89
|
+
define_method "latitude_#{direction}" do |distance|
|
90
|
+
rount_float( latitude_in_decimal_degrees + send( "delta_latitude_#{direction}", distance ), 6 )
|
91
|
+
end
|
92
|
+
|
93
|
+
define_method "longitude_#{direction}" do |distance|
|
94
|
+
rount_float( longitude_in_decimal_degrees + send( "delta_longitude_#{direction}", distance ), 6 )
|
95
|
+
end
|
96
|
+
|
97
|
+
define_method "bounding_box_#{direction}_location" do |distance|
|
98
|
+
Location.new send( "latitude_#{direction}", distance ),
|
99
|
+
send( "longitude_#{direction}", distance )
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# Measuring theta from due east.
|
105
|
+
{
|
106
|
+
:northeast => 45,
|
107
|
+
:northwest => 135,
|
108
|
+
:southwest => 225,
|
109
|
+
:southeast => 315
|
110
|
+
}.each do |direction, value|
|
111
|
+
|
112
|
+
define_method "#{direction}_theta" do
|
113
|
+
value
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def rount_float( val, precision )
|
119
|
+
sprintf( "%.#{precision}f", val ).to_f
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module GeonamesClient
|
2
|
+
class NearbyStreet
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize( options )
|
7
|
+
@name = options[:name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.all( *names )
|
11
|
+
names.map { |name| NearbyStreet.new( :name => name ) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==( another_nearby_street )
|
15
|
+
return false unless another_nearby_street.is_a?( NearbyStreet )
|
16
|
+
return false unless another_nearby_street.name == name
|
17
|
+
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def <=>( another_nearby_street )
|
22
|
+
return -1 if name < another_nearby_street.name
|
23
|
+
return 1 if name > another_nearby_street.name
|
24
|
+
|
25
|
+
0
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module GeonamesClient
|
4
|
+
class Service
|
5
|
+
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
base_uri ServiceDefinition.address
|
9
|
+
|
10
|
+
attr_reader :api_key
|
11
|
+
|
12
|
+
def initialize( api_key )
|
13
|
+
@api_key = api_key
|
14
|
+
end
|
15
|
+
|
16
|
+
def service_definition
|
17
|
+
@service_definition ||= ServiceDefinition.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_nearby_streets( options )
|
21
|
+
options.merge!( :username => api_key )
|
22
|
+
|
23
|
+
NearbyStreet.all *nearby_streets( options ).sort
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_nearby_streets_within_radius( options )
|
27
|
+
options.merge!( :username => api_key )
|
28
|
+
|
29
|
+
street_names = (nearby_streets( options ) +
|
30
|
+
nearby_streets_northeast( options ) +
|
31
|
+
nearby_streets_northwest( options ) +
|
32
|
+
nearby_streets_southeast( options ) +
|
33
|
+
nearby_streets_southwest( options ) ).uniq
|
34
|
+
|
35
|
+
|
36
|
+
NearbyStreet.all *street_names.sort
|
37
|
+
end
|
38
|
+
|
39
|
+
def nearby_streets( options )
|
40
|
+
uri = service_definition.full_nearby_streets_uri( options )
|
41
|
+
|
42
|
+
response = self.class.get( uri )
|
43
|
+
|
44
|
+
check_response_for_error( response )
|
45
|
+
|
46
|
+
response.parsed_response['geonames']['streetSegment'].map { |s| s['name'] }.uniq.compact
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_response_for_error( response )
|
50
|
+
geonames = response['geonames']
|
51
|
+
return unless geonames
|
52
|
+
error = geonames['status']
|
53
|
+
|
54
|
+
unless error.nil?
|
55
|
+
raise "Geonames returned error: (#{error['value']}) #{error['message']}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
%w(
|
60
|
+
northeast
|
61
|
+
northwest
|
62
|
+
southwest
|
63
|
+
southeast
|
64
|
+
).each do |direction|
|
65
|
+
|
66
|
+
define_method "nearby_streets_#{direction}" do |options|
|
67
|
+
location = bounding_box( options )[direction.to_sym]
|
68
|
+
lat = location.first
|
69
|
+
long = location.last
|
70
|
+
|
71
|
+
uri = service_definition.full_nearby_streets_uri( :latitude => lat,
|
72
|
+
:longitude => long,
|
73
|
+
:username => api_key )
|
74
|
+
|
75
|
+
response = self.class.get( uri )
|
76
|
+
|
77
|
+
check_response_for_error( response )
|
78
|
+
geonames = response.parsed_response['geonames']
|
79
|
+
geonames.nil? ? [] : response.parsed_response['geonames']['streetSegment'].map { |s| s['name'] }.uniq.compact
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def bounding_box( options )
|
85
|
+
location = Location.new( options[:latitude].to_f,
|
86
|
+
options[:longitude].to_f )
|
87
|
+
|
88
|
+
location.bounding_box_locations_as_hash( options[:radius] || default_radius )
|
89
|
+
end
|
90
|
+
|
91
|
+
def default_radius
|
92
|
+
402
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module GeonamesClient
|
2
|
+
class ServiceDefinition
|
3
|
+
|
4
|
+
def self.address
|
5
|
+
'api.geonames.org'
|
6
|
+
end
|
7
|
+
|
8
|
+
def base_uri
|
9
|
+
['http://', self.class.address].join
|
10
|
+
end
|
11
|
+
|
12
|
+
def nearby_streets_path
|
13
|
+
'/findNearbyStreets'
|
14
|
+
end
|
15
|
+
|
16
|
+
def nearby_streets_json_path
|
17
|
+
'/findNearbyStreetsJSON'
|
18
|
+
end
|
19
|
+
|
20
|
+
def latitude_parameter
|
21
|
+
'lat'
|
22
|
+
end
|
23
|
+
|
24
|
+
def longitude_parameter
|
25
|
+
'lng'
|
26
|
+
end
|
27
|
+
|
28
|
+
def username_parameter
|
29
|
+
'username'
|
30
|
+
end
|
31
|
+
|
32
|
+
def nearby_streets_base_path( format=:xml )
|
33
|
+
format = format.to_sym
|
34
|
+
|
35
|
+
raise "Invalid format: expected one of #{available_formats.join( ', ' )}" unless available_formats.include?( format )
|
36
|
+
|
37
|
+
return [base_uri,
|
38
|
+
format == :xml ? nearby_streets_path : nearby_streets_json_path].join ''
|
39
|
+
end
|
40
|
+
|
41
|
+
def full_nearby_streets_uri( params={} )
|
42
|
+
expected_parameters.each do |p|
|
43
|
+
raise "Please provide the :#{p} parameter" unless params.has_key?( p.to_sym )
|
44
|
+
end
|
45
|
+
|
46
|
+
format = params.delete( :format ) || default_format
|
47
|
+
|
48
|
+
[nearby_streets_base_path( format ), query_string( params )].join '?'
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def default_format
|
54
|
+
:xml
|
55
|
+
end
|
56
|
+
|
57
|
+
def available_formats
|
58
|
+
[:xml, :json]
|
59
|
+
end
|
60
|
+
|
61
|
+
def expected_parameters
|
62
|
+
%w(
|
63
|
+
latitude
|
64
|
+
longitude
|
65
|
+
username
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def query_string( params )
|
70
|
+
expected_parameters.map do |p|
|
71
|
+
[send( "#{p}_parameter" ), params[p.to_sym]].join '='
|
72
|
+
end.join '&'
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|