geoiq 0.0.3
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/lib/geoiq.rb +53 -0
- data/lib/geoiq/analysis.rb +21 -0
- data/lib/geoiq/auth.rb +21 -0
- data/lib/geoiq/base_model.rb +59 -0
- data/lib/geoiq/client.rb +18 -0
- data/lib/geoiq/dataset.rb +123 -0
- data/lib/geoiq/errors.rb +4 -0
- data/lib/geoiq/map.rb +63 -0
- data/lib/geoiq/search.rb +26 -0
- metadata +108 -0
data/lib/geoiq.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'pathname'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
dir = Pathname(__FILE__).dirname.expand_path
|
8
|
+
require dir+"geoiq/auth"
|
9
|
+
|
10
|
+
require dir+"geoiq/base_model"
|
11
|
+
require dir+"geoiq/errors"
|
12
|
+
require dir+"geoiq/search"
|
13
|
+
require dir+"geoiq/map"
|
14
|
+
require dir+"geoiq/dataset"
|
15
|
+
require dir+"geoiq/analysis"
|
16
|
+
|
17
|
+
|
18
|
+
class Geoiq
|
19
|
+
attr_reader :request, :auth, :api_methods
|
20
|
+
|
21
|
+
def initialize(url, username, password, options = {})
|
22
|
+
# @api_methods = %w(clients contacts projects tasks people)
|
23
|
+
@api_methods = %w(dataset search map)
|
24
|
+
|
25
|
+
@auth = Auth.new(url, username, password)
|
26
|
+
# raise InvalidCredentials unless credentials.valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
def dataset
|
30
|
+
@dataset||= Geoiq::Dataset.new(auth)
|
31
|
+
end
|
32
|
+
|
33
|
+
def search(query, options={}, format='json')
|
34
|
+
Geoiq::Search.new(auth).search(query, options, format)
|
35
|
+
end
|
36
|
+
|
37
|
+
def map(options={})
|
38
|
+
Geoiq::Map.new(auth, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def analysis(options={})
|
42
|
+
Geoiq::Analysis.new(auth, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def client(url, username, password, options = {})
|
48
|
+
new(url, username, password, options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class Analysis < BaseModel
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(auth, options={})
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def create(options={})
|
10
|
+
response = request(:post, "/analysis.json", {:query => options})
|
11
|
+
id = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
12
|
+
|
13
|
+
return Geoiq::Dataset.new(auth).find(id)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/geoiq/auth.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class Auth
|
3
|
+
attr_accessor :url, :username, :password, :ssl
|
4
|
+
|
5
|
+
def initialize(url, username, password)
|
6
|
+
@url, @username, @password = url, username, password
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?
|
10
|
+
!url.nil? && !username.nil? && !password.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def basic_auth
|
14
|
+
Base64.encode64("#{username}:#{password}").delete("\r\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
def host
|
18
|
+
@url
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class BaseModel
|
3
|
+
attr_reader :auth, :json
|
4
|
+
|
5
|
+
def initialize(auth, options={})
|
6
|
+
@auth = auth
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def api_methods(methods)
|
12
|
+
class_eval <<-END
|
13
|
+
def api_methods
|
14
|
+
#{methods.inspect}
|
15
|
+
end
|
16
|
+
END
|
17
|
+
end
|
18
|
+
|
19
|
+
def crud
|
20
|
+
%w(find create update delete)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
# parse in json and create a new model
|
29
|
+
def self.parse(response, auth, options=nil)
|
30
|
+
model = self.new(auth, options)
|
31
|
+
json = JSON.parse(response.body)
|
32
|
+
model.json = json #stuff the json in there for good measure
|
33
|
+
model.attributes.each do |a|
|
34
|
+
model.send("#{a}=", json[a])
|
35
|
+
end
|
36
|
+
|
37
|
+
model
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def request(method, path, options = {})
|
42
|
+
|
43
|
+
response = HTTParty.send(method, "#{auth.url}#{path}", :query => options[:query], :body => options[:body], :headers => {"Accept" => "application/xml", "Content-Type" => "application/xml; charset=utf-8", "Authorization" => "Basic #{auth.basic_auth}"}.update(options[:headers] || {}), :format => :plain)
|
44
|
+
case response.code
|
45
|
+
when 503
|
46
|
+
p 503 #TODO, raise errors
|
47
|
+
else
|
48
|
+
response
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def requires_geoiq_id
|
54
|
+
raise NoGeoiqIDFoundError unless self.geoiq_id
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/lib/geoiq/client.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Geoiq
|
2
|
+
|
3
|
+
class Client
|
4
|
+
include HTTParty
|
5
|
+
default_timeout 240
|
6
|
+
|
7
|
+
def initialize(url, username=nil, password=nil)
|
8
|
+
@username = username
|
9
|
+
@url = url
|
10
|
+
self.class.base_uri(url)
|
11
|
+
@auth = {:username => username, :password => password}
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class Dataset < BaseModel
|
3
|
+
api_methods crud + %w(features csv_upload)
|
4
|
+
|
5
|
+
attr_accessor :geoiq_id, :title, :description, :tags, :published, :data_type, :feature_count, :link, :json
|
6
|
+
|
7
|
+
def attributes
|
8
|
+
%w{title description tags published data_type feature_count link}
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(auth, options = {})
|
12
|
+
self.geoiq_id = options.delete(:geoiq_id) if options.include?(:geoiq_id)
|
13
|
+
self.title = options[:title] || "Untitled"
|
14
|
+
self.description = options[:description] || ""
|
15
|
+
self.tags = options[:tags] || ""
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# datasets.find(123)
|
20
|
+
def find(id, options={})
|
21
|
+
options = {:include_geometry=>0}
|
22
|
+
response = request(:get, "/datasets/#{id}.json", {:query => options})
|
23
|
+
dataset = Geoiq::Dataset.parse(response, auth, {:geoiq_id => id})
|
24
|
+
dataset
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(options)
|
28
|
+
requires_geoiq_id
|
29
|
+
self.title ||= options[:title]
|
30
|
+
self.description ||= options[:description]
|
31
|
+
self.tags ||= options[:tags]
|
32
|
+
self.attributes ||= options[:attributes]
|
33
|
+
overlay = {:overlay => options}
|
34
|
+
response = request(:put, "/datasets/#{self.geoiq_id}.json", {:query => overlay})
|
35
|
+
return true if response["status"].to_i == 200 || response["status"].to_i == 201
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete
|
39
|
+
requires_geoiq_id
|
40
|
+
response = request(:delete, "/datasets/#{self.geoiq_id}.json")
|
41
|
+
return true if response["status"].to_i == 204
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def features(options={})
|
46
|
+
requires_geoiq_id
|
47
|
+
|
48
|
+
response = request(:get, "/datasets/#{self.geoiq_id}/features.json", {:query => options})
|
49
|
+
features = JSON.parse(response.body)
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def csv_upload(filename, options={})
|
55
|
+
type = "text/csv"
|
56
|
+
|
57
|
+
content = File.read(filename)
|
58
|
+
response = request(:post, "/datasets.json",
|
59
|
+
{:body => content,
|
60
|
+
:headers =>{ "Content-Type" => "#{type}"},
|
61
|
+
:query => options})
|
62
|
+
|
63
|
+
id = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
64
|
+
|
65
|
+
return find(id)
|
66
|
+
end
|
67
|
+
|
68
|
+
def shp_upload(shp_file, dbf_file, shx_file)
|
69
|
+
|
70
|
+
body = shp_upload_body(shp_file, dbf_file, shx_file)
|
71
|
+
response = request(:post, "/datasets.json",
|
72
|
+
{:body => body,
|
73
|
+
:headers =>{ "Content-Type" => "multipart/form-data, boundary=89d6e3836995"}
|
74
|
+
})
|
75
|
+
id = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
76
|
+
|
77
|
+
return find(id)
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
# Create a new dataset by passing in a url, and optional type
|
82
|
+
# type = csv,kml,rss, wms, tile
|
83
|
+
def url_upload(url, options={})
|
84
|
+
query = {:url => url}.merge(options)
|
85
|
+
response = request(:post, "/datasets.json", {:query => query})
|
86
|
+
id = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
87
|
+
|
88
|
+
return find(id)
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def shp_upload_body(shp_file, dbf_file, shx_file)
|
94
|
+
boundary = "89d6e3836995"
|
95
|
+
|
96
|
+
body = []
|
97
|
+
|
98
|
+
body << "--#{boundary}\r\n"
|
99
|
+
body << "Content-Disposition: form-data; name=\"dataset[shp]\"; filename=\"#{File.basename(shp_file)}\"\r\n"
|
100
|
+
body << "Content-Type: application/octet-stream\r\n"
|
101
|
+
body << "\r\n"
|
102
|
+
body << File.read(shp_file)
|
103
|
+
|
104
|
+
body << "\r\n--#{boundary}\r\n"
|
105
|
+
body << "Content-Disposition: form-data; name=\"dataset[dbf]\"; filename=\"#{File.basename(dbf_file)}\"\r\n"
|
106
|
+
body << "Content-Type: application/octet-stream\r\n"
|
107
|
+
body << "\r\n"
|
108
|
+
body << File.read(dbf_file)
|
109
|
+
|
110
|
+
body << "\r\n--#{boundary}\r\n"
|
111
|
+
body << "Content-Disposition: form-data; name=\"dataset[shx]\"; filename=\"#{File.basename(shx_file)}\"\r\n"
|
112
|
+
body << "Content-Type: application/octet-stream\r\n"
|
113
|
+
body << "\r\n"
|
114
|
+
body << File.read(shx_file)
|
115
|
+
|
116
|
+
body << "\r\n--#{boundary}--\r\n"
|
117
|
+
|
118
|
+
body.join
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
data/lib/geoiq/errors.rb
ADDED
data/lib/geoiq/map.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class Map < BaseModel
|
3
|
+
api_methods crud + %w(add_layer)
|
4
|
+
|
5
|
+
attr_accessor :geoiq_id, :title, :description, :tags, :basemap, :published, :extent, :layers, :json
|
6
|
+
|
7
|
+
def attributes
|
8
|
+
%w{title description tags basemap extent layers}
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(auth, options={})
|
12
|
+
self.geoiq_id = options.delete(:geoiq_id) if options.include?(:geoiq_id)
|
13
|
+
self.title = options[:title] || "Untitled Map"
|
14
|
+
self.tags = (options[:tags] || []).join(",")
|
15
|
+
self.extent = options[:extent] || [-180,-90,180,90]
|
16
|
+
self.basemap = options[:basemap] || "Acetate"
|
17
|
+
self.layers = options[:layers] || []
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(id, options={})
|
22
|
+
response = request(:get, "/maps/#{id}.json", {:query => options})
|
23
|
+
map = Geoiq::Map.parse(response, auth, {:geoiq_id => id})
|
24
|
+
map
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(options={})
|
28
|
+
self.attributes.each do |a|
|
29
|
+
options.merge!({a => self.send(a)})
|
30
|
+
end
|
31
|
+
|
32
|
+
response = request(:post, "/maps.json", {:query => options})
|
33
|
+
|
34
|
+
id = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
35
|
+
|
36
|
+
return find(id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(options={})
|
40
|
+
requires_geoiq_id
|
41
|
+
response = request(:put, "/maps/#{self.geoiq_id}.json", {:query => options})
|
42
|
+
return true if response["status"].to_i == 200 || response["status"].to_i == 201
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete
|
46
|
+
requires_geoiq_id
|
47
|
+
response = request(:delete, "/maps/#{self.geoiq_id}.json")
|
48
|
+
return true if response["status"].to_i == 204
|
49
|
+
end
|
50
|
+
|
51
|
+
# layers are an array of ids of datasets to add
|
52
|
+
def add_layer(layer)
|
53
|
+
requires_geoiq_id
|
54
|
+
options = {:source => "finder:#{layer}"}
|
55
|
+
response = request(:post, "/maps/#{self.geoiq_id}/layers.json", {:query => options})
|
56
|
+
layer_index = response.headers["location"].match(/(\d+)\.json/)[1].to_i
|
57
|
+
return layer_index if response["status"].to_i == 201
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
data/lib/geoiq/search.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Geoiq
|
2
|
+
class Search
|
3
|
+
attr_reader :auth
|
4
|
+
def initialize(auth, options={})
|
5
|
+
@auth = auth
|
6
|
+
end
|
7
|
+
|
8
|
+
#format json/atom/kml
|
9
|
+
def search(query, options={}, format='json')
|
10
|
+
params = {:query => query}.merge(options)
|
11
|
+
response = request(:get, "/search.#{format}", {:query => params })
|
12
|
+
if format == 'json'
|
13
|
+
return results = JSON.parse(response.body)
|
14
|
+
else
|
15
|
+
return response.body
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def request(method, path, options = {})
|
22
|
+
response = HTTParty.send(method, "#{auth.url}#{path}", :query => options[:query], :body => options[:body], :headers => {"Accept" => "application/xml", "Content-Type" => "application/xml; charset=utf-8", "Authorization" => "Basic #{auth.basic_auth}"}.update(options[:headers] || {}), :format => :plain)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geoiq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Waters, John Hinnegan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: &2151938260 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.7.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2151938260
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: json
|
27
|
+
requirement: &2151936400 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.9
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2151936400
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: shoulda
|
38
|
+
requirement: &2151935760 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2151935760
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: fakeweb
|
49
|
+
requirement: &2151934960 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2151934960
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: geo_ruby
|
60
|
+
requirement: &2151933720 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2151933720
|
69
|
+
description:
|
70
|
+
email: tim.waters@geoiq.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- lib/geoiq/analysis.rb
|
76
|
+
- lib/geoiq/auth.rb
|
77
|
+
- lib/geoiq/base_model.rb
|
78
|
+
- lib/geoiq/client.rb
|
79
|
+
- lib/geoiq/dataset.rb
|
80
|
+
- lib/geoiq/errors.rb
|
81
|
+
- lib/geoiq/map.rb
|
82
|
+
- lib/geoiq/search.rb
|
83
|
+
- lib/geoiq.rb
|
84
|
+
homepage: http://github.com/fortiusone/geoiq_gem
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.10
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: API Wrapper around Geocommons website and the GeoIQ applications
|
108
|
+
test_files: []
|