geonames_client 1.0.0
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.
- 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
|