steflewandowski-geoapi 0.2.1
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/LICENSE +21 -0
- data/README +156 -0
- data/geoapi.gemspec +36 -0
- data/lib/geoapi/client.rb +32 -0
- data/lib/geoapi/entity.rb +308 -0
- data/lib/geoapi/entry.rb +12 -0
- data/lib/geoapi/geo_object.rb +126 -0
- data/lib/geoapi/geometry.rb +138 -0
- data/lib/geoapi/neighborhood.rb +17 -0
- data/lib/geoapi/query.rb +61 -0
- data/lib/geoapi/user_view.rb +11 -0
- data/lib/geoapi/version.rb +8 -0
- data/lib/geoapi/view.rb +100 -0
- data/lib/geoapi.rb +89 -0
- metadata +109 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Chris Bruce
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
= OVERVIEW
|
2
|
+
|
3
|
+
Unfortunately I've decided to 'fail fast' and am giving up on developing this gem:
|
4
|
+
The API isn't yet reliable enough to be able to develop with it - I'm consistently seeing the following:
|
5
|
+
|
6
|
+
* 504 bad gateway
|
7
|
+
* Connections that remain open
|
8
|
+
* Every other request giving a response, others just time out
|
9
|
+
* Search for user-entities doesn't appear to function (the reason for the app I am working on)
|
10
|
+
|
11
|
+
Sorry - if anyone wants to pick up where I left off, feel free.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
== Code examples:
|
16
|
+
|
17
|
+
=== Setting the API KEY
|
18
|
+
|
19
|
+
There are three methods for setting the apikey variable which must be sent with all requests. They are:
|
20
|
+
|
21
|
+
Defining it. Easiest: sets the API Key for use globally. Use this method unless you need multiple API Keys:
|
22
|
+
|
23
|
+
GEOAPI_KEY = "<my-apikey>"
|
24
|
+
|
25
|
+
For Rails, put this in environment.rb
|
26
|
+
|
27
|
+
Using an Environment variable in your shell.
|
28
|
+
|
29
|
+
ENV["GEOAPI_KEY"] = <my-apikey>
|
30
|
+
|
31
|
+
Using a 'Client' so you can use more than one API Key per application:
|
32
|
+
|
33
|
+
@client = GeoAPI::Client.new("<my-apikey>")
|
34
|
+
@entity = GeoAPI::Entity.find_by_id('12345', :client=>@client)
|
35
|
+
|
36
|
+
@other_client = GeoAPI::Client.new("<my-other-apikey>")
|
37
|
+
@other_entity = GeoAPI::Entity.find_by_id('abcde', :client=>@other_client)
|
38
|
+
|
39
|
+
You can also send :apikey=>"<my-apikey>" in options for Entity methods:
|
40
|
+
|
41
|
+
@entity = GeoAPI::Entity.find_by_id('12345', :apikey=>"<my-apikey>")
|
42
|
+
|
43
|
+
=== Creating new Entities
|
44
|
+
|
45
|
+
@entity = Entity.create_at_lat_lng(:id=>"moseley",:name=>"Moseley", :lat=>52.446506, :lng=>1.888213)
|
46
|
+
|
47
|
+
Creates a new Entity object at the given latitude/longitude point.
|
48
|
+
|
49
|
+
Other ways of creating entities are not yet supported, but there are Polygon and Multipoint models which need building.
|
50
|
+
|
51
|
+
== Finding Entities
|
52
|
+
|
53
|
+
Entity.search(options)
|
54
|
+
Performs and Entity search on the API. Takes a hash of options as documented on GeoAPI.com
|
55
|
+
|
56
|
+
Entity.find(options)
|
57
|
+
Finds a specific entity - you must pass :guid or :id
|
58
|
+
|
59
|
+
== Standard CRUD methods
|
60
|
+
|
61
|
+
Entity.create_at_lat_lng(:id=>"moseley",:name=>"Moseley", :lat=>52.446506, :lng=>1.888213)
|
62
|
+
The easiest way to create a new User Entity - requires an ID and a name.
|
63
|
+
|
64
|
+
Entity.find_by_id("moseley")
|
65
|
+
Gets an entity and returns the result.
|
66
|
+
|
67
|
+
Entity.find_by_guid("user-abc123-moseley")
|
68
|
+
An ID is useful for your application, but its actual GUID can also be used to retrieve it.
|
69
|
+
|
70
|
+
Entity.delete({:id=>"moseley"}) and
|
71
|
+
@entity.delete
|
72
|
+
Destroys an entity, either via guid or id.
|
73
|
+
|
74
|
+
@entity.update
|
75
|
+
|
76
|
+
== Eager loading and caching
|
77
|
+
|
78
|
+
This gem does _not_ eager load all results of a search, nor does it cache them, In order to use an item retrieved from a request, you must first load it. Eg.:
|
79
|
+
|
80
|
+
@entities = Entity.find(options)
|
81
|
+
|
82
|
+
@entities.each do |e|
|
83
|
+
e.load
|
84
|
+
puts "#{e.name} is at #{e.lat},#{e.lng}"
|
85
|
+
end
|
86
|
+
|
87
|
+
=== Automatically generated accessor functions for all Views and UserViews
|
88
|
+
|
89
|
+
@entity.twitter_view
|
90
|
+
@entity.twitter_view_entries
|
91
|
+
|
92
|
+
@entity.flickr_view
|
93
|
+
@entity.flickr_view_entries
|
94
|
+
@entity.<my_application>_view_entries
|
95
|
+
|
96
|
+
|
97
|
+
= NOTE
|
98
|
+
|
99
|
+
This is still actively being developed and is very alpha. You can currently conduct a simple search and an MQL query. The results are returned as ruby hash.
|
100
|
+
|
101
|
+
== TODO
|
102
|
+
|
103
|
+
- Allow updates to views.
|
104
|
+
|
105
|
+
|
106
|
+
= GeoAPI
|
107
|
+
|
108
|
+
A Ruby wrapper for the GeoAPI.com APIs. This gem was almost entirely inspired by the various geoplanet gems.
|
109
|
+
|
110
|
+
== Usage
|
111
|
+
|
112
|
+
=== Reverse Geocoding:
|
113
|
+
|
114
|
+
require 'geoapi'
|
115
|
+
GeoAPI.apikey = [Your App ID Here]
|
116
|
+
|
117
|
+
# Location
|
118
|
+
latitude = -27.000
|
119
|
+
longitude = -131.000
|
120
|
+
|
121
|
+
# Non Required Options
|
122
|
+
optional_parameters = {:radius => '500m', :type => 'POI', "include-parents" => true, :limit => 5, :pretty => true}
|
123
|
+
|
124
|
+
# Simple Search
|
125
|
+
result = GeoAPI::Query.simple_search(latitude, longitude, optional_parameters)
|
126
|
+
|
127
|
+
# MQL Query
|
128
|
+
q = {:lat => 37.75629, :lon => -122.4213, :radius => "1km", :entity => [{:type => "business", :guid => nil}]}
|
129
|
+
results = GeoAPI::Query.query(q)
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
== REQUIREMENTS:
|
134
|
+
|
135
|
+
To use this library, you must have a valid GeoAPI.com API Key.
|
136
|
+
You can get one at http://api.geoapi.com
|
137
|
+
|
138
|
+
Additionally, geoapi has the following gem dependencies:
|
139
|
+
|
140
|
+
* rest-client >= 0.9
|
141
|
+
* json >= 1.1.3
|
142
|
+
|
143
|
+
Please note that if you have ActiveSupport::JSON defined (either by
|
144
|
+
manually having loaded it or when you use geoapi within a Rails
|
145
|
+
application) the json dependency will be ignored and geoapi uses
|
146
|
+
ActiveSupport::JSON instead.
|
147
|
+
|
148
|
+
== INSTALL:
|
149
|
+
|
150
|
+
This gem is hosted on Gemcutter. To install gemcutter:
|
151
|
+
gem install gemcutter
|
152
|
+
gem tumble
|
153
|
+
|
154
|
+
To install geoapi after gemcutter:
|
155
|
+
gem install geoapi
|
156
|
+
|
data/geoapi.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "steflewandowski-geoapi"
|
3
|
+
s.version = "0.2.1"
|
4
|
+
s.date = "2009-11-10"
|
5
|
+
s.summary = "A Ruby wrapper for the GeoAPI.com API."
|
6
|
+
s.email = "stef@stef.io"
|
7
|
+
s.homepage = "http://github.com/steflewandowski/GeoAPI/"
|
8
|
+
s.description = "A Ruby wrapper for the GeoAPI.com API based on the work of Chris Bruce. See http://api.geoapi.com for more information about the API."
|
9
|
+
s.authors = ["Stef Lewandowski","Chris Bruce"]
|
10
|
+
|
11
|
+
s.files = [
|
12
|
+
"README",
|
13
|
+
"LICENSE",
|
14
|
+
"geoapi.gemspec",
|
15
|
+
"lib/geoapi.rb",
|
16
|
+
"lib/geoapi/geo_object.rb",
|
17
|
+
"lib/geoapi/geometry.rb",
|
18
|
+
"lib/geoapi/query.rb",
|
19
|
+
"lib/geoapi/entity.rb",
|
20
|
+
"lib/geoapi/entry.rb",
|
21
|
+
"lib/geoapi/view.rb",
|
22
|
+
"lib/geoapi/user_view.rb",
|
23
|
+
"lib/geoapi/version.rb",
|
24
|
+
"lib/geoapi/client",
|
25
|
+
"lib/geoapi/neighborhood"
|
26
|
+
]
|
27
|
+
|
28
|
+
s.add_dependency("rest-client", [">= 0.9"])
|
29
|
+
s.add_dependency("crack")
|
30
|
+
s.add_dependency("httparty")
|
31
|
+
s.add_dependency("uuidtools")
|
32
|
+
|
33
|
+
|
34
|
+
s.has_rdoc = false
|
35
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# To connect to GeoAPI, either:
|
5
|
+
#
|
6
|
+
# Add export GEOAPI_KEY=<your-api-key> in your .bashrc file
|
7
|
+
#
|
8
|
+
# @client = GeoAPI::Client.new
|
9
|
+
#
|
10
|
+
# OR
|
11
|
+
#
|
12
|
+
# @client = GeoAPI::Client.new('<your-api-key>')
|
13
|
+
#
|
14
|
+
# OR set GEOAPI_KEY='<your-api-key>' before including GeoAPI
|
15
|
+
#
|
16
|
+
# @client = GeoAPI::Client.new
|
17
|
+
|
18
|
+
def initialize(api_key=nil)
|
19
|
+
@api_key = api_key || ENV['GEOAPI_KEY'] || GeoAPI::GEOAPI_KEY
|
20
|
+
end
|
21
|
+
|
22
|
+
def api_key
|
23
|
+
@api_key
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.id_from_guid(guid,apikey)
|
27
|
+
id = guid.sub('user-','')
|
28
|
+
id = id.sub("#{apikey}-",'')
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class Entity < GeoAPI::GeoObject
|
3
|
+
|
4
|
+
attr_accessor :guid, :id, :name, :entity_type, :geom, :url, :views, :userviews, :raw_json, :errors, :shorturl, :raw_json
|
5
|
+
|
6
|
+
|
7
|
+
alias_method :geometry, :geom
|
8
|
+
|
9
|
+
def latitude
|
10
|
+
@latitude ||= geometry.latitude unless geometry.blank?
|
11
|
+
end
|
12
|
+
|
13
|
+
def longitude
|
14
|
+
@longitude ||= geometry.longitude unless geometry.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :lat, :latitude
|
18
|
+
alias_method :lon, :longitude
|
19
|
+
alias_method :lng, :longitude
|
20
|
+
|
21
|
+
# Class methods
|
22
|
+
|
23
|
+
|
24
|
+
def self.create(params)
|
25
|
+
puts "GEOAPI::Entity.create #{params.to_json}"
|
26
|
+
#required: name, geom
|
27
|
+
#optional: pass id and it will create a new guid for you as user-<apikey>-<id>
|
28
|
+
|
29
|
+
raise ArgumentError, "A name is required (pass :name in parameters)" unless params.has_key?(:name)
|
30
|
+
raise ArgumentError, "A geometry is required (pass :geom in parameters)" unless params.has_key?(:geom)
|
31
|
+
|
32
|
+
api_key = self.api_key_from_parameters(params)
|
33
|
+
|
34
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
35
|
+
|
36
|
+
id = params[:id] || UUIDTools::UUID.timestamp_create().to_s
|
37
|
+
|
38
|
+
post_url = "/e"
|
39
|
+
post_url = "/e/user-#{api_key}-#{id}?apikey=#{api_key}" unless id.blank?
|
40
|
+
post_url = "/e/#{params[:guid]}?apikey=#{api_key}" unless params[:guid].blank?
|
41
|
+
|
42
|
+
puts post_url
|
43
|
+
|
44
|
+
params.delete(:id) if params.has_key?(:id)
|
45
|
+
params.delete(:guid) if params.has_key?(:guid)
|
46
|
+
|
47
|
+
begin
|
48
|
+
results = Entity.post(post_url, {:body=> params.to_json})
|
49
|
+
rescue
|
50
|
+
raise BadRequest, "There was a problem communicating with the API"
|
51
|
+
end
|
52
|
+
|
53
|
+
raise BadRequest, results['error'] unless results['error'].blank?
|
54
|
+
|
55
|
+
#todo the result does not contain the guid, so merge it back in. Possible point of failure here?
|
56
|
+
|
57
|
+
guid = results['query']['params']['guid']
|
58
|
+
Entity.new(results['result'].merge({'guid'=>guid, 'id'=>GeoAPI::Client.id_from_guid(guid,api_key)}))
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.destroy(params)
|
62
|
+
|
63
|
+
puts "GEOAPI::Entity.destroy #{params.to_json}"
|
64
|
+
|
65
|
+
raise ArgumentError, "An id or guid is required (pass :id or :guid in parameters)" unless params.has_key?(:id) || params.has_key?(:guid)
|
66
|
+
|
67
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
68
|
+
|
69
|
+
begin
|
70
|
+
unless params[:guid].blank?
|
71
|
+
delete("/e/#{params[:guid]}?apikey=#{api_key}")
|
72
|
+
else
|
73
|
+
delete("/e/user-#{api_key}-#{params[:id]}?apikey=#{api_key}") unless params[:id].blank?
|
74
|
+
end
|
75
|
+
|
76
|
+
rescue
|
77
|
+
raise BadRequest, "There was a problem communicating with the API"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.create_at_lat_lng(*args)
|
82
|
+
|
83
|
+
params = args.extract_options!
|
84
|
+
params = params == {} ? nil : params
|
85
|
+
|
86
|
+
puts "GEOAPI::Entity.create_at_lat_lng #{params.to_json}"
|
87
|
+
|
88
|
+
raise ArgumentError, ":lat must be sent as a parameter" unless params.has_key?(:lat)
|
89
|
+
raise ArgumentError, ":lng must be sent as a parameter" unless params.has_key?(:lng)
|
90
|
+
puts "test API key #{api_key}"
|
91
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
92
|
+
|
93
|
+
p = GeoAPI::Point.new(:lat => params[:lat],:lng => params[:lng])
|
94
|
+
|
95
|
+
params.delete(:lat)
|
96
|
+
params.delete(:lng)
|
97
|
+
|
98
|
+
self.create(params.merge({:geom=>p}))
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.find(*args)
|
102
|
+
|
103
|
+
puts "GEOAPI::Entity.find #{args.to_s}"
|
104
|
+
|
105
|
+
raise ArgumentError, "First argument must be symbol (:all or :get)" unless args.first.kind_of?(Symbol)
|
106
|
+
|
107
|
+
params = args.extract_options!
|
108
|
+
params = params == {} ? nil : params
|
109
|
+
|
110
|
+
api_key = self.api_key_from_parameters(params)
|
111
|
+
|
112
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
113
|
+
|
114
|
+
case args.first
|
115
|
+
|
116
|
+
when :all
|
117
|
+
results = []
|
118
|
+
else
|
119
|
+
results = nil
|
120
|
+
|
121
|
+
raise ArgumentError, "Arguments should include a :guid or :id" if params[:guid].blank? && params[:id].blank?
|
122
|
+
|
123
|
+
params[:guid] = "user-#{api_key}-#{the_id}" unless params[:id].blank?
|
124
|
+
|
125
|
+
response = get("/e/#{params[:guid]}?apikey=#{api_key}")
|
126
|
+
|
127
|
+
begin
|
128
|
+
|
129
|
+
rescue
|
130
|
+
raise BadRequest, "There was a problem communicating with the API"
|
131
|
+
end
|
132
|
+
|
133
|
+
results = Entity.new(response['result'].merge({'guid'=>params[:guid]})) unless response['result'].blank? #the api doesn't return a guid in json?!
|
134
|
+
end
|
135
|
+
|
136
|
+
results
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.find_by_id(the_id, options={})
|
141
|
+
puts "GEOAPI::Entity.find_by_id #{the_id}"
|
142
|
+
|
143
|
+
api_key = self.api_key_from_parameters(options)
|
144
|
+
|
145
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
146
|
+
|
147
|
+
self.find(:get, :guid=>"user-#{api_key}-#{the_id}")
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.find_by_guid(the_guid, options={})
|
151
|
+
puts "GEOAPI::Entity.find_by_guid #{the_guid}"
|
152
|
+
|
153
|
+
api_key = self.api_key_from_parameters(options)
|
154
|
+
|
155
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
156
|
+
|
157
|
+
self.find(:get, :guid=>the_guid)
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Instance methods
|
162
|
+
def initialize(attrs)
|
163
|
+
super attrs
|
164
|
+
self.setup(attrs) unless attrs.blank?
|
165
|
+
end
|
166
|
+
|
167
|
+
def setup(attrs)
|
168
|
+
puts "Setup Entity with attributes: #{attrs.to_json}"
|
169
|
+
api_key = @api_key
|
170
|
+
api_key ||= self.api_key_from_parameters(params)
|
171
|
+
|
172
|
+
self.guid = attrs['guid'] if attrs.has_key?('guid')
|
173
|
+
self.guid = "user-#{@api_key}-#{attrs['id']}" if attrs.has_key?('id')
|
174
|
+
puts "GEOAPI::Entity.setup #{self.guid}"
|
175
|
+
self.id = attrs['id'] if attrs.has_key?('id')
|
176
|
+
self.id = GeoAPI::Client.id_from_guid(self.guid,api_key) if self.id.blank?
|
177
|
+
self.errors = attrs['error']
|
178
|
+
self.name = attrs['name']
|
179
|
+
self.name ||= attrs['meta']['name'] unless attrs['meta'].blank?
|
180
|
+
self.entity_type = attrs['type']
|
181
|
+
self.shorturl = attrs['shorturl']
|
182
|
+
|
183
|
+
self.geom = GeoAPI::Geometry.from_hash(attrs['geom']) unless attrs['geom'].blank?
|
184
|
+
self.geom ||= GeoAPI::Geometry.from_hash(attrs['meta']['geom']) unless attrs['meta'].blank?
|
185
|
+
|
186
|
+
|
187
|
+
self.views = []
|
188
|
+
unless attrs['views'].blank?
|
189
|
+
if attrs['views'].size > 0
|
190
|
+
attrs['views'].each do |view|
|
191
|
+
self.views << GeoAPI::View.new({'name'=>view, 'guid'=>self.guid})
|
192
|
+
|
193
|
+
# Dynamically create methods like twitter_view
|
194
|
+
|
195
|
+
(class <<self; self; end).send :define_method, :"#{view}_view" do
|
196
|
+
find_view("#{view}")
|
197
|
+
end
|
198
|
+
|
199
|
+
(class <<self; self; end).send :define_method, :"#{view}_view_entries" do
|
200
|
+
find_view_entries("#{view}")
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
self.userviews = []
|
207
|
+
unless attrs['userviews'].blank?
|
208
|
+
if attrs['userviews'].size > 0
|
209
|
+
attrs['userviews'].each do |view|
|
210
|
+
self.userviews << GeoAPI::UserView.new({'name'=>view, 'guid'=>self.guid})
|
211
|
+
|
212
|
+
# Dynamically create methods like myapp_userview
|
213
|
+
class << self
|
214
|
+
define_method "#{view}_userview" do
|
215
|
+
find_view("#{view}")
|
216
|
+
end
|
217
|
+
|
218
|
+
define_method :"#{view}_entries" do
|
219
|
+
#todo needs caching here
|
220
|
+
find_view("#{view}").entries
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
self
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
def type #type is a reserved word
|
233
|
+
self.entity_type
|
234
|
+
end
|
235
|
+
|
236
|
+
def update
|
237
|
+
puts "GEOAPI::Entity.update #{self.guid}"
|
238
|
+
|
239
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
240
|
+
|
241
|
+
self.setup(post("/e/#{guid}?apikey=#{api_key}", {:body=>self.to_json}))
|
242
|
+
end
|
243
|
+
|
244
|
+
def load
|
245
|
+
puts "GEOAPI::Entity.load #{self.guid}"
|
246
|
+
|
247
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
248
|
+
|
249
|
+
raise ArgumentError, "Properties should include a .guid or .id" if self.guid.blank? && self.id.blank?
|
250
|
+
|
251
|
+
the_guid = self.guid
|
252
|
+
the_guid ||= "user-#{api_key}-#{self.id}"
|
253
|
+
|
254
|
+
begin
|
255
|
+
response = self.class.get("/e/#{the_guid}?apikey=#{api_key}")
|
256
|
+
rescue
|
257
|
+
raise BadRequest, "There was a problem communicating with the API"
|
258
|
+
end
|
259
|
+
|
260
|
+
self.setup(response['result'].merge({'guid'=>self.guid }))
|
261
|
+
|
262
|
+
self
|
263
|
+
end
|
264
|
+
|
265
|
+
def delete
|
266
|
+
puts "GEOAPI::Entity.delete #{self.guid}"
|
267
|
+
|
268
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
269
|
+
|
270
|
+
raise ArgumentError, "Object has no :guid" if self.guid.blank?
|
271
|
+
begin
|
272
|
+
Entity.destroy(:guid=>self.guid)
|
273
|
+
rescue
|
274
|
+
raise BadRequest, "There was a problem communicating with the API"
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
def destroy
|
280
|
+
self.delete
|
281
|
+
end
|
282
|
+
|
283
|
+
def save
|
284
|
+
update
|
285
|
+
end
|
286
|
+
|
287
|
+
def to_s
|
288
|
+
self.name
|
289
|
+
end
|
290
|
+
|
291
|
+
def to_json options=nil
|
292
|
+
{:name=>name, :guid=>guid, :type=>entity_type, :geom=>geom, :views=>views, :userviews=>userviews, :shorturl=>shorturl}.to_json
|
293
|
+
end
|
294
|
+
|
295
|
+
# Common facility methods
|
296
|
+
|
297
|
+
def find_view view_name
|
298
|
+
views.each do |view|
|
299
|
+
return view if view.name == view_name
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def find_view_entries view_name
|
304
|
+
find_view(view_name).load.entries
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
308
|
+
end
|
data/lib/geoapi/entry.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class GeoObject
|
3
|
+
|
4
|
+
include HTTParty
|
5
|
+
|
6
|
+
format :json
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :api_key
|
10
|
+
end
|
11
|
+
|
12
|
+
#default_params Proc.new { :apikey => api_key} }
|
13
|
+
|
14
|
+
base_uri GeoAPI::API_URL
|
15
|
+
|
16
|
+
# Allow users to set the API key explicitly, or gain it from other sources.
|
17
|
+
# Makes for more readable code, and allows multiple keys to be used in the one application.
|
18
|
+
|
19
|
+
def initialize(attrs)
|
20
|
+
#raise ArgumentError, "A :client must be passed to when creating a GeoObject, unless unless ENV['GEOAPI_KEY'] or is set"
|
21
|
+
|
22
|
+
@api_key = self.class.api_key_from_parameters(attrs)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.api_key
|
27
|
+
@api_key ||= GeoAPI::GEOAPI_KEY
|
28
|
+
@api_key ||= ENV["GEOAPI_KEY"]
|
29
|
+
puts "API KEY: #{@api_key}"
|
30
|
+
@api_key
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.api_key_from_parameters(attrs)
|
34
|
+
unless attrs.blank?
|
35
|
+
the_api_key = attrs[:client].api_key if attrs.has_key?(:client)
|
36
|
+
the_api_key ||= attrs[:apikey] if attrs.has_key?(:apikey)
|
37
|
+
the_api_key ||= attrs[:api_key] if attrs.has_key?(:api_key)
|
38
|
+
the_api_key ||= attrs[:api_key] if attrs.has_key?(:api_key)
|
39
|
+
end
|
40
|
+
the_api_key ||= self.api_key
|
41
|
+
puts "API Key from parameters: #{the_api_key}"
|
42
|
+
@api_key = the_api_key
|
43
|
+
the_api_key
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.post path, options={}
|
47
|
+
puts "Post: #{path} : #{options.to_s}"
|
48
|
+
timeout = options[:timeout] || 5
|
49
|
+
options.delete(:timeout)
|
50
|
+
retryable( :tries => 2 ) do
|
51
|
+
Timeout::timeout(timeout) do |t|
|
52
|
+
super path, options
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.get path, options={}
|
58
|
+
puts "Get: #{path} : #{options.to_s}"
|
59
|
+
timeout = options[:timeout] || 5
|
60
|
+
options.delete(:timeout)
|
61
|
+
puts options.to_s
|
62
|
+
puts "Timeout #{timeout}"
|
63
|
+
retryable( :tries => 2 ) do
|
64
|
+
Timeout::timeout(timeout) do |t|
|
65
|
+
super path, options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.delete path, options={}
|
71
|
+
puts "Delete: #{path} : #{options.to_s}"
|
72
|
+
timeout = options[:timeout] || 5
|
73
|
+
options.delete(:timeout)
|
74
|
+
retryable( :tries => 2 ) do
|
75
|
+
Timeout::timeout(timeout) do |t|
|
76
|
+
super path, options
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.search(conditions, options={})
|
82
|
+
puts "GEOAPI::Entity.search #{conditions.to_s}"
|
83
|
+
|
84
|
+
raise ArgumentError, ":lat and :lng are required for search" unless conditions.has_key?(:lat) && conditions.has_key?(:lng)
|
85
|
+
|
86
|
+
api_key = self.api_key_from_parameters(options)
|
87
|
+
|
88
|
+
raise ArgumentError, "An API Key is required" if api_key.blank?
|
89
|
+
|
90
|
+
# Accepts all conditions from the API and passes them through - http://docs.geoapi.com/Simple-Search
|
91
|
+
|
92
|
+
conditions.merge!({:lat=>conditions[:lat],:lon=>conditions[:lng],:apikey=>api_key})
|
93
|
+
conditions.delete(:lng)
|
94
|
+
|
95
|
+
response = get("/search", {:timeout=>60, :query=>conditions})
|
96
|
+
|
97
|
+
begin
|
98
|
+
|
99
|
+
rescue
|
100
|
+
raise BadRequest, "There was a problem communicating with the API"
|
101
|
+
end
|
102
|
+
|
103
|
+
results = []
|
104
|
+
unless response['result'].blank?
|
105
|
+
response['result'].each do |result|
|
106
|
+
results << self.new(result)
|
107
|
+
end
|
108
|
+
results.reverse!
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.find params
|
113
|
+
# Find a given object by location passed as :lat, :lng
|
114
|
+
raise ArgumentError, ":lat must be sent as a parameter" unless params.has_key?(:lat)
|
115
|
+
raise ArgumentError, ":lng must be sent as a parameter" unless params.has_key?(:lng)
|
116
|
+
|
117
|
+
self.search({:lat=>params[:lat], :lng=>params[:lng],:type=>self.entity_type})
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.entity_type
|
121
|
+
"user-entity"
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class Geometry
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :coords, :geometry_type
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
# Class methods
|
10
|
+
|
11
|
+
def self.new_from_class_name class_name
|
12
|
+
geom = case class_name.downcase.gsub('_','')
|
13
|
+
|
14
|
+
when "point" then GeoAPI::Point.new
|
15
|
+
|
16
|
+
when "polygon" then GeoAPI::Polygon.new
|
17
|
+
|
18
|
+
when "multipoint" then GeoAPI::Polygon.new
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_json json
|
25
|
+
unless json.blank?
|
26
|
+
attrs = Crack::JSON.parse(json)
|
27
|
+
|
28
|
+
geom = Geometry.new_from_class_name json['type']
|
29
|
+
|
30
|
+
unless geom.blank?
|
31
|
+
|
32
|
+
geom.geometry_type = attrs['type']
|
33
|
+
|
34
|
+
geom.coords = attrs['coordinates']
|
35
|
+
|
36
|
+
geom
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_hash hash
|
43
|
+
|
44
|
+
unless hash.blank?
|
45
|
+
geom = Geometry.new_from_class_name hash['type']
|
46
|
+
|
47
|
+
unless geom.blank?
|
48
|
+
|
49
|
+
geom.geometry_type = hash['type']
|
50
|
+
|
51
|
+
geom.coords = hash['coordinates']
|
52
|
+
|
53
|
+
puts "Got geometry: #{geom}"
|
54
|
+
|
55
|
+
geom
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Instance methods
|
63
|
+
|
64
|
+
def coordinates
|
65
|
+
coords
|
66
|
+
end
|
67
|
+
|
68
|
+
def type
|
69
|
+
geometry_type
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_json options=nil
|
73
|
+
{:type=>self.geometry_type, :coordinates=>self.coords}.to_json
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize attrs
|
77
|
+
@geometry_type = self.class.name.split('::').last
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
class Point < GeoAPI::Geometry
|
83
|
+
|
84
|
+
attr_accessor :geometry_type, :coords
|
85
|
+
|
86
|
+
def latitude
|
87
|
+
coords[0]
|
88
|
+
end
|
89
|
+
|
90
|
+
def longitude
|
91
|
+
coords[1]
|
92
|
+
end
|
93
|
+
|
94
|
+
def initialize *args
|
95
|
+
|
96
|
+
params = args.extract_options!
|
97
|
+
params = params == {} ? nil : params
|
98
|
+
|
99
|
+
puts "GEOAPI::Point.new #{params.to_json}"
|
100
|
+
|
101
|
+
#raise ArgumentError, ":lat (latitude) must be sent as a parameter to the GeoAPI::Point constructor" unless params.has_key?(:lat)
|
102
|
+
#raise ArgumentError, ":lng (longitude) must be sent as a parameter to the GeoAPI::Point constructor" unless params.has_key?(:lng)
|
103
|
+
|
104
|
+
self.coords = [params[:lng].to_f, params[:lat].to_f] unless params.blank? || params[:lat].blank?
|
105
|
+
super args
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
class Multipoint < GeoAPI::Geometry
|
112
|
+
|
113
|
+
attr_accessor :geometry_type, :coords
|
114
|
+
|
115
|
+
def initialize attrs
|
116
|
+
|
117
|
+
self.coords = []
|
118
|
+
super attrs
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class Polygon < GeoAPI::Geometry
|
125
|
+
|
126
|
+
attr_accessor :geometry_type, :coords
|
127
|
+
|
128
|
+
def initialize attrs
|
129
|
+
self.coords = []
|
130
|
+
super attrs
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
#todo add additional classes
|
137
|
+
|
138
|
+
end
|
data/lib/geoapi/query.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class Query
|
3
|
+
|
4
|
+
class << self
|
5
|
+
# Uses GeoAPI's simple search method
|
6
|
+
def simple_search(lat, lon, options = {})
|
7
|
+
options[:lat] = lat
|
8
|
+
options[:lon] = lon
|
9
|
+
url = build_url('search', options)
|
10
|
+
get_then_parse(url)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Uses GeoAPI's MQL query method
|
14
|
+
def query(query)
|
15
|
+
q = JSON.generate(query)
|
16
|
+
url = build_url('q', {:q => URI.escape(q)})
|
17
|
+
get_then_parse(url)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def get_then_parse(url)
|
22
|
+
JSON.parse(get(url))
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_url(resource_path, options = {})
|
26
|
+
|
27
|
+
options[:apikey] ||= GeoAPI.apikey
|
28
|
+
query_string = build_query_params(options)
|
29
|
+
|
30
|
+
"#{GeoAPI::API_URL}#{resource_path}#{query_string}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(url)
|
34
|
+
RestClient.get(url)
|
35
|
+
rescue RestClient::RequestFailed
|
36
|
+
raise BadRequest, "Parameter invalid"
|
37
|
+
rescue RestClient::ResourceNotFound
|
38
|
+
raise NotFound, "GUID invalid"
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
# Take options and build query string
|
44
|
+
def build_query_params(options)
|
45
|
+
query = {}
|
46
|
+
|
47
|
+
#convert True/False
|
48
|
+
options.each_pair do |key, value|
|
49
|
+
new_key = key.to_s
|
50
|
+
new_val = case value
|
51
|
+
when TrueClass then 1
|
52
|
+
when FalseClass then 0
|
53
|
+
else value
|
54
|
+
end
|
55
|
+
query[new_key] = new_val
|
56
|
+
end
|
57
|
+
"?" + query.map{|k,v| "#{k}=#{v}"}.join('&')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/geoapi/view.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module GeoAPI
|
2
|
+
class View < GeoAPI::GeoObject
|
3
|
+
|
4
|
+
attr_accessor :name, :guid, :view_type, :id, :entries
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :path_prefix
|
8
|
+
end
|
9
|
+
|
10
|
+
GeoAPI::VIEW_PATH_PREFIX = "view"
|
11
|
+
GeoAPI::USERVIEW_PATH_PREFIX = "userview"
|
12
|
+
|
13
|
+
|
14
|
+
# Class methods
|
15
|
+
|
16
|
+
def self.path_prefix
|
17
|
+
case self.to_s
|
18
|
+
when "GeoAPI::View" then VIEW_PATH_PREFIX
|
19
|
+
|
20
|
+
when "GeoAPI::UserView" then USERVIEW_PATH_PREFIX
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.find(*args)
|
25
|
+
|
26
|
+
#raise ArgumentError, "First argument must be symbol (:all or :get)" unless args.first.kind_of?(Symbol)
|
27
|
+
|
28
|
+
params = args.extract_options!
|
29
|
+
params = params == {} ? nil : params
|
30
|
+
|
31
|
+
results = nil
|
32
|
+
params[:guid] = "user-#{GeoAPI::API_KEY}-#{params[:id]}" unless params[:id].blank?
|
33
|
+
raise ArgumentError, "Arguments should include a entity :guid or an :id" if params[:guid].blank? && params[:id].blank?
|
34
|
+
raise ArgumentError, "Arguments should include a view :name" if params[:name].blank?
|
35
|
+
|
36
|
+
begin
|
37
|
+
debugger
|
38
|
+
|
39
|
+
response = get("/e/#{params[:guid]}/#{self.class.path_prefix}/#{params[:name]}")
|
40
|
+
rescue
|
41
|
+
raise BadRequest, "There was a problem communicating with the API"
|
42
|
+
end
|
43
|
+
|
44
|
+
entries = {'entries' => response['result']} # There are no entries in this view
|
45
|
+
|
46
|
+
results = View.new(entries.merge({'guid'=>params[:guid], 'name'=>params[:name]})) unless response['result'].blank? #the api doesn't return a guid in json?!
|
47
|
+
|
48
|
+
results
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Instance methods
|
53
|
+
def initialize attrs
|
54
|
+
setup(attrs)
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup attrs
|
58
|
+
self.name = attrs['name']
|
59
|
+
self.guid = attrs['guid']
|
60
|
+
self.view_type = attrs['type']
|
61
|
+
|
62
|
+
self.entries = []
|
63
|
+
unless attrs['entries'].blank?
|
64
|
+
if attrs['entries'].size > 0
|
65
|
+
attrs['entries'].each do |entry|
|
66
|
+
self.entries << GeoAPI::Entry.new({'properties'=>entry})
|
67
|
+
end
|
68
|
+
self.entries.reverse!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def load
|
75
|
+
raise ArgumentError, "Properties should include a .guid or .id" if self.guid.blank? && self.id.blank?
|
76
|
+
raise ArgumentError, "Properties should include a .name" if self.name.blank?
|
77
|
+
|
78
|
+
the_guid = self.guid
|
79
|
+
|
80
|
+
the_guid ||= "user-#{GeoAPI::API_KEY}-#{self.id}"
|
81
|
+
|
82
|
+
begin
|
83
|
+
response = self.class.get("/e/#{the_guid}/#{self.class.path_prefix}/#{self.name}")
|
84
|
+
rescue
|
85
|
+
raise BadRequest, "There was a problem communicating with the API"
|
86
|
+
end
|
87
|
+
|
88
|
+
entries = {'entries' => response['result']} # There are no entries in this view
|
89
|
+
|
90
|
+
self.setup(entries.merge({'guid'=>self.guid, 'name'=>self.name }))
|
91
|
+
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_json options=nil
|
96
|
+
{:name=>name, :guid=>guid, :type=>view_type}.to_json
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/lib/geoapi.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
%w{rubygems rest_client httparty json crack/json uuidtools}.each { |x| require x }
|
3
|
+
|
4
|
+
# Patch HTTParty to debug
|
5
|
+
HTTParty::Request.class_eval do
|
6
|
+
class << self
|
7
|
+
attr_accessor :debug
|
8
|
+
end
|
9
|
+
self.debug = true
|
10
|
+
|
11
|
+
def perform_with_debug
|
12
|
+
if self.class.debug
|
13
|
+
puts "HTTParty making #{http_method::METHOD} request to:"
|
14
|
+
puts uri
|
15
|
+
puts "With Body: #{body}"
|
16
|
+
end
|
17
|
+
perform_without_debug
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :perform_without_debug, :perform
|
21
|
+
alias_method :perform, :perform_with_debug
|
22
|
+
end
|
23
|
+
|
24
|
+
# monkey patch HTTParty to use a configurable timeout
|
25
|
+
module HTTParty
|
26
|
+
class Request
|
27
|
+
private
|
28
|
+
def http
|
29
|
+
http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
|
30
|
+
http.use_ssl = (uri.port == 443)
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
http.open_timeout = http.read_timeout = options[:timeout].to_i if options[:timeout].to_i > 0
|
33
|
+
http
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def retryable(options = {}, &block)
|
39
|
+
opts = { :tries => 1, :on => Exception }.merge(options)
|
40
|
+
|
41
|
+
retry_exception, retries = opts[:on], opts[:tries]
|
42
|
+
|
43
|
+
begin
|
44
|
+
return yield
|
45
|
+
rescue retry_exception
|
46
|
+
retry if (retries -= 1) > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
yield
|
50
|
+
end
|
51
|
+
|
52
|
+
class Array
|
53
|
+
# Extract options from a set of arguments. Removes and returns the last element in the array if it's a hash, otherwise returns a blank hash.
|
54
|
+
#
|
55
|
+
# def options(*args)
|
56
|
+
# args.extract_options!
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# options(1, 2) # => {}
|
60
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
61
|
+
def extract_options!
|
62
|
+
last.is_a?(::Hash) ? pop : {}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module GeoAPI
|
67
|
+
API_VERSION = "v1"
|
68
|
+
API_URL = "http://api.geoapi.com/#{API_VERSION}/"
|
69
|
+
|
70
|
+
class ArgumentError < StandardError; end
|
71
|
+
class BadRequest < StandardError; end
|
72
|
+
class NotFound < StandardError; end
|
73
|
+
class NotAcceptable < StandardError; end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
78
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
79
|
+
|
80
|
+
require 'geoapi/geo_object'
|
81
|
+
require 'geoapi/geometry'
|
82
|
+
require 'geoapi/version'
|
83
|
+
require 'geoapi/entity'
|
84
|
+
require 'geoapi/entry'
|
85
|
+
require 'geoapi/view'
|
86
|
+
require 'geoapi/user_view'
|
87
|
+
require 'geoapi/query'
|
88
|
+
require 'geoapi/client'
|
89
|
+
require 'geoapi/neighborhood'
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: steflewandowski-geoapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stef Lewandowski
|
8
|
+
- Chris Bruce
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-11-10 00:00:00 +00:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rest-client
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0.9"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: crack
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: httparty
|
38
|
+
type: :runtime
|
39
|
+
version_requirement:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: uuidtools
|
48
|
+
type: :runtime
|
49
|
+
version_requirement:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
description: A Ruby wrapper for the GeoAPI.com API based on the work of Chris Bruce. See http://api.geoapi.com for more information about the API.
|
57
|
+
email: stef@stef.io
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files: []
|
63
|
+
|
64
|
+
files:
|
65
|
+
- README
|
66
|
+
- LICENSE
|
67
|
+
- geoapi.gemspec
|
68
|
+
- lib/geoapi.rb
|
69
|
+
- lib/geoapi/geo_object.rb
|
70
|
+
- lib/geoapi/geometry.rb
|
71
|
+
- lib/geoapi/query.rb
|
72
|
+
- lib/geoapi/entity.rb
|
73
|
+
- lib/geoapi/entry.rb
|
74
|
+
- lib/geoapi/view.rb
|
75
|
+
- lib/geoapi/user_view.rb
|
76
|
+
- lib/geoapi/version.rb
|
77
|
+
- lib/geoapi/client.rb
|
78
|
+
- lib/geoapi/neighborhood.rb
|
79
|
+
has_rdoc: true
|
80
|
+
homepage: http://github.com/steflewandowski/GeoAPI/
|
81
|
+
licenses: []
|
82
|
+
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- --main
|
86
|
+
- README.rdoc
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: "0"
|
100
|
+
version:
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.3.5
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: A Ruby wrapper for the GeoAPI.com API.
|
108
|
+
test_files: []
|
109
|
+
|