citysdk 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -27
- data/bin/{csdk → citysdk-cli} +0 -0
- data/lib/citysdk/api.rb +64 -105
- data/lib/citysdk/file_reader.rb +87 -89
- data/lib/citysdk/importer.rb +34 -41
- data/lib/citysdk/util.rb +4 -5
- data/lib/citysdk.rb +5 -6
- data/spec/api_spec.rb +2 -6
- data/spec/import_spec.rb +7 -7
- metadata +4 -5
- data/examples/simple_api.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 470ce38f410d78f4caf61b12f9a26a7e42f8fab9
|
4
|
+
data.tar.gz: 67fb900ec6bdf7a09db87fb81e4f808fe037b676
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 761fde18d53a8a0f1cfceb9b687841ec324a98c70283b5b7ee4a33ed813305392949f37d69ae9bcb6e0d6a3eea7051aa37d916450cc3acda14eb77a9222ce8c6
|
7
|
+
data.tar.gz: 8eb62b0eafccb689ea4036631676954dd72275da1ca409e8d1a5e1cde7315325cd5dcacbd730db33d9339c922e4d44be705033851e4b87a4792600a53d0f3b4f
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# CitySDK GEM
|
2
2
|
|
3
|
-
The CitySDK gem encapulates the CitySDK LD
|
4
|
-
The CitySDK LD
|
5
|
-
Find the platform itself on [
|
3
|
+
The CitySDK gem encapulates the CitySDK LD API, and offers high-level file import functionalities.
|
4
|
+
The CitySDK LD API is part of an open data distribution platform developed in the EU CitySDK program by [Waag Society](http://waag.org).
|
5
|
+
Find the platform itself on [GitHub](https://github.com/waagsociety/citysdk-ld), background is [here](http://dev.citysdk.waag.org).
|
6
6
|
|
7
|
-
In order to best get an overview of the way to use the
|
8
|
-
|
9
|
-
|
7
|
+
In order to best get an overview of the way to use the gem to import files into the CitySDK LD API, have a look at the [`admr` importer](https://github.com/waagsociety/citysdk-amsterdam/tree/master/importers/admr) for the top-level administrative regions in the Netherlands. The data consists of three ESRI Shapefiles; the importer is well-commented, explaining most of the possibilities of the gem.
|
8
|
+
|
9
|
+
The `bin` directory contains a preliminary version of the CitySDK LD API CLI tool. __😁 Warning, unfinished 😁!__
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
@@ -18,12 +18,11 @@ If you're using Bundler, add the gem to Gemfile.
|
|
18
18
|
|
19
19
|
gem 'citysdk'
|
20
20
|
|
21
|
-
Then run `bundle install`.
|
22
|
-
|
21
|
+
Then, run `bundle install`.
|
23
22
|
|
24
23
|
## Usage
|
25
|
-
|
26
|
-
The gem exposes
|
24
|
+
|
25
|
+
The gem can be used on two different levels, either simply as a wrapper around the API, or as a means to read, convert and import various types of data files. The gem exposes its functionality through three different objects:
|
27
26
|
|
28
27
|
- CitySDK::API
|
29
28
|
- CitySDK::FileReader
|
@@ -33,38 +32,29 @@ The FileReader can be used stand-alone to read, edit and save data files, the Im
|
|
33
32
|
|
34
33
|
The FileReader has support for CSV, Shape and (Geo)Json files. XML is currently not supported; we recommend [OpenRefine](https://github.com/OpenRefine/OpenRefine/wiki/Downloads) to convert these to either CSV or JSON.
|
35
34
|
|
36
|
-
|
37
35
|
### CitySDK::API Usage
|
38
36
|
|
39
|
-
|
40
|
-
CALL | Description
|
37
|
+
Call | Description
|
41
38
|
|:-------------------------------------|:-------------------------------------------------------
|
42
39
|
`@api = CitySDK::API.new('<endpoint IP>')` | Establish a link to the particular endpoint
|
43
40
|
`@api.authenticate('<name>','<password>')` | For reading this is not necessary, for writing and deleting you need to authenticate. The authentication times out if not used (is reset by writing to the API). This call takes an optional block for immediate automatic release when the block has been called.
|
44
|
-
`@api.get path` | Simply issue a 'GET' against the API; the results are returned as a
|
45
|
-
`@api.put path,data` | PUT a resource; see [
|
46
|
-
`@api.post path,data` | POST a resource; see [
|
47
|
-
`@api.patch path,data` | PATCH a resource; see [
|
41
|
+
`@api.get path` | Simply issue a 'GET' against the API; the results are returned as a Ruby Hash.
|
42
|
+
`@api.put path,data` | PUT a resource; see [documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
|
43
|
+
`@api.post path,data` | POST a resource; see [documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
|
44
|
+
`@api.patch path,data` | PATCH a resource; see [documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
|
48
45
|
`@api.delete path` | Issue a DELETE to the API; path points to the resource to delete. Requires authentication.
|
49
|
-
`@api.release` | This call will flush any buffered object that were scheduled to be created or updated. See also batch_size
|
46
|
+
`@api.release` | This call will flush any buffered object that were scheduled to be created or updated. See also `batch_size`, below.
|
50
47
|
`@api.set_layer(layername)` | Set the the layer for subsequent 'create_object' calls. User must be authenticate for this layer in order to sucesfully create objects.
|
51
48
|
`@api.create_object(objhash)` | Adds an object to the database. See also batch_size, below.
|
52
49
|
`@api.layers` | Shortcut for `get '/layers'`
|
53
50
|
`@api.owners` | Shortcut for `get '/owners'`
|
54
51
|
`@api.objects(layer=nil)` | Shortcut for `get '/objects'`. When a layer name is supplied, returns only objects from with data on this layer, and the layerdata itself.
|
55
52
|
`@api.next` | When more results are available, returns the next page.
|
56
|
-
`@api.format = <format>` | Specify the output format. Currently supported are
|
57
|
-
`@api.
|
53
|
+
`@api.format = <format>` | Specify the output format. Currently supported are `json-ld` and `json`.
|
54
|
+
`@api.per_page = <per_page>` | Specify the number of features returned; default is 25.
|
58
55
|
`@api.batch_size = <n>` | When adding objects thorugh 'create_object', they are buffered until '<n>' objects are available, then a single call is issuesd to the API.
|
59
56
|
`@api.last_result` | Returns a Hash with the last HTTP status and the headers returned from the last call.
|
60
57
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
58
|
## Contributing
|
69
59
|
|
70
60
|
1. Fork it
|
data/bin/{csdk → citysdk-cli}
RENAMED
File without changes
|
data/lib/citysdk/api.rb
CHANGED
@@ -1,16 +1,8 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'faraday'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
4
|
module CitySDK
|
7
5
|
|
8
|
-
def log(m)
|
9
|
-
File.open(File.expand_path('~/csdk.log'), "a") do |f|
|
10
|
-
f.write(m + "\n")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
class HostException < ::Exception
|
15
7
|
end
|
16
8
|
|
@@ -18,35 +10,30 @@ module CitySDK
|
|
18
10
|
attr_reader :last_result
|
19
11
|
attr_reader :error
|
20
12
|
attr_accessor :batch_size
|
21
|
-
attr_accessor :
|
13
|
+
attr_accessor :per_page
|
22
14
|
attr_accessor :format
|
23
15
|
|
24
|
-
|
25
|
-
type: "FeatureCollection",
|
26
|
-
features: []
|
27
|
-
}
|
28
|
-
|
29
|
-
def initialize(host, port=nil)
|
16
|
+
def initialize(host)
|
30
17
|
@error = '';
|
31
18
|
@layer = '';
|
32
19
|
@batch_size = 1000;
|
33
|
-
@
|
20
|
+
@per_page = 25;
|
34
21
|
@format = 'jsonld'
|
35
22
|
@updated = @created = 0;
|
36
|
-
set_host(host
|
23
|
+
set_host(host)
|
37
24
|
end
|
38
|
-
|
39
|
-
def authenticate(n,p)
|
40
|
-
@name = n;
|
41
|
-
@passw = p;
|
42
25
|
|
43
|
-
|
44
|
-
|
45
|
-
|
26
|
+
def authenticate(name, password)
|
27
|
+
@name = name;
|
28
|
+
@password = password;
|
29
|
+
|
30
|
+
resp = @connection.get '/session', { name: @name, password: @password }
|
31
|
+
if resp.status.between?(200, 299)
|
32
|
+
resp = CitySDK::parse_json(resp.body)
|
46
33
|
if (resp.class == Hash) and resp[:session_key]
|
47
34
|
@connection.headers['X-Auth'] = resp[:session_key]
|
48
35
|
else
|
49
|
-
raise Exception.new(
|
36
|
+
raise Exception.new('Invalid credentials')
|
50
37
|
end
|
51
38
|
else
|
52
39
|
raise Exception.new(resp.body)
|
@@ -61,55 +48,41 @@ module CitySDK
|
|
61
48
|
true
|
62
49
|
end
|
63
50
|
|
64
|
-
def set_host(host
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@host.gsub!(/^http(s)?:\/\//,'')
|
69
|
-
|
70
|
-
if port.nil?
|
71
|
-
if host =~ /^(.*):(\d+)$/
|
72
|
-
@port = $2
|
73
|
-
@host = $1
|
74
|
-
else
|
75
|
-
@port = 80
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
if !($nohttps or @host =~ /.+\.dev/ or @host == 'localhost' or @host == '127.0.0.1' or @host == '0.0.0.0')
|
80
|
-
@connection = Faraday.new :url => "https://#{@host}", :ssl => {:verify => false }
|
51
|
+
def set_host(host)
|
52
|
+
if host.index('https') == 0
|
53
|
+
@connection = Faraday.new url: host, ssl: { verify: false }
|
81
54
|
else
|
82
|
-
@connection = Faraday.new :
|
55
|
+
@connection = Faraday.new url: host
|
83
56
|
end
|
57
|
+
|
84
58
|
@connection.headers = {
|
85
|
-
:user_agent => '
|
59
|
+
:user_agent => 'CitySDK LD API GEM ' + CitySDK::VERSION,
|
86
60
|
:content_type => 'application/json'
|
87
61
|
}
|
88
|
-
begin
|
62
|
+
begin
|
89
63
|
get('/')
|
90
64
|
rescue Exception => e
|
91
|
-
raise CitySDK::Exception.new("Trouble connecting to
|
65
|
+
raise CitySDK::Exception.new("Trouble connecting to API @ #{host}")
|
92
66
|
end
|
93
|
-
@create =
|
67
|
+
@create = {
|
68
|
+
type: "FeatureCollection",
|
69
|
+
features: []
|
70
|
+
}
|
94
71
|
end
|
95
|
-
|
96
|
-
def
|
72
|
+
|
73
|
+
def add_format(path)
|
97
74
|
if path !~ /format/
|
98
75
|
path = path + ((path =~ /\?/) ? "&" : "?") + "format=#{@format}"
|
99
76
|
end
|
100
77
|
return path if path =~ /per_page/
|
101
|
-
path + "&per_page=#{@
|
102
|
-
end
|
103
|
-
|
104
|
-
def set_createTemplate(ctpl)
|
105
|
-
ctpl[:features] = []
|
106
|
-
@create = @@create_tpl = ctpl
|
78
|
+
path + "&per_page=#{@per_page}"
|
107
79
|
end
|
108
80
|
|
109
81
|
def set_layer(l)
|
82
|
+
create_flush
|
110
83
|
@layer = l
|
111
84
|
end
|
112
|
-
|
85
|
+
|
113
86
|
def next
|
114
87
|
@next ? get(@next) : "{}"
|
115
88
|
end
|
@@ -130,85 +103,72 @@ module CitySDK
|
|
130
103
|
@create[:features] << n
|
131
104
|
create_flush if @create[:features].length >= @batch_size
|
132
105
|
end
|
133
|
-
|
106
|
+
|
134
107
|
def authorized?
|
135
|
-
!! @connection.headers['X-Auth']
|
108
|
+
!! @connection.headers['X-Auth']
|
136
109
|
end
|
137
110
|
|
138
111
|
def release
|
139
|
-
|
112
|
+
# send any remaining entries in the create buffer
|
113
|
+
create_flush
|
140
114
|
if authorized?
|
141
115
|
resp = @connection.delete('/session')
|
142
116
|
if resp.status.between?(200, 299)
|
143
117
|
@connection.headers.delete('X-Auth')
|
144
118
|
else
|
145
|
-
@error = CitySDK::
|
119
|
+
@error = CitySDK::parse_json(resp.body)[:error]
|
146
120
|
raise HostException.new(@error)
|
147
121
|
end
|
148
122
|
end
|
149
123
|
return {created: @created}
|
150
124
|
end
|
151
|
-
|
125
|
+
|
152
126
|
def delete(path)
|
153
|
-
|
154
|
-
resp = @connection.delete(addFormat(path))
|
155
|
-
if resp.status.between?(200, 299)
|
156
|
-
@last_result = { status: resp.status, headers: resp.headers }
|
157
|
-
return (resp.body and resp.body !~ /\s*/) ? CitySDK::parseJson(resp.body) : ''
|
158
|
-
end
|
159
|
-
@error = CitySDK::parseJson(resp.body)[:error]
|
160
|
-
raise HostException.new(@error)
|
161
|
-
end
|
162
|
-
raise CitySDK::Exception.new("DELETE needs authorization.")
|
127
|
+
write :delete, path
|
163
128
|
end
|
164
|
-
|
165
|
-
def post(path,data)
|
166
|
-
if authorized?
|
167
|
-
resp = @connection.post(addFormat(path),data.to_json)
|
168
|
-
@last_result = { status: resp.status, headers: resp.headers }
|
169
|
-
return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
|
170
|
-
@error = resp.body # CitySDK::parseJson(resp.body)[:error]
|
171
129
|
|
172
|
-
|
173
|
-
|
174
|
-
|
130
|
+
def post(path, data)
|
131
|
+
write :post, path, data
|
132
|
+
end
|
175
133
|
|
176
|
-
|
177
|
-
|
178
|
-
raise CitySDK::Exception.new("POST needs authorization.")
|
134
|
+
def patch(path, data)
|
135
|
+
write :patch, path, data
|
179
136
|
end
|
180
137
|
|
181
|
-
def
|
182
|
-
|
183
|
-
resp = @connection.patch(addFormat(path),data.to_json)
|
184
|
-
@last_result = { status: resp.status, headers: resp.headers }
|
185
|
-
return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
|
186
|
-
@error = CitySDK::parseJson(resp.body)[:error]
|
187
|
-
raise HostException.new(@error)
|
188
|
-
end
|
189
|
-
raise CitySDK::Exception.new("PATCH needs authorization.")
|
138
|
+
def put(path, data)
|
139
|
+
write :put, path, data
|
190
140
|
end
|
191
141
|
|
192
|
-
def
|
193
|
-
if authorized?
|
194
|
-
|
142
|
+
def write(method, path, data = nil)
|
143
|
+
if authorized?
|
144
|
+
payload = data ? data.to_json : nil
|
145
|
+
resp = @connection.send(method, path, payload)
|
195
146
|
@last_result = { status: resp.status, headers: resp.headers }
|
196
|
-
|
197
|
-
|
147
|
+
|
148
|
+
if resp.status == 401 and @name and @password
|
149
|
+
# API was authenticated before, so probably timed out. Try again!
|
150
|
+
if authenticate(@name, @password)
|
151
|
+
resp = @connection.send(method, path, payload)
|
152
|
+
@last_result = { status: resp.status, headers: resp.headers }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
return CitySDK::parse_json(resp.body) if resp.status.between?(200, 299)
|
157
|
+
@error = CitySDK::parse_json(resp.body)[:error] || {status: resp.status}
|
198
158
|
raise HostException.new(@error)
|
199
159
|
end
|
200
|
-
raise CitySDK::Exception.new("
|
160
|
+
raise CitySDK::Exception.new("#{method.upcase} needs authorization")
|
201
161
|
end
|
202
162
|
|
203
163
|
def get(path)
|
204
|
-
resp = @connection.get(
|
164
|
+
resp = @connection.get(add_format(path))
|
205
165
|
@next = (resp.headers['Link'] =~ /^<(.+)>;\s*rel="next"/) ? $1 : nil
|
206
166
|
@last_result = { status: resp.status, headers: resp.headers }
|
207
|
-
return CitySDK::
|
208
|
-
@error = CitySDK::
|
167
|
+
return CitySDK::parse_json(resp.body) if resp.status.between?(200, 299)
|
168
|
+
@error = CitySDK::parse_json(resp.body)[:error]
|
209
169
|
raise HostException.new(@error)
|
210
170
|
end
|
211
|
-
|
171
|
+
|
212
172
|
def create_flush
|
213
173
|
if @create[:features].length > 0
|
214
174
|
tally post("/layers/#{@layer}/objects",@create)
|
@@ -219,8 +179,7 @@ module CitySDK
|
|
219
179
|
def tally(res)
|
220
180
|
@created += res.length
|
221
181
|
end
|
222
|
-
|
182
|
+
|
223
183
|
end
|
224
184
|
|
225
185
|
end
|
226
|
-
|
data/lib/citysdk/file_reader.rb
CHANGED
@@ -8,48 +8,48 @@ require 'tmpdir'
|
|
8
8
|
module CitySDK
|
9
9
|
|
10
10
|
class FileReader
|
11
|
-
|
11
|
+
|
12
12
|
RE_Y = /lat|(y.*coord)|(y.*pos.*)|(y.*loc(atie|ation)?)/i
|
13
13
|
RE_X = /lon|lng|(x.*coord)|(x.*pos.*)|(x.*loc(atie|ation)?)/i
|
14
14
|
RE_GEO = /^(geom(etry)?|location|locatie|coords|coordinates)$/i
|
15
15
|
RE_NAME = /(title|titel|naam|name)/i
|
16
16
|
RE_A_NAME = /^(naam|name|title|titel)$/i
|
17
|
-
|
17
|
+
|
18
18
|
attr_reader :file, :content,:params
|
19
19
|
|
20
20
|
def initialize(pars)
|
21
21
|
@params = pars
|
22
22
|
file_path = File.expand_path(@params[:file_path])
|
23
23
|
if File.extname(file_path) == '.csdk'
|
24
|
-
|
24
|
+
read_csdk(file_path)
|
25
25
|
else
|
26
26
|
ext = @params[:originalfile] ? File.extname(@params[:originalfile]) : File.extname(file_path)
|
27
27
|
case ext
|
28
28
|
when /\.zip/i
|
29
|
-
|
29
|
+
read_zip(file_path)
|
30
30
|
when /\.(geo)?json/i
|
31
|
-
|
31
|
+
read_json(file_path)
|
32
32
|
when /\.shp/i
|
33
|
-
|
33
|
+
read_shapefile(file_path)
|
34
34
|
when /\.csv|tsv/i
|
35
|
-
|
35
|
+
read_csv(file_path)
|
36
36
|
when /\.csdk/i
|
37
|
-
|
37
|
+
read_csdk(file_path)
|
38
38
|
else
|
39
39
|
raise "Unknown or unsupported file type: #{ext}."
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
@params[:rowcount] = @content.length
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
get_fields unless @params[:fields]
|
45
|
+
guess_name unless @params[:name]
|
46
|
+
guess_srid unless @params[:srid]
|
47
|
+
find_unique_field unless @params[:unique_id]
|
48
|
+
get_address unless @params[:hasaddress]
|
49
|
+
set_id_name
|
50
50
|
end
|
51
|
-
|
52
|
-
def
|
51
|
+
|
52
|
+
def get_address
|
53
53
|
pd = pc = hn = ad = false
|
54
54
|
@params[:housenumber] = nil
|
55
55
|
@params[:hasaddress] = 'unknown'
|
@@ -67,7 +67,7 @@ module CitySDK
|
|
67
67
|
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
70
|
+
def set_id_name
|
71
71
|
count = 123456
|
72
72
|
if @params[:unique_id]
|
73
73
|
@content.each do |h|
|
@@ -86,8 +86,8 @@ module CitySDK
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
90
|
-
def
|
89
|
+
|
90
|
+
def find_unique_field
|
91
91
|
fields = {}
|
92
92
|
@params[:unique_id] = nil
|
93
93
|
@content.each do |h|
|
@@ -103,10 +103,10 @@ module CitySDK
|
|
103
103
|
break
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
end
|
108
108
|
|
109
|
-
def
|
109
|
+
def guess_name
|
110
110
|
@params[:name] = nil
|
111
111
|
@params[:fields].reverse.each do |k|
|
112
112
|
if(k.to_s =~ RE_A_NAME)
|
@@ -119,7 +119,7 @@ module CitySDK
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
def
|
122
|
+
def get_fields
|
123
123
|
@params[:fields] = []
|
124
124
|
@params[:original_fields] = []
|
125
125
|
@params[:alternate_fields] = {}
|
@@ -130,10 +130,10 @@ module CitySDK
|
|
130
130
|
@params[:alternate_fields][k] = k
|
131
131
|
end
|
132
132
|
end
|
133
|
-
|
134
|
-
def
|
133
|
+
|
134
|
+
def guess_srid
|
135
135
|
return unless @content[0][:geometry] and @content[0][:geometry].class == Hash
|
136
|
-
@params[:srid] = 4326
|
136
|
+
@params[:srid] = 4326
|
137
137
|
g = @content[0][:geometry][:coordinates]
|
138
138
|
if(g)
|
139
139
|
while g[0].is_a?(Array)
|
@@ -141,19 +141,19 @@ module CitySDK
|
|
141
141
|
end
|
142
142
|
lon = g[0]
|
143
143
|
lat = g[1]
|
144
|
-
# if lon > -180.0 and lon < 180.0 and lat > -90.0 and lat < 90.0
|
145
|
-
# @params[:srid] = 4326
|
144
|
+
# if lon > -180.0 and lon < 180.0 and lat > -90.0 and lat < 90.0
|
145
|
+
# @params[:srid] = 4326
|
146
146
|
# else
|
147
147
|
if lon.between?(-7000.0,300000.0) and lat.between?(289000.0,629000.0)
|
148
148
|
# Dutch new rd system
|
149
149
|
@params[:srid] = 28992
|
150
150
|
end
|
151
|
-
else
|
152
|
-
|
151
|
+
else
|
152
|
+
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
156
|
-
def
|
155
|
+
|
156
|
+
def find_col_sep(f)
|
157
157
|
a = f.gets
|
158
158
|
b = f.gets
|
159
159
|
[";","\t","|"].each do |s|
|
@@ -162,7 +162,7 @@ module CitySDK
|
|
162
162
|
','
|
163
163
|
end
|
164
164
|
|
165
|
-
def
|
165
|
+
def is_wkb_geometry?(s)
|
166
166
|
begin
|
167
167
|
f = GeoRuby::SimpleFeatures::GeometryFactory::new
|
168
168
|
p = GeoRuby::SimpleFeatures::HexEWKBParser.new(f)
|
@@ -174,7 +174,7 @@ module CitySDK
|
|
174
174
|
nil
|
175
175
|
end
|
176
176
|
|
177
|
-
def
|
177
|
+
def is_wkt_geometry?(s)
|
178
178
|
begin
|
179
179
|
f = GeoRuby::SimpleFeatures::GeometryFactory::new
|
180
180
|
p = GeoRuby::SimpleFeatures::EWKTParser.new(f)
|
@@ -187,7 +187,7 @@ module CitySDK
|
|
187
187
|
end
|
188
188
|
|
189
189
|
GEOMETRIES = ["point", "multipoint", "linestring", "multilinestring", "polygon", "multipolygon"]
|
190
|
-
def
|
190
|
+
def is_geo_json?(s)
|
191
191
|
return nil if s.class != Hash
|
192
192
|
begin
|
193
193
|
if GEOMETRIES.include?(s[:type].downcase)
|
@@ -207,8 +207,8 @@ module CitySDK
|
|
207
207
|
nil
|
208
208
|
end
|
209
209
|
|
210
|
-
def
|
211
|
-
# begin
|
210
|
+
def geom_from_text(coords)
|
211
|
+
# begin
|
212
212
|
# a = factory.parse_wkt(coords)
|
213
213
|
# rescue
|
214
214
|
# end
|
@@ -219,14 +219,14 @@ module CitySDK
|
|
219
219
|
coor = $2.gsub('(','[').gsub(')',']')
|
220
220
|
coor = coor.gsub(/([-+]?[0-9]*\.?[0-9]+)\s+([-+]?[0-9]*\.?[0-9]+)/) { "[#{$1},#{$2}]" }
|
221
221
|
coor = JSON.parse(coor)
|
222
|
-
return { :type => type,
|
222
|
+
return { :type => type,
|
223
223
|
:coordinates => coor }
|
224
224
|
end
|
225
225
|
end
|
226
226
|
{}
|
227
227
|
end
|
228
|
-
|
229
|
-
def
|
228
|
+
|
229
|
+
def find_geometry(xfield=nil, yfield=nil)
|
230
230
|
unless(xfield and yfield)
|
231
231
|
@params[:hasgeometry] = nil
|
232
232
|
xs = true
|
@@ -236,35 +236,35 @@ module CitySDK
|
|
236
236
|
next if k.nil?
|
237
237
|
|
238
238
|
if k.to_s =~ RE_GEO
|
239
|
-
|
240
|
-
srid,g_type =
|
239
|
+
|
240
|
+
srid,g_type = is_wkb_geometry?(v)
|
241
241
|
if(srid)
|
242
242
|
@params[:srid] = srid
|
243
243
|
@params[:geomtry_type] = g_type
|
244
244
|
@content.each do |h|
|
245
|
-
a,b,g =
|
245
|
+
a,b,g = is_wkb_geometry?(h[:properties][:data][k])
|
246
246
|
h[:geometry] = g
|
247
247
|
h[:properties][:data].delete(k)
|
248
248
|
end
|
249
249
|
@params[:hasgeometry] = k
|
250
250
|
return true
|
251
251
|
end
|
252
|
-
|
253
|
-
|
254
|
-
srid,g_type =
|
252
|
+
|
253
|
+
|
254
|
+
srid,g_type = is_wkt_geometry?(v)
|
255
255
|
if(srid)
|
256
256
|
@params[:srid] = srid
|
257
257
|
@params[:geomtry_type] = g_type
|
258
258
|
@content.each do |h|
|
259
|
-
a,b,g =
|
259
|
+
a,b,g = is_wkt_geometry?(h[:properties][:data][k])
|
260
260
|
h[:geometry] = g
|
261
261
|
h[:properties][:data].delete(k)
|
262
262
|
end
|
263
263
|
@params[:hasgeometry] = k
|
264
264
|
return true
|
265
265
|
end
|
266
|
-
|
267
|
-
srid,g_type =
|
266
|
+
|
267
|
+
srid,g_type = is_geo_json?(v)
|
268
268
|
if(srid)
|
269
269
|
@params[:srid] = srid
|
270
270
|
@params[:geomtry_type] = g_type
|
@@ -275,9 +275,9 @@ module CitySDK
|
|
275
275
|
@params[:hasgeometry] = k
|
276
276
|
return true
|
277
277
|
end
|
278
|
-
|
278
|
+
|
279
279
|
end
|
280
|
-
|
280
|
+
|
281
281
|
hdc = k.to_s.downcase
|
282
282
|
if hdc == 'longitude' or hdc == 'lon' or hdc == 'x'
|
283
283
|
xfield=k; xs=false
|
@@ -285,7 +285,7 @@ module CitySDK
|
|
285
285
|
if hdc == 'latitude' or hdc == 'lat' or hdc == 'y'
|
286
286
|
yfield=k; ys=false
|
287
287
|
end
|
288
|
-
xfield = k if xs and (hdc =~ RE_X)
|
288
|
+
xfield = k if xs and (hdc =~ RE_X)
|
289
289
|
yfield = k if ys and (hdc =~ RE_Y)
|
290
290
|
end
|
291
291
|
end
|
@@ -305,19 +305,18 @@ module CitySDK
|
|
305
305
|
# factory = ::RGeo::Cartesian.preferred_factory()
|
306
306
|
@params[:hasgeometry] = "[#{xfield}]"
|
307
307
|
@content.each do |h|
|
308
|
-
h[:geometry] =
|
308
|
+
h[:geometry] = geom_from_text(h[:properties][:data][xfield])
|
309
309
|
h[:properties][:data].delete(xfield) if h[:geometry]
|
310
310
|
end
|
311
311
|
@params[:geomtry_type] = ''
|
312
312
|
@params[:fields].delete(xfield) if @params[:fields]
|
313
313
|
return true
|
314
314
|
end
|
315
|
-
|
316
|
-
|
315
|
+
|
317
316
|
false
|
318
317
|
end
|
319
|
-
|
320
|
-
def
|
318
|
+
|
319
|
+
def read_csv(path)
|
321
320
|
@file = path
|
322
321
|
c=''
|
323
322
|
File.open(path, "r:bom|utf-8") do |fd|
|
@@ -330,12 +329,12 @@ module CitySDK
|
|
330
329
|
c = c.force_encoding('utf-8')
|
331
330
|
c = c.gsub(/\r\n?/, "\n")
|
332
331
|
@content = []
|
333
|
-
@params[:colsep] =
|
332
|
+
@params[:colsep] = find_col_sep(StringIO.new(c)) unless @params[:colsep]
|
334
333
|
csv = CSV.new(c, :col_sep => @params[:colsep], :headers => true, :skip_blanks =>true)
|
335
334
|
csv.header_convert { |h| h.blank? ? '_' : h.strip.gsub(/\s+/,'_') }
|
336
335
|
csv.convert { |h| h ? h.strip : '' }
|
337
336
|
index = 0
|
338
|
-
begin
|
337
|
+
begin
|
339
338
|
csv.each do |row|
|
340
339
|
r = row.to_hash
|
341
340
|
h = {}
|
@@ -348,17 +347,17 @@ module CitySDK
|
|
348
347
|
rescue => e
|
349
348
|
raise CitySDK::Exception.new("Read CSV; line #{index}; #{e.message}")
|
350
349
|
end
|
351
|
-
|
350
|
+
find_geometry
|
352
351
|
end
|
353
352
|
|
354
|
-
def
|
353
|
+
def read_json(path)
|
355
354
|
@content = []
|
356
355
|
@file = path
|
357
356
|
raw = ''
|
358
357
|
File.open(path, "r:bom|utf-8") do |fd|
|
359
358
|
raw = fd.read
|
360
359
|
end
|
361
|
-
hash = CitySDK::
|
360
|
+
hash = CitySDK::parse_json(raw)
|
362
361
|
|
363
362
|
if hash.is_a?(Hash) and hash[:type] and (hash[:type] == 'FeatureCollection')
|
364
363
|
# GeoJSON
|
@@ -382,44 +381,43 @@ module CitySDK
|
|
382
381
|
end
|
383
382
|
end
|
384
383
|
end
|
385
|
-
|
384
|
+
|
386
385
|
if val
|
387
386
|
val.each do |h|
|
388
387
|
@content << { :properties => {:data => h} }
|
389
388
|
end
|
390
389
|
end
|
391
|
-
|
390
|
+
find_geometry
|
392
391
|
end
|
393
392
|
end
|
394
393
|
|
395
|
-
def
|
394
|
+
def srid_from_prj(str)
|
396
395
|
begin
|
397
396
|
connection = Faraday.new :url => "http://prj2epsg.org"
|
398
397
|
resp = connection.get('/search.json', {:mode => 'wkt', :terms => str})
|
399
|
-
if resp.status.between?(200, 299)
|
400
|
-
resp = CitySDK::
|
398
|
+
if resp.status.between?(200, 299)
|
399
|
+
resp = CitySDK::parse_json resp.body
|
401
400
|
@params[:srid] = resp[:codes][0][:code].to_i
|
402
401
|
end
|
403
402
|
rescue
|
404
403
|
end
|
405
404
|
end
|
406
405
|
|
407
|
-
def
|
408
|
-
|
406
|
+
def read_shapefile(path)
|
407
|
+
|
409
408
|
@content = []
|
410
409
|
@file = path
|
411
|
-
|
410
|
+
|
412
411
|
prj = path.gsub(/.shp$/i,"") + '.prj'
|
413
412
|
prj = File.exists?(prj) ? File.read(prj) : nil
|
414
|
-
|
415
|
-
|
413
|
+
srid_from_prj(prj) if (prj and @params[:srid].nil?)
|
414
|
+
|
416
415
|
@params[:hasgeometry] = 'ESRI Shape'
|
417
|
-
|
418
|
-
|
416
|
+
|
419
417
|
GeoRuby::Shp4r::ShpFile.open(path) do |shp|
|
420
418
|
shp.each do |shape|
|
421
419
|
h = {}
|
422
|
-
h[:geometry] = CitySDK::
|
420
|
+
h[:geometry] = CitySDK::parse_json(shape.geometry.to_json) #a GeoRuby SimpleFeature
|
423
421
|
h[:properties] = {:data => {}}
|
424
422
|
att_data = shape.data #a Hash
|
425
423
|
shp.fields.each do |field|
|
@@ -431,17 +429,17 @@ module CitySDK
|
|
431
429
|
end
|
432
430
|
end
|
433
431
|
end
|
434
|
-
|
435
|
-
def
|
432
|
+
|
433
|
+
def read_csdk(path)
|
436
434
|
h = Marshal.load(File.read(path))
|
437
435
|
@params = h[:config]
|
438
436
|
@content = h[:content]
|
439
|
-
end
|
440
|
-
|
441
|
-
def
|
442
|
-
begin
|
443
|
-
Dir.mktmpdir("cdkfi_#{File.basename(path).gsub(/\A/,'')}") do |dir|
|
444
|
-
raise CitySDK::Exception.new("Error unzipping #{path}.", {:originalfile => path}, __FILE__,__LINE__) if not system "unzip '#{path}' -d '#{dir}' > /dev/null 2>&1"
|
437
|
+
end
|
438
|
+
|
439
|
+
def read_zip(path)
|
440
|
+
begin
|
441
|
+
Dir.mktmpdir("cdkfi_#{File.basename(path).gsub(/\A/,'')}") do |dir|
|
442
|
+
raise CitySDK::Exception.new("Error unzipping #{path}.", {:originalfile => path}, __FILE__, __LINE__) if not system "unzip '#{path}' -d '#{dir}' > /dev/null 2>&1"
|
445
443
|
if File.directory?(dir + '/' + File.basename(path).chomp(File.extname(path)))
|
446
444
|
dir = dir + '/' + File.basename(path).chomp(File.extname(path) )
|
447
445
|
end
|
@@ -449,21 +447,21 @@ module CitySDK
|
|
449
447
|
next if f =~ /^\./
|
450
448
|
case File.extname(f)
|
451
449
|
when /\.(geo)?json/i
|
452
|
-
|
450
|
+
read_json(dir+'/'+f)
|
453
451
|
return
|
454
452
|
when /\.shp/i
|
455
|
-
|
453
|
+
read_shapefile(dir+'/'+f)
|
456
454
|
return
|
457
455
|
when /\.csv|tsv/i
|
458
|
-
|
456
|
+
read_csv(dir+'/'+f)
|
459
457
|
return
|
460
458
|
end
|
461
459
|
end
|
462
460
|
end
|
463
461
|
rescue Exception => e
|
464
|
-
raise CitySDK::Exception.new(e.message, {:originalfile => path}, __FILE__,__LINE__)
|
462
|
+
raise CitySDK::Exception.new(e.message, {:originalfile => path}, __FILE__, __LINE__)
|
465
463
|
end
|
466
|
-
raise CitySDK::Exception.new("Could not proecess file #{path}", {:originalfile => path}, __FILE__,__LINE__)
|
464
|
+
raise CitySDK::Exception.new("Could not proecess file #{path}", {:originalfile => path}, __FILE__, __LINE__)
|
467
465
|
end
|
468
466
|
|
469
467
|
def write(path=nil)
|
@@ -480,6 +478,6 @@ module CitySDK
|
|
480
478
|
end
|
481
479
|
|
482
480
|
end
|
483
|
-
|
481
|
+
|
484
482
|
end
|
485
483
|
|
data/lib/citysdk/importer.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
|
2
2
|
module CitySDK
|
3
|
-
|
3
|
+
|
4
4
|
class Importer
|
5
5
|
attr_reader :filereader, :api, :params
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(pars, fr = nil)
|
8
8
|
@params = pars
|
9
|
-
|
9
|
+
|
10
10
|
raise Exception.new("Missing :host in Importer parameters.") if @params[:host].nil?
|
11
|
-
raise Exception.new("Missing :
|
11
|
+
raise Exception.new("Missing :layer in Importer parameters.") if @params[:layer].nil?
|
12
12
|
raise Exception.new("Missing :file_path in Importer parameters.") if @params[:file_path].nil?
|
13
13
|
|
14
14
|
@api = CitySDK::API.new(@params[:host])
|
@@ -20,16 +20,16 @@ module CitySDK
|
|
20
20
|
|
21
21
|
@params[:addresslayer] = 'bag.vbo' if @params[:addressleyer].nil?
|
22
22
|
@params[:addressfield] = 'postcode_huisnummer' if @params[:addressfield].nil?
|
23
|
-
|
23
|
+
|
24
24
|
@filereader = fr || FileReader.new(@params)
|
25
25
|
end
|
26
|
-
|
27
|
-
|
26
|
+
|
27
|
+
|
28
28
|
def write(path)
|
29
29
|
return @filereader.write(path)
|
30
30
|
end
|
31
|
-
|
32
|
-
def
|
31
|
+
|
32
|
+
def set_parameterr(k,v)
|
33
33
|
begin
|
34
34
|
@params[(k.to_sym rescue k) || k] = v
|
35
35
|
return true
|
@@ -42,7 +42,7 @@ module CitySDK
|
|
42
42
|
begin
|
43
43
|
sign_out if @signed_in
|
44
44
|
@api.set_host(@params[:host])
|
45
|
-
@api.set_layer(@params[:
|
45
|
+
@api.set_layer(@params[:layer])
|
46
46
|
@api.authenticate(@params[:name],@params[:password])
|
47
47
|
@signed_in = true
|
48
48
|
rescue => e
|
@@ -56,65 +56,58 @@ module CitySDK
|
|
56
56
|
@signed_in = false
|
57
57
|
return @api.release
|
58
58
|
end
|
59
|
-
|
60
|
-
def
|
59
|
+
|
60
|
+
def filter_fields(h)
|
61
61
|
data = {}
|
62
62
|
h.each_key do |k|
|
63
63
|
k = (k.to_sym rescue k) || k
|
64
64
|
j = @params[:alternate_fields][k]
|
65
|
-
data[j] = h[k] if @params[:fields].include?(k)
|
65
|
+
data[j] = h[k] if @params[:fields].include?(k) and j
|
66
66
|
end
|
67
67
|
data
|
68
68
|
end
|
69
|
-
|
70
|
-
|
71
|
-
def geomToJSON(a)
|
72
|
-
# puts JSON.pretty_generate(a)
|
73
|
-
a
|
74
|
-
end
|
75
|
-
|
76
|
-
def doImport(&block)
|
69
|
+
|
70
|
+
def do_import(&block)
|
77
71
|
result = {
|
78
|
-
:
|
79
|
-
:
|
72
|
+
created: 0,
|
73
|
+
not_added: 0
|
80
74
|
}
|
81
|
-
|
75
|
+
|
82
76
|
failed = nil
|
83
|
-
|
84
|
-
# if @params[:hasaddress] == 'certain'
|
85
|
-
# failed = addToAddress(&block)
|
86
|
-
# end
|
87
|
-
|
77
|
+
|
88
78
|
# TODO: add possibility to add node to postal code
|
79
|
+
# if @params[:hasaddress] == 'certain'
|
80
|
+
# failed = add_to_address(&block)
|
81
|
+
# end
|
89
82
|
|
90
83
|
if failed == []
|
91
84
|
result[:updated] += @filereader.content.length
|
92
85
|
return result
|
93
86
|
end
|
94
|
-
|
95
|
-
if failed
|
87
|
+
|
88
|
+
if failed
|
96
89
|
result[:updated] += (@filereader.content.length - failed.length)
|
97
90
|
end
|
98
|
-
|
91
|
+
|
99
92
|
objects = failed || @filereader.content
|
100
93
|
count = objects.length
|
101
94
|
|
102
95
|
begin
|
103
96
|
sign_in
|
104
|
-
|
97
|
+
|
105
98
|
if @params[:hasgeometry]
|
106
99
|
begin
|
107
100
|
objects.each do |record|
|
108
|
-
|
101
|
+
|
109
102
|
node = {
|
110
103
|
type: 'Feature',
|
111
104
|
properties: record[:properties],
|
112
|
-
geometry:
|
105
|
+
geometry: record[:geometry],
|
113
106
|
}
|
114
|
-
|
115
|
-
node[:properties][:data] =
|
107
|
+
|
108
|
+
node[:properties][:data] = filter_fields(record[:properties][:data])
|
116
109
|
node[:crs] = { type: 'EPSG', properties: { code: @params[:srid] } } if @params[:srid] != 4326
|
117
|
-
|
110
|
+
|
118
111
|
node[:properties][:title] = node[:properties][:data][@params[:title]] if @params[:title]
|
119
112
|
|
120
113
|
yield(node[:properties]) if block_given?
|
@@ -139,7 +132,7 @@ module CitySDK
|
|
139
132
|
return result
|
140
133
|
end
|
141
134
|
|
142
|
-
def
|
135
|
+
def add_to_address()
|
143
136
|
failed = []
|
144
137
|
if @params[:postcode] and @params[:housenumber]
|
145
138
|
begin
|
@@ -160,8 +153,8 @@ module CitySDK
|
|
160
153
|
qres[:status]='nix'
|
161
154
|
end
|
162
155
|
if qres[:status]=='success' and qres[:results] and qres[:results][0]
|
163
|
-
url = '/' + qres[:results][0][:cdk_id] + '/' + @params[:
|
164
|
-
data =
|
156
|
+
url = '/' + qres[:results][0][:cdk_id] + '/' + @params[:layer]
|
157
|
+
data = filter_fields(row)
|
165
158
|
yield({addto: qres[:results][0][:cdk_id], data: data}) if block_given?
|
166
159
|
n = @api.put(url,{'data'=>data})
|
167
160
|
else
|
data/lib/citysdk/util.rb
CHANGED
@@ -21,13 +21,12 @@ end
|
|
21
21
|
|
22
22
|
|
23
23
|
module CitySDK
|
24
|
-
|
24
|
+
|
25
25
|
# for debugging purposes...
|
26
26
|
def jsonlog(o)
|
27
27
|
puts JSON.pretty_generate({ o.class.to_s => o })
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
30
|
class Exception < ::Exception
|
32
31
|
def initialize(message,parms=nil,srcfile=nil,srcline=nil)
|
33
32
|
if parms and srcfile and srcline
|
@@ -41,11 +40,11 @@ module CitySDK
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
|
-
def self.
|
43
|
+
def self.parse_json(str)
|
45
44
|
begin
|
46
|
-
return
|
45
|
+
return str.blank? ? {} : JSON.parse(str, symbolize_names: true)
|
47
46
|
rescue Exception => e
|
48
|
-
raise CitySDK::Exception.new("#{e.message}; input: #{
|
47
|
+
raise CitySDK::Exception.new("#{e.message}; input: #{str}")
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
data/lib/citysdk.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative './citysdk/util.rb'
|
2
|
+
require_relative './citysdk/api.rb'
|
3
|
+
require_relative './citysdk/file_reader.rb'
|
4
|
+
require_relative './citysdk/importer.rb'
|
5
5
|
|
6
6
|
module CitySDK
|
7
|
-
VERSION =
|
7
|
+
VERSION = '1.0.2'
|
8
8
|
end
|
9
|
-
|
data/spec/api_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
|
2
|
-
|
3
2
|
module CitySDK
|
4
3
|
TEST_HOST = 'localhost:9292'
|
5
4
|
# TEST_HOST = 'test-api.citysdk.waag.org'
|
@@ -20,14 +19,11 @@ module CitySDK
|
|
20
19
|
licence: "CC0",
|
21
20
|
fields: []
|
22
21
|
}
|
23
|
-
|
22
|
+
|
24
23
|
$api = API.new(TEST_HOST)
|
25
24
|
|
26
|
-
|
27
|
-
|
28
25
|
describe API do
|
29
26
|
|
30
|
-
|
31
27
|
it "can be connected to" do
|
32
28
|
expect($api.class).to be(CitySDK::API)
|
33
29
|
end
|
@@ -67,5 +63,5 @@ module CitySDK
|
|
67
63
|
end
|
68
64
|
|
69
65
|
end
|
70
|
-
|
66
|
+
|
71
67
|
end
|
data/spec/import_spec.rb
CHANGED
@@ -7,7 +7,7 @@ module CitySDK
|
|
7
7
|
def newImporter(f)
|
8
8
|
@importer = Importer.new({
|
9
9
|
file_path: f,
|
10
|
-
host: TEST_HOST,
|
10
|
+
host: TEST_HOST,
|
11
11
|
layername: TEST_LAYER[:name]
|
12
12
|
})
|
13
13
|
end
|
@@ -30,9 +30,9 @@ module CitySDK
|
|
30
30
|
it "can make a layer and delete" do
|
31
31
|
|
32
32
|
newImporter('./spec/files/hotels.csv')
|
33
|
-
|
34
|
-
@importer.
|
35
|
-
@importer.
|
33
|
+
|
34
|
+
@importer.set_parameter(:name,TEST_USER)
|
35
|
+
@importer.set_parameter(:password,TEST_PASS)
|
36
36
|
@importer.sign_in
|
37
37
|
res = @importer.api.post('/layers',TEST_LAYER)
|
38
38
|
expect( (!!res[:features] and res[:features].length == 1) ).to be(true)
|
@@ -43,18 +43,18 @@ module CitySDK
|
|
43
43
|
res = @importer.api.get("/layers/test.rspec/objects")
|
44
44
|
expect( (!!res[:features] and res[:features].length == 0) ).to be(true)
|
45
45
|
|
46
|
-
@importer.api.authenticate(TEST_USER,TEST_PASS) do
|
46
|
+
@importer.api.authenticate(TEST_USER,TEST_PASS) do
|
47
47
|
expect( @importer.api.delete("/layers/#{TEST_LAYER[:name]}") ).to eq({})
|
48
48
|
end
|
49
49
|
|
50
50
|
end
|
51
51
|
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
describe "FileReader" do
|
55
55
|
|
56
56
|
it "can parse json" do
|
57
|
-
j = CitySDK::
|
57
|
+
j = CitySDK::parse_json('{ "arr" : [0,1,1,1], "hash": {"aap": "noot"}, "num": 0 }')
|
58
58
|
expect(j[:arr].length).to be(4)
|
59
59
|
expect(j[:num].class).to be(Fixnum)
|
60
60
|
expect(j[:hash][:aap]).to eq("noot")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: citysdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Demeyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dbf
|
@@ -98,7 +98,7 @@ description: Encapsulates the CitySDK api.
|
|
98
98
|
email:
|
99
99
|
- tom@waag.org
|
100
100
|
executables:
|
101
|
-
-
|
101
|
+
- citysdk-cli
|
102
102
|
extensions: []
|
103
103
|
extra_rdoc_files: []
|
104
104
|
files:
|
@@ -108,9 +108,8 @@ files:
|
|
108
108
|
- LICENSE.txt
|
109
109
|
- README.md
|
110
110
|
- Rakefile
|
111
|
-
- bin/
|
111
|
+
- bin/citysdk-cli
|
112
112
|
- citysdk.gemspec
|
113
|
-
- examples/simple_api.rb
|
114
113
|
- lib/citysdk.rb
|
115
114
|
- lib/citysdk/api.rb
|
116
115
|
- lib/citysdk/file_reader.rb
|
data/examples/simple_api.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# check the wiki for detailed api usage: https://github.com/waagsociety/citysdk-ld/wiki
|
4
|
-
|
5
|
-
require 'citysdk'
|
6
|
-
include CitySDK
|
7
|
-
|
8
|
-
api = API.new('api.citysdk.waag.org') # point to a hosted instance of the api.
|
9
|
-
|
10
|
-
# simple GET
|
11
|
-
# GET requests do not need authentication
|
12
|
-
|
13
|
-
endpoint = api.get '/'
|
14
|
-
puts "Enpoint is: #{endpoint[:features][0][:properties][:title]}."
|
15
|
-
|
16
|
-
first10layers = api.get('/layers')
|
17
|
-
puts "First layer: #{JSON.pretty_generate(first10layers[:features][0])}"
|
18
|
-
|
19
|
-
# find out how many owners the endpoint knows
|
20
|
-
owners = api.get('/owners?per_page=1&count')
|
21
|
-
puts "Number of data maintaners: #{api.last_result[:headers]['x-result-count']}"
|
22
|
-
|
23
|
-
# authenticate for write actions.
|
24
|
-
unless api.authenticate('<name>','<passw>')
|
25
|
-
puts "Did not authenticate..."
|
26
|
-
exit
|
27
|
-
end
|
28
|
-
|
29
|
-
# make a layer
|
30
|
-
# everybody can wite to the temporary 'test' domain:
|
31
|
-
|
32
|
-
layer = {
|
33
|
-
name: "test.cities",
|
34
|
-
owner: "citysdk",
|
35
|
-
title: "Cities: 🏠🏢🏣🏨🏫🏬🏭🏡",
|
36
|
-
description: "Cities big and small.",
|
37
|
-
data_sources: [ "http://fantasy.com" ],
|
38
|
-
authoritative: false,
|
39
|
-
rdf_type: "dbp:City",
|
40
|
-
category: "administrative",
|
41
|
-
subcategory: "cities",
|
42
|
-
licence: "CC0"
|
43
|
-
}
|
44
|
-
|
45
|
-
api.post('/layers',layer)
|
46
|
-
|
47
|
-
# add data to this layer
|
48
|
-
# attach to the node representing the city of Rotterdam
|
49
|
-
object = {type: "Feature",
|
50
|
-
geometry: {
|
51
|
-
type: 'Point',
|
52
|
-
coordinates: [4.4646,51.9222] },
|
53
|
-
properties: {
|
54
|
-
id: 'Rotterdam',
|
55
|
-
title: 'Rotterdam',
|
56
|
-
data: {
|
57
|
-
a: 1,
|
58
|
-
b: 2
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
api.post('/layers/test.cities/objects', object)
|
64
|
-
|
65
|
-
|
66
|
-
# don't forget to release! this will also send 'unfilled' batches to the backend.
|
67
|
-
api.release
|
68
|
-
|