simplegeo 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +20 -7
- data/LICENSE +1 -1
- data/README.rdoc +108 -3
- data/Rakefile +14 -16
- data/VERSION +1 -1
- data/lib/simple_geo/client.rb +171 -0
- data/lib/simple_geo/connection.rb +109 -0
- data/lib/simple_geo/endpoint.rb +71 -0
- data/lib/simple_geo/hash_utils.rb +24 -0
- data/lib/simple_geo/record.rb +56 -0
- data/lib/simple_geo.rb +23 -0
- data/lib/simplegeo.rb +2 -177
- data/simplegeo.gemspec +41 -27
- data/spec/client_spec.rb +1180 -0
- data/spec/fixtures/contains.json +127 -0
- data/spec/fixtures/get_density_by_day.json +833 -0
- data/spec/fixtures/get_density_by_hour.json +36 -0
- data/spec/fixtures/get_history.json +13 -0
- data/spec/fixtures/get_nearby.json +84 -0
- data/spec/fixtures/get_record.json +38 -0
- data/spec/fixtures/get_records.json +197 -0
- data/spec/fixtures/layer_info.json +8 -0
- data/spec/fixtures/nearby_address.json +21 -0
- data/spec/fixtures/no_such_record.json +4 -0
- data/spec/fixtures/nonetype_not_iterable.json +4 -0
- data/spec/fixtures/overlaps.json +41 -0
- data/spec/spec_helper.rb +21 -7
- metadata +61 -46
- data/spec/simplegeo_spec.rb +0 -89
- data/spec/test_keys.yml +0 -2
data/.document
ADDED
data/.gitignore
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
-
|
2
|
-
*.swo
|
3
|
-
*.swn
|
4
|
-
.tmp_*
|
5
|
-
.project
|
6
|
-
._*
|
1
|
+
## MAC OS
|
7
2
|
.DS_Store
|
8
|
-
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,11 +1,116 @@
|
|
1
|
-
=
|
1
|
+
= sg-ruby
|
2
2
|
|
3
|
-
|
3
|
+
A SimpleGeo Ruby client.
|
4
4
|
|
5
5
|
For the specific documentation on APIs (and the full list of parameters) see:
|
6
6
|
|
7
7
|
http://help.simplegeo.com/faqs/api-documentation/endpoints
|
8
8
|
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
Open the Terminal or other UNIX shell and type:
|
12
|
+
|
13
|
+
sudo gem install sg-ruby
|
14
|
+
|
15
|
+
== Examples
|
16
|
+
|
17
|
+
Start by requiring SimpleGeo and setting your authentication credentials:
|
18
|
+
|
19
|
+
require 'simple_geo'
|
20
|
+
SimpleGeo::Client.set_credentials('token', 'secret')
|
21
|
+
|
22
|
+
=== Getting a record
|
23
|
+
|
24
|
+
record = SimpleGeo::Client.get_record('com.simplegeo.global.geonames', '5373629')
|
25
|
+
|
26
|
+
=== Getting multiple records
|
27
|
+
|
28
|
+
records = SimpleGeo::Client.get_records('com.simplegeo.global.geonames', ['1234', '5678'])
|
29
|
+
|
30
|
+
=== Adding a record
|
31
|
+
|
32
|
+
record = SimpleGeo::Record.new({
|
33
|
+
:id => '1234',
|
34
|
+
:created => Time.now,
|
35
|
+
:lat => 37.759650000000001,
|
36
|
+
:lon => -122.42608,
|
37
|
+
:layer => 'com.example.testlayer',
|
38
|
+
:properties => {
|
39
|
+
:test_property => 'foobar'
|
40
|
+
}
|
41
|
+
})
|
42
|
+
SimpleGeo::Client.add_record(record)
|
43
|
+
|
44
|
+
=== Updating a record
|
45
|
+
|
46
|
+
record = SimpleGeo::Client.get_record('com.example.testlayer', '1234')
|
47
|
+
record.lat = 40.714269
|
48
|
+
record.lon = -74.005973
|
49
|
+
SimpleGeo::Client.add_record(record)
|
50
|
+
|
51
|
+
=== Adding / updating multiple records
|
52
|
+
|
53
|
+
records = [
|
54
|
+
SimpleGeo::Record.new({
|
55
|
+
:id => '1234',
|
56
|
+
:created => Time.now,
|
57
|
+
:lat => 37.759650000000001,
|
58
|
+
:lon => -122.42608,
|
59
|
+
:layer => 'com.example.testlayer',
|
60
|
+
:properties => {
|
61
|
+
:test_property => 'foobar'
|
62
|
+
}
|
63
|
+
}),
|
64
|
+
SimpleGeo::Record.new({
|
65
|
+
:id => '5678',
|
66
|
+
:created => Time.now,
|
67
|
+
:lat => 37.755470000000003,
|
68
|
+
:lon => -122.420646,
|
69
|
+
:layer => 'com.example.testlayer',
|
70
|
+
:properties => {
|
71
|
+
:mad_prop => 'baz'
|
72
|
+
}
|
73
|
+
})
|
74
|
+
]
|
75
|
+
SimpleGeo::Client.add_records('com.example.testlayer', records)
|
76
|
+
|
77
|
+
=== Deleting a record
|
78
|
+
|
79
|
+
SimpleGeo::Client.delete_record('1234')
|
80
|
+
|
81
|
+
=== Getting a record's history
|
82
|
+
|
83
|
+
history = SimpleGeo::Client.get_history('com.example.testlayer', '1234')
|
84
|
+
|
85
|
+
=== Getting nearby records
|
86
|
+
|
87
|
+
See http://help.simplegeo.com/faqs/api-documentation/endpoints for other optional params
|
88
|
+
|
89
|
+
# by lat, lon
|
90
|
+
records = SimpleGeo::Client.get_nearby_records('com.example.testlayer',
|
91
|
+
:lat => 37.759650000000001,
|
92
|
+
:lon => -122.42608)
|
93
|
+
|
94
|
+
# by geohash
|
95
|
+
records = SimpleGeo::Client.get_nearby_records('com.example.testlayer',
|
96
|
+
:geohash => '9q8yy1ujcsfm')
|
97
|
+
|
98
|
+
=== Getting a nearby address for a lat and lon
|
99
|
+
|
100
|
+
nearby_address = SimpleGeo::Client.get_nearby_address(37.759650000000001, -122.42608)
|
101
|
+
|
102
|
+
=== Getting SpotRank density information
|
103
|
+
|
104
|
+
# by day
|
105
|
+
density_info = SimpleGeo::Client.get_density(37.75965, -122.42608, 'sat')
|
106
|
+
|
107
|
+
# by hour
|
108
|
+
density_info = SimpleGeo::Client.get_density(37.75965, -122.42608, 'sat', '16' )
|
109
|
+
|
110
|
+
=== Other APIs
|
111
|
+
|
112
|
+
For more examples see: spec/client_spec.rb
|
113
|
+
|
9
114
|
== Note on Patches/Pull Requests
|
10
115
|
|
11
116
|
* Fork the project.
|
@@ -18,4 +123,4 @@ http://help.simplegeo.com/faqs/api-documentation/endpoints
|
|
18
123
|
|
19
124
|
== Copyright
|
20
125
|
|
21
|
-
Copyright (c) 2010
|
126
|
+
Copyright (c) 2010 Dan Dofter. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -5,16 +5,16 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "simplegeo"
|
8
|
-
gem.summary = %Q{
|
9
|
-
gem.
|
10
|
-
gem.
|
11
|
-
gem.
|
12
|
-
|
13
|
-
gem.
|
14
|
-
gem.
|
15
|
-
|
16
|
-
gem.
|
17
|
-
gem.
|
8
|
+
gem.summary = %Q{A SimpleGeo Ruby Client}
|
9
|
+
gem.email = "dan@dofter.com"
|
10
|
+
gem.homepage = "http://github.com/archfear/sg-ruby"
|
11
|
+
gem.authors = ["Dan Dofter"]
|
12
|
+
|
13
|
+
gem.add_dependency("oauth", ">= 0.4.0")
|
14
|
+
gem.add_dependency("json_pure")
|
15
|
+
|
16
|
+
gem.add_development_dependency "rspec", ">= 1.2.0"
|
17
|
+
gem.add_development_dependency("fakeweb", ">= 1.2.0")
|
18
18
|
end
|
19
19
|
Jeweler::GemcutterTasks.new
|
20
20
|
rescue LoadError
|
@@ -31,22 +31,20 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
31
31
|
spec.libs << 'lib' << 'spec'
|
32
32
|
spec.pattern = 'spec/**/*_spec.rb'
|
33
33
|
spec.rcov = true
|
34
|
+
spec.rcov_opts << "--sort coverage"
|
35
|
+
spec.rcov_opts << "--exclude gems,spec"
|
34
36
|
end
|
35
37
|
|
36
38
|
task :spec => :check_dependencies
|
37
39
|
|
38
40
|
task :default => :spec
|
39
41
|
|
40
|
-
|
41
|
-
gem 'hanna'
|
42
|
-
require 'hanna/rdoctask'
|
43
|
-
|
42
|
+
require 'rake/rdoctask'
|
44
43
|
Rake::RDocTask.new do |rdoc|
|
45
44
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
45
|
|
47
46
|
rdoc.rdoc_dir = 'rdoc'
|
48
|
-
rdoc.title = "simplegeo #{version}"
|
47
|
+
rdoc.title = "simplegeo-ruby #{version}"
|
49
48
|
rdoc.rdoc_files.include('README*')
|
50
49
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
-
|
52
50
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module SimpleGeo
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
@@connection = nil
|
6
|
+
@@debug = false
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def set_credentials(token, secret)
|
11
|
+
@@connection = Connection.new(token, secret)
|
12
|
+
@@connection.debug = @@debug
|
13
|
+
end
|
14
|
+
|
15
|
+
def debug=(debug_flag)
|
16
|
+
@@debug = debug_flag
|
17
|
+
@@connection.debug = @@debug if @@connection
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug
|
21
|
+
@@debug
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_record(record)
|
25
|
+
raise SimpleGeoError, "Record has no layer" if record.layer.nil?
|
26
|
+
put Endpoint.record(record.layer, record.id), record
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_record(layer, id)
|
30
|
+
delete Endpoint.record(layer, id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_record(layer, id)
|
34
|
+
record_hash = get Endpoint.record(layer, id)
|
35
|
+
record = Record.parse_geojson_hash(record_hash)
|
36
|
+
record.layer = layer
|
37
|
+
record
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_records(layer, records)
|
41
|
+
features = {
|
42
|
+
:type => 'FeatureCollection',
|
43
|
+
:features => records.collect { |record| record.to_hash }
|
44
|
+
}
|
45
|
+
post Endpoint.add_records(layer), features
|
46
|
+
end
|
47
|
+
|
48
|
+
# This request currently generates a 500 error if an unknown id is passed in.
|
49
|
+
def get_records(layer, ids)
|
50
|
+
features_hash = get Endpoint.records(layer, ids)
|
51
|
+
records = []
|
52
|
+
features_hash['features'].each do |feature_hash|
|
53
|
+
record = Record.parse_geojson_hash(feature_hash)
|
54
|
+
record.layer = layer
|
55
|
+
records << record
|
56
|
+
end
|
57
|
+
records
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_history(layer, id)
|
61
|
+
history_geojson = get Endpoint.history(layer, id)
|
62
|
+
history = []
|
63
|
+
history_geojson['geometries'].each do |point|
|
64
|
+
history << {
|
65
|
+
:created => Time.at(point['created']),
|
66
|
+
:lat => point['coordinates'][1],
|
67
|
+
:lon => point['coordinates'][0]
|
68
|
+
}
|
69
|
+
end
|
70
|
+
history
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_nearby_records(layer, options)
|
74
|
+
if options[:geohash]
|
75
|
+
endpoint = Endpoint.nearby_geohash(layer, options.delete(:geohash))
|
76
|
+
elsif options[:lat] && options[:lon]
|
77
|
+
endpoint = Endpoint.nearby_coordinates(layer,
|
78
|
+
options.delete(:lat), options.delete(:lon))
|
79
|
+
else
|
80
|
+
raise SimpleGeoError, "Either geohash or lat and lon is required"
|
81
|
+
end
|
82
|
+
|
83
|
+
options = nil if options.empty?
|
84
|
+
features_hash = get(endpoint, options)
|
85
|
+
nearby_records = {
|
86
|
+
:next_cursor => features_hash['next_cursor'],
|
87
|
+
:records => []
|
88
|
+
}
|
89
|
+
features_hash['features'].each do |feature_hash|
|
90
|
+
record = Record.parse_geojson_hash(feature_hash)
|
91
|
+
record.layer = layer
|
92
|
+
record_info = {
|
93
|
+
:distance => feature_hash['distance'],
|
94
|
+
:record => record
|
95
|
+
}
|
96
|
+
nearby_records[:records] << record_info
|
97
|
+
end
|
98
|
+
nearby_records
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_nearby_address(lat, lon)
|
102
|
+
geojson_hash = get Endpoint.nearby_address(lat, lon)
|
103
|
+
HashUtils.symbolize_keys geojson_hash['properties']
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_layer_information(layer)
|
107
|
+
layer_info = get Endpoint.layer(layer)
|
108
|
+
layer_info.delete('selfLink')
|
109
|
+
HashUtils.symbolize_keys(layer_info)
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_density(lat, lon, day, hour=nil)
|
113
|
+
geojson_hash = get Endpoint.density(lat, lon, day, hour)
|
114
|
+
geojson_hash = HashUtils.recursively_symbolize_keys(geojson_hash)
|
115
|
+
if hour.nil?
|
116
|
+
density_info = []
|
117
|
+
geojson_hash[:features].each do |hour_geojson_hash|
|
118
|
+
density_info << hour_geojson_hash[:properties].merge(
|
119
|
+
{:geometry => hour_geojson_hash[:geometry]})
|
120
|
+
end
|
121
|
+
density_info
|
122
|
+
else
|
123
|
+
geojson_hash[:properties].merge({:geometry => geojson_hash[:geometry]})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_overlaps(south, west, north, east, options=nil)
|
128
|
+
info = get Endpoint.overlaps(south, west, north, east), options
|
129
|
+
HashUtils.recursively_symbolize_keys(info)
|
130
|
+
end
|
131
|
+
|
132
|
+
# this API call seems to always return a 404
|
133
|
+
def get_boundary(id)
|
134
|
+
info = get Endpoint.boundary(id)
|
135
|
+
HashUtils.recursively_symbolize_keys(info)
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_contains(lat, lon)
|
139
|
+
info = get Endpoint.contains(lat, lon)
|
140
|
+
HashUtils.recursively_symbolize_keys(info)
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_locate(ip)
|
144
|
+
info = get Endpoint.locate(ip)
|
145
|
+
HashUtils.recursively_symbolize_keys(info)
|
146
|
+
end
|
147
|
+
|
148
|
+
def get(endpoint, data=nil)
|
149
|
+
raise NoConnectionEstablished if @@connection.nil?
|
150
|
+
@@connection.get endpoint, data
|
151
|
+
end
|
152
|
+
|
153
|
+
def delete(endpoint, data=nil)
|
154
|
+
raise NoConnectionEstablished if @@connection.nil?
|
155
|
+
@@connection.delete endpoint, data
|
156
|
+
end
|
157
|
+
|
158
|
+
def post(endpoint, data=nil)
|
159
|
+
raise NoConnectionEstablished if @@connection.nil?
|
160
|
+
@@connection.post endpoint, data
|
161
|
+
end
|
162
|
+
|
163
|
+
def put(endpoint, data=nil)
|
164
|
+
raise NoConnectionEstablished if @@connection.nil?
|
165
|
+
@@connection.put endpoint, data
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module SimpleGeo
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
attr_accessor :debug
|
5
|
+
|
6
|
+
def initialize(token, secret)
|
7
|
+
consumer = OAuth::Consumer.new(token, secret, :site => REALM)
|
8
|
+
@access_token = OAuth::AccessToken.new(consumer)
|
9
|
+
debug = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(endpoint, data=nil)
|
13
|
+
request :get, endpoint, data
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete(endpoint, data=nil)
|
17
|
+
request :delete, endpoint, data
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(endpoint, data=nil)
|
21
|
+
request :post, endpoint, data
|
22
|
+
end
|
23
|
+
|
24
|
+
def put(endpoint, data=nil)
|
25
|
+
request :put, endpoint, data
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def request(method, endpoint, data)
|
31
|
+
headers = {'User-Agent' => "SimpleGeo Ruby Client v#{VERSION}"}
|
32
|
+
|
33
|
+
if [:get, :delete].include?(method) && !data.nil?
|
34
|
+
endpoint = endpoint + '?' + build_query(data)
|
35
|
+
end
|
36
|
+
|
37
|
+
if debug
|
38
|
+
puts "request: #{method.to_s.upcase} #{endpoint}"
|
39
|
+
puts "headers:"
|
40
|
+
headers.each do |key, value|
|
41
|
+
puts "#{key}=#{value}"
|
42
|
+
end
|
43
|
+
if [:post, :put].include?(method) && !data.nil?
|
44
|
+
puts "data:"
|
45
|
+
puts data.to_json
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
case method
|
50
|
+
when :get, :delete
|
51
|
+
response = @access_token.request(method, endpoint, headers)
|
52
|
+
when :post, :put
|
53
|
+
data = data.to_json unless data.nil?
|
54
|
+
response = @access_token.request(method, endpoint, data, headers)
|
55
|
+
end
|
56
|
+
|
57
|
+
if debug
|
58
|
+
puts "\nresponse: #{response.code}"
|
59
|
+
puts "headers:"
|
60
|
+
response.header.each do |key, value|
|
61
|
+
puts "#{key}=#{value}"
|
62
|
+
end
|
63
|
+
puts "body:"
|
64
|
+
puts response.body
|
65
|
+
end
|
66
|
+
|
67
|
+
raise_errors(response)
|
68
|
+
|
69
|
+
if response.body.empty?
|
70
|
+
content = nil
|
71
|
+
else
|
72
|
+
begin
|
73
|
+
content = JSON.parse(response.body)
|
74
|
+
rescue JSON::ParserError
|
75
|
+
raise DecodeError, "content: <#{response.body}>"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
content
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_query(data)
|
83
|
+
data.map do |key, value|
|
84
|
+
[key.to_s, URI.escape(value.to_s)].join('=')
|
85
|
+
end.join('&')
|
86
|
+
end
|
87
|
+
|
88
|
+
def raise_errors(response)
|
89
|
+
response_description = "(#{response.code}): #{response.message}"
|
90
|
+
response_description += " - #{response.body}" unless response.body.empty?
|
91
|
+
|
92
|
+
case response.code.to_i
|
93
|
+
when 401
|
94
|
+
raise Unauthorized
|
95
|
+
when 404
|
96
|
+
raise NotFound
|
97
|
+
when 500
|
98
|
+
raise ServerError, "SimpleGeo had an internal error. Please let them know. #{response_description}"
|
99
|
+
when 502..503
|
100
|
+
raise Unavailable, response_description
|
101
|
+
else
|
102
|
+
unless response.is_a? Net::HTTPSuccess
|
103
|
+
raise SimpleGeoError, response_description
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SimpleGeo
|
2
|
+
|
3
|
+
class Endpoint
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def record(layer, id)
|
7
|
+
endpoint_url "records/#{layer}/#{id}.json"
|
8
|
+
end
|
9
|
+
|
10
|
+
def records(layer, ids)
|
11
|
+
ids = ids.join(',') if ids.is_a? Array
|
12
|
+
endpoint_url "records/#{layer}/#{ids}.json"
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_records(layer)
|
16
|
+
endpoint_url "records/#{layer}.json"
|
17
|
+
end
|
18
|
+
|
19
|
+
def history(layer, id)
|
20
|
+
endpoint_url "records/#{layer}/#{id}/history.json"
|
21
|
+
end
|
22
|
+
|
23
|
+
def nearby_geohash(layer, geohash)
|
24
|
+
endpoint_url "records/#{layer}/nearby/#{geohash}.json"
|
25
|
+
end
|
26
|
+
|
27
|
+
def nearby_coordinates(layer, lat, lon)
|
28
|
+
endpoint_url "records/#{layer}/nearby/#{lat},#{lon}.json"
|
29
|
+
end
|
30
|
+
|
31
|
+
def nearby_address(lat, lon)
|
32
|
+
endpoint_url "nearby/address/#{lat},#{lon}.json"
|
33
|
+
end
|
34
|
+
|
35
|
+
def density(lat, lon, day, hour=nil)
|
36
|
+
if hour.nil?
|
37
|
+
path = "density/#{day}/#{lat},#{lon}.json"
|
38
|
+
else
|
39
|
+
path = "density/#{day}/#{hour}/#{lat},#{lon}.json"
|
40
|
+
end
|
41
|
+
endpoint_url path
|
42
|
+
end
|
43
|
+
|
44
|
+
def layer(layer)
|
45
|
+
endpoint_url "layer/#{layer}.json"
|
46
|
+
end
|
47
|
+
|
48
|
+
def contains(lat, lon)
|
49
|
+
endpoint_url "contains/#{lat},#{lon}.json"
|
50
|
+
end
|
51
|
+
|
52
|
+
def overlaps(south, west, north, east)
|
53
|
+
endpoint_url "overlaps/#{south},#{west},#{north},#{east}.json"
|
54
|
+
end
|
55
|
+
|
56
|
+
def boundary(id)
|
57
|
+
endpoint_url "boundary/#{id}.json"
|
58
|
+
end
|
59
|
+
|
60
|
+
def locate(ip)
|
61
|
+
endpoint_url "locate/#{ip}.json"
|
62
|
+
end
|
63
|
+
|
64
|
+
def endpoint_url(path)
|
65
|
+
[REALM, API_VERSION, path].join('/')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimpleGeo
|
2
|
+
class HashUtils
|
3
|
+
def self.symbolize_keys(hash)
|
4
|
+
hash.inject({}) do |options, (key, value)|
|
5
|
+
options[(key.to_sym rescue key) || key] = value
|
6
|
+
options
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.recursively_symbolize_keys(object)
|
11
|
+
if object.is_a? Hash
|
12
|
+
symbolized_hash = symbolize_keys(object)
|
13
|
+
symbolized_hash.each do |key, value|
|
14
|
+
symbolized_hash[key] = recursively_symbolize_keys(value)
|
15
|
+
end
|
16
|
+
symbolized_hash
|
17
|
+
elsif object.is_a? Array
|
18
|
+
object.map { |value| recursively_symbolize_keys(value) }
|
19
|
+
else
|
20
|
+
object
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module SimpleGeo
|
2
|
+
class Record
|
3
|
+
attr_accessor :layer, :id, :lat, :lon, :type, :created, :properties
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
options = {
|
7
|
+
:created => Time.now,
|
8
|
+
:type => 'object',
|
9
|
+
:properties => {}
|
10
|
+
}.merge(options)
|
11
|
+
|
12
|
+
@id = options[:id]
|
13
|
+
@layer = options[:layer]
|
14
|
+
@type = options[:type]
|
15
|
+
@lat = options[:lat]
|
16
|
+
@lon = options[:lon]
|
17
|
+
@created = options[:created]
|
18
|
+
@properties = options[:properties]
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_hash
|
22
|
+
{
|
23
|
+
:type => 'Feature',
|
24
|
+
:id => id,
|
25
|
+
:created => created.to_i,
|
26
|
+
:geometry => {
|
27
|
+
:type => 'Point',
|
28
|
+
:coordinates => [ lon, lat ]
|
29
|
+
},
|
30
|
+
:properties => properties.merge({
|
31
|
+
:type => type
|
32
|
+
})
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_json
|
37
|
+
self.to_hash.to_json
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
other.class == self.class && self.to_hash == other.to_hash
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.parse_geojson_hash(json_hash)
|
45
|
+
Record.new(
|
46
|
+
:id => json_hash['id'],
|
47
|
+
:type => json_hash['properties'].delete('type'),
|
48
|
+
:lat => json_hash['geometry']['coordinates'][1],
|
49
|
+
:lon => json_hash['geometry']['coordinates'][0],
|
50
|
+
:created => Time.at(json_hash['created']),
|
51
|
+
:properties => HashUtils.recursively_symbolize_keys(json_hash['properties'])
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/simple_geo.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
require 'oauth'
|
4
|
+
|
5
|
+
require 'simple_geo/hash_utils'
|
6
|
+
require 'simple_geo/connection'
|
7
|
+
require 'simple_geo/endpoint'
|
8
|
+
require 'simple_geo/client'
|
9
|
+
require 'simple_geo/record'
|
10
|
+
|
11
|
+
module SimpleGeo
|
12
|
+
API_VERSION = '0.1'.freeze
|
13
|
+
REALM = "http://api.simplegeo.com"
|
14
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
|
15
|
+
|
16
|
+
class SimpleGeoError < StandardError; end
|
17
|
+
class Unauthorized < SimpleGeoError; end
|
18
|
+
class NotFound < SimpleGeoError; end
|
19
|
+
class ServerError < SimpleGeoError; end
|
20
|
+
class Unavailable < SimpleGeoError; end
|
21
|
+
class DecodeError < SimpleGeoError; end
|
22
|
+
class NoConnectionEstablished < SimpleGeoError; end
|
23
|
+
end
|