simplegeo 0.0.3 → 0.1.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/.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
|