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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fd2afe55971d61fbecb78c89d4a828a93adc22f
4
- data.tar.gz: fcf46e34bf468cad4b75325172587dfab8bc2a63
3
+ metadata.gz: 470ce38f410d78f4caf61b12f9a26a7e42f8fab9
4
+ data.tar.gz: 67fb900ec6bdf7a09db87fb81e4f808fe037b676
5
5
  SHA512:
6
- metadata.gz: cdc4b57532d758e9f794d836db960f95c6868a88281f129c14884b555654e540fd6cbeb79641d93ec80ec9f428ac69ae4f870a14d8b3ac3b4bb39bbf3e1633e3
7
- data.tar.gz: fc6897d281e7beed34b6e35578177691979f559d3d79beee149c045c253ba7543f2f4768217ba860f35c34cfb12fca24a7a660ab85e7eb3081a26511bee16006
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-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).
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 GEM to import files into the CitySDK LD-API, have a look at the 'admr' importer for the top-level administrative regions in the Netherlands.
8
- The data consists of three ESRI shape files; the importer is well commented, explaining most of the possibilities of the GEM.
9
- Please download the importer [here](https://github.com/waagsociety/citysdk-amsterdam/tree/master/importers/admr)
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
- 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.
26
- The gem exposes it's functionality through three different objects:
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 ruby Hash.
45
- `@api.put path,data` | PUT a resource; see [Documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
46
- `@api.post path,data` | POST a resource; see [Documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
47
- `@api.patch path,data` | PATCH a resource; see [Documentation](https://github.com/waagsociety/citysdk-ld/wiki/Objects)
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, below.
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 (Geo)JSON and (Geo)JSON-LD.
57
- `@api.page_size = <page_size>` | Specify the number of features returned; default is 25.
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
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 :page_size
13
+ attr_accessor :per_page
22
14
  attr_accessor :format
23
15
 
24
- @@create_tpl = {
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
- @page_size = 25;
20
+ @per_page = 25;
34
21
  @format = 'jsonld'
35
22
  @updated = @created = 0;
36
- set_host(host,port)
23
+ set_host(host)
37
24
  end
38
-
39
- def authenticate(n,p)
40
- @name = n;
41
- @passw = p;
42
25
 
43
- resp = @connection.get '/session', { :name => @name, :password => @passw }
44
- if resp.status.between?(200, 299)
45
- resp = CitySDK::parseJson(resp.body)
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("Invalid credentials")
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,port=nil)
65
- @host = host
66
- @port = port
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 :url => "http://#{@host}:#{@port}"
55
+ @connection = Faraday.new url: host
83
56
  end
57
+
84
58
  @connection.headers = {
85
- :user_agent => 'CitySDK_API GEM ' + CitySDK::VERSION,
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 api @ #{host}")
65
+ raise CitySDK::Exception.new("Trouble connecting to API @ #{host}")
92
66
  end
93
- @create = @@create_tpl
67
+ @create = {
68
+ type: "FeatureCollection",
69
+ features: []
70
+ }
94
71
  end
95
-
96
- def addFormat(path)
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=#{@page_size}"
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
- create_flush # send any remaining entries in the create buffer
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::parseJson(resp.body)[:error]
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
- if authorized?
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
- File.open(File.expand_path("~/post_error_data.json"),"w") do |fd|
173
- fd.write(JSON.pretty_generate({error: @error, data: data}))
174
- end
130
+ def post(path, data)
131
+ write :post, path, data
132
+ end
175
133
 
176
- raise HostException.new(@error)
177
- end
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 patch(path,data)
182
- if authorized?
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 put(path,data)
193
- if authorized?
194
- resp = @connection.put(addFormat(path),data.to_json)
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
- return CitySDK::parseJson(resp.body) if resp.status.between?(200, 299)
197
- @error = CitySDK::parseJson(resp.body)[:error] || {status: resp.status}
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("PUT needs authorization.")
160
+ raise CitySDK::Exception.new("#{method.upcase} needs authorization")
201
161
  end
202
162
 
203
163
  def get(path)
204
- resp = @connection.get(addFormat(path))
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::parseJson(resp.body) if resp.status.between?(200, 299)
208
- @error = CitySDK::parseJson(resp.body)[:error]
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
-
@@ -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
- readCsdk(file_path)
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
- readZip(file_path)
29
+ read_zip(file_path)
30
30
  when /\.(geo)?json/i
31
- readJSON(file_path)
31
+ read_json(file_path)
32
32
  when /\.shp/i
33
- readShape(file_path)
33
+ read_shapefile(file_path)
34
34
  when /\.csv|tsv/i
35
- readCsv(file_path)
35
+ read_csv(file_path)
36
36
  when /\.csdk/i
37
- readCsdk(file_path)
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
- getFields unless @params[:fields]
45
- guessName unless @params[:name]
46
- guessSRID unless @params[:srid]
47
- findUniqueField unless @params[:unique_id]
48
- getAddress unless @params[:hasaddress]
49
- setId_Name
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 getAddress
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 setId_Name
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 findUniqueField
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 guessName
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 getFields
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 guessSRID
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 findColSep(f)
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 isWkbGeometry(s)
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 isWktGeometry(s)
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 isGeoJSON(s)
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 geomFromText(coords)
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 findGeometry(xfield=nil, yfield=nil)
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 = isWkbGeometry(v)
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 = isWkbGeometry(h[:properties][:data][k])
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 = isWktGeometry(v)
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 = isWktGeometry(h[:properties][:data][k])
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 = isGeoJSON(v)
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] = geomFromText(h[:properties][:data][xfield])
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 readCsv(path)
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] = findColSep(StringIO.new(c)) unless @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
- findGeometry
350
+ find_geometry
352
351
  end
353
352
 
354
- def readJSON(path)
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::parseJson(raw)
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
- findGeometry
390
+ find_geometry
392
391
  end
393
392
  end
394
393
 
395
- def sridFromPrj(str)
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::parseJson resp.body
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 readShape(path)
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
- sridFromPrj(prj) if (prj and @params[:srid].nil?)
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::parseJson(shape.geometry.to_json) #a GeoRuby SimpleFeature
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 readCsdk(path)
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 readZip(path)
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
- readJSON(dir+'/'+f)
450
+ read_json(dir+'/'+f)
453
451
  return
454
452
  when /\.shp/i
455
- readShape(dir+'/'+f)
453
+ read_shapefile(dir+'/'+f)
456
454
  return
457
455
  when /\.csv|tsv/i
458
- readCsv(dir+'/'+f)
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
 
@@ -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 :layername in Importer parameters.") if @params[:layername].nil?
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 setParameter(k,v)
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[:layername])
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 filterFields(h)
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
- :created => 0,
79
- :not_added => 0
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: geomToJSON(record[:geometry]),
105
+ geometry: record[:geometry],
113
106
  }
114
-
115
- node[:properties][:data] = filterFields(record[: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 addToAddress()
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[:layername]
164
- data = filterFields(row)
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.parseJson(jsonstring)
43
+ def self.parse_json(str)
45
44
  begin
46
- return jsonstring.blank? ? {} : JSON.parse(jsonstring,symbolize_names: true)
45
+ return str.blank? ? {} : JSON.parse(str, symbolize_names: true)
47
46
  rescue Exception => e
48
- raise CitySDK::Exception.new("#{e.message}; input: #{jsonstring}")
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
- require 'citysdk/util.rb'
2
- require 'citysdk/api.rb'
3
- require 'citysdk/file_reader.rb'
4
- require 'citysdk/importer.rb'
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 = "1.0.1"
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.setParameter(:name,TEST_USER)
35
- @importer.setParameter(:password,TEST_PASS)
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::parseJson('{ "arr" : [0,1,1,1], "hash": {"aap": "noot"}, "num": 0 }')
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.1
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-24 00:00:00.000000000 Z
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
- - csdk
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/csdk
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
@@ -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
-